1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9
10 cfg = config.services.xserver.displayManager.startx;
11
12 # WM session script
13 # Note: this assumes a single WM has been enabled
14 sessionScript = lib.concatMapStringsSep "\n" (
15 i: i.start
16 ) config.services.xserver.windowManager.session;
17
18in
19
20{
21
22 ###### interface
23
24 options = {
25 services.xserver.displayManager.startx = {
26 enable = lib.mkOption {
27 type = lib.types.bool;
28 default = false;
29 description = ''
30 Whether to enable the dummy "startx" pseudo-display manager, which
31 allows users to start X manually via the `startx` command from a
32 virtual terminal.
33
34 ::: {.note}
35 The X server will run under the current user, not as root.
36 :::
37 '';
38 };
39
40 generateScript = lib.mkOption {
41 type = lib.types.bool;
42 default = false;
43 description = ''
44 Whether to generate the system-wide xinitrc script (/etc/X11/xinit/xinitrc).
45 This script will take care of setting up the session for systemd user
46 services, running the window manager and cleaning up on exit.
47
48 ::: {.note}
49 This script will only be used by `startx` when both `.xinitrc` does not
50 exists and the `XINITRC` environment variable is unset.
51 :::
52 '';
53 };
54
55 extraCommands = lib.mkOption {
56 type = lib.types.lines;
57 default = "";
58 description = ''
59 Shell commands to be added to the system-wide xinitrc script.
60 '';
61 };
62
63 };
64 };
65
66 ###### implementation
67
68 config = lib.mkIf cfg.enable {
69 services.xserver.exportConfiguration = true;
70
71 # Other displayManagers log to /dev/null because they're services and put
72 # Xorg's stdout in the journal
73 #
74 # To send log to Xorg's default log location ($XDG_DATA_HOME/xorg/), we do
75 # not specify a log file when running X
76 services.xserver.logFile = lib.mkDefault null;
77
78 # Implement xserverArgs via xinit's system-wide xserverrc
79 environment.etc."X11/xinit/xserverrc".source = pkgs.writeShellScript "xserverrc" ''
80 exec ${pkgs.xorg.xorgserver}/bin/X \
81 ${toString config.services.xserver.displayManager.xserverArgs} "$@"
82 '';
83
84 # Add a sane system-wide xinitrc script
85 environment.etc."X11/xinit/xinitrc" = lib.mkIf cfg.generateScript {
86 source = pkgs.writeShellScript "xinitrc" ''
87 ${cfg.extraCommands}
88
89 # start user services
90 systemctl --user import-environment DISPLAY XDG_SESSION_ID
91 systemctl --user start nixos-fake-graphical-session.target
92
93 # run the window manager script
94 ${sessionScript}
95 wait $waitPID
96
97 # stop services and all subprocesses
98 systemctl --user stop nixos-fake-graphical-session.target
99 kill 0
100 '';
101 };
102
103 environment.systemPackages = with pkgs; [ xorg.xinit ];
104
105 };
106
107}