at 24.11-pre 8.9 kB view raw
1{ config, lib, options, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.picom; 8 opt = options.services.picom; 9 10 pairOf = x: with types; 11 addCheck (listOf x) (y: length y == 2) 12 // { description = "pair of ${x.description}"; }; 13 14 mkDefaultAttrs = mapAttrs (n: v: mkDefault v); 15 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};"); 23 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 ''; 36 37 toConf = attrs: concatStringsSep "\n" (mkAttrsString true cfg.settings); 38 39 configFile = pkgs.writeText "picom.conf" (toConf cfg.settings); 40 41in { 42 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 ]; 54 55 options.services.picom = { 56 enable = mkOption { 57 type = types.bool; 58 default = false; 59 description = '' 60 Whether or not to enable Picom as the X.org composite manager. 61 ''; 62 }; 63 64 package = mkPackageOption pkgs "picom" { }; 65 66 fade = mkOption { 67 type = types.bool; 68 default = false; 69 description = '' 70 Fade windows in and out. 71 ''; 72 }; 73 74 fadeDelta = mkOption { 75 type = types.ints.positive; 76 default = 10; 77 example = 5; 78 description = '' 79 Time between fade animation step (in ms). 80 ''; 81 }; 82 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 = '' 88 Opacity change between fade steps (in and out). 89 ''; 90 }; 91 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 = '' 101 List of conditions of windows that should not be faded. 102 See `picom(1)` man page for more examples. 103 ''; 104 }; 105 106 shadow = mkOption { 107 type = types.bool; 108 default = false; 109 description = '' 110 Draw window shadows. 111 ''; 112 }; 113 114 shadowOffsets = mkOption { 115 type = pairOf types.int; 116 default = [ (-15) (-15) ]; 117 example = [ (-10) (-15) ]; 118 description = '' 119 Left and right offset for shadows (in pixels). 120 ''; 121 }; 122 123 shadowOpacity = mkOption { 124 type = types.numbers.between 0 1; 125 default = 0.75; 126 example = 0.8; 127 description = '' 128 Window shadows opacity. 129 ''; 130 }; 131 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 = '' 141 List of conditions of windows that should have no shadow. 142 See `picom(1)` man page for more examples. 143 ''; 144 }; 145 146 activeOpacity = mkOption { 147 type = types.numbers.between 0 1; 148 default = 1.0; 149 example = 0.8; 150 description = '' 151 Opacity of active windows. 152 ''; 153 }; 154 155 inactiveOpacity = mkOption { 156 type = types.numbers.between 0.1 1; 157 default = 1.0; 158 example = 0.8; 159 description = '' 160 Opacity of inactive windows. 161 ''; 162 }; 163 164 menuOpacity = mkOption { 165 type = types.numbers.between 0 1; 166 default = 1.0; 167 example = 0.8; 168 description = '' 169 Opacity of dropdown and popup menu. 170 ''; 171 }; 172 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 = '' 187 Rules for specific window types. 188 ''; 189 }; 190 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 = '' 199 Rules that control the opacity of windows, in format PERCENT:PATTERN. 200 ''; 201 }; 202 203 backend = mkOption { 204 type = types.enum [ "egl" "glx" "xrender" "xr_glx_hybrid" ]; 205 default = "xrender"; 206 description = '' 207 Backend to use: `egl`, `glx`, `xrender` or `xr_glx_hybrid`. 208 ''; 209 }; 210 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; 223 224 description = '' 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 }; 230 231 settings = with types; 232 let 233 scalar = oneOf [ bool int float str ] 234 // { description = "scalar types"; }; 235 236 libConfig = oneOf [ scalar (listOf libConfig) (attrsOf libConfig) ] 237 // { description = "libconfig type"; }; 238 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 }; 247 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 = '' 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 }; 265 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; 274 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; 281 282 # opacity 283 active-opacity = cfg.activeOpacity; 284 inactive-opacity = cfg.inactiveOpacity; 285 286 wintypes = cfg.wintypes; 287 288 opacity-rule = cfg.opacityRules; 289 290 # other options 291 backend = cfg.backend; 292 vsync = cfg.vSync; 293 }; 294 295 systemd.user.services.picom = { 296 description = "Picom composite manager"; 297 wantedBy = [ "graphical-session.target" ]; 298 partOf = [ "graphical-session.target" ]; 299 300 # Temporarily fixes corrupt colours with Mesa 18 301 environment = mkIf (cfg.backend == "glx") { 302 allow_rgb10_configs = "false"; 303 }; 304 305 serviceConfig = { 306 ExecStart = "${getExe cfg.package} --config ${configFile}"; 307 RestartSec = 3; 308 Restart = "always"; 309 }; 310 }; 311 312 environment.systemPackages = [ cfg.package ]; 313 }; 314 315 meta.maintainers = with lib.maintainers; [ rnhmjoj ]; 316 317}