Thursday, September 13, 2007

X11 idle time and focused window in Python

For my Evolution New Mail Notification script, I wanted to make the notification popups not enabled when I'm already working within evolution (e.g. the Evolution window is focused) and I also didn't want to play sounds when I'm working on the computer, because I will see the visual notification, anyway (e.g. the X11 idle time is less than some specified timeout).

To accomplish that, I had to write a bit of Python code for two simple tasks:
  • Get the window name and/or class of the currently focused window
  • Get the idle time of the X11 session, e.g. the time since the last input event
The window name/class getting can be done with the help of the Python X Library and the idle time can be done using some obscure ctypes loading of libXss.so and doing a bit of C-bindings stuff, which I found by searching the web. Here, I want to share the code with you in case you need it for some project of yours:

Window Name and Class for the focused window
import Xlib.display
display = Xlib.display.Display()
focus = display.get_input_focus()
print "WM Class: %s" % ( focus.focus.get_wm_class(), )
print "WM Name: %s" % ( focus.focus.get_wm_name(), )
X11 Idle Time using the XScreenSaver extension
import ctypes
import os

class XScreenSaverInfo( ctypes.Structure):
""" typedef struct { ... } XScreenSaverInfo; """
_fields_ = [('window', ctypes.c_ulong), # screen saver window
('state', ctypes.c_int), # off,on,disabled
('kind', ctypes.c_int), # blanked,internal,external
('since', ctypes.c_ulong), # milliseconds
('idle', ctypes.c_ulong), # milliseconds
('event_mask', ctypes.c_ulong)] # events

xlib = ctypes.cdll.LoadLibrary( 'libX11.so')
dpy = xlib.XOpenDisplay( os.environ['DISPLAY'])
root = xlib.XDefaultRootWindow( dpy)
xss = ctypes.cdll.LoadLibrary( 'libXss.so')
xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo)
xss_info = xss.XScreenSaverAllocInfo()
xss.XScreenSaverQueryInfo( dpy, root, xss_info)
print "Idle time in milliseconds: %d" % ( xss_info.contents.idle, )
If you're interested in a real-world example usage of this code, feel free to check out my evolution-newmail.py new mail notification script that works with Evolution over D-BUS.

1 comment:

Unknown said...

hey man i was wondering how to do the exact same thing! great post i'm sure this took a while to figure out