Inhibit screensaver with Python Inhibit screensaver with Python linux linux

Inhibit screensaver with Python


I have been looking into this a while ago and finally ended up using xdg-screensaver which I call via subprocess.

import subprocessdef suspend_screensaver():    window_id = subprocess.Popen('xwininfo -root | grep xwininfo | cut -d" " -f4', stdout=subprocess.PIPE, shell=True).stdout.read().strip()    #run xdg-screensaver on root window    subprocess.call(['xdg-screensaver', 'suspend', window_id])def resume_screensaver(window_id):    subprocess.Popen('xdg-screensaver resume ' + window_id, shell=True)

This is not ideal but apparently there is no other solution that would not involve messing around with DE-specific stuff like dbus or gnome-screensaver-command.

I don't really like the call to xwininfo and wish there was a cleaner way but so far could not find anything better. Another issue with the xwininfo approach is that it uses the id of the root window instead of the app window. Using the app window id instead of the root window would remove the need for the resume_screensaver method since it would then resume as soon as the window is destroyed.

And if you want to simulate keystrokes here is a naive bash script I have been using for some time. It does require xdotool which has to be installed separately.

#!/bin/bashwhile : do   sleep 200   nice -n 1 xdotool key shift   echo .done

UPDATE

After having used the python solution above for over a year, it was found to occasionally create zombie processes and/or too many instances of xdg-screensaver, so after digging around, I found a simpler alternative which is Gnome-specific, but works for me even in a non-Gnome DE (XFCE) since the core Gnome libraries are required by many GTK-based apps even if you don't have a Gnome desktop.

import subprocessdef suspend_screensaver():    'suspend linux screensaver'    proc = subprocess.Popen('gsettings set org.gnome.desktop.screensaver idle-activation-enabled false', shell=True)    proc.wait()def resume_screensaver():    'resume linux screensaver'    proc = subprocess.Popen('gsettings set org.gnome.desktop.screensaver idle-activation-enabled true', shell=True)    proc.wait()


I know this question is old, but there is a more modern answer to it: now most DE on linux use dbus to communicate, and you can use this:

in shell, using kde tools:

qdbus org.freedesktop.ScreenSaver /ScreenSaver org.freedesktop.ScreenSaver.Inhibit "myapps" "because I want it"

this dbus call will return a cookie (a number) that will be needed to uninhibit the screesaver:

qdbus org.freedesktop.ScreenSaver /ScreenSaver org.freedesktop.ScreenSaver.UnInhibit $COOKIE

In python, it will be something like

import dbusbus = dbus.SessionBus()saver = bus.get_object('org.freedesktop.ScreenSaver', '/ScreenSaver')saver_interface = dbus.Interface(saver, dbus_interface='org.freedesktop.ScreenSaver')# now we can inhibit the screensavercookie=saver_interface.Inhibit("myapps", "because I want it")# we can also restore itsaver_interface.UnInhibit(cookie)


Discussion

TLDR; there aren't any cross-DE ways to inhibit the screensaver with pure Python. However the question also asked about doing so with Linux (presumably from the shell). To be clear, there aren't any particularly good cross-DE ways to do so in Linux, but at least there is potential. You probably want to use the hackish xdg-screensaver shell script.

This is a topic I've spent some time on. I wasn't happy with any of the solutions out there, so after playing around with some homebrew tools, I ended up modifying the caffeine project to suit my needs and have been using it happily ever since. I'll summarize some of what I've learned in the process.

In case you aren't familiar with it, I'd recommend checking out caffeine (Launchpad PPA @ https://launchpad.net/~caffeine-developers/+archive/ubuntu/ppa).

The caffeine project mostly consists of the following scripts: caffeine-screensaver caffeine caffeine-indicator caffeinate

caffeine and caffeine-indicator are written in Python 3 whereas caffeine-screensaver is a rebranded xdg-screensaver written in shell script.

The first half of ccpizza's answer is great as it is cross-DE and very similar to caffeine's implementation. I haven't had any issues with xdg-screensaver zombie processes but I'm sure it could be remedied if I better knew the use-case or the conditions under which it was occurring. Just a FYI that running xdg-screensaver suspend ROOT_WINDOW_ID will background a tracking process and leave it running indefinitely (until it is resumed).

If you're interested in implementing a truly cross-DE solution then I would strongly recommend examining the aforementioned xdg-screensaver/caffeine-screensaver. The many forks of lightsOn are ripe as well.

xdg-screensaver detects the desktop environment (KDE, Gnome, XFCE, LXDE, xscreensaver, or gnome-screensaver) and acts accordingly. For the xdg-screensaver suspend command, it runs xset -dpms to disable DPMS, DE-specific commands, then watches the supplied window ID for it's duration. If the window disappears, the resume command is run and xdg-screensaver exits. The xdg-screensaver resume command consists of xset +dpms (only if DPMS was originally enabled) then the DE-specific commands.

Note that xdg-screensaver will only track the supplied window ID if xprop is available (it's part of x11-utils, so it should be). To track the window, it backgrounds xprop -id WINDOW_ID -spy to monitor the window for changes. It stores the PID of the aforemention process along with window ID in a lockfile to reference upon suspend and resume. The original state of DPMS is referenced in a separate lockfile. The lockfiles should ensure there are no duplicate processes.

The script is a complete mess, so I empathize with anyone unfortunate enough to use it, but I haven't encountered any issues. You probably don't want to reinvent the wheel so if you are creating something for public consumption then I'd recommend you just co-opt it. If you're creating something for personal use, then just dig through it and use the commands specific to your DE.

ccpizza suggesting using subprocess.Popen('xwininfo -root | grep xwininfo | cut -d" " -f4', stdout=subprocess.PIPE, shell=True).stdout.read().strip() to get the desktop's root window ID. Using the desktop's root window ID with xdg-screensaver suspend will disable the desktop's screensaver indefinitely. Using a specific window's ID will disable the desktop's screensaver for the duration of the window.


Shell Script

To determine the active window ID, you can run the following:

xprop -root _NET_ACTIVE_WINDOW | awk -F '[ ,]' '{print $5}'

To determine the root window ID, you can run the following:

xwininfo -root | awk '/^xwininfo: Window id: / {print $4}'

To determine the screensaver timeout, you can run the following:

xset q | awk '/^  timeout: / {print $2}'

NOTE: the result will be 0 if the screensaver is disabled

To determine whether DPMS is enabled or disabled, you can run the following:

xset q | awk '/^  DPMS is / {print tolower($3)}'

Python Script

There are pure Python options as well. The Xlib module is great for this, as is ewmh (which is a wrapper around Xlib).

To determine the active window ID with ewmh:

active_id = hex(ewmh.EWMH().getActiveWindow().id)

To determine the root window ID with ewmh:

root_id = hex(ewmh.EWMH().root.id)

To determine the active window ID with Xlib:

from Xlib.display import Displayfrom Xlib.X import AnyPropertyTypeactive_id = hex(Display().screen().root.get_full_property(Display().get_atom('_NET_ACTIVE_WINDOW'), AnyPropertyType).value[0])

To determine the root window ID with Xlib:

from Xlib.display import Displayroot_id = hex(Display().screen().root.id)

To determine the screensaver timeout with Xlib:

from Xlib.display import Displaytimeout = Display().get_screen_saver().timeout