1{ config, lib, pkgs, utils, ... }:
2
3with lib;
4
5let
6 cfg = config.services.logind;
7
8 logindHandlerType = types.enum [
9 "ignore" "poweroff" "reboot" "halt" "kexec" "suspend"
10 "hibernate" "hybrid-sleep" "suspend-then-hibernate" "lock"
11 ];
12in
13{
14 options.services.logind = {
15 extraConfig = mkOption {
16 default = "";
17 type = types.lines;
18 example = "IdleAction=lock";
19 description = ''
20 Extra config options for systemd-logind.
21 See [logind.conf(5)](https://www.freedesktop.org/software/systemd/man/logind.conf.html)
22 for available options.
23 '';
24 };
25
26 killUserProcesses = mkOption {
27 default = false;
28 type = types.bool;
29 description = ''
30 Specifies whether the processes of a user should be killed
31 when the user logs out. If true, the scope unit corresponding
32 to the session and all processes inside that scope will be
33 terminated. If false, the scope is "abandoned"
34 (see [systemd.scope(5)](https://www.freedesktop.org/software/systemd/man/systemd.scope.html#)),
35 and processes are not killed.
36
37 See [logind.conf(5)](https://www.freedesktop.org/software/systemd/man/logind.conf.html#KillUserProcesses=)
38 for more details.
39 '';
40 };
41
42 powerKey = mkOption {
43 default = "poweroff";
44 example = "ignore";
45 type = logindHandlerType;
46
47 description = ''
48 Specifies what to do when the power key is pressed.
49 '';
50 };
51
52 powerKeyLongPress = mkOption {
53 default = "ignore";
54 example = "reboot";
55 type = logindHandlerType;
56
57 description = ''
58 Specifies what to do when the power key is long-pressed.
59 '';
60 };
61
62 rebootKey = mkOption {
63 default = "reboot";
64 example = "ignore";
65 type = logindHandlerType;
66
67 description = ''
68 Specifies what to do when the reboot key is pressed.
69 '';
70 };
71
72 rebootKeyLongPress = mkOption {
73 default = "poweroff";
74 example = "ignore";
75 type = logindHandlerType;
76
77 description = ''
78 Specifies what to do when the reboot key is long-pressed.
79 '';
80 };
81
82 suspendKey = mkOption {
83 default = "suspend";
84 example = "ignore";
85 type = logindHandlerType;
86
87 description = ''
88 Specifies what to do when the suspend key is pressed.
89 '';
90 };
91
92 suspendKeyLongPress = mkOption {
93 default = "hibernate";
94 example = "ignore";
95 type = logindHandlerType;
96
97 description = ''
98 Specifies what to do when the suspend key is long-pressed.
99 '';
100 };
101
102 hibernateKey = mkOption {
103 default = "hibernate";
104 example = "ignore";
105 type = logindHandlerType;
106
107 description = ''
108 Specifies what to do when the hibernate key is pressed.
109 '';
110 };
111
112 hibernateKeyLongPress = mkOption {
113 default = "ignore";
114 example = "suspend";
115 type = logindHandlerType;
116
117 description = ''
118 Specifies what to do when the hibernate key is long-pressed.
119 '';
120 };
121
122 lidSwitch = mkOption {
123 default = "suspend";
124 example = "ignore";
125 type = logindHandlerType;
126
127 description = ''
128 Specifies what to do when the laptop lid is closed.
129 '';
130 };
131
132 lidSwitchExternalPower = mkOption {
133 default = cfg.lidSwitch;
134 defaultText = literalExpression "services.logind.lidSwitch";
135 example = "ignore";
136 type = logindHandlerType;
137
138 description = ''
139 Specifies what to do when the laptop lid is closed
140 and the system is on external power. By default use
141 the same action as specified in services.logind.lidSwitch.
142 '';
143 };
144
145 lidSwitchDocked = mkOption {
146 default = "ignore";
147 example = "suspend";
148 type = logindHandlerType;
149
150 description = ''
151 Specifies what to do when the laptop lid is closed
152 and another screen is added.
153 '';
154 };
155 };
156
157 config = {
158 systemd.additionalUpstreamSystemUnits = [
159 "systemd-logind.service"
160 "autovt@.service"
161 "systemd-user-sessions.service"
162 ] ++ optionals config.systemd.package.withImportd [
163 "dbus-org.freedesktop.import1.service"
164 ] ++ optionals config.systemd.package.withMachined [
165 "dbus-org.freedesktop.machine1.service"
166 ] ++ optionals config.systemd.package.withPortabled [
167 "dbus-org.freedesktop.portable1.service"
168 ] ++ [
169 "dbus-org.freedesktop.login1.service"
170 "user@.service"
171 "user-runtime-dir@.service"
172 ];
173
174 environment.etc = {
175 "systemd/logind.conf".text = ''
176 [Login]
177 KillUserProcesses=${if cfg.killUserProcesses then "yes" else "no"}
178 HandlePowerKey=${cfg.powerKey}
179 HandlePowerKeyLongPress=${cfg.powerKeyLongPress}
180 HandleRebootKey=${cfg.rebootKey}
181 HandleRebootKeyLongPress=${cfg.rebootKeyLongPress}
182 HandleSuspendKey=${cfg.suspendKey}
183 HandleSuspendKeyLongPress=${cfg.suspendKeyLongPress}
184 HandleHibernateKey=${cfg.hibernateKey}
185 HandleHibernateKeyLongPress=${cfg.hibernateKeyLongPress}
186 HandleLidSwitch=${cfg.lidSwitch}
187 HandleLidSwitchExternalPower=${cfg.lidSwitchExternalPower}
188 HandleLidSwitchDocked=${cfg.lidSwitchDocked}
189 ${cfg.extraConfig}
190 '';
191 };
192
193 # Restarting systemd-logind breaks X11
194 # - upstream commit: https://cgit.freedesktop.org/xorg/xserver/commit/?id=dc48bd653c7e101
195 # - systemd announcement: https://github.com/systemd/systemd/blob/22043e4317ecd2bc7834b48a6d364de76bb26d91/NEWS#L103-L112
196 # - this might be addressed in the future by xorg
197 #systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ];
198 systemd.services.systemd-logind.restartIfChanged = false;
199 systemd.services.systemd-logind.stopIfChanged = false;
200
201 # The user-runtime-dir@ service is managed by systemd-logind we should not touch it or else we break the users' sessions.
202 systemd.services."user-runtime-dir@".stopIfChanged = false;
203 systemd.services."user-runtime-dir@".restartIfChanged = false;
204 };
205}