jD91mZM2 / xidlehook

GitLab: https://gitlab.com/jD91mZM2/xidlehook
MIT License
387 stars 33 forks source link

[Feature Request] generic --not-when flag #41

Closed sidequestboy closed 4 years ago

sidequestboy commented 4 years ago

It would be nice if we could have a generic --not-when flag that takes a script as an argument and runs the timer conditionally on its exit code. e.g.

xidlehook --not-when youtube --timer 'xscreensaver-command activate'

and we could write our own checking scripts for youtube, etc.

jD91mZM2 commented 4 years ago

You could always compose your own xidlehook application consisting of the conditions you want, using xidlehook-core.

Though, if you just want to run a bash command you could just do xidlehook --timer 'some-command-here && xscreensaver-command activate'

sidequestboy commented 4 years ago

Thanks for the reply!

The differences I see between your proposed workaround and the request are (1) it applies only to one timer, and (2) it moves to the next timer in the chain even if the check fails, which is not the behaviour of the --not-when-* flags which actually prevent the timer (and all subsequent timers) being run.

On a related note to (1), the ability to apply --not-when-* checks to individual timers in the chain could be very useful. For example, I might want my screensaver to come on while there's audio, but to prevent my suspend command. A workaround for this use-case might be to nest xidlehooks:

#! /usr/bin/env bash

suspend_hook() {
    xidlehook --not-when-audio --timer 300 'systemctl suspend' ''
}
export -f suspend_hook

xidlehook --timer 300 'xscreensaver-command -activate' '' \
          --timer 0 suspend_hook ''

But I imagine it would be nicer to write the above like so:

xidlehook --timer 300 'xscreensaver-command -activate' '' \
          --timer 300 'systemctl suspend' '' --not-when-audio

I am curious about Rust, but haven't touched it yet! Implementing my own client might be a good challenge for me though! I'll take a look at xidlehook-core :)

To summarize, I think two improvements could be made to the command syntax -

I actually can't come up with a reasonable workaround for the first suggestion - I think it would involve process management and nested xidlehooks.

jD91mZM2 commented 4 years ago

I can see the value in having --not-when-* stick to a timer, feel free to send a PR. The module API should make this rather easy. The Progress enum in xidlehook-core/src/modules/mod.rs needs a "Skip" option, and then I suppose the built-in modules could choose to skip it or something. Or maybe we could do something like --not-when <module> <action> that either aborts the chain or skips ahead. I don't know. :)

But I am very uncertain about having some kind of generic --not-when, because while I like the idea, it seems like overengineering to support custom scripts when we already have an activation hook script right there you can choose to run whatever checks you want in and maybe kill the xidlehook process or disable timers with the socket API.

Keep in mind that xidlehook isn't meant for ease of usage, since you're supposed to just start it in some shell script somewhere rather than run it and have it read some config files. There shall be no --not-when <custom thing> because that is not pure :)

sidequestboy commented 4 years ago

Gotcha. I understand the desire to keep things minimal. (:

FWIW, I think this bash script achieves the desired functionality

#! /usr/bin/env bash

youtube_is_running() {
    # custom stuff here
    return 1
}

pid=
while true; do
    if ! youtube_is_running; then
        if [ -z $pid ]; then
            xidlehook --timer 5 'xscreensaver-command -activate' '' &
            pid=$!
        fi
    elif [ ! -z $pid ]; then
        kill $pid
        pid=
    fi
    sleep 1
done
jD91mZM2 commented 4 years ago

@jameh Does something like this work instead? I'm trying to avoid as many spinloops as possible :)

Pretend this script lives as /my/script/path/here.sh

#! /usr/bin/env bash

youtube_is_running() {
    # custom stuff here
    return 1
}

IFS='' read -r -d '' TIMER_COMMAND <<EOF

if youtube_is_running; then
    # YouTube is running, exit xidlehook for now
    respawn_task() {
        # Do a spin loop waiting for YouTube to exit
        while youtube_is_running; do
            sleep 1 # or whatever delay/trigger you want
        done

        # Restart xidlehook
        exec /my/script/path/here.sh
    }

    # Launch task and exit xidlehook
    respawn_task &
    pkill $PPID
fi

EOF

exec xidlehook --timer 5 "$LOCKER_COMMAND" ''
MarcelRobitaille commented 3 years ago

Though, if you just want to run a bash command you could just do xidlehook --timer 'some-command-here && xscreensaver-command activate'

What if a timer that exits >0 causes all subsequent timers to not run? That would mean we could use this proposed workaround. I don't know if this would be "pure", but this solution or custom --not-when seems cleaner to me than killing and restarting xidlehook.