Add fake gnome-session so that gnome-screensaver can get IDLE time
[dotfiles/scripts.git] / SessionManager.py
1 #!/usr/bin/python
2 """
3 SessionManager
4 Copyright (c) 2010--2011, Olivier Mehani <shtrom@ssji.net>
5 All rights reserved.
6
7 $Id$
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].
10
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
18
19 Redistribution and use in source and binary forms, with or without
20 modification, are permitted provided that the following conditions
21 are met:
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.
30
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.
42
43 """
44
45 __version__ = "$Revision$"
46
47
48 import dbus
49 import dbus.service
50 import dbus.glib
51 import gobject
52
53 import gtk
54
55 import ctypes
56 import os
57
58 import gconf
59
60 import signal
61
62
63 ogSM    = 'org.gnome.SessionManager'
64 ogSMp   = '/org/gnome/SessionManager'
65 ogSMP   = 'org.gnome.SessionManager.Presence'
66 ogSMPp  = '/org/gnome/SessionManager/Presence'
67
68 class SessionManager(dbus.service.Object):
69     def __init__(self):
70         bus_name = dbus.service.BusName(ogSM,
71             bus=dbus.SessionBus())
72         dbus.service.Object.__init__(self, bus_name,
73             ogSMp)
74         self.presence = SessionManagerPresence()
75         #print "%s emulation ready" % ogSM
76
77     def get_smp(self):
78         return self.presence
79
80
81 class SessionManagerPresence(dbus.service.Object):
82     PRESENCE_AVAILABLE  = 0
83     PRESENCE_INVISIBLE  = 1
84     PRESENCE_BUSY               = 2
85     PRESENCE_IDLE               = 3
86     
87     status                      = PRESENCE_AVAILABLE
88     status_text         = ""
89
90     def __init__(self):
91         bus_name = dbus.service.BusName(ogSMP,
92             bus=dbus.SessionBus())
93         dbus.service.Object.__init__(self, bus_name,
94             ogSMPp)
95         #print "%s emulation ready" % ogSMP
96
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,
103             }
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,
111         in_signature='ssv')
112     def Set(self, interface_name, property_name, value):
113         #print "%s.Set(%s, %s, %s)" % \
114         #       (ogSMP, interface_name, property_name, value)
115         pass
116
117     @dbus.service.method(dbus_interface=ogSMP, in_signature='u')
118     def SetStatus(self, status):
119         self.status = status
120
121     @dbus.service.method(dbus_interface=ogSMP, in_signature='u')
122     def SetStatusText(self, status_text):
123         self.status_text = status_text
124
125     @dbus.service.signal(dbus_interface=ogSMP, signature='u')
126     def StatusChanged(self, status):
127         self.SetStatus(status)
128
129     @dbus.service.signal(dbus_interface=ogSMP, signature='s')
130     def StatusTextChanged(self, status_text):
131         self.SetStatusText(status_text)
132
133
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
143         
144     def __init__(self, idle_timeout):
145         self.idle_timeout = idle_timeout
146         self.idle       = False
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)
154     
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
160         
161         if idle >= self.idle_timeout:
162             if not self.idle:
163                 print "Becoming idle"
164                 self.idle = True
165                 smp.StatusChanged(smp.PRESENCE_IDLE)
166         else:
167             if self.idle:
168                 print "Not idle anymore"
169                 self.idle = False
170                 smp.StatusChanged(smp.PRESENCE_AVAILABLE)
171         
172         gobject.timeout_add(10000, self.check_idle, smp)
173     
174
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
179 else:
180     # 5 minutes
181     idle_delay = 300
182
183 sessmgr = SessionManager()
184
185 xssic = XScreenSaverIdleChecker(idle_delay)
186 xssic.check_idle(sessmgr.get_smp())
187
188 gtk.main()