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