4 Copyright (c) 2010--2011, Olivier Mehani <shtrom@ssji.net>
8 A drop-in replacement for org.gnome.SessionManager, doing almost nothing.
9 Loosely based on basic instructions at [0,1,2,3,5,6].
11 [0] http://people.gnome.org/~mccann/gnome-session/docs/gnome-session.html
12 [1] http://www.amk.ca/diary/2007/04/rough_notes_python_and_dbus.html
13 [2] http://paste.lisp.org/display/45824
14 [3] http://www.lamalex.net/2010/03/help-does-anyone-know-how-to-export-properties-with-python-dbus/
15 [4] http://thp.io/2007/09/x11-idle-time-and-focused-window-in.html
16 [5] http://www.eurion.net/python-snippets/snippet/GConf%3A%20get_set%20values.html
17 [6] http://lists.gnupg.org/pipermail/gnupg-users/2006-March/028189.html
19 Redistribution and use in source and binary forms, with or without
20 modification, are permitted provided that the following conditions
22 1. Redistributions of source code must retain the above copyright notice, this
23 list of conditions and the following disclaimer.
24 2. Redistributions in binary form must reproduce the above copyright notice,
25 this list of conditions and the following disclaimer in the documentation
26 and/or other materials provided with the distribution.
27 3. Neither the name of Olivier Mehani nor the names of its contributors
28 may be used to endorse or promote products derived from this software
29 without specific prior written permission.
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
32 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
35 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 POSSIBILITY OF SUCH DAMAGE.
45 __version__ = "$Revision$"
63 ogSM = 'org.gnome.SessionManager'
64 ogSMp = '/org/gnome/SessionManager'
65 ogSMP = 'org.gnome.SessionManager.Presence'
66 ogSMPp = '/org/gnome/SessionManager/Presence'
68 class SessionManager(dbus.service.Object):
70 bus_name = dbus.service.BusName(ogSM,
71 bus=dbus.SessionBus())
72 dbus.service.Object.__init__(self, bus_name,
74 self.presence = SessionManagerPresence()
75 #print "%s emulation ready" % ogSM
81 class SessionManagerPresence(dbus.service.Object):
82 PRESENCE_AVAILABLE = 0
83 PRESENCE_INVISIBLE = 1
87 status = PRESENCE_AVAILABLE
91 bus_name = dbus.service.BusName(ogSMP,
92 bus=dbus.SessionBus())
93 dbus.service.Object.__init__(self, bus_name,
95 #print "%s emulation ready" % ogSMP
97 @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
98 in_signature='s', out_signature='a{sv}')
99 def GetAll(self, interface_name):
100 print "%s.GetAll(%s)" % (ogSMP, interface_name)
101 return {'status': dbus.UInt32(self.status),
102 'status-text': self.status_text,
104 @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
105 in_signature='ss', out_signature='v')
106 def Get(self, interface_name, property_name):
107 #print "%s.Get(%s, %s)" % (ogSMP, interface_name, property_name)
108 #print " -> %s" % str(self.GetAll(interface_name)[property_name])
109 return self.GetAll(interface_name)[property_name]
110 @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
112 def Set(self, interface_name, property_name, value):
113 #print "%s.Set(%s, %s, %s)" % \
114 # (ogSMP, interface_name, property_name, value)
117 @dbus.service.method(dbus_interface=ogSMP, in_signature='u')
118 def SetStatus(self, status):
121 @dbus.service.method(dbus_interface=ogSMP, in_signature='u')
122 def SetStatusText(self, status_text):
123 self.status_text = status_text
125 @dbus.service.signal(dbus_interface=ogSMP, signature='u')
126 def StatusChanged(self, status):
127 self.SetStatus(status)
129 @dbus.service.signal(dbus_interface=ogSMP, signature='s')
130 def StatusTextChanged(self, status_text):
131 self.SetStatusText(status_text)
134 class XScreenSaverIdleChecker():
135 class XScreenSaverInfo(ctypes.Structure):
136 """ typedef struct { ... } XScreenSaverInfo; """
137 _fields_ = [('window', ctypes.c_ulong), # screen saver window
138 ('state', ctypes.c_int), # off,on,disabled
139 ('kind', ctypes.c_int), # blanked,internal,external
140 ('since', ctypes.c_ulong), # milliseconds
141 ('idle', ctypes.c_ulong), # milliseconds
142 ('event_mask', ctypes.c_ulong)] # events
144 def __init__(self, idle_timeout):
145 self.idle_timeout = idle_timeout
147 self.xlib = ctypes.cdll.LoadLibrary('libX11.so.6')
148 self.dpy = self.xlib.XOpenDisplay(os.environ['DISPLAY'])
149 self.root = self.xlib.XDefaultRootWindow(self.dpy)
150 self.xss = ctypes.cdll.LoadLibrary('libXss.so.1')
151 self.xss.XScreenSaverAllocInfo.restype \
152 = ctypes.POINTER(self.XScreenSaverInfo)
153 print ("XScreenSaverIdleChecker ready with timeout %d" % idle_timeout)
155 def check_idle(self, smp):
156 print "Checking idleness..."
157 xss_info = self.xss.XScreenSaverAllocInfo()
158 self.xss.XScreenSaverQueryInfo(self.dpy, self.root, xss_info)
159 idle = xss_info.contents.idle/1000
161 if idle >= self.idle_timeout:
163 print "Becoming idle"
165 smp.StatusChanged(smp.PRESENCE_IDLE)
168 print "Not idle anymore"
170 smp.StatusChanged(smp.PRESENCE_AVAILABLE)
172 gobject.timeout_add(10000, self.check_idle, smp)
175 gclient = gconf.client_get_default()
176 gvalue = gclient.get('/apps/gnome-screensaver/idle_delay')
177 if gvalue is not None:
178 idle_delay = gvalue.get_int() * 60
183 sessmgr = SessionManager()
185 xssic = XScreenSaverIdleChecker(idle_delay)
186 xssic.check_idle(sessmgr.get_smp())