at 25.11-pre 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 ]; 281 282 ###### interface 283 284 options = { 285 286 services.xserver = { 287 288 enable = mkOption { 289 type = types.bool; 290 default = false; 291 description = '' 292 Whether to enable the X server. 293 ''; 294 }; 295 296 autorun = mkOption { 297 type = types.bool; 298 default = true; 299 description = '' 300 Whether to start the X server automatically. 301 ''; 302 }; 303 304 excludePackages = mkOption { 305 default = [ ]; 306 example = literalExpression "[ pkgs.xterm ]"; 307 type = types.listOf types.package; 308 description = "Which X11 packages to exclude from the default environment"; 309 }; 310 311 exportConfiguration = mkOption { 312 type = types.bool; 313 default = false; 314 description = '' 315 Whether to symlink the X server configuration under 316 {file}`/etc/X11/xorg.conf`. 317 ''; 318 }; 319 320 enableTCP = mkOption { 321 type = types.bool; 322 default = false; 323 description = '' 324 Whether to allow the X server to accept TCP connections. 325 ''; 326 }; 327 328 autoRepeatDelay = mkOption { 329 type = types.nullOr types.int; 330 default = null; 331 description = '' 332 Sets the autorepeat delay (length of time in milliseconds that a key must be depressed before autorepeat starts). 333 ''; 334 }; 335 336 autoRepeatInterval = mkOption { 337 type = types.nullOr types.int; 338 default = null; 339 description = '' 340 Sets the autorepeat interval (length of time in milliseconds that should elapse between autorepeat-generated keystrokes). 341 ''; 342 }; 343 344 inputClassSections = mkOption { 345 type = types.listOf types.lines; 346 default = [ ]; 347 example = literalExpression '' 348 [ ''' 349 Identifier "Trackpoint Wheel Emulation" 350 MatchProduct "ThinkPad USB Keyboard with TrackPoint" 351 Option "EmulateWheel" "true" 352 Option "EmulateWheelButton" "2" 353 Option "Emulate3Buttons" "false" 354 ''' 355 ] 356 ''; 357 description = "Content of additional InputClass sections of the X server configuration file."; 358 }; 359 360 modules = mkOption { 361 type = types.listOf types.path; 362 default = [ ]; 363 example = literalExpression "[ pkgs.xf86_input_wacom ]"; 364 description = "Packages to be added to the module search path of the X server."; 365 }; 366 367 resolutions = mkOption { 368 type = types.listOf types.attrs; 369 default = [ ]; 370 example = [ 371 { 372 x = 1600; 373 y = 1200; 374 } 375 { 376 x = 1024; 377 y = 786; 378 } 379 ]; 380 description = '' 381 The screen resolutions for the X server. The first element 382 is the default resolution. If this list is empty, the X 383 server will automatically configure the resolution. 384 ''; 385 }; 386 387 videoDrivers = mkOption { 388 type = types.listOf types.str; 389 default = [ 390 "modesetting" 391 "fbdev" 392 ]; 393 example = [ 394 "nvidia" 395 "amdgpu" 396 ]; 397 # TODO(@oxij): think how to easily add the rest, like those nvidia things 398 relatedPackages = concatLists ( 399 mapAttrsToList ( 400 n: v: 401 optional (hasPrefix "xf86video" n) { 402 path = [ 403 "xorg" 404 n 405 ]; 406 title = removePrefix "xf86video" n; 407 } 408 ) pkgs.xorg 409 ); 410 description = '' 411 The names of the video drivers the configuration 412 supports. They will be tried in order until one that 413 supports your card is found. 414 Don't combine those with "incompatible" OpenGL implementations, 415 e.g. free ones (mesa-based) with proprietary ones. 416 417 For unfree "nvidia*", the supported GPU lists are on 418 https://www.nvidia.com/object/unix.html 419 ''; 420 }; 421 422 videoDriver = mkOption { 423 type = types.nullOr types.str; 424 default = null; 425 example = "i810"; 426 description = '' 427 The name of the video driver for your graphics card. This 428 option is obsolete; please set the 429 {option}`services.xserver.videoDrivers` instead. 430 ''; 431 }; 432 433 drivers = mkOption { 434 type = types.listOf types.attrs; 435 internal = true; 436 description = '' 437 A list of attribute sets specifying drivers to be loaded by 438 the X11 server. 439 ''; 440 }; 441 442 dpi = mkOption { 443 type = types.nullOr types.int; 444 default = null; 445 description = '' 446 Force global DPI resolution to use for X server. It's recommended to 447 use this only when DPI is detected incorrectly; also consider using 448 `Monitor` section in configuration file instead. 449 ''; 450 }; 451 452 updateDbusEnvironment = mkOption { 453 type = types.bool; 454 default = false; 455 description = '' 456 Whether to update the DBus activation environment after launching the 457 desktop manager. 458 ''; 459 }; 460 461 xkb = { 462 layout = mkOption { 463 type = types.str; 464 default = "us"; 465 description = '' 466 X keyboard layout, or multiple keyboard layouts separated by commas. 467 ''; 468 }; 469 470 model = mkOption { 471 type = types.str; 472 default = "pc104"; 473 example = "presario"; 474 description = '' 475 X keyboard model. 476 ''; 477 }; 478 479 options = mkOption { 480 type = types.commas; 481 default = "terminate:ctrl_alt_bksp"; 482 example = "grp:caps_toggle,grp_led:scroll"; 483 description = '' 484 X keyboard options; layout switching goes here. 485 ''; 486 }; 487 488 variant = mkOption { 489 type = types.str; 490 default = ""; 491 example = "colemak"; 492 description = '' 493 X keyboard variant. 494 ''; 495 }; 496 497 dir = mkOption { 498 type = types.path; 499 default = "${pkgs.xkeyboard_config}/etc/X11/xkb"; 500 defaultText = literalExpression ''"''${pkgs.xkeyboard_config}/etc/X11/xkb"''; 501 description = '' 502 Path used for -xkbdir xserver parameter. 503 ''; 504 }; 505 }; 506 507 config = mkOption { 508 type = types.lines; 509 description = '' 510 The contents of the configuration file of the X server 511 ({file}`xorg.conf`). 512 513 This option is set by multiple modules, and the configs are 514 concatenated together. 515 516 In Xorg configs the last config entries take precedence, 517 so you may want to use `lib.mkAfter` on this option 518 to override NixOS's defaults. 519 ''; 520 }; 521 522 filesSection = mkOption { 523 type = types.lines; 524 default = ""; 525 example = ''FontPath "/path/to/my/fonts"''; 526 description = "Contents of the first `Files` section of the X server configuration file."; 527 }; 528 529 deviceSection = mkOption { 530 type = types.lines; 531 default = ""; 532 example = "VideoRAM 131072"; 533 description = "Contents of the first Device section of the X server configuration file."; 534 }; 535 536 screenSection = mkOption { 537 type = types.lines; 538 default = ""; 539 example = '' 540 Option "RandRRotation" "on" 541 ''; 542 description = "Contents of the first Screen section of the X server configuration file."; 543 }; 544 545 monitorSection = mkOption { 546 type = types.lines; 547 default = ""; 548 example = "HorizSync 28-49"; 549 description = "Contents of the first Monitor section of the X server configuration file."; 550 }; 551 552 enableTearFree = mkEnableOption "the TearFree option in the first Device section"; 553 554 extraConfig = mkOption { 555 type = types.lines; 556 default = ""; 557 description = "Additional contents (sections) included in the X server configuration file"; 558 }; 559 560 xrandrHeads = mkOption { 561 default = [ ]; 562 example = [ 563 "HDMI-0" 564 { 565 output = "DVI-0"; 566 primary = true; 567 } 568 { 569 output = "DVI-1"; 570 monitorConfig = "Option \"Rotate\" \"left\""; 571 } 572 ]; 573 type = 574 with types; 575 listOf ( 576 coercedTo str 577 (output: { 578 inherit output; 579 }) 580 (submodule { 581 options = xrandrOptions; 582 }) 583 ); 584 # Set primary to true for the first head if no other has been set 585 # primary already. 586 apply = 587 heads: 588 let 589 hasPrimary = any (x: x.primary) heads; 590 firstPrimary = head heads // { 591 primary = true; 592 }; 593 newHeads = singleton firstPrimary ++ tail heads; 594 in 595 if heads != [ ] && !hasPrimary then newHeads else heads; 596 description = '' 597 Multiple monitor configuration, just specify a list of XRandR 598 outputs. The individual elements should be either simple strings or 599 an attribute set of output options. 600 601 If the element is a string, it is denoting the physical output for a 602 monitor, if it's an attribute set, you must at least provide the 603 {option}`output` option. 604 605 The monitors will be mapped from left to right in the order of the 606 list. 607 608 By default, the first monitor will be set as the primary monitor if 609 none of the elements contain an option that has set 610 {option}`primary` to `true`. 611 612 ::: {.note} 613 Only one monitor is allowed to be primary. 614 ::: 615 616 Be careful using this option with multiple graphic adapters or with 617 drivers that have poor support for XRandR, unexpected things might 618 happen with those. 619 ''; 620 }; 621 622 serverFlagsSection = mkOption { 623 default = ""; 624 type = types.lines; 625 example = '' 626 Option "BlankTime" "0" 627 Option "StandbyTime" "0" 628 Option "SuspendTime" "0" 629 Option "OffTime" "0" 630 ''; 631 description = "Contents of the ServerFlags section of the X server configuration file."; 632 }; 633 634 moduleSection = mkOption { 635 type = types.lines; 636 default = ""; 637 example = '' 638 SubSection "extmod" 639 EndSubsection 640 ''; 641 description = "Contents of the Module section of the X server configuration file."; 642 }; 643 644 serverLayoutSection = mkOption { 645 type = types.lines; 646 default = ""; 647 example = '' 648 Option "AIGLX" "true" 649 ''; 650 description = "Contents of the ServerLayout section of the X server configuration file."; 651 }; 652 653 extraDisplaySettings = mkOption { 654 type = types.lines; 655 default = ""; 656 example = "Virtual 2048 2048"; 657 description = "Lines to be added to every Display subsection of the Screen section."; 658 }; 659 660 defaultDepth = mkOption { 661 type = types.int; 662 default = 0; 663 example = 8; 664 description = "Default colour depth."; 665 }; 666 667 fontPath = mkOption { 668 type = types.nullOr types.str; 669 default = null; 670 example = "unix/:7100"; 671 description = '' 672 Set the X server FontPath. Defaults to null, which 673 means the compiled in defaults will be used. See 674 man xorg.conf for details. 675 ''; 676 }; 677 678 tty = mkOption { 679 type = types.nullOr types.int; 680 default = 7; 681 description = "Virtual console for the X server."; 682 }; 683 684 display = mkOption { 685 type = types.nullOr types.int; 686 default = 0; 687 description = "Display number for the X server."; 688 }; 689 690 virtualScreen = mkOption { 691 type = types.nullOr types.attrs; 692 default = null; 693 example = { 694 x = 2048; 695 y = 2048; 696 }; 697 description = '' 698 Virtual screen size for Xrandr. 699 ''; 700 }; 701 702 logFile = mkOption { 703 type = types.nullOr types.str; 704 default = "/dev/null"; 705 example = "/var/log/Xorg.0.log"; 706 description = '' 707 Controls the file Xorg logs to. 708 709 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. 710 711 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`). 712 ''; 713 }; 714 715 verbose = mkOption { 716 type = types.nullOr types.int; 717 default = 3; 718 example = 7; 719 description = '' 720 Controls verbosity of X logging. 721 ''; 722 }; 723 724 enableCtrlAltBackspace = mkOption { 725 type = types.bool; 726 default = false; 727 description = '' 728 Whether to enable the DontZap option, which binds Ctrl+Alt+Backspace 729 to forcefully kill X. This can lead to data loss and is disabled 730 by default. 731 ''; 732 }; 733 734 terminateOnReset = mkOption { 735 type = types.bool; 736 default = true; 737 description = '' 738 Whether to terminate X upon server reset. 739 ''; 740 }; 741 742 upscaleDefaultCursor = mkOption { 743 type = types.bool; 744 default = false; 745 description = '' 746 Upscale the default X cursor to be more visible on high-density displays. 747 Requires `config.services.xserver.dpi` to be set. 748 ''; 749 }; 750 }; 751 752 }; 753 754 ###### implementation 755 756 config = mkIf cfg.enable { 757 services.displayManager.enable = true; 758 759 services.xserver.displayManager.lightdm.enable = 760 let 761 dmConf = cfg.displayManager; 762 default = 763 !( 764 dmConf.gdm.enable 765 || config.services.displayManager.sddm.enable 766 || dmConf.xpra.enable 767 || dmConf.sx.enable 768 || dmConf.startx.enable 769 || config.services.greetd.enable 770 || config.services.displayManager.ly.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 [ 884 "-config ${configFile}" 885 "-xkbdir" 886 "${cfg.xkb.dir}" 887 ] 888 ++ optional (cfg.display != null) ":${toString cfg.display}" 889 ++ optional (cfg.tty != null) "vt${toString cfg.tty}" 890 ++ optional (cfg.dpi != null) "-dpi ${toString cfg.dpi}" 891 ++ optional (cfg.logFile != null) "-logfile ${toString cfg.logFile}" 892 ++ optional (cfg.verbose != null) "-verbose ${toString cfg.verbose}" 893 ++ optional (!cfg.enableTCP) "-nolisten tcp" 894 ++ optional (cfg.autoRepeatDelay != null) "-ardelay ${toString cfg.autoRepeatDelay}" 895 ++ optional (cfg.autoRepeatInterval != null) "-arinterval ${toString cfg.autoRepeatInterval}" 896 ++ optional cfg.terminateOnReset "-terminate"; 897 898 services.xserver.modules = concatLists (catAttrs "modules" cfg.drivers) ++ [ 899 xorg.xorgserver.out 900 xorg.xf86inputevdev.out 901 ]; 902 903 system.checks = singleton ( 904 pkgs.runCommand "xkb-validated" 905 { 906 inherit (cfg.xkb) 907 dir 908 model 909 layout 910 variant 911 options 912 ; 913 nativeBuildInputs = with pkgs.buildPackages; [ xkbvalidate ]; 914 preferLocalBuild = true; 915 } 916 '' 917 ${optionalString ( 918 config.environment.sessionVariables ? XKB_CONFIG_ROOT 919 ) "export XKB_CONFIG_ROOT=${config.environment.sessionVariables.XKB_CONFIG_ROOT}"} 920 XKB_CONFIG_ROOT="$dir" xkbvalidate "$model" "$layout" "$variant" "$options" 921 touch "$out" 922 '' 923 ); 924 925 services.xserver.config = '' 926 Section "ServerFlags" 927 Option "AllowMouseOpenFail" "on" 928 Option "DontZap" "${if cfg.enableCtrlAltBackspace then "off" else "on"}" 929 ${indent cfg.serverFlagsSection} 930 EndSection 931 932 Section "Module" 933 ${indent cfg.moduleSection} 934 EndSection 935 936 Section "Monitor" 937 Identifier "Monitor[0]" 938 ${indent cfg.monitorSection} 939 EndSection 940 941 # Additional "InputClass" sections 942 ${flip (concatMapStringsSep "\n") cfg.inputClassSections (inputClassSection: '' 943 Section "InputClass" 944 ${indent inputClassSection} 945 EndSection 946 '')} 947 948 949 Section "ServerLayout" 950 Identifier "Layout[all]" 951 ${indent cfg.serverLayoutSection} 952 # Reference the Screen sections for each driver. This will 953 # cause the X server to try each in turn. 954 ${flip concatMapStrings (filter (d: d.display) cfg.drivers) (d: '' 955 Screen "Screen-${d.name}[0]" 956 '')} 957 EndSection 958 959 # For each supported driver, add a "Device" and "Screen" 960 # section. 961 ${flip concatMapStrings cfg.drivers (driver: '' 962 963 Section "Device" 964 Identifier "Device-${driver.name}[0]" 965 Driver "${driver.driverName or driver.name}" 966 ${indent (optionalString cfg.enableTearFree ''Option "TearFree" "true"'')} 967 ${indent cfg.deviceSection} 968 ${indent (driver.deviceSection or "")} 969 ${indent xrandrDeviceSection} 970 EndSection 971 ${optionalString driver.display '' 972 973 Section "Screen" 974 Identifier "Screen-${driver.name}[0]" 975 Device "Device-${driver.name}[0]" 976 ${optionalString (cfg.monitorSection != "") '' 977 Monitor "Monitor[0]" 978 ''} 979 980 ${indent cfg.screenSection} 981 ${indent (driver.screenSection or "")} 982 983 ${optionalString (cfg.defaultDepth != 0) '' 984 DefaultDepth ${toString cfg.defaultDepth} 985 ''} 986 987 ${optionalString 988 ( 989 driver.name != "virtualbox" 990 && (cfg.resolutions != [ ] || cfg.extraDisplaySettings != "" || cfg.virtualScreen != null) 991 ) 992 ( 993 let 994 f = depth: '' 995 SubSection "Display" 996 Depth ${toString depth} 997 ${optionalString (cfg.resolutions != [ ]) 998 "Modes ${concatMapStrings (res: ''"${toString res.x}x${toString res.y}"'') cfg.resolutions}" 999 } 1000 ${indent cfg.extraDisplaySettings} 1001 ${optionalString ( 1002 cfg.virtualScreen != null 1003 ) "Virtual ${toString cfg.virtualScreen.x} ${toString cfg.virtualScreen.y}"} 1004 EndSubSection 1005 ''; 1006 in 1007 concatMapStrings f [ 1008 8 1009 16 1010 24 1011 ] 1012 ) 1013 } 1014 1015 EndSection 1016 ''} 1017 '')} 1018 1019 ${xrandrMonitorSections} 1020 1021 ${cfg.extraConfig} 1022 ''; 1023 1024 fonts.packages = [ 1025 (if cfg.upscaleDefaultCursor then fontcursormisc_hidpi else pkgs.xorg.fontcursormisc) 1026 pkgs.xorg.fontmiscmisc 1027 ]; 1028 1029 }; 1030 1031 # uses relatedPackages 1032 meta.buildDocsInSandbox = false; 1033}