nixos/preload: init
[NixPkgs.git] / nixos / modules / services / x11 / picom.nix
blob3df0ea9e60bb0de63864f660968120afea12216f
1 { config, lib, options, pkgs, ... }:
3 with lib;
5 let
7   cfg = config.services.picom;
8   opt = options.services.picom;
10   pairOf = x: with types;
11     addCheck (listOf x) (y: length y == 2)
12     // { description = "pair of ${x.description}"; };
14   mkDefaultAttrs = mapAttrs (n: v: mkDefault v);
16   # Basically a tinkered lib.generators.mkKeyValueDefault
17   # It either serializes a top-level definition "key: { values };"
18   # or an expression "key = { values };"
19   mkAttrsString = top:
20     mapAttrsToList (k: v:
21       let sep = if (top && isAttrs v) then ":" else "=";
22       in "${escape [ sep ] k}${sep}${mkValueString v};");
24   # This serializes a Nix expression to the libconfig format.
25   mkValueString = v:
26          if types.bool.check  v then boolToString v
27     else if types.int.check   v then toString v
28     else if types.float.check v then toString v
29     else if types.str.check   v then "\"${escape [ "\"" ] v}\""
30     else if builtins.isList   v then "[ ${concatMapStringsSep " , " mkValueString v} ]"
31     else if types.attrs.check v then "{ ${concatStringsSep " " (mkAttrsString false v) } }"
32     else throw ''
33                  invalid expression used in option services.picom.settings:
34                  ${v}
35                '';
37   toConf = attrs: concatStringsSep "\n" (mkAttrsString true cfg.settings);
39   configFile = pkgs.writeText "picom.conf" (toConf cfg.settings);
41 in {
43   imports = [
44     (mkAliasOptionModuleMD [ "services" "compton" ] [ "services" "picom" ])
45     (mkRemovedOptionModule [ "services" "picom" "refreshRate" ] ''
46       This option corresponds to `refresh-rate`, which has been unused
47       since picom v6 and was subsequently removed by upstream.
48       See https://github.com/yshui/picom/commit/bcbc410
49     '')
50     (mkRemovedOptionModule [ "services" "picom" "experimentalBackends" ] ''
51       This option was removed by upstream since picom v10.
52     '')
53   ];
55   options.services.picom = {
56     enable = mkOption {
57       type = types.bool;
58       default = false;
59       description = lib.mdDoc ''
60         Whether or not to enable Picom as the X.org composite manager.
61       '';
62     };
64     package = mkPackageOptionMD pkgs "picom" { };
66     fade = mkOption {
67       type = types.bool;
68       default = false;
69       description = lib.mdDoc ''
70         Fade windows in and out.
71       '';
72     };
74     fadeDelta = mkOption {
75       type = types.ints.positive;
76       default = 10;
77       example = 5;
78       description = lib.mdDoc ''
79         Time between fade animation step (in ms).
80       '';
81     };
83     fadeSteps = mkOption {
84       type = pairOf (types.numbers.between 0.01 1);
85       default = [ 0.028 0.03 ];
86       example = [ 0.04 0.04 ];
87       description = lib.mdDoc ''
88         Opacity change between fade steps (in and out).
89       '';
90     };
92     fadeExclude = mkOption {
93       type = types.listOf types.str;
94       default = [];
95       example = [
96         "window_type *= 'menu'"
97         "name ~= 'Firefox$'"
98         "focused = 1"
99       ];
100       description = lib.mdDoc ''
101         List of conditions of windows that should not be faded.
102         See `picom(1)` man page for more examples.
103       '';
104     };
106     shadow = mkOption {
107       type = types.bool;
108       default = false;
109       description = lib.mdDoc ''
110         Draw window shadows.
111       '';
112     };
114     shadowOffsets = mkOption {
115       type = pairOf types.int;
116       default = [ (-15) (-15) ];
117       example = [ (-10) (-15) ];
118       description = lib.mdDoc ''
119         Left and right offset for shadows (in pixels).
120       '';
121     };
123     shadowOpacity = mkOption {
124       type = types.numbers.between 0 1;
125       default = 0.75;
126       example = 0.8;
127       description = lib.mdDoc ''
128         Window shadows opacity.
129       '';
130     };
132     shadowExclude = mkOption {
133       type = types.listOf types.str;
134       default = [];
135       example = [
136         "window_type *= 'menu'"
137         "name ~= 'Firefox$'"
138         "focused = 1"
139       ];
140       description = lib.mdDoc ''
141         List of conditions of windows that should have no shadow.
142         See `picom(1)` man page for more examples.
143       '';
144     };
146     activeOpacity = mkOption {
147       type = types.numbers.between 0 1;
148       default = 1.0;
149       example = 0.8;
150       description = lib.mdDoc ''
151         Opacity of active windows.
152       '';
153     };
155     inactiveOpacity = mkOption {
156       type = types.numbers.between 0.1 1;
157       default = 1.0;
158       example = 0.8;
159       description = lib.mdDoc ''
160         Opacity of inactive windows.
161       '';
162     };
164     menuOpacity = mkOption {
165       type = types.numbers.between 0 1;
166       default = 1.0;
167       example = 0.8;
168       description = lib.mdDoc ''
169         Opacity of dropdown and popup menu.
170       '';
171     };
173     wintypes = mkOption {
174       type = types.attrs;
175       default = {
176         popup_menu = { opacity = cfg.menuOpacity; };
177         dropdown_menu = { opacity = cfg.menuOpacity; };
178       };
179       defaultText = literalExpression ''
180         {
181           popup_menu = { opacity = config.${opt.menuOpacity}; };
182           dropdown_menu = { opacity = config.${opt.menuOpacity}; };
183         }
184       '';
185       example = {};
186       description = lib.mdDoc ''
187         Rules for specific window types.
188       '';
189     };
191     opacityRules = mkOption {
192       type = types.listOf types.str;
193       default = [];
194       example = [
195         "95:class_g = 'URxvt' && !_NET_WM_STATE@:32a"
196         "0:_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'"
197       ];
198       description = lib.mdDoc ''
199         Rules that control the opacity of windows, in format PERCENT:PATTERN.
200       '';
201     };
203     backend = mkOption {
204       type = types.enum [ "egl" "glx" "xrender" "xr_glx_hybrid" ];
205       default = "xrender";
206       description = lib.mdDoc ''
207         Backend to use: `egl`, `glx`, `xrender` or `xr_glx_hybrid`.
208       '';
209     };
211     vSync = mkOption {
212       type = with types; either bool
213         (enum [ "none" "drm" "opengl" "opengl-oml" "opengl-swc" "opengl-mswc" ]);
214       default = false;
215       apply = x:
216         let
217           res = x != "none";
218           msg = "The type of services.picom.vSync has changed to bool:"
219                 + " interpreting ${x} as ${boolToString res}";
220         in
221           if isBool x then x
222           else warn msg res;
224       description = lib.mdDoc ''
225         Enable vertical synchronization. Chooses the best method
226         (drm, opengl, opengl-oml, opengl-swc, opengl-mswc) automatically.
227         The bool value should be used, the others are just for backwards compatibility.
228       '';
229     };
231     settings = with types;
232     let
233       scalar = oneOf [ bool int float str ]
234         // { description = "scalar types"; };
236       libConfig = oneOf [ scalar (listOf libConfig) (attrsOf libConfig) ]
237         // { description = "libconfig type"; };
239       topLevel = attrsOf libConfig
240         // { description = ''
241                libconfig configuration. The format consists of an attributes
242                set (called a group) of settings. Each setting can be a scalar type
243                (boolean, integer, floating point number or string), a list of
244                scalars or a group itself
245              '';
246            };
248     in mkOption {
249       type = topLevel;
250       default = { };
251       example = literalExpression ''
252         blur =
253           { method = "gaussian";
254             size = 10;
255             deviation = 5.0;
256           };
257       '';
258       description = lib.mdDoc ''
259         Picom settings. Use this option to configure Picom settings not exposed
260         in a NixOS option or to bypass one.  For the available options see the
261         CONFIGURATION FILES section at `picom(1)`.
262       '';
263     };
264   };
266   config = mkIf cfg.enable {
267     services.picom.settings = mkDefaultAttrs {
268       # fading
269       fading           = cfg.fade;
270       fade-delta       = cfg.fadeDelta;
271       fade-in-step     = elemAt cfg.fadeSteps 0;
272       fade-out-step    = elemAt cfg.fadeSteps 1;
273       fade-exclude     = cfg.fadeExclude;
275       # shadows
276       shadow           = cfg.shadow;
277       shadow-offset-x  = elemAt cfg.shadowOffsets 0;
278       shadow-offset-y  = elemAt cfg.shadowOffsets 1;
279       shadow-opacity   = cfg.shadowOpacity;
280       shadow-exclude   = cfg.shadowExclude;
282       # opacity
283       active-opacity   = cfg.activeOpacity;
284       inactive-opacity = cfg.inactiveOpacity;
286       wintypes         = cfg.wintypes;
288       opacity-rule     = cfg.opacityRules;
290       # other options
291       backend          = cfg.backend;
292       vsync            = cfg.vSync;
293     };
295     systemd.user.services.picom = {
296       description = "Picom composite manager";
297       wantedBy = [ "graphical-session.target" ];
298       partOf = [ "graphical-session.target" ];
300       # Temporarily fixes corrupt colours with Mesa 18
301       environment = mkIf (cfg.backend == "glx") {
302         allow_rgb10_configs = "false";
303       };
305       serviceConfig = {
306         ExecStart = "${getExe cfg.package} --config ${configFile}";
307         RestartSec = 3;
308         Restart = "always";
309       };
310     };
312     environment.systemPackages = [ cfg.package ];
313   };
315   meta.maintainers = with lib.maintainers; [ rnhmjoj ];