1{ config, lib, pkgs, ... }:
2
3with lib;
4with builtins;
5
6let
7
8 cfg = config.services.compton;
9
10 floatBetween = a: b: with lib; with types;
11 addCheck str (x: versionAtLeast x a && versionOlder x b);
12
13 pairOf = x: with types; addCheck (listOf x) (y: lib.length y == 2);
14
15 opacityRules = optionalString (length cfg.opacityRules != 0)
16 (concatMapStringsSep ",\n" (rule: ''"${rule}"'') cfg.opacityRules);
17
18 configFile = pkgs.writeText "compton.conf"
19 (optionalString cfg.fade ''
20 # fading
21 fading = true;
22 fade-delta = ${toString cfg.fadeDelta};
23 fade-in-step = ${elemAt cfg.fadeSteps 0};
24 fade-out-step = ${elemAt cfg.fadeSteps 1};
25 fade-exclude = ${toJSON cfg.fadeExclude};
26 '' +
27 optionalString cfg.shadow ''
28
29 # shadows
30 shadow = true;
31 shadow-offset-x = ${toString (elemAt cfg.shadowOffsets 0)};
32 shadow-offset-y = ${toString (elemAt cfg.shadowOffsets 1)};
33 shadow-opacity = ${cfg.shadowOpacity};
34 shadow-exclude = ${toJSON cfg.shadowExclude};
35 '' + ''
36
37 # opacity
38 active-opacity = ${cfg.activeOpacity};
39 inactive-opacity = ${cfg.inactiveOpacity};
40 menu-opacity = ${cfg.menuOpacity};
41
42 opacity-rule = [
43 ${opacityRules}
44 ];
45
46 # other options
47 backend = ${toJSON cfg.backend};
48 vsync = ${toJSON cfg.vSync};
49 refresh-rate = ${toString cfg.refreshRate};
50 '' + cfg.extraOptions);
51
52in {
53
54 options.services.compton = {
55 enable = mkOption {
56 type = types.bool;
57 default = false;
58 description = ''
59 Whether of not to enable Compton as the X.org composite manager.
60 '';
61 };
62
63 fade = mkOption {
64 type = types.bool;
65 default = false;
66 description = ''
67 Fade windows in and out.
68 '';
69 };
70
71 fadeDelta = mkOption {
72 type = types.addCheck types.int (x: x > 0);
73 default = 10;
74 example = 5;
75 description = ''
76 Time between fade animation step (in ms).
77 '';
78 };
79
80 fadeSteps = mkOption {
81 type = pairOf (floatBetween "0.01" "1.01");
82 default = [ "0.028" "0.03" ];
83 example = [ "0.04" "0.04" ];
84 description = ''
85 Opacity change between fade steps (in and out).
86 (numbers in range 0.01 - 1.0)
87 '';
88 };
89
90 fadeExclude = mkOption {
91 type = types.listOf types.str;
92 default = [];
93 example = [
94 "window_type *= 'menu'"
95 "name ~= 'Firefox$'"
96 "focused = 1"
97 ];
98 description = ''
99 List of conditions of windows that should not be faded.
100 See <literal>compton(1)</literal> man page for more examples.
101 '';
102 };
103
104 shadow = mkOption {
105 type = types.bool;
106 default = false;
107 description = ''
108 Draw window shadows.
109 '';
110 };
111
112 shadowOffsets = mkOption {
113 type = pairOf types.int;
114 default = [ (-15) (-15) ];
115 example = [ (-10) (-15) ];
116 description = ''
117 Left and right offset for shadows (in pixels).
118 '';
119 };
120
121 shadowOpacity = mkOption {
122 type = floatBetween "0.0" "1.01";
123 default = "0.75";
124 example = "0.8";
125 description = ''
126 Window shadows opacity (number in range 0.0 - 1.0).
127 '';
128 };
129
130 shadowExclude = mkOption {
131 type = types.listOf types.str;
132 default = [];
133 example = [
134 "window_type *= 'menu'"
135 "name ~= 'Firefox$'"
136 "focused = 1"
137 ];
138 description = ''
139 List of conditions of windows that should have no shadow.
140 See <literal>compton(1)</literal> man page for more examples.
141 '';
142 };
143
144 activeOpacity = mkOption {
145 type = floatBetween "0.0" "1.01";
146 default = "1.0";
147 example = "0.8";
148 description = ''
149 Opacity of active windows (number in range 0.0 - 1.0).
150 '';
151 };
152
153 inactiveOpacity = mkOption {
154 type = floatBetween "0.1" "1.01";
155 default = "1.0";
156 example = "0.8";
157 description = ''
158 Opacity of inactive windows (number in range 0.1 - 1.0).
159 '';
160 };
161
162 menuOpacity = mkOption {
163 type = floatBetween "0.0" "1.01";
164 default = "1.0";
165 example = "0.8";
166 description = ''
167 Opacity of dropdown and popup menu (number in range 0.0 - 1.0).
168 '';
169 };
170
171 opacityRules = mkOption {
172 type = types.listOf types.str;
173 default = [];
174 example = [
175 "95:class_g = 'URxvt' && !_NET_WM_STATE@:32a"
176 "0:_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'"
177 ];
178 description = ''
179 Rules that control the opacity of windows, in format PERCENT:PATTERN.
180 '';
181 };
182
183 backend = mkOption {
184 type = types.enum [ "glx" "xrender" "xr_glx_hybrid" ];
185 default = "xrender";
186 description = ''
187 Backend to use: <literal>glx</literal>, <literal>xrender</literal> or <literal>xr_glx_hybrid</literal>.
188 '';
189 };
190
191 vSync = mkOption {
192 type = types.enum [
193 "none" "drm" "opengl"
194 "opengl-oml" "opengl-swc" "opengl-mswc"
195 ];
196 default = "none";
197 example = "opengl-swc";
198 description = ''
199 Enable vertical synchronization using the specified method.
200 See <literal>compton(1)</literal> man page an explanation.
201 '';
202 };
203
204 refreshRate = mkOption {
205 type = types.addCheck types.int (x: x >= 0);
206 default = 0;
207 example = 60;
208 description = ''
209 Screen refresh rate (0 = automatically detect).
210 '';
211 };
212
213 package = mkOption {
214 type = types.package;
215 default = pkgs.compton;
216 defaultText = "pkgs.compton";
217 example = literalExample "pkgs.compton";
218 description = ''
219 Compton derivation to use.
220 '';
221 };
222
223 extraOptions = mkOption {
224 type = types.lines;
225 default = "";
226 example = ''
227 unredir-if-possible = true;
228 dbe = true;
229 '';
230 description = ''
231 Additional Compton configuration.
232 '';
233 };
234 };
235
236 config = mkIf cfg.enable {
237 systemd.user.services.compton = {
238 description = "Compton composite manager";
239 wantedBy = [ "graphical-session.target" ];
240 partOf = [ "graphical-session.target" ];
241 serviceConfig = {
242 ExecStart = "${cfg.package}/bin/compton --config ${configFile}";
243 RestartSec = 3;
244 Restart = "always";
245 };
246 };
247
248 environment.systemPackages = [ cfg.package ];
249 };
250
251}