diff options
Diffstat (limited to 'infra/libkookie/home-manager/modules/services/xsuspender.nix')
-rw-r--r-- | infra/libkookie/home-manager/modules/services/xsuspender.nix | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/infra/libkookie/home-manager/modules/services/xsuspender.nix b/infra/libkookie/home-manager/modules/services/xsuspender.nix new file mode 100644 index 000000000000..7d855f05d51f --- /dev/null +++ b/infra/libkookie/home-manager/modules/services/xsuspender.nix @@ -0,0 +1,195 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.xsuspender; + + iniFormat = pkgs.formats.ini { }; + + 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; + example = "echo resuming ..."; + }; + + 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 { + description = + "Also suspend descendant processes that match this regex."; + 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; + }; + }; + }; + +in { + meta.maintainers = [ maintainers.offline ]; + + options = { + services.xsuspender = { + enable = mkEnableOption "XSuspender"; + + defaults = mkOption { + description = "XSuspender defaults."; + type = xsuspenderOptions; + default = { }; + }; + + rules = mkOption { + description = "Attribute set of XSuspender rules."; + type = types.attrsOf xsuspenderOptions; + default = { }; + 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 = iniFormat.type; + internal = true; + }; + }; + }; + + config = mkIf cfg.enable { + services.xsuspender.iniContent = let + mkSection = values: + filterAttrs (_: v: v != null) { + match_wm_class_contains = values.matchWmClassContains; + match_wm_class_group_contains = values.matchWmClassGroupContains; + match_wm_name_contains = values.matchWmNameContains; + suspend_delay = values.suspendDelay; + resume_every = values.resumeEvery; + resume_for = values.resumeFor; + exec_suspend = values.execSuspend; + exec_resume = values.execResume; + send_signals = values.sendSignals; + suspend_subtree_pattern = values.suspendSubtreePattern; + only_on_battery = values.onlyOnBattery; + auto_suspend_on_battery = values.autoSuspendOnBattery; + downclock_on_battery = values.downclockOnBattery; + }; + in { + Default = mkSection cfg.defaults; + } // mapAttrs (_: mkSection) cfg.rules; + + # To make the xsuspender tool available. + home.packages = [ pkgs.xsuspender ]; + + xdg.configFile."xsuspender.conf".source = + iniFormat.generate "xsuspender.conf" cfg.iniContent; + + systemd.user.services.xsuspender = { + Unit = { + Description = "XSuspender"; + After = [ "graphical-session-pre.target" ]; + PartOf = [ "graphical-session.target" ]; + X-Restart-Triggers = + [ "${config.xdg.configFile."xsuspender.conf".source}" ]; + }; + + Service = { + ExecStart = "${pkgs.xsuspender}/bin/xsuspender"; + Environment = mkIf cfg.debug [ "G_MESSAGE_DEBUG=all" ]; + }; + + Install = { WantedBy = [ "graphical-session.target" ]; }; + }; + }; +} |