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