View previous topic :: View next topic |
Author |
Message |
VinzC Watchman
Joined: 17 Apr 2004 Posts: 5098 Location: Dark side of the mood
|
Posted: Sun Jun 26, 2016 9:33 pm Post subject: HOWTO: Deactivate xscreensaver while watching online videos |
|
|
Hi all. This is a sequel from a thread I posted a while ago. I came out with this script today and I have just tested it while watching videos on Youtube with Firefox. The script can be updated for use with any browser though.
See also Syl20 nice & simple implementation.
The background story
I love xscreensaver. But I just hate it when I have to tuck it off while I'm away from the keyboard, watching videos, for instance. On one hand the developers of mplayer have come with a nifty solution: heartbeat-cmd. Unfortunately you can't expect Mozilla to implement the same trick. So we have to do it ourselves, right?...
Prerequisite
As krinn rightfully hints, /proc/pid/io may not always be available. You have to make sure your kernel configuration includes the following:
Kernel config: | Enable extended accounting over taskstats (CONFIG_TASK_XACCT)
* Enable per-task storage I/O accounting (CONFIG_TASK_IO_ACCOUNTING=y) |
Note that very same configuration is required if you use iotop.
How does it work
It's best (IMHO) to have the script run on as many distributions as possible instead of relying on extensions or modules, which are browser- or desktop-environment-dependent. Xorg comes with plenty of tools, which used appropriately can get us close to what we want.
Instead of deactivating xscreensaver from within Firefox, we want to a) detect what the active (i.e. currently focused) window is, b) check the process it belongs to, c) if it is busy downloading (a video, whatever...) While a) and b) are easy, c) is less straightforward. How can we detect a browser that pulls down a video from Youtube? Or any video? Check the URL? No, too cumbersome.
A browser that shows a video is supposed to cause disk activity. In general (and it's true with Youtube) videos aren't downloaded at once (unless they're very short) but slowly enough to not hog up the whole bandwidth. That's the most daring assumption I made. If you check the kernel I/O information for a given process ID you'll see a few hints as to what amount of data a process is pulling off or throwing at the storage. Check write_bytes in /proc/<PID>/io for short.
If the browser doesn't write to the disk for 30 seconds the script exits. Otherwise it sends the deactivate beacon to xscreensaver.
EDIT: Here's an updated version that I run on my laptop. The update accounts for the presence of a power manager, which may co-exist with a screen saver such as xscreensaver. In such cases deactivate screen saving is just not enough. The trick I used is to switch to presentation mode (an underused featured, speaking for myself) to temporarily disable energy saving while the screen is busy but no input is detected. Since complexity slightly increased, I also included a self-explained help section, you know, just in case .
Running it from the command line is also improved, along with rudimentary diagnostics. I also introduced a way to support other DE than just Xfce. I didn't implement it though but I thought of dynamically loading DE modules (see xfce_ prefixes. It would require a dedicated command line argument but it should be not too difficult to add.
One last note: it might interfere with the presentation settings on your machine. I don't use it at all so I didn't think of a non-intrusive solution. Feel free to comment & suggest if you use that feature with your power manager application .
Important note: I also changed the command line interface, which now requires a -P option for gathering the DISPLAY variable.
Here's the script.
/usr/local/bin/keep-active.sh: | #!/bin/sh
#
# This script tries to inhibit screen saving while there's a browser
# which is detected active, i.e. exhibiting disk activity for a given
# amount of time. The detection algorithm is triggered only when the
# browser window is on the foreground, i.e. the window with the focus.
#
# The script may be run from the command line or a cron job. The main
# goal is to compensate for the lack of features in browsers to block
# or suspend power savings while the screen is busy, say rendering
# videos, for example.
#
# Author: Vinz C. <vinzc@users.sf.net>
# Configuration variables. These affect how long a program remains idle
# i.e. without disk activity. Disk activity is checked as many times as
# MAX_COUNT (in seconds) for a total amount of LOOP_DELAY x MAX_COUNT .
#
MAX_COUNT=3 # Number of times no disk activity is detected
LOOP_DELAY=10 # Seconds to wait once activity is detected
VERBOSE=false
# [Supposedly] read-only variable
NAME=${0##*/} # This script's name
# Process watch indicators
last_write_bytes=0 # Most recent bytes written to disk
count=0 # Iteration count
# Writes a message to the standard error or the system log
# on a non interactive shell
message()
{
tty -s && echo "$*">&2 || logger -t $NAME "$*"
}
# Writes an error message to the standard error or the system log
# on a non interactive shell and exit with a return code if non zero
error()
{
local ret=$1
shift && message "$*"
[ $ret -eq 0 ] || exit $ret
}
# Writes a message to the standard error or the system log
# on a non interactive shell but only in verbose mode
verbose()
{
$VERBOSE && message "$*"
}
# Find the DISPLAY environment variable of a given process
find_display()
{
local PID=$(pgrep -u $UID $1) || return $?
eval $(grep -Eoa 'DISPLAY=[:09.]+' /proc/$PID/environ)
}
# Return non-zero if the given process window has he focus on DISPLAY
#
# Force xprop formatting to output eval assignment expressions, such
# as '_NET_ACTIVE_WINDOW' and '_NET_WM_PID' (eval doesn't accept spaces
# around the equal sign.)
pid_if_active()
{
# Get active window ID
local _NET_ACTIVE_WINDOW
eval $(xprop -root -notype -f _NET_ACTIVE_WINDOW 32x '=$0\n' _NET_ACTIVE_WINDOW 2>/dev/null)
[ -n "$_NET_ACTIVE_WINDOW" ] || return 1
# Get its process ID, set PID if found
local _NET_WM_PID
eval $(xprop -id $_NET_ACTIVE_WINDOW -notype -f _NET_WM_PID 32c '=$0\n' _NET_WM_PID 2>/dev/null)
[ -n "$_NET_WM_PID" ] || return 1
# Is it the process which name was passed as an argument?
grep -Eqs "$@" /proc/$_NET_WM_PID/cmdline && PID=$_NET_WM_PID
}
# Deactivate (temporarily) the screensaver for DISPLAY
keep_active()
{
# Keep useless babling out...
DISPLAY=$DISPLAY xscreensaver-command -deactivate >/dev/null
}
# Xfce-specific: enable/disable presentation mode
xfce_presentation_mode()
{
$XFCES_POWER_MGR && [ -n "$1" ] && xfconf-query -c xfce4-power-manager \
-p /xfce4-power-manager/presentation-mode -s $1
}
# Xfce-specific: deactivate screen saver and set presentation mode
# On Xfce presentation mode doesn't (seem to) prevent xsvreensaver
# from activating itself so both must be taken care of.
xfce_keep_active()
{
keep_active
xfce_presentation_mode true
}
usage()
{
cat <<-EOF
Usage: $NAME [-h][-P name][-d delay][-c count][-v][--debug] process
Watch for disk activity of a process and temporarily disable power saving
until no disk activity is detected. This script is intended for use when
watching videos in a[ny] browser since none of them include features to
disable power saving while the screen is busy and input is idle.
process Process (typically a browser name (not PID) to watch for.
-P name Fetch the DISPLAY environment variable from process name.
If run from Xfce "name" will be xfce4-session. This is
useful when running multiple DE or on a machine with more
than one user account.
The DISPLAY environment variable is deduced and passed to
\`xprop´ and other applications that need it to work.
-d delay Delay (in seconds) to wait between loops once disk activity
is detected.
-c count Loop no more than \`count´ if there's no disk activity.
-v Verbose mode (e.g. when run from the command line)
--debug Run the script with \`set -x´
-h This help screen.
DESCRIPTION
This script may be run as a cron job, in whch case -P is required for a
valid DISPLAY variable to exist for monitoring X properties. It can also
be run from the command line, in a terminal or from a TTY. In the latter
case the argumen -P is also required and for the same reasons.
The algorithm used in this script assumes every browser caches what it
fetches from the interwebs, which should include video streams as well.
So it might fail in very predictible circumstances and specific contexts.
The script first detects if the process, which name is passed as an argument
has its window in the foreground then monitors disk activity. Power saving
is temporarily disabled and presentation mode enabled (if present) as soon
as disk activity is detected. If no disk activity is detected then power
saving is "restored" — i.e. set to default values because the script is
stateless.
USE CASES
When run as a cron job the period should be less than the idle delay that
triggers power (or screen) saving. For example, on a laptop where screen
blanking occurs after 20 minues and xscreensaver is run after 10 minutes,
the script might need to run every five minutes.
EOF
}
# Parse command line arguments
while getopts "hP:vc:d:-:" opt; do
case $opt in
P) find_display $OPTARG || error $? "No DISPLAY found for $OPTARG." ;;
d) LOOP_DELAY=$OPTARG ;;
c) MAX_COUNT=$OPTARG ;;
v) VERBOSE=true ;;
h) usage && exit 0 ;;
-) case "$OPTARG" in
debug) set -x ;;
esac ;;
?) usage && exit 1 ;;
esac
done && shift $((OPTIND - 1)) || exit $?
# Don't run twice on the same process
pgrep -u $UID -f "$NAME" | grep -v $$ | xargs ps | grep -qE "$0\s+.*$1" && \
message "Already watching ..." && \
exit 0
# Abort if there's no detected DISPLAY
[ -n "$DISPLAY" ] || error $? "No display found."
export DISPLAY
pid_if_active $1 || exit 0
verbose "Watching $PID ..."
# Xfce-specific: Detect the presence of a (running) power manager
XFCE_POWER_MGR=false
pgrep -u $UID -f 'xfce4-power-manager' >/dev/null && XFCE_POWER_MGR=true
$XFCE_POWER_MGR && verbose "Using Xfce power manager"
# Set/reset presentation settings on exit (disabled by default
# except when disk activity is detected while the process has
# the focus)
$XFCE_POWER_MGR && trap "xfce_presentation_mode false" EXIT INT
while [ $count -lt $MAX_COUNT ]; do
# Check active window process. If the window is not active,
# power saving will be restored
pid_if_active $1 || exit 0
# Check how many bytes the process has written to disk.
# The loop will track the process for as long as it detects
# some disk activity...
eval $(sed -rn '/^write_bytes/s/:\s+/=/p' /proc/$PID/io || echo write_bytes=0)
if [ $last_write_bytes -ne $write_bytes ]; then
if [ $last_write_bytes -ne 0 ]; then
xfce_keep_active
verbose "Detected $((write_bytes - last_write_bytes)) bytes written"
fi
last_write_bytes=$write_bytes
count=0
else
(( count++ ))
verbose "$NAME: No activity detected ($count)"
fi
sleep ${LOOP_DELAY}
done
# This forces a clean exit code if run from cron:
exit 0
|
EDIT: Bug fixed in the 10s loop; every time the script is executed might prevent the screensaver from running for good since last_write_bytes always starts from 0, which always differs from what's in /proc/$_NET_WM_PID/io on the first iteration.
I successfully ran it from a cron job for a couple of hours while watching videos on Youtube:
crontab -e: | */5 * * * * /usr/local/bin/keep-active.sh -P xfce4-session firefox |
The script runs with bash. Making it run with dash shouldn't be too difficult. On my machine the screen saver delay is set to 10 minutes. So far it has been enough. The screen saver started as expected after I closed the video tab and left my machine idle for a little more than 10 minutes. Not sure one needs to close the video tab though.
One caveat is that the screen saver will also be deactivated if you leave your browser active while downloading something. Just switch to another window to fix that.
If you want to check, say, seamonkey and firefox, thanks to the grep clause:
crontab -e: | */5 * * * * /usr/local/bin/keep-active.sh -P xfce4-session 'seamonkey|firefox' |
Hope this helps. _________________ Gentoo addict: tomorrow I quit, I promise!... Just one more emerge...
1739!
Last edited by VinzC on Sun Dec 23, 2018 8:10 pm; edited 6 times in total |
|
Back to top |
|
|
krinn Watchman
Joined: 02 May 2003 Posts: 7470
|
Posted: Mon Jun 27, 2016 11:11 am Post subject: |
|
|
some notes:
Code: | sleep 3 && xprop -root -notype -f _NET_ACTIVE_WINDOW 32x '=$0\n' _NET_ACTIVE_WINDOW
(sleep 3 so i have time to click on firefox windows)
_NET_ACTIVE_WINDOW=0x100008e
xprop -id 0x100008e -notype -f _NET_WM_PID 32c '=$0\n' _NET_WM_PID
_NET_WM_PID=5939
|
Code: | LANG=C ls /proc/5939/i*
ls: cannot access '/proc/5939/i*': No such file or directory |
- are you sure /proc/pid/io is always there? for my firefox i have none. making the test for write_bytes not that reliable
- i fail to see the fullscreen check. my tests were made with firefox not fullscreen and they pass it well.
edit: in case it help, my "dirty" solve to that problem is: open vlc with a movie, hit pause: vlc disable screen saving (i have no screensaver to disable myself, except the monitors getting off) |
|
Back to top |
|
|
VinzC Watchman
Joined: 17 Apr 2004 Posts: 5098 Location: Dark side of the mood
|
Posted: Mon Jun 27, 2016 11:36 am Post subject: |
|
|
krinn wrote: | some notes:
...
- are you sure /proc/pid/io is always there? for my firefox i have none. making the test for write_bytes not that reliable
- i fail to see the fullscreen check. my tests were made with firefox not fullscreen and they pass it well. |
Dumb me!... I wrote this HOWTO right before going to sleep. Indeed there's no check for _NET_WM_STATE_FULLSCREEN as I later acknowledged any focused web browser window that is using storage continuously must mean to deactivate the screen saver... So the check was there in a first draft of my script, now it's gone. So indeed if you are viewing videos, the screen saver should be deactivated regardless of the full screen state. I'll update my post accordingly.
As for your second point, I can tell it's also present on Manjaro, which runs my laptop. It's filed in your kernel config "Enable per-task storage I/O accounting" (CONFIG_TASK_IO_ACCOUNTING).
krinn wrote: | edit: in case it help, my "dirty" solve to that problem is: open vlc with a movie, hit pause: vlc disable screen saving (i have no screensaver to disable myself, except the monitors getting off) |
I don't have VLC on my Gentoo machine and wanted as few dependencies as possible. _________________ Gentoo addict: tomorrow I quit, I promise!... Just one more emerge...
1739! |
|
Back to top |
|
|
krinn Watchman
Joined: 02 May 2003 Posts: 7470
|
Posted: Mon Jun 27, 2016 3:00 pm Post subject: |
|
|
Code: | grep CONFIG_TASK /usr/src/linux/.config
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
# CONFIG_TASK_XACCT is not set
# CONFIG_TASKS_RCU is not set
|
Well at least good to note it need a kernel option, but from my kernel, it also mean some minimal kernel version. (i'm using 3.18.30) |
|
Back to top |
|
|
VinzC Watchman
Joined: 17 Apr 2004 Posts: 5098 Location: Dark side of the mood
|
Posted: Tue Jun 28, 2016 2:48 pm Post subject: |
|
|
krinn wrote: | Code: | grep CONFIG_TASK /usr/src/linux/.config
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
# CONFIG_TASK_XACCT is not set
# CONFIG_TASKS_RCU is not set
|
Well at least good to note it need a kernel option, but from my kernel, it also mean some minimal kernel version. (i'm using 3.18.30) |
You need to enable CONFIG_TASK_XACCT to see CONFIG_TASK_IO_ACCOUNTING. Updating the thread ... Done. _________________ Gentoo addict: tomorrow I quit, I promise!... Just one more emerge...
1739! |
|
Back to top |
|
|
Syl20 l33t
Joined: 04 Aug 2005 Posts: 621 Location: France
|
Posted: Tue Jun 28, 2016 5:29 pm Post subject: |
|
|
I'm looking for a solution to this problem, more or less, for years... So I made some tests yesterday, but, unfortunately, Firefox is too much quiet : the "write_bytes" field isn't increased often enough to block the screensaver on my computer.
My config : amd64 stable, firefox 46, watching Youtube HTML5 videos, xscreensaver configured to blank the screen after five minutes of inactivity, and the script is cronned every two minutes (so there are two executions before the screensaver starting).
That said, this way is interesting, thank you. I'll try to dig a little more, to see if I can find something working on my systems. |
|
Back to top |
|
|
VinzC Watchman
Joined: 17 Apr 2004 Posts: 5098 Location: Dark side of the mood
|
Posted: Tue Jun 28, 2016 7:50 pm Post subject: |
|
|
Syl20 wrote: | I'm looking for a solution to this problem, more or less, for years... So I made some tests yesterday, but, unfortunately, Firefox is too much quiet : the "write_bytes" field isn't increased often enough to block the screensaver on my computer.
My config : amd64 stable, firefox 46, watching Youtube HTML5 videos, xscreensaver configured to blank the screen after five minutes of inactivity, and the script is cronned every two minutes (so there are two executions before the screensaver starting).
That said, this way is interesting, thank you. I'll try to dig a little more, to see if I can find something working on my systems. |
There are a few ways from here. A couple of options I thought of - looking into the window title with xprop
- monitoring firefox's network traffic — which would maybe require throttling with fast internet connections, in case the download process is too quick
- find another field from /proc/<pid> to monitor
- use the fullscreen property alone to deactivate xscreensaver
Maybe also the idle delay you gave xscreensaver is a little too short. I know some applications do restrain from writing to the disk for some period. Don't know if it's the case with firefox but you might want to increase xscreensaver idle delay up to 10 minutes like I did and, why not, increase the number of 10s loops in the script... _________________ Gentoo addict: tomorrow I quit, I promise!... Just one more emerge...
1739! |
|
Back to top |
|
|
Syl20 l33t
Joined: 04 Aug 2005 Posts: 621 Location: France
|
Posted: Thu Jun 30, 2016 10:05 am Post subject: |
|
|
I should have some time to spend on this next weekend. Thank you for the tips. |
|
Back to top |
|
|
krinn Watchman
Joined: 02 May 2003 Posts: 7470
|
Posted: Thu Jun 30, 2016 3:29 pm Post subject: |
|
|
how about netstat -p | firefox
if you get an ESTABLISHED state, it is at work. |
|
Back to top |
|
|
frankenputer n00b
Joined: 09 Mar 2016 Posts: 26
|
Posted: Thu Jun 30, 2016 3:44 pm Post subject: |
|
|
krinn wrote: | how about netstat -p | firefox
if you get an ESTABLISHED state, it is at work. |
Code: | netstat -n | gawk '/^tcp/ {state=$NF} END {print state}'
netstat -n | gawk \
'/^tcp/ {
st[$NF]++;
}
END {
for (k in st) {
print k,"\t",st[k];
}
}'
|
Edit:
I think the more correct approach will be to check the CPU load and if it matches certain load to execute xset -dmps and xset s off
Code: | ps -eo pcpu,comm | gawk '{ if ($1 > 20) { print $1,$2 } }'
# 32.4 chrome |
|
|
Back to top |
|
|
VinzC Watchman
Joined: 17 Apr 2004 Posts: 5098 Location: Dark side of the mood
|
Posted: Fri Jul 01, 2016 8:47 pm Post subject: |
|
|
krinn wrote: | how about netstat -p | firefox
if you get an ESTABLISHED state, it is at work. |
Might be worth trying . I believe keep alive connections/scripts might defeat this test but definitely worth combining with other detection steps.
frankenputer wrote: | I think the more correct approach will be to check the CPU load and if it matches certain load to execute xset -dmps and xset s off
Code: | ps -eo pcpu,comm | gawk '{ if ($1 > 20) { print $1,$2 } }'
# 32.4 chrome |
|
Hmmm... not sure. Web sites with heavy animations might defeat the detection on a "non-accelerated-graphics" (i.e. between old and very, very old) machine, for instance. _________________ Gentoo addict: tomorrow I quit, I promise!... Just one more emerge...
1739! |
|
Back to top |
|
|
Syl20 l33t
Joined: 04 Aug 2005 Posts: 621 Location: France
|
Posted: Mon Jul 04, 2016 3:44 pm Post subject: |
|
|
Ok, I've a working script. I decided to deactivate the screensaver only when the browser window has both focused and fullscreen (not maximized) states. That does the job, according to my habits.
Code: | #!/bin/bash
# This script tries to inhibit the screen saver while Firefox (or any other
# browser) is full screen. It is intended to run as a cron job every
# minute or so, i.e. any period shorter than xscreensaver lock time.
#
# Note this script uses xprop formatting to output eval compatible assignment
# expressions, such as _NET_ACTIVE_WINDOW and _NET_WM_PID. IF we don't do
# that xprop output contains extraneous spaces that mess things up.
set -uef -o pipefail
[ -z "$@" ] && exit 1
NAV="$1" # Browser, as it appears in `ps` list
# First, is the browser running ?
PID=$(pgrep --delimiter " " --uid "$UID" "$NAV")
[ -z "$PID" ] && exit 0
# Second, am I focused on it ?
DISPLAYS=""
DISPLAY=""
for pid in $PID
do
eval $(grep -Eoa 'DISPLAY=[:09.]+' "/proc/$pid/environ")
[ -z "$DISPLAY" ] && continue
DISPLAYS="$DISPLAYS $DISPLAY"
done
for DISPLAY in $(echo $DISPLAYS | tr " " "\n" | sort -u)
do
export DISPLAY
# Get active window ID
eval $(xprop -root -notype -f _NET_ACTIVE_WINDOW 32x '=$0\n' _NET_ACTIVE_WINDOW)
[ -z "$_NET_ACTIVE_WINDOW" ] && exit 1
# Get its process ID
eval $(xprop -id "$_NET_ACTIVE_WINDOW" -notype -f _NET_WM_PID 32c '=$0\n' _NET_WM_PID)
[ -z "$_NET_WM_PID" ] && exit 1
# Check the process name
grep -q "$NAV" "/proc/$_NET_WM_PID/cmdline" || continue
# Third, is the browser window full-screen ?
xprop -id "$_NET_ACTIVE_WINDOW" -notype "_NET_WM_STATE" | grep -q "_NET_WM_STATE_FULLSCREEN" || continue
# Ok, all the requirements are met.
xscreensaver-command -deactivate > /dev/null 2>&1
xset dpms s reset > /dev/null 2>&1
exit 0
done |
Even if firefox is still mono-processus, I decided to make this script multi-processus compliant. But, most of the times, on a personal computer, there's only one display used at a given time. Rarely two. Splitting the windows properties detections into two different for loops limits the number of executed commands.
I had to add the "xset dpms s reset" command to deactivate all the screen blanking capabilities.
Thank you VinzC for the ideas, the base script, and the motivation to finish this long quest... |
|
Back to top |
|
|
VinzC Watchman
Joined: 17 Apr 2004 Posts: 5098 Location: Dark side of the mood
|
Posted: Thu Jul 07, 2016 5:42 pm Post subject: |
|
|
Syl20 wrote: | Thank you VinzC for the ideas, the base script, and the motivation to finish this long quest... |
My pleasure. Glad you found a working solution . _________________ Gentoo addict: tomorrow I quit, I promise!... Just one more emerge...
1739! |
|
Back to top |
|
|
VinzC Watchman
Joined: 17 Apr 2004 Posts: 5098 Location: Dark side of the mood
|
Posted: Sun Dec 23, 2018 12:46 pm Post subject: |
|
|
I updated my script to work on laptops with a power management application such as xfce4-power-manager. I was annoyed my script didn't prevent the screen from blanking in some circumstances so I decided to improve it. Here's the results.
Peace, Merry Christmas and Happy New Year everyone. _________________ Gentoo addict: tomorrow I quit, I promise!... Just one more emerge...
1739! |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|