5

I am trying to use xprintidle to get the X (Unity) idle time so that I can put my monitor to sleep after a certain time. (I have to use xset dpms force off because my monitor will not come back on when using normal Ubuntu power/suspend settings. Different problem...) But xprintidle will reset to 0 ms every 30 seconds whether I am using my machine or not. i.e., whether I am moving the mouse/clicking/scrolling or typing on the keyboard. I suspect that something is causing Unity to think that I'm not idle, but I can't figure out what that might be.

Here is an output showing the problem:

x-pc-linux% while [[ $(xprintidle) -lt 60000 ]]; do
                echo "$(date +%T) $(xprintidle)" && sleep 1;
            done
13:24:47 12
13:24:48 917
13:24:49 1924
13:24:50 2933
13:24:51 3940
13:24:52 4946
13:24:53 5955
13:24:54 6963
13:24:55 7969
13:24:56 8976
13:24:57 9982
13:24:58 10990
.
. # snip
.
13:25:08 21061
13:25:09 22069
13:25:10 23078
13:25:11 24085
13:25:12 342
13:25:13 1350
13:25:14 2358
13:25:15 3364
13:25:16 4372
13:25:17 5380
13:25:18 6388
13:25:19 7395
13:25:20 8402
13:25:21 9409
13:25:22 10417
.
. # snip
.
13:25:35 23511
13:25:36 24519
13:25:37 25525
13:25:38 26532
13:25:39 27540
13:25:40 28549
13:25:41 29556
13:25:42 551
13:25:43 1559
13:25:44 2566
^C% 

Notice how the idle time resets at the 12 second and 42 second mark. (Ok, so I have the ultimate answer, but not to this question!)

I have also tried running w (What does idle time output from "w" command tell?), but unfortunately it shows "?xdm?" for X idle time.

x-pc-linux% w
 13:37:47 up 2 days,  3:28,  4 users,  load average: 1.76, 2.04, 2.07
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
***      :0       :0               Sat10   ?xdm?   4days  0.59s /sbin/upstart --user
***      pts/1    :0               Sat10    2:09m  0.39s  0.30s zsh
***      pts/4    :0               Sun14    0.00s  5:34   0.00s w
***      pts/12   192.168.1.144    11:20   20:11  13.41s 13.32s zsh

[Edit] I've also tried getting the idle time directly from the XScreenSaver extension as done here in Andrey Sidorov's answer, but I get the same timer reset every 30 seconds.

The x.org documentation only mentions

The idle field specifies the number of milliseconds since the last input was received from the user on any of the input devices.

  • 1
    I cannot find any documentation describing what actions would reset the timeout. Frustrating. – earthmeLon Oct 19 '15 at 21:35
  • xprintidle is triggered by keyboard- and mouse events (not screen events). Something must simulate either one of those. Any background script or process running that could be doing that? Terrible job, but looking through your processes should include the one. Starting with ps -u <username> – Jacob Vlijm Oct 20 '15 at 05:43
  • This is frustrating and good at the same time; I can't reproduce the problem anymore. I had to restart when my monitor went to sleep in order to see anything on the screen, and now xprintidle works as expected. I had restarted before and the problem was still there. I'll keep track of what processes I start per @JacobVlijm's suggestion in case it comes back... – SO_fix_the_vote_sorting_bug Oct 20 '15 at 22:37
  • I ultimately figured this out by testing my idle script every so often. Turns out that if I have the game ARK:Survival running in the background, it will reset the idle field from XScreenSaverAllocInfo() every 30 seconds. – SO_fix_the_vote_sorting_bug Oct 26 '15 at 00:51

2 Answers2

8

Looking at the source for xprintidle (see below for how I did this), we see:

This program prints the "idle time" of the user to stdout.  The "idle
time" is the number of milliseconds since input was received on any
input device.  If unsuccessful, the program prints a message to stderr
and exits with a non-zero exit code.

So, I suppose that moving the mouse would reset the timeout. This make sense, since the timeout in question is leading to screen blanking/locking.

Looking further in the source, one sees the functions that xprintidle uses. (XScreenSaverAllocInfo(), DPMSQueryExtension(), etc). Reading the man page for these functions will give you more detail (man XScreenSaverAllocInfo).

How I got the source to look at:

# Includes several set-up-the-environment steps
mkdir ${HOME}/apt-src  
cd ${HOME}/apt-src
sudo apt-get install apt-src
apt-src install xprintidle
cd xprintidle-0.2/
ls
less xprintidle.c
cd ..
apt-src remove xprintidle
waltinator
  • 36,399
0

In my case it was OBS which resets the idle timer every ~30 seconds when the virtual camera is active.

I wrote a script to ignore the 30 second wrap around. That way you can still take action based on idle even if you can't figure out what's causing the periodic idle reset.

https://github.com/poleguy/sweep/blob/master/check_idle.py

The key logic is this:

def get_idle_corrected():
    # get idle time, but ignoring any resets that occur at a 30 second period
    # because these are due to obs interrupting the idle to force the screen active
    global idle_last
    global time_start
    time_end  = time.monotonic()
idle = int(subprocess.check_output(&quot;xprintidle&quot;).decode(&quot;utf-8&quot;).strip())/1000
if idle &gt; idle_last:
    # still idle
    pass
elif idle_last + poll_period - idle &gt; idle_periodic_reset_low and idle_last + poll_period - idle &lt; idle_periodic_reset_high:
    # ignore periodic reset near 30 seconds due to obs
    pass
else:
    # idle time went down, but not near the expected periodic reset due to obs.
    # so this is reported as a true idle reset
    time_start = time.monotonic() + idle
idle_last = idle
print(f'idle {idle}, idle_corrected {time_end - time_start:0.3f}')
# return the time elapsed since we saw a non-periodic reset of the idle count
return time_end - time_start

poleguy
  • 155