2019-05-24 09:13:55 +02:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
|
|
cfg = config.services.xsuspender;
|
|
|
|
|
|
|
|
xsuspenderOptions = types.submodule {
|
|
|
|
options = {
|
|
|
|
matchWmClassContains = mkOption {
|
|
|
|
description = "Match windows that wm class contains string.";
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
matchWmClassGroupContains = mkOption {
|
|
|
|
description = "Match windows where wm class group contains string.";
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
matchWmNameContains = mkOption {
|
|
|
|
description = "Match windows where wm name contains string.";
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
suspendDelay = mkOption {
|
|
|
|
description = "Initial suspend delay in seconds.";
|
|
|
|
type = types.int;
|
|
|
|
default = 5;
|
|
|
|
};
|
|
|
|
|
|
|
|
resumeEvery = mkOption {
|
|
|
|
description = "Resume interval in seconds.";
|
|
|
|
type = types.int;
|
|
|
|
default = 50;
|
|
|
|
};
|
|
|
|
|
|
|
|
resumeFor = mkOption {
|
|
|
|
description = "Resume duration in seconds.";
|
|
|
|
type = types.int;
|
|
|
|
default = 5;
|
|
|
|
};
|
|
|
|
|
|
|
|
execSuspend = mkOption {
|
|
|
|
description = ''
|
|
|
|
Before suspending, execute this shell script. If it fails,
|
|
|
|
abort suspension.
|
|
|
|
'';
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
example = ''echo "suspending window $XID of process $PID"'';
|
|
|
|
};
|
|
|
|
|
|
|
|
execResume = mkOption {
|
|
|
|
description = ''
|
|
|
|
Before resuming, execute this shell script. Resume the
|
|
|
|
process regardless script failure.
|
|
|
|
'';
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
2020-02-02 00:39:17 +01:00
|
|
|
example = "echo resuming ...";
|
2019-05-24 09:13:55 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
sendSignals = mkOption {
|
|
|
|
description = ''
|
|
|
|
Whether to send SIGSTOP / SIGCONT signals or not.
|
|
|
|
If false just the exec scripts are run.
|
|
|
|
'';
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
suspendSubtreePattern = mkOption {
|
2020-02-02 00:39:17 +01:00
|
|
|
description =
|
|
|
|
"Also suspend descendant processes that match this regex.";
|
2019-05-24 09:13:55 +02:00
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
onlyOnBattery = mkOption {
|
|
|
|
description = "Whether to enable process suspend only on battery.";
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
autoSuspendOnBattery = mkOption {
|
|
|
|
description = ''
|
|
|
|
Whether to auto-apply rules when switching to battery
|
|
|
|
power even if the window(s) didn't just lose focus.
|
|
|
|
'';
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
downclockOnBattery = mkOption {
|
|
|
|
description = ''
|
|
|
|
Limit CPU consumption for this factor when on battery power.
|
|
|
|
Value 1 means 50% decrease, 2 means 66%, 3 means 75% etc.
|
|
|
|
'';
|
|
|
|
type = types.int;
|
|
|
|
default = 0;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-02-02 00:39:17 +01:00
|
|
|
in {
|
2019-05-24 09:13:55 +02:00
|
|
|
meta.maintainers = [ maintainers.offline ];
|
|
|
|
|
|
|
|
options = {
|
|
|
|
services.xsuspender = {
|
|
|
|
enable = mkEnableOption "XSuspender";
|
|
|
|
|
|
|
|
defaults = mkOption {
|
|
|
|
description = "XSuspender defaults.";
|
|
|
|
type = xsuspenderOptions;
|
2020-02-02 00:39:17 +01:00
|
|
|
default = { };
|
2019-05-24 09:13:55 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
rules = mkOption {
|
|
|
|
description = "Attribute set of XSuspender rules.";
|
|
|
|
type = types.attrsOf xsuspenderOptions;
|
2020-02-02 00:39:17 +01:00
|
|
|
default = { };
|
2019-05-24 09:13:55 +02:00
|
|
|
example = {
|
|
|
|
Chromium = {
|
|
|
|
suspendDelay = 10;
|
|
|
|
matchWmClassContains = "chromium-browser";
|
|
|
|
suspendSubtreePattern = "chromium";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
debug = mkOption {
|
|
|
|
description = "Whether to enable debug output.";
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
iniContent = mkOption {
|
|
|
|
type = types.attrsOf types.attrs;
|
|
|
|
internal = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
2020-02-02 00:39:17 +01:00
|
|
|
services.xsuspender.iniContent = let
|
|
|
|
mkSection = values:
|
|
|
|
filterAttrs (_: v: v != null) {
|
2019-07-04 13:44:59 +02:00
|
|
|
match_wm_class_contains = values.matchWmClassContains;
|
|
|
|
match_wm_class_group_contains = values.matchWmClassGroupContains;
|
|
|
|
match_wm_name_contains = values.matchWmNameContains;
|
2019-05-24 09:13:55 +02:00
|
|
|
suspend_delay = values.suspendDelay;
|
|
|
|
resume_every = values.resumeEvery;
|
|
|
|
resume_for = values.resumeFor;
|
|
|
|
exec_suspend = values.execSuspend;
|
|
|
|
exec_resume = values.execResume;
|
|
|
|
send_signals = values.sendSignals;
|
2019-07-04 13:44:59 +02:00
|
|
|
suspend_subtree_pattern = values.suspendSubtreePattern;
|
2019-05-24 09:13:55 +02:00
|
|
|
only_on_battery = values.onlyOnBattery;
|
|
|
|
auto_suspend_on_battery = values.autoSuspendOnBattery;
|
|
|
|
downclock_on_battery = values.downclockOnBattery;
|
|
|
|
};
|
2020-02-02 00:39:17 +01:00
|
|
|
in {
|
|
|
|
Default = mkSection cfg.defaults;
|
|
|
|
} // mapAttrs (_: mkSection) cfg.rules;
|
2019-05-24 09:13:55 +02:00
|
|
|
|
|
|
|
# To make the xsuspender tool available.
|
|
|
|
home.packages = [ pkgs.xsuspender ];
|
|
|
|
|
2020-02-02 00:39:17 +01:00
|
|
|
xdg.configFile."xsuspender.conf".text = generators.toINI { } cfg.iniContent;
|
2019-05-24 09:13:55 +02:00
|
|
|
|
|
|
|
systemd.user.services.xsuspender = {
|
|
|
|
Unit = {
|
|
|
|
Description = "XSuspender";
|
|
|
|
After = [ "graphical-session-pre.target" ];
|
|
|
|
PartOf = [ "graphical-session.target" ];
|
2020-02-02 00:39:17 +01:00
|
|
|
X-Restart-Triggers =
|
|
|
|
[ "${config.xdg.configFile."xsuspender.conf".source}" ];
|
2019-05-24 09:13:55 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Service = {
|
|
|
|
ExecStart = "${pkgs.xsuspender}/bin/xsuspender";
|
|
|
|
Environment = mkIf cfg.debug [ "G_MESSAGE_DEBUG=all" ];
|
|
|
|
};
|
|
|
|
|
2020-02-02 00:39:17 +01:00
|
|
|
Install = { WantedBy = [ "graphical-session.target" ]; };
|
2019-05-24 09:13:55 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|