I'm looking for a decent, non-lame way to inhibit xscreensaver, kscreensaver, or gnome-screensaver, whichever might be running, preferably in a screensaver-agnostic manner, and it absolutely positively must execute fast.
I've read the xscreensaver FAQ.
I have a gtk based game program that's cranking out 30 frames/second while mixing several channels of audio, and since it's controlled by a joystick, sometimes "the" screensaver will kick in. I put "the" in quotes, because there are at least three different popular screensavers, xscreensaver, gnome-screensaver, and kscreensaver, each with their own unique and clunky methods by which an application might inhibit them.
Has anybody encapsulated the code to inhibit all of these into a fast chunk of code? Oh, and it has to be GPL compatible.
Currently my code simply whines piteously about the uncooperative screensaver developers if any screensaver is detected and the joystick is in use, and doesn't actually try to do anything other than advise the user to manually disable the screensaver, as the only other thing I can think to do is so incredibly ugly that I simply refuse to do it.
Just wondering if anybody else has run into this, and what they've done, and if they did anything, if it was as ugly as it seems to me it would have to be, or if there's some elegant solution out there... Seems like maybe synthesizing X events somehow to fool the screensaver into thinking there's some activity might do the trick in a universal way, but I'm really not sure how to do that (and hoping you wouldn't need to be root to do it.)
Any ideas?
Hmm, unfortunately, at least on Fedora core 8, this does not appear to work.
The xdg-screensaver script is there, and seems to be intended to work, it just doesn't actually work.
Once you do "xdg-screensaver suspend window-id", where window id is gotten from within the program via
xwindow_id = GDK_WINDOW_XWINDOW (GTK_WIDGET (widget)->window);
Or whether the window id is gotten via xprop, and xdg-screensaver run manually, two processes are created:
[scameron@zuul wordwarvi]$ ps -efa | grep xdg
scameron 4218 1 0 20:12 pts/2 00:00:00 /bin/sh /usr/bin/xdg-screensaver suspend 0x3a00004
scameron 4223 1 0 20:12 pts/2 00:00:00 /bin/sh /usr/bin/xdg-screensaver suspend 0x3a00004
scameron 4313 3151 0 20:15 pts/1 00:00:00 grep xdg
[scameron@zuul wordwarvi]$
And they never die, even after the program they are supposedly waiting for dies, and the screensaver is never re-enabled.
[scameron@zuul wordwarvi]$ xdg-screensaver status
disabled
[scameron@zuul wordwarvi]$ ls -ltr /tmp | grep xdg
-rw------- 1 scameron scameron 15 2009-01-20 20:12 xdg-screensaver-scameron--0.0
[scameron@zuul wordwarvi]$
Running xdg-screensaver resume window-id does not resume the screensaver.
To re-enable the screensaver, I have to manually kill them, and manually remove the files it leaves around in /tmp:
[scameron@zuul wordwarvi]$ kill 4218 4223
[scameron@zuul wordwarvi]$ rm /tmp/xdg-screensaver-scameron--0.0
[scameron@zuul wordwarvi]$ xdg-screensaver status
enabled
[scameron@zuul wordwarvi]$
So, good intentions, but doesn't seem to actually work.
No, of course not expecting to run it every frame, but don't want it causing hiccups when it does run, is all. With my thought of synthesizing X events, I was imagining it would be just often enough to make the screen saver think there was activity.
Looking at xdg-screensaver (which seems to be a shell script that ultimately just does a "wait" for my process -- cool) it seems to be made to do just what I want. I knew I couldn't be the only or first one to face this problem.
No, but yes...
There's no nice clean way to do this. In my opinion there should be a mechanism administrated by the X server, which both screensavers and interested applications can voluntarily use to negotiate suppression of any screensaver during the runtime of one or more programs. But no such mechanism yet exists to my knowledge. GNOME and KDE look to be implementing a DBUS approach to this problem, but in my opinion even if it becomes widespread (it isn't yet widespread enough to rely on it in 3rd party code) it's not the right approach.
However, xdg-screensaver is a FreeDesktop standardised shell script which you can run as a sub-process to control the screensaver. It controls most popular screensavers, and the OS vendor would be responsible for updating it/ maintaining it to work with newer screensavers or better ways of doing this in the future. Unlike many other kludges it will automatically re-enable the screensaver if your application crashes or exits via some route that forgets to call the re-enable code. See the manual page for details in how to use it.
As a GTK+ user probably the trickiest aspects of this for you would be creating the sub-process to run the shell script (if you haven't done this before you will want to find a tutorial about using fork + exec) and getting the XWindow ID of your application's main window to give to xdg-screensaver.
You ask that the code should be "fast". This makes me wonder if you're expecting to run it every frame - don't. The xdg-screensaver solution allows you to disable or renable the screensaver explicitly, rather than trying to suppress it once per frame or anything like that.
Try this: xdg-screensaver suspend [window id]
(see: http://portland.freedesktop.org/xdg-utils-1.0/xdg-screensaver.html)
a Bash script solution:
activ_win_id=`DISPLAY=:0.${display} xprop -root _NET_ACTIVE_WINDOW`
activ_win_id=${activ_win_id:40:9}
xdg-screensaver suspend $activ_win_id
It works for gnome-screensaver.
And there's the more complicated DBus "inhibit" method: https://people.gnome.org/~mccann/gnome-screensaver/docs/gnome-screensaver.html#gs-method-Inhibit
dbus-send --session \
--dest=org.gnome.ScreenSaver \
--type=method_call \
--print-reply \
--reply-timeout=20000 \
/org/gnome/ScreenSaver \
org.gnome.ScreenSaver.Inhibit \
[application name e.g. ""] \
[reason e.g."playing a game"] \
[non-zero-random-integer e.g. 123]
Edit 2019/12/04:
I went back to this and found out that dbus-send
doesn't work properly now. The Inhibit
method is released as soon as the D-Bus connection is released (which happens when dbus-send
exits).
A good method (working with Gnome 3.34) is the following python script:
#!/usr/bin/python
# coding=utf-8
# Usage: gnome-inhibit <command-line>
# Example: gnome-inhibit mpv video.mp4
import subprocess
import dbus
import sys
import os
bus = dbus.SessionBus()
proxy = bus.get_object('org.freedesktop.ScreenSaver','/org/freedesktop/ScreenSaver')
iface = dbus.Interface(proxy, 'org.freedesktop.ScreenSaver')
cookie = iface.Inhibit(sys.argv[1], "gnome-inhibit")
print("Inhibiting screensaver (pid: %d)" % os.getpid())
print("Executing: %s" % subprocess.list2cmdline(sys.argv[1:]))
subprocess.check_call(sys.argv[1:])
Old answer that doesn't work anymore:
The current way (under Gnome 3.22 and possibly others such as KDE) seems to be this, which returns an uninhibition cookie as an uint32
:
dbus-send --session \
--dest=org.freedesktop.ScreenSaver \
--type=method_call \
--print-reply \
--reply-timeout=20000 \
/org/freedesktop/ScreenSaver \
org.freedesktop.ScreenSaver.Inhibit \
string:program string:reason
Then, to disable the inhibition :
dbus-send --session \
--dest=org.freedesktop.ScreenSaver \
--type=method_call \
--print-reply \
--reply-timeout=20000 \
/org/freedesktop/ScreenSaver \
org.freedesktop.ScreenSaver.UnInhibit \
uint32:<inhibit-cookie>
Here is a small script that disables the screensaver for a given program, then later restores it on exit.
(D-Feet has been especially helpful for introspecting the ever-changing D-Bus method names)
Movie-players typically disable screensavers. You could poke around the mplayer-code to see how they do it.
For regular X, they use XScreenSaverSuspend where supported.
It is not an entirely desktop-agnostic solution, but if core Gnome libraries are installed (many GTK-based apps require them) it could work on other desktop environments too:
Disable screensaver:
gsettings set org.gnome.desktop.screensaver idle-activation-enabled false
(Re)enable screensaver:
gsettings set org.gnome.desktop.screensaver idle-activation-enabled true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With