Add fake gnome-session so that gnome-screensaver can get IDLE time
authorJulien Valroff <julien@kirya.net>
Mon, 30 May 2011 05:08:05 +0000 (07:08 +0200)
committerJulien Valroff <julien@kirya.net>
Mon, 30 May 2011 05:08:05 +0000 (07:08 +0200)
SessionManager.py [new file with mode: 0755]

diff --git a/SessionManager.py b/SessionManager.py
new file mode 100755 (executable)
index 0000000..fb5508b
--- /dev/null
@@ -0,0 +1,188 @@
+#!/usr/bin/python
+"""
+SessionManager
+Copyright (c) 2010--2011, Olivier Mehani <shtrom@ssji.net>
+All rights reserved.
+
+$Id$
+A drop-in replacement for org.gnome.SessionManager, doing almost nothing.
+Loosely based on basic instructions at [0,1,2,3,5,6].
+
+[0] http://people.gnome.org/~mccann/gnome-session/docs/gnome-session.html
+[1] http://www.amk.ca/diary/2007/04/rough_notes_python_and_dbus.html
+[2] http://paste.lisp.org/display/45824
+[3] http://www.lamalex.net/2010/03/help-does-anyone-know-how-to-export-properties-with-python-dbus/
+[4] http://thp.io/2007/09/x11-idle-time-and-focused-window-in.html
+[5] http://www.eurion.net/python-snippets/snippet/GConf%3A%20get_set%20values.html
+[6] http://lists.gnupg.org/pipermail/gnupg-users/2006-March/028189.html
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of Olivier Mehani nor the names of its contributors
+may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+"""
+
+__version__ = "$Revision$"
+
+
+import dbus
+import dbus.service
+import dbus.glib
+import gobject
+
+import gtk
+
+import ctypes
+import os
+
+import gconf
+
+import signal
+
+
+ogSM   = 'org.gnome.SessionManager'
+ogSMp  = '/org/gnome/SessionManager'
+ogSMP  = 'org.gnome.SessionManager.Presence'
+ogSMPp = '/org/gnome/SessionManager/Presence'
+
+class SessionManager(dbus.service.Object):
+    def __init__(self):
+        bus_name = dbus.service.BusName(ogSM,
+            bus=dbus.SessionBus())
+        dbus.service.Object.__init__(self, bus_name,
+            ogSMp)
+        self.presence = SessionManagerPresence()
+        #print "%s emulation ready" % ogSM
+
+    def get_smp(self):
+        return self.presence
+
+
+class SessionManagerPresence(dbus.service.Object):
+    PRESENCE_AVAILABLE  = 0
+    PRESENCE_INVISIBLE  = 1
+    PRESENCE_BUSY              = 2
+    PRESENCE_IDLE              = 3
+    
+    status                     = PRESENCE_AVAILABLE
+    status_text                = ""
+
+    def __init__(self):
+        bus_name = dbus.service.BusName(ogSMP,
+            bus=dbus.SessionBus())
+        dbus.service.Object.__init__(self, bus_name,
+            ogSMPp)
+        #print "%s emulation ready" % ogSMP
+
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
+        in_signature='s', out_signature='a{sv}')
+    def GetAll(self, interface_name):
+        print "%s.GetAll(%s)" % (ogSMP, interface_name)
+        return {'status':              dbus.UInt32(self.status),
+            'status-text':  self.status_text,
+            }
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
+        in_signature='ss', out_signature='v')
+    def Get(self, interface_name, property_name):
+        #print "%s.Get(%s, %s)" % (ogSMP, interface_name, property_name)
+        #print " -> %s" % str(self.GetAll(interface_name)[property_name])
+        return self.GetAll(interface_name)[property_name]
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
+        in_signature='ssv')
+    def Set(self, interface_name, property_name, value):
+        #print "%s.Set(%s, %s, %s)" % \
+        #      (ogSMP, interface_name, property_name, value)
+        pass
+
+    @dbus.service.method(dbus_interface=ogSMP, in_signature='u')
+    def SetStatus(self, status):
+        self.status = status
+
+    @dbus.service.method(dbus_interface=ogSMP, in_signature='u')
+    def SetStatusText(self, status_text):
+        self.status_text = status_text
+
+    @dbus.service.signal(dbus_interface=ogSMP, signature='u')
+    def StatusChanged(self, status):
+        self.SetStatus(status)
+
+    @dbus.service.signal(dbus_interface=ogSMP, signature='s')
+    def StatusTextChanged(self, status_text):
+        self.SetStatusText(status_text)
+
+
+class XScreenSaverIdleChecker():
+    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
+        
+    def __init__(self, idle_timeout):
+        self.idle_timeout = idle_timeout
+        self.idle      = False
+        self.xlib      = ctypes.cdll.LoadLibrary('libX11.so.6')
+        self.dpy       = self.xlib.XOpenDisplay(os.environ['DISPLAY'])
+        self.root      = self.xlib.XDefaultRootWindow(self.dpy)
+        self.xss       = ctypes.cdll.LoadLibrary('libXss.so.1')
+        self.xss.XScreenSaverAllocInfo.restype \
+                = ctypes.POINTER(self.XScreenSaverInfo)
+        print ("XScreenSaverIdleChecker ready with timeout %d" % idle_timeout)
+    
+    def check_idle(self, smp):
+        print "Checking idleness..."
+        xss_info = self.xss.XScreenSaverAllocInfo()
+        self.xss.XScreenSaverQueryInfo(self.dpy, self.root, xss_info)
+        idle = xss_info.contents.idle/1000
+        
+        if idle >= self.idle_timeout:
+            if not self.idle:
+                print "Becoming idle"
+                self.idle = True
+                smp.StatusChanged(smp.PRESENCE_IDLE)
+        else:
+            if self.idle:
+                print "Not idle anymore"
+                self.idle = False
+                smp.StatusChanged(smp.PRESENCE_AVAILABLE)
+        
+        gobject.timeout_add(10000, self.check_idle, smp)
+    
+
+gclient = gconf.client_get_default()
+gvalue = gclient.get('/apps/gnome-screensaver/idle_delay')
+if gvalue is not None:
+    idle_delay = gvalue.get_int() * 60
+else:
+    # 5 minutes
+    idle_delay = 300
+
+sessmgr = SessionManager()
+
+xssic = XScreenSaverIdleChecker(idle_delay)
+xssic.check_idle(sessmgr.get_smp())
+
+gtk.main()