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