picom: sync module with the NixOS version

This brings a few advantages:

- Use of float instead of strings to represent float values,

- Use of structure settings, and

- Better type checking for some settings

Also add thiagokokada as codeowner of picom.
This commit is contained in:
Thiago Kenji Okada 2022-05-05 22:56:43 +01:00 committed by Robert Helgesson
parent 0639aa34f1
commit b908e61dfa
No known key found for this signature in database
GPG key ID: 36BDAA14C2797E89
6 changed files with 218 additions and 195 deletions

3
.github/CODEOWNERS vendored
View file

@ -386,6 +386,9 @@
/modules/services/pasystray.nix @pltanton /modules/services/pasystray.nix @pltanton
/modules/services/picom.nix @thiagokokada
/tests/modules/services/picom @thiagokokada
/modules/services/pbgopy.nix @ivarwithoutbones /modules/services/pbgopy.nix @ivarwithoutbones
/tests/modules/services/pbgopy @ivarwithoutbones /tests/modules/services/pbgopy @ivarwithoutbones

View file

@ -75,6 +75,15 @@ Of course, you can move the assignment of <<opt-home.username>>,
<<opt-home.homeDirectory>>, and <<opt-home.stateVersion>> to some <<opt-home.homeDirectory>>, and <<opt-home.stateVersion>> to some
other file or simply place them in your `home.nix`. other file or simply place them in your `home.nix`.
* The `services.picom` module has been refactored to use structural
settings.
+
As a result `services.picom.extraOptions` has been removed in favor of
<<opt-services.picom.settings>>. Also, `services.picom.blur*` were
removed since upstream changed the blur settings to be more flexible.
You can migrate the blur settings to use
<<opt-services.picom.settings>> instead.
[[sec-release-22.11-state-version-changes]] [[sec-release-22.11-state-version-changes]]
=== State Version Changes === State Version Changes

View file

@ -583,6 +583,20 @@ in
A new module is available: 'services.sctd'. A new module is available: 'services.sctd'.
''; '';
} }
{
time = "2022-07-12T08:59:50+00:00";
condition = config.services.picom.enable;
message = ''
The 'services.picom' module has been refactored to use structural
settings.
As a result 'services.picom.extraOptions' has been removed in favor of
'services.picom.settings'. Also, 'services.picom.blur*' were removed
since upstream changed the blur settings to be more flexible. You can
migrate the blur settings to use 'services.picom.settings' instead.
'';
}
]; ];
}; };
} }

View file

@ -1,89 +1,77 @@
{ config, lib, pkgs, ... }: { config, options, lib, pkgs, ... }:
let let
inherit (builtins) toJSON toString; inherit (builtins) elemAt isAttrs isBool length mapAttrs toJSON;
inherit (lib) inherit (lib)
concatStringsSep elemAt literalExpression mkEnableOption mkIf mkOption boolToString concatMapStringsSep concatStringsSep escape literalExpression
mkRemovedOptionModule optional optionalAttrs optionalString types; mapAttrsToList mkEnableOption mkRemovedOptionModule mkDefault mkIf mkOption
optional types warn;
cfg = config.services.picom; cfg = config.services.picom;
opt = options.services.picom;
configFile = optionalString cfg.fade '' pairOf = x:
# fading with types;
fading = true; addCheck (listOf x) (y: length y == 2) // {
fade-delta = ${toString cfg.fadeDelta}; description = "pair of ${x.description}";
fade-in-step = ${elemAt cfg.fadeSteps 0};
fade-out-step = ${elemAt cfg.fadeSteps 1};
fade-exclude = ${toJSON cfg.fadeExclude};
'' + optionalString cfg.shadow ''
# shadows
shadow = true;
shadow-offset-x = ${toString (elemAt cfg.shadowOffsets 0)};
shadow-offset-y = ${toString (elemAt cfg.shadowOffsets 1)};
shadow-opacity = ${cfg.shadowOpacity};
shadow-exclude = ${toJSON cfg.shadowExclude};
'' + optionalString cfg.blur ''
# blur
blur-background = true;
blur-background-exclude = ${toJSON cfg.blurExclude};
'' + ''
# opacity
active-opacity = ${cfg.activeOpacity};
inactive-opacity = ${cfg.inactiveOpacity};
inactive-dim = ${cfg.inactiveDim};
opacity-rule = ${toJSON cfg.opacityRule};
wintypes:
{
dock = { shadow = ${toJSON (!cfg.noDockShadow)}; };
dnd = { shadow = ${toJSON (!cfg.noDNDShadow)}; };
popup_menu = { opacity = ${cfg.menuOpacity}; };
dropdown_menu = { opacity = ${cfg.menuOpacity}; };
}; };
# other options floatBetween = a: b:
backend = ${toJSON cfg.backend}; with types;
vsync = ${toJSON cfg.vSync}; let
'' + cfg.extraOptions; # toString prints floats with hardcoded high precision
floatToString = f: toJSON f;
in addCheck float (x: x <= b && x >= a) // {
description = "a floating point number in "
+ "range [${floatToString a}, ${floatToString b}]";
};
mkDefaultAttrs = mapAttrs (n: v: mkDefault v);
# Basically a tinkered lib.generators.mkKeyValueDefault
# It either serializes a top-level definition "key: { values };"
# or an expression "key = { values };"
mkAttrsString = top:
mapAttrsToList (k: v:
let sep = if (top && isAttrs v) then ": " else " = ";
in "${escape [ sep ] k}${sep}${mkValueString v};");
# This serializes a Nix expression to the libconfig format.
mkValueString = v:
if types.bool.check v then
boolToString v
else if types.int.check v then
toString v
else if types.float.check v then
toString v
else if types.str.check v then
''"${escape [ ''"'' ] v}"''
else if builtins.isList v then
"[ ${concatMapStringsSep " , " mkValueString v} ]"
else if types.attrs.check v then
"{ ${concatStringsSep " " (mkAttrsString false v)} }"
else
throw ''
invalid expression used in option services.picom.settings:
${v}
'';
toConf = attrs: concatStringsSep "\n" (mkAttrsString true cfg.settings);
configFile = toConf cfg.settings;
in { in {
imports = [
(mkRemovedOptionModule [ "services" "picom" "refreshRate" ]
"The option `refresh-rate` has been deprecated by upstream.")
(mkRemovedOptionModule [ "services" "picom" "extraOptions" ]
"This option has been replaced by `services.picom.settings`.")
];
options.services.picom = { options.services.picom = {
enable = mkEnableOption "Picom X11 compositor"; enable = mkEnableOption "Picom X11 compositor";
blur = mkOption { experimentalBackends = mkEnableOption "the new experimental backends";
type = types.bool;
default = false;
description = ''
Enable background blur on transparent windows.
'';
};
blurExclude = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "class_g = 'slop'" "class_i = 'polybar'" ];
description = ''
List of windows to exclude background blur.
See the
<citerefentry>
<refentrytitle>picom</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
man page for more examples.
'';
};
experimentalBackends = mkOption {
type = types.bool;
default = false;
description = ''
Whether to use the new experimental backends.
'';
};
fade = mkOption { fade = mkOption {
type = types.bool; type = types.bool;
@ -94,7 +82,7 @@ in {
}; };
fadeDelta = mkOption { fadeDelta = mkOption {
type = types.int; type = types.ints.positive;
default = 10; default = 10;
example = 5; example = 5;
description = '' description = ''
@ -103,9 +91,9 @@ in {
}; };
fadeSteps = mkOption { fadeSteps = mkOption {
type = types.listOf types.str; type = pairOf (floatBetween 1.0e-2 1);
default = [ "0.028" "0.03" ]; default = [ 2.8e-2 3.0e-2 ];
example = [ "0.04" "0.04" ]; example = [ 4.0e-2 4.0e-2 ];
description = '' description = ''
Opacity change between fade steps (in and out). Opacity change between fade steps (in and out).
''; '';
@ -117,12 +105,7 @@ in {
example = [ "window_type *= 'menu'" "name ~= 'Firefox$'" "focused = 1" ]; example = [ "window_type *= 'menu'" "name ~= 'Firefox$'" "focused = 1" ];
description = '' description = ''
List of conditions of windows that should not be faded. List of conditions of windows that should not be faded.
See the See <literal>picom(1)</literal> man page for more examples.
<citerefentry>
<refentrytitle>picom</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
man page for more examples.
''; '';
}; };
@ -135,20 +118,20 @@ in {
}; };
shadowOffsets = mkOption { shadowOffsets = mkOption {
type = types.listOf types.int; type = pairOf types.int;
default = [ (-15) (-15) ]; default = [ (-15) (-15) ];
example = [ (-10) (-15) ]; example = [ (-10) (-15) ];
description = '' description = ''
Horizontal and vertical offsets for shadows (in pixels). Left and right offset for shadows (in pixels).
''; '';
}; };
shadowOpacity = mkOption { shadowOpacity = mkOption {
type = types.str; type = floatBetween 0 1;
default = "0.75"; default = 0.75;
example = "0.8"; example = 0.8;
description = '' description = ''
Window shadows opacity (number in range 0 - 1). Window shadows opacity.
''; '';
}; };
@ -158,87 +141,72 @@ in {
example = [ "window_type *= 'menu'" "name ~= 'Firefox$'" "focused = 1" ]; example = [ "window_type *= 'menu'" "name ~= 'Firefox$'" "focused = 1" ];
description = '' description = ''
List of conditions of windows that should have no shadow. List of conditions of windows that should have no shadow.
See the See <literal>picom(1)</literal> man page for more examples.
<citerefentry>
<refentrytitle>picom</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
man page for more examples.
'';
};
noDockShadow = mkOption {
type = types.bool;
default = true;
description = ''
Avoid shadow on docks.
'';
};
noDNDShadow = mkOption {
type = types.bool;
default = true;
description = ''
Avoid shadow on drag-and-drop windows.
''; '';
}; };
activeOpacity = mkOption { activeOpacity = mkOption {
type = types.str; type = floatBetween 0 1;
default = "1.0"; default = 1.0;
example = "0.8"; example = 0.8;
description = '' description = ''
Opacity of active windows. Opacity of active windows.
''; '';
}; };
inactiveDim = mkOption {
type = types.str;
default = "0.0";
example = "0.2";
description = ''
Dim inactive windows.
'';
};
inactiveOpacity = mkOption { inactiveOpacity = mkOption {
type = types.str; type = floatBetween 0.1 1;
default = "1.0"; default = 1.0;
example = "0.8"; example = 0.8;
description = '' description = ''
Opacity of inactive windows. Opacity of inactive windows.
''; '';
}; };
menuOpacity = mkOption { menuOpacity = mkOption {
type = types.str; type = floatBetween 0 1;
default = "1.0"; default = 1.0;
example = "0.8"; example = 0.8;
description = '' description = ''
Opacity of dropdown and popup menu. Opacity of dropdown and popup menu.
''; '';
}; };
opacityRule = mkOption { wintypes = mkOption {
type = types.attrs;
default = {
popup_menu = { opacity = cfg.menuOpacity; };
dropdown_menu = { opacity = cfg.menuOpacity; };
};
defaultText = literalExpression ''
{
popup_menu = { opacity = config.${opt.menuOpacity}; };
dropdown_menu = { opacity = config.${opt.menuOpacity}; };
}
'';
example = { };
description = ''
Rules for specific window types.
'';
};
opacityRules = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ ]; default = [ ];
example = [ "87:class_i ?= 'scratchpad'" "91:class_i ?= 'xterm'" ]; example = [
"95:class_g = 'URxvt' && !_NET_WM_STATE@:32a"
"0:_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'"
];
description = '' description = ''
List of opacity rules. Rules that control the opacity of windows, in format PERCENT:PATTERN.
See the
<citerefentry>
<refentrytitle>picom</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
man page for more examples.
''; '';
}; };
backend = mkOption { backend = mkOption {
type = types.str; type = types.enum [ "glx" "xrender" "xr_glx_hybrid" ];
default = "glx"; default = "xrender";
description = '' description = ''
Backend to use: <literal>glx</literal> or <literal>xrender</literal>. Backend to use: <literal>glx</literal>, <literal>xrender</literal> or <literal>xr_glx_hybrid</literal>.
''; '';
}; };
@ -256,33 +224,75 @@ in {
defaultText = literalExpression "pkgs.picom"; defaultText = literalExpression "pkgs.picom";
example = literalExpression "pkgs.picom"; example = literalExpression "pkgs.picom";
description = '' description = ''
picom derivation to use. Picom derivation to use.
''; '';
}; };
extraOptions = mkOption { settings = with types;
type = types.lines; let
default = ""; scalar = oneOf [ bool int float str ] // {
example = '' description = "scalar types";
unredir-if-possible = true; };
dbe = true;
libConfig = oneOf [ scalar (listOf libConfig) (attrsOf libConfig) ] // {
description = "libconfig type";
};
topLevel = attrsOf libConfig // {
description = ''
libconfig configuration. The format consists of an attributes
set (called a group) of settings. Each setting can be a scalar type
(boolean, integer, floating point number or string), a list of
scalars or a group itself
'';
};
in mkOption {
type = topLevel;
default = { };
example = literalExpression ''
blur =
{ method = "gaussian";
size = 10;
deviation = 5.0;
};
''; '';
description = '' description = ''
Additional Picom configuration. Picom settings. Use this option to configure Picom settings not exposed
in a NixOS option or to bypass one. For the available options see the
CONFIGURATION FILES section at <literal>picom(1)</literal>.
''; '';
}; };
}; };
imports = [
(mkRemovedOptionModule [ "services" "picom" "refreshRate" ]
"The option `refresh-rate` has been deprecated by upstream.")
];
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [ services.picom.settings = mkDefaultAttrs {
(lib.hm.assertions.assertPlatform "services.picom" pkgs # fading
lib.platforms.linux) fading = cfg.fade;
]; fade-delta = cfg.fadeDelta;
fade-in-step = elemAt cfg.fadeSteps 0;
fade-out-step = elemAt cfg.fadeSteps 1;
fade-exclude = cfg.fadeExclude;
# shadows
shadow = cfg.shadow;
shadow-offset-x = elemAt cfg.shadowOffsets 0;
shadow-offset-y = elemAt cfg.shadowOffsets 1;
shadow-opacity = cfg.shadowOpacity;
shadow-exclude = cfg.shadowExclude;
# opacity
active-opacity = cfg.activeOpacity;
inactive-opacity = cfg.inactiveOpacity;
wintypes = cfg.wintypes;
opacity-rule = cfg.opacityRules;
# other options
backend = cfg.backend;
vsync = cfg.vSync;
};
home.packages = [ cfg.package ]; home.packages = [ cfg.package ];
@ -307,4 +317,6 @@ in {
}; };
}; };
}; };
meta.maintainers = with lib.maintainers; [ thiagokokada ];
} }

View file

@ -1,33 +1,18 @@
# fading active-opacity = 1.000000;
fading = true; backend = "xrender";
dbe = true;
fade-delta = 5; fade-delta = 5;
fade-in-step = 0.04; fade-exclude = [ "window_type *= 'menu'" , "name ~= 'Firefox$'" , "focused = 1" ];
fade-out-step = 0.04; fade-in-step = 0.040000;
fade-exclude = ["window_type *= 'menu'","name ~= 'Firefox$'","focused = 1"]; fade-out-step = 0.040000;
fading = true;
# shadows inactive-opacity = 1.000000;
opacity-rule = [ ];
shadow = true; shadow = true;
shadow-exclude = [ "window_type *= 'menu'" , "name ~= 'Firefox$'" , "focused = 1" ];
shadow-offset-x = -10; shadow-offset-x = -10;
shadow-offset-y = -15; shadow-offset-y = -15;
shadow-opacity = 0.8; shadow-opacity = 0.800000;
shadow-exclude = ["window_type *= 'menu'","name ~= 'Firefox$'","focused = 1"];
# opacity
active-opacity = 1.0;
inactive-opacity = 1.0;
inactive-dim = 0.0;
opacity-rule = [];
wintypes:
{
dock = { shadow = false; };
dnd = { shadow = false; };
popup_menu = { opacity = 1.0; };
dropdown_menu = { opacity = 1.0; };
};
# other options
backend = "xrender";
vsync = true;
unredir-if-possible = true; unredir-if-possible = true;
dbe = true; vsync = true;
wintypes: { dropdown_menu = { opacity = 1.000000; }; popup_menu = { opacity = 1.000000; }; };

View file

@ -5,20 +5,20 @@
enable = true; enable = true;
fade = true; fade = true;
fadeDelta = 5; fadeDelta = 5;
fadeSteps = [ "0.04" "0.04" ]; fadeSteps = [ 4.0e-2 4.0e-2 ];
fadeExclude = fadeExclude =
[ "window_type *= 'menu'" "name ~= 'Firefox$'" "focused = 1" ]; [ "window_type *= 'menu'" "name ~= 'Firefox$'" "focused = 1" ];
shadow = true; shadow = true;
shadowOffsets = [ (-10) (-15) ]; shadowOffsets = [ (-10) (-15) ];
shadowOpacity = "0.8"; shadowOpacity = 0.8;
shadowExclude = shadowExclude =
[ "window_type *= 'menu'" "name ~= 'Firefox$'" "focused = 1" ]; [ "window_type *= 'menu'" "name ~= 'Firefox$'" "focused = 1" ];
backend = "xrender"; backend = "xrender";
vSync = true; vSync = true;
extraOptions = '' settings = {
unredir-if-possible = true; "unredir-if-possible" = true;
dbe = true; "dbe" = true;
''; };
experimentalBackends = true; experimentalBackends = true;
}; };