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