From f74dc9c70bc05c87bf2ebb9a5e60665a87753ce5 Mon Sep 17 00:00:00 2001 From: Dominik Schrempf Date: Mon, 7 Jun 2021 22:13:43 +0200 Subject: [PATCH] xidlehook: add module (#1761) Co-authored-by: Nicolas Berbiche --- .github/CODEOWNERS | 4 +- modules/misc/news.nix | 8 ++ modules/modules.nix | 1 + modules/services/xidlehook.nix | 149 +++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 modules/services/xidlehook.nix diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a97b03d66..e2d338e1b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -300,6 +300,8 @@ /modules/services/xembed-sni-proxy.nix @rycee +/modules/services/xidlehook.nix @dschrempf + /modules/services/xscreensaver.nix @rycee /modules/services/xsuspender.nix @offlinehacker @@ -310,4 +312,4 @@ /modules/xresources.nix @rycee -/modules/xsession.nix @rycee +/modules/xsession.nix @rycee \ No newline at end of file diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 497e6bc09..7185c8c4d 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -2061,6 +2061,14 @@ in A new module is available: 'programs.piston-cli'. ''; } + + { + time = "2021-06-02T04:24:10+00:00"; + condition = hostPlatform.isLinux; + message = '' + A new module is available: 'services.xidlehook'. + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index c28304514..3139e7b03 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -219,6 +219,7 @@ let (loadModule ./services/wlsunset.nix { condition = hostPlatform.isLinux; }) (loadModule ./services/xcape.nix { condition = hostPlatform.isLinux; }) (loadModule ./services/xembed-sni-proxy.nix { condition = hostPlatform.isLinux; }) + (loadModule ./services/xidlehook.nix { condition = hostPlatform.isLinux; }) (loadModule ./services/xscreensaver.nix { }) (loadModule ./services/xsuspender.nix { condition = hostPlatform.isLinux; }) (loadModule ./systemd.nix { }) diff --git a/modules/services/xidlehook.nix b/modules/services/xidlehook.nix new file mode 100644 index 000000000..da91de850 --- /dev/null +++ b/modules/services/xidlehook.nix @@ -0,0 +1,149 @@ +# Wrapper around xidlehook. + +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xidlehook; + + notEmpty = list: filter (x: x != "" && x != null) (flatten list); + + timers = let + toTimer = timer: + "--timer ${toString timer.delay} ${ + escapeShellArgs [ timer.command timer.canceller ] + }"; + in map toTimer (filter (timer: timer.command != null) cfg.timers); + + script = pkgs.writeShellScript "xidlehook" '' + ${concatStringsSep "\n" + (mapAttrsToList (name: value: "export ${name}=${value}") + cfg.environment or { })} + ${concatStringsSep " " (notEmpty [ + "${cfg.package}/bin/xidlehook" + (optionalString cfg.once "--once") + (optionalString cfg.not-when-fullscreen "--not-when-fullscreen") + (optionalString cfg.not-when-audio "--not-when-audio") + timers + ])} + ''; +in { + meta.maintainers = [ maintainers.dschrempf ]; + + options.services.xidlehook = { + enable = mkEnableOption "xidlehook systemd service"; + + package = mkOption { + type = types.package; + default = pkgs.xidlehook; + defaultText = "pkgs.xidlehook"; + description = "The package to use for xidlehook."; + }; + + environment = mkOption { + type = types.attrsOf types.str; + default = { }; + example = literalExample '' + { + "primary-display" = "$(xrandr | awk '/ primary/{print $1}')"; + } + ''; + description = '' + Extra environment variables to be exported in the script. + These options are passed unescaped as export name=value. + ''; + }; + + not-when-fullscreen = mkOption { + type = types.bool; + default = false; + example = true; + description = "Disable locking when a fullscreen application is in use."; + }; + + not-when-audio = mkOption { + type = types.bool; + default = false; + example = true; + description = "Disable locking when audio is playing."; + }; + + once = mkEnableOption "running the program once and exiting"; + + timers = mkOption { + type = types.listOf (types.submodule { + options = { + delay = mkOption { + type = types.ints.unsigned; + example = 60; + description = "Time before executing the command."; + }; + command = mkOption { + type = types.nullOr types.str; + example = literalExample '' + ''${pkgs.libnotify}/bin/notify-send "Idle" "Sleeping in 1 minute" + ''; + description = '' + Command executed after the idle timeout is reached. + Path to executables are accepted. + The command is automatically escaped. + ''; + }; + canceller = mkOption { + type = types.str; + default = ""; + example = literalExample '' + ''${pkgs.libnotify}/bin/notify-send "Idle" "Resuming activity" + ''; + description = '' + Command executed when the user becomes active again. + This is only executed if the next timer has not been reached. + Path to executables are accepted. + The command is automatically escaped. + ''; + }; + }; + }); + default = [ ]; + example = literalExample '' + [ + { + delay = 60; + command = "xrandr --output \"$PRIMARY_DISPLAY\" --brightness .1"; + canceller = "xrandr --output \"$PRIMARY_DISPLAY\" --brightness 1"; + } + { + delay = 120; + command = "''${pkgs.writeShellScript "my-script" ''' + # A complex script to run + '''}"; + } + ] + ''; + description = '' + A set of commands to be executed after a specific idle timeout. + The commands specified in command and canceller + are passed escaped to the script. + To use or re-use environment variables that are script-dependent, specify them + in the environment section. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.xidlehook = { + Unit = { + Description = "xidlehook service"; + PartOf = [ "graphical-session.target" ]; + After = [ "graphical-session.target" ]; + ConditionEnvironment = [ "DISPLAY" ]; + }; + Service = { + Type = if cfg.once then "oneshot" else "simple"; + ExecStart = "${script}"; + }; + Install.WantedBy = [ "graphical-session.target" ]; + }; + }; +}