This allows us to move the retry behavior into a separate decorator.
The semantic is a bit different as, now, if there is another iteration
pending, it is lost.
For some reason, this makes X probe again the monitors. Switch to
`xrandr --current` seems to make this problem goes away. Maybe, this
is also `polybar --list-monitors` keeping a grab while polybar is
starting.
This seems cleaner than using `getattr()` to initialize the variable
inside the function.
Also, the debouncer function does not need this and can work with a
dictionary mapping functions to their worker.
There are some artifacts with xr_glx_hybrid and it is not available as
experimental. Let's try glx with experimental backend. No tearing.
Tested with https://www.youtube.com/watch?v=MfL_JkcEFbE.
I think this is more correct. Dampen is used in network world, but
debounce seems more common (notably, we debounce push buttons).
Another word could be throttle but that does not match as we need to
react to the last event of a batch instead of the first (and we sure
don't want to drop the last).
This is cleaner than putting arbitrary attributes inside a task. The
scheduling will be done later, so it is safe to put put everything
inside the namespace object and avoid polluting the function
namespace.
We have a worker running as long as there is work. The optional sleep
is not implemented. There is a slight semantic difference: the work is
not postponed indefinitely.
Cancellation is asynchronous. So, there was a race condition where we
were throwing away the task we just scheduled. Don't really on
cancellation for synchronization. We also want to have only one
instance running. So, use locks to ensure only one instance is running
and only cancel running functions while in sleeping phase, otherwise,
let them run.
Currently, this OK, however, it is assumed the function has somehow
the same effect whatever the arguments we provide. This is true for
the two callbacks we use `@dampen` on.