at 23.11-pre 9.0 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 = lib.mdDoc '' 60 Whether or not to enable Picom as the X.org composite manager. 61 ''; 62 }; 63 64 fade = mkOption { 65 type = types.bool; 66 default = false; 67 description = lib.mdDoc '' 68 Fade windows in and out. 69 ''; 70 }; 71 72 fadeDelta = mkOption { 73 type = types.ints.positive; 74 default = 10; 75 example = 5; 76 description = lib.mdDoc '' 77 Time between fade animation step (in ms). 78 ''; 79 }; 80 81 fadeSteps = mkOption { 82 type = pairOf (types.numbers.between 0.01 1); 83 default = [ 0.028 0.03 ]; 84 example = [ 0.04 0.04 ]; 85 description = lib.mdDoc '' 86 Opacity change between fade steps (in and out). 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 = lib.mdDoc '' 99 List of conditions of windows that should not be faded. 100 See `picom(1)` man page for more examples. 101 ''; 102 }; 103 104 shadow = mkOption { 105 type = types.bool; 106 default = false; 107 description = lib.mdDoc '' 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 = lib.mdDoc '' 117 Left and right offset for shadows (in pixels). 118 ''; 119 }; 120 121 shadowOpacity = mkOption { 122 type = types.numbers.between 0 1; 123 default = 0.75; 124 example = 0.8; 125 description = lib.mdDoc '' 126 Window shadows opacity. 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 = lib.mdDoc '' 139 List of conditions of windows that should have no shadow. 140 See `picom(1)` man page for more examples. 141 ''; 142 }; 143 144 activeOpacity = mkOption { 145 type = types.numbers.between 0 1; 146 default = 1.0; 147 example = 0.8; 148 description = lib.mdDoc '' 149 Opacity of active windows. 150 ''; 151 }; 152 153 inactiveOpacity = mkOption { 154 type = types.numbers.between 0.1 1; 155 default = 1.0; 156 example = 0.8; 157 description = lib.mdDoc '' 158 Opacity of inactive windows. 159 ''; 160 }; 161 162 menuOpacity = mkOption { 163 type = types.numbers.between 0 1; 164 default = 1.0; 165 example = 0.8; 166 description = lib.mdDoc '' 167 Opacity of dropdown and popup menu. 168 ''; 169 }; 170 171 wintypes = mkOption { 172 type = types.attrs; 173 default = { 174 popup_menu = { opacity = cfg.menuOpacity; }; 175 dropdown_menu = { opacity = cfg.menuOpacity; }; 176 }; 177 defaultText = literalExpression '' 178 { 179 popup_menu = { opacity = config.${opt.menuOpacity}; }; 180 dropdown_menu = { opacity = config.${opt.menuOpacity}; }; 181 } 182 ''; 183 example = {}; 184 description = lib.mdDoc '' 185 Rules for specific window types. 186 ''; 187 }; 188 189 opacityRules = mkOption { 190 type = types.listOf types.str; 191 default = []; 192 example = [ 193 "95:class_g = 'URxvt' && !_NET_WM_STATE@:32a" 194 "0:_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'" 195 ]; 196 description = lib.mdDoc '' 197 Rules that control the opacity of windows, in format PERCENT:PATTERN. 198 ''; 199 }; 200 201 backend = mkOption { 202 type = types.enum [ "egl" "glx" "xrender" "xr_glx_hybrid" ]; 203 default = "xrender"; 204 description = lib.mdDoc '' 205 Backend to use: `egl`, `glx`, `xrender` or `xr_glx_hybrid`. 206 ''; 207 }; 208 209 vSync = mkOption { 210 type = with types; either bool 211 (enum [ "none" "drm" "opengl" "opengl-oml" "opengl-swc" "opengl-mswc" ]); 212 default = false; 213 apply = x: 214 let 215 res = x != "none"; 216 msg = "The type of services.picom.vSync has changed to bool:" 217 + " interpreting ${x} as ${boolToString res}"; 218 in 219 if isBool x then x 220 else warn msg res; 221 222 description = lib.mdDoc '' 223 Enable vertical synchronization. Chooses the best method 224 (drm, opengl, opengl-oml, opengl-swc, opengl-mswc) automatically. 225 The bool value should be used, the others are just for backwards compatibility. 226 ''; 227 }; 228 229 settings = with types; 230 let 231 scalar = oneOf [ bool int float str ] 232 // { description = "scalar types"; }; 233 234 libConfig = oneOf [ scalar (listOf libConfig) (attrsOf libConfig) ] 235 // { description = "libconfig type"; }; 236 237 topLevel = attrsOf libConfig 238 // { description = '' 239 libconfig configuration. The format consists of an attributes 240 set (called a group) of settings. Each setting can be a scalar type 241 (boolean, integer, floating point number or string), a list of 242 scalars or a group itself 243 ''; 244 }; 245 246 in mkOption { 247 type = topLevel; 248 default = { }; 249 example = literalExpression '' 250 blur = 251 { method = "gaussian"; 252 size = 10; 253 deviation = 5.0; 254 }; 255 ''; 256 description = lib.mdDoc '' 257 Picom settings. Use this option to configure Picom settings not exposed 258 in a NixOS option or to bypass one. For the available options see the 259 CONFIGURATION FILES section at `picom(1)`. 260 ''; 261 }; 262 }; 263 264 config = mkIf cfg.enable { 265 services.picom.settings = mkDefaultAttrs { 266 # fading 267 fading = cfg.fade; 268 fade-delta = cfg.fadeDelta; 269 fade-in-step = elemAt cfg.fadeSteps 0; 270 fade-out-step = elemAt cfg.fadeSteps 1; 271 fade-exclude = cfg.fadeExclude; 272 273 # shadows 274 shadow = cfg.shadow; 275 shadow-offset-x = elemAt cfg.shadowOffsets 0; 276 shadow-offset-y = elemAt cfg.shadowOffsets 1; 277 shadow-opacity = cfg.shadowOpacity; 278 shadow-exclude = cfg.shadowExclude; 279 280 # opacity 281 active-opacity = cfg.activeOpacity; 282 inactive-opacity = cfg.inactiveOpacity; 283 284 wintypes = cfg.wintypes; 285 286 opacity-rule = cfg.opacityRules; 287 288 # other options 289 backend = cfg.backend; 290 vsync = cfg.vSync; 291 }; 292 293 systemd.user.services.picom = { 294 description = "Picom composite manager"; 295 wantedBy = [ "graphical-session.target" ]; 296 partOf = [ "graphical-session.target" ]; 297 298 # Temporarily fixes corrupt colours with Mesa 18 299 environment = mkIf (cfg.backend == "glx") { 300 allow_rgb10_configs = "false"; 301 }; 302 303 serviceConfig = { 304 ExecStart = "${pkgs.picom}/bin/picom --config ${configFile}"; 305 RestartSec = 3; 306 Restart = "always"; 307 }; 308 }; 309 310 environment.systemPackages = [ pkgs.picom ]; 311 }; 312 313 meta.maintainers = with lib.maintainers; [ rnhmjoj ]; 314 315}