diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index aa7c0d2e..e165a6f2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -311,6 +311,9 @@ /modules/services/redshift-gammastep @rycee @petabyteboy @thiagokokada /tests/modules/redshift-gammastep @thiagokokada +/modules/services/screen-locker.nix @jrobsonchase +/tests/modules/services/screen-locker @jrobsonchase + /modules/services/status-notifier-watcher.nix @pltanton /modules/services/syncthing.nix @rycee diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix index 20663a28..badab65b 100644 --- a/modules/lib/maintainers.nix +++ b/modules/lib/maintainers.nix @@ -127,4 +127,10 @@ githubId = 605641; name = "Bart Bakker"; }; + jrobsonchase = { + email = "josh@robsonchase.com"; + github = "jrobsonchase"; + githubId = 1553581; + name = "Josh Robson Chase"; + }; } diff --git a/modules/misc/news.nix b/modules/misc/news.nix index a2aa80d7..a81a86f3 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -2203,6 +2203,16 @@ in A new module is available: 'programs.bottom'. ''; } + + { + time = "2021-09-23T17:04:48+00:00"; + message = '' + 'xautolock' is now optional in 'services.screen-locker', and the + 'services.screen-locker' options have been reorganized for clarity. + See the 'xautolock' and 'xss-lock' options modules in + 'services.screen-locker'. + ''; + } ]; }; } diff --git a/modules/services/screen-locker.nix b/modules/services/screen-locker.nix index 4da24b74..34794d1c 100644 --- a/modules/services/screen-locker.nix +++ b/modules/services/screen-locker.nix @@ -7,6 +7,20 @@ let cfg = config.services.screen-locker; in { + meta.maintainers = [ lib.hm.maintainers.jrobsonchase ]; + + imports = let + origOpt = name: [ "services" "screen-locker" name ]; + xautolockOpt = name: [ "services" "screen-locker" "xautolock" name ]; + xssLockOpt = name: [ "services" "screen-locker" "xss-lock" name ]; + in [ + (mkRenamedOptionModule (origOpt "xssLockExtraOptions") + (xssLockOpt "extraOptions")) + (mkRenamedOptionModule (origOpt "xautolockExtraOptions") + (xautolockOpt "extraOptions")) + (mkRenamedOptionModule (origOpt "enableDetectSleep") + (xautolockOpt "detectSleep")) + ]; options.services.screen-locker = { enable = mkEnableOption "screen locker for X session"; @@ -17,81 +31,118 @@ in { example = "\${pkgs.i3lock}/bin/i3lock -n -c 000000"; }; - enableDetectSleep = mkOption { - type = types.bool; - default = true; - description = '' - Whether to reset timers when awaking from sleep. - ''; - }; - inactiveInterval = mkOption { type = types.int; default = 10; description = '' Inactive time interval in minutes after which session will be locked. The minimum is 1 minute, and the maximum is 1 hour. + If is true, it will use this setting. See . + Otherwise, this will be used with xset to configure + the X server's screensaver timeout. ''; }; - xautolockExtraOptions = mkOption { - type = types.listOf types.str; - default = [ ]; - description = '' - Extra command-line arguments to pass to xautolock. - ''; - }; - - xssLockExtraOptions = mkOption { - type = types.listOf types.str; - default = [ ]; - description = '' - Extra command-line arguments to pass to xss-lock. - ''; - }; - }; - - config = mkIf cfg.enable { - assertions = [ - (lib.hm.assertions.assertPlatform "services.screen-locker" pkgs - lib.platforms.linux) - ]; - - systemd.user.services.xautolock-session = { - Unit = { - Description = "xautolock, session locker service"; - After = [ "graphical-session-pre.target" ]; - PartOf = [ "graphical-session.target" ]; + xautolock = { + enable = mkOption { + type = types.bool; + default = true; + description = "Use xautolock for time-based locking."; }; - Install = { WantedBy = [ "graphical-session.target" ]; }; + package = mkOption { + type = types.package; + default = pkgs.xautolock; + description = '' + Package providing the xautolock binary. + ''; + }; - Service = { - ExecStart = concatStringsSep " " ([ - "${pkgs.xautolock}/bin/xautolock" - "-time ${toString cfg.inactiveInterval}" - "-locker '${pkgs.systemd}/bin/loginctl lock-session $XDG_SESSION_ID'" - ] ++ optional cfg.enableDetectSleep "-detectsleep" - ++ cfg.xautolockExtraOptions); + detectSleep = mkOption { + type = types.bool; + default = true; + description = '' + Whether to reset xautolock timers when awaking from sleep. + No effect if is false. + ''; + }; + + extraOptions = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + Extra command-line arguments to pass to xautolock. + No effect if is false. + ''; }; }; - systemd.user.services.xss-lock = { - Unit = { - Description = "xss-lock, session locker service"; - After = [ "graphical-session-pre.target" ]; - PartOf = [ "graphical-session.target" ]; + xss-lock = { + package = mkOption { + type = types.package; + default = pkgs.xss-lock; + description = '' + Package providing the xss-lock binary. + ''; }; - Install = { WantedBy = [ "graphical-session.target" ]; }; - - Service = { - ExecStart = concatStringsSep " " - ([ "${pkgs.xss-lock}/bin/xss-lock" "-s \${XDG_SESSION_ID}" ] - ++ cfg.xssLockExtraOptions ++ [ "-- ${cfg.lockCmd}" ]); + extraOptions = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + Extra command-line arguments to pass to xss-lock. + ''; }; }; }; + config = mkIf cfg.enable (mkMerge [ + { + assertions = [ + (lib.hm.assertions.assertPlatform "services.screen-locker" pkgs + lib.platforms.linux) + ]; + + systemd.user.services.xss-lock = { + Unit = { + Description = "xss-lock, session locker service"; + After = [ "graphical-session-pre.target" ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { WantedBy = [ "graphical-session.target" ]; }; + + Service = { + ExecStart = concatStringsSep " " + ([ "${cfg.xss-lock.package}/bin/xss-lock" "-s \${XDG_SESSION_ID}" ] + ++ cfg.xss-lock.extraOptions ++ [ "-- ${cfg.lockCmd}" ]); + }; + }; + } + (mkIf (!cfg.xautolock.enable) { + systemd.user.services.xss-lock.Service.ExecStartPre = + "${pkgs.xorg.xset}/bin/xset s ${toString (cfg.inactiveInterval * 60)}"; + }) + (mkIf cfg.xautolock.enable { + systemd.user.services.xautolock-session = { + Unit = { + Description = "xautolock, session locker service"; + After = [ "graphical-session-pre.target" ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { WantedBy = [ "graphical-session.target" ]; }; + + Service = { + ExecStart = concatStringsSep " " ([ + "${cfg.xautolock.package}/bin/xautolock" + "-time ${toString cfg.inactiveInterval}" + "-locker '${pkgs.systemd}/bin/loginctl lock-session \${XDG_SESSION_ID}'" + ] ++ optional cfg.xautolock.detectSleep "-detectsleep" + ++ cfg.xautolock.extraOptions); + }; + }; + }) + ]); } diff --git a/tests/default.nix b/tests/default.nix index cf51d4aa..a65ee7c2 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -132,6 +132,7 @@ import nmt { ./modules/services/playerctld ./modules/services/polybar ./modules/services/redshift-gammastep + ./modules/services/screen-locker ./modules/services/sxhkd ./modules/services/syncthing ./modules/services/trayer diff --git a/tests/modules/services/screen-locker/basic-configuration.nix b/tests/modules/services/screen-locker/basic-configuration.nix new file mode 100644 index 00000000..9eee2a8e --- /dev/null +++ b/tests/modules/services/screen-locker/basic-configuration.nix @@ -0,0 +1,30 @@ +{ config, pkgs, ... }: + +{ + config = { + services.screen-locker = { + enable = true; + inactiveInterval = 5; + lockCmd = "${pkgs.i3lock}/bin/i3lock -n -c AA0000"; + xss-lock = { extraOptions = [ "-test" ]; }; + xautolock = { + enable = true; + detectSleep = true; + extraOptions = [ "-test" ]; + }; + }; + + test.stubs.i3lock = { }; + test.stubs.xss-lock = { }; + + nmt.script = '' + xssService=home-files/.config/systemd/user/xss-lock.service + xautolockService=home-files/.config/systemd/user/xautolock-session.service + + assertFileExists $xssService + assertFileRegex $xssService 'ExecStart=.*/bin/xss-lock.*-test.*i3lock -n -c AA0000' + assertFileExists $xautolockService + assertFileRegex $xautolockService 'ExecStart=.*/bin/xautolock.*-time 5.*-detectsleep.*-test.*' + ''; + }; +} diff --git a/tests/modules/services/screen-locker/default.nix b/tests/modules/services/screen-locker/default.nix new file mode 100644 index 00000000..667defc5 --- /dev/null +++ b/tests/modules/services/screen-locker/default.nix @@ -0,0 +1,5 @@ +{ + screen-locker-basic-configuration = ./basic-configuration.nix; + screen-locker-no-xautolock = ./no-xautolock.nix; + screen-locker-moved-options = ./moved-options.nix; +} diff --git a/tests/modules/services/screen-locker/moved-options.nix b/tests/modules/services/screen-locker/moved-options.nix new file mode 100644 index 00000000..4c9cad19 --- /dev/null +++ b/tests/modules/services/screen-locker/moved-options.nix @@ -0,0 +1,36 @@ +{ config, pkgs, options, lib, ... }: + +{ + config = { + services.screen-locker = { + enable = true; + inactiveInterval = 5; + lockCmd = "${pkgs.i3lock}/bin/i3lock -n -c AA0000"; + xssLockExtraOptions = [ "-test" ]; + xautolockExtraOptions = [ "-test" ]; + enableDetectSleep = true; + }; + + test.stubs.i3lock = { }; + test.stubs.xss-lock = { }; + + # Use the same verification script as the basic configuration. The result + # with the old options should be identical. + nmt.script = (import ./basic-configuration.nix { + inherit config pkgs; + }).config.nmt.script; + + test.asserts.warnings.expected = with lib; + let + renamed = { + xssLockExtraOptions = "xss-lock.extraOptions"; + xautolockExtraOptions = "xautolock.extraOptions"; + enableDetectSleep = "xautolock.detectSleep"; + }; + in mapAttrsToList (old: new: + builtins.replaceStrings [ "\n" ] [ " " ] '' + The option `services.screen-locker.${old}' defined in + ${showFiles options.services.screen-locker.${old}.files} + has been renamed to `services.screen-locker.${new}'.'') renamed; + }; +} diff --git a/tests/modules/services/screen-locker/no-xautolock.nix b/tests/modules/services/screen-locker/no-xautolock.nix new file mode 100644 index 00000000..03ab0868 --- /dev/null +++ b/tests/modules/services/screen-locker/no-xautolock.nix @@ -0,0 +1,24 @@ +{ config, pkgs, ... }: + +{ + config = { + services.screen-locker = { + enable = true; + inactiveInterval = 5; + lockCmd = "${pkgs.i3lock}/bin/i3lock -n -c AA0000"; + xss-lock = { extraOptions = [ "-test" ]; }; + xautolock = { enable = false; }; + }; + + test.stubs.i3lock = { }; + test.stubs.xss-lock = { }; + + nmt.script = '' + xssService=home-files/.config/systemd/user/xss-lock.service + + assertFileExists $xssService + assertFileRegex $xssService 'ExecStart=.*/bin/xss-lock.*-test.*i3lock -n -c AA0000' + assertFileRegex $xssService 'ExecStartPre=.*/xset s 300' + ''; + }; +}