1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 import os
36 import glob
37 import random
38 from xdg import BaseDirectory
39
40 import backend
41 import services
42 import utils
43
44 import dbus
45 from stat import S_IRWXU, S_IRWXG, S_IRWXO
46 import gettext
47 import screenlets
48 gettext.textdomain('screenlets')
49 gettext.bindtextdomain('screenlets', screenlets.INSTALL_PREFIX + '/share/locale')
50
52 return gettext.gettext(s)
53
54
55
56 TMP_DIR = '/tmp/screenlets'
57 TMP_FILE = 'screenlets.' + os.environ['USER'] + '.running'
58
59
61 """The ScreenletSession manages instances of a Screenlet and handles
62 saving/restoring options. Each Screenlet contains a reference to its
63 session. Multiple instances of the same Screenlet share the same
64 session-object."""
65
66
67 - def __init__ (self, screenlet_classobj, backend_type='caching', name='default'):
68 object.__init__(self)
69
70 if not screenlet_classobj.__name__.endswith('Screenlet'):
71
72 raise Exception("ScreenletSession.__init__ has to be called with a valid Screenlet-classobject as first argument!")
73
74 self.name = name
75 self.screenlet = screenlet_classobj
76 self.instances = []
77 self.tempfile = TMP_DIR + '/' + TMP_FILE
78
79 self.__parse_commandline()
80
81 p = screenlet_classobj.__name__[:-9] + '/' + self.name + '/'
82 self.path = BaseDirectory.load_first_config('Screenlets/' + p)
83 if self.path == None:
84 self.path = BaseDirectory.save_config_path('Screenlets/' + p)
85 if self.path == None: self.path = (os.environ['HOME'] + '.config/Screenlets/' + p)
86 if self.path:
87 if backend_type == 'caching':
88 self.backend = backend.CachingBackend(path=self.path)
89 elif backend_type == 'gconf':
90 self.backend = backend.GconfBackend()
91 else:
92
93 self.backend = backend.ScreenletsBackend()
94 print "Unable to init backend - settings will not be saved!"
95
96
97
98 proc = os.popen("""ps axo "%p,%a" | grep "python.*screenlets-daemon.py" | grep -v grep|cut -d',' -f1""").read()
99
100 procs = proc.split('\n')
101 if len(procs) <= 1:
102 os.system('python -u ' + screenlets.INSTALL_PREFIX + '/share/screenlets-manager/screenlets-daemon.py &')
103 print 'No Daemon, Launching Daemon'
104 self.connect_daemon()
105
107 """Connect to org.screenlets.ScreenletsDaemon."""
108 self.daemon_iface = None
109 bus = dbus.SessionBus()
110 if bus:
111 try:
112 proxy_obj = bus.get_object(screenlets.DAEMON_BUS, screenlets.DAEMON_PATH)
113 if proxy_obj:
114 self.daemon_iface = dbus.Interface(proxy_obj, screenlets.DAEMON_IFACE)
115 except Exception, ex:
116 print "Error in screenlets.session.connect_daemon: %s" % ex
117
119 """Create a new instance with ID 'id' and add it to this session. The
120 function returns either the new Screenlet-instance or None."""
121
122 if id==None or id=='' or self.get_instance_by_id(id) != None:
123 print "ID is unset or already in use - creating new one!"
124 id = self.__get_next_id()
125 dirlst = glob.glob(self.path + '*')
126 tdlen = len(self.path)
127 for filename in dirlst:
128 filename = filename[tdlen:]
129 print 'Loaded config from: %s' % filename
130 if filename.endswith(id + '.ini'):
131
132 sl = self.create_instance(id=filename[:-4], enable_saving=False)
133 if sl:
134
135 print "Set options in %s" % sl.__name__
136
137 self.__restore_options_from_backend(sl, self.path+filename)
138 sl.enable_saving(True)
139
140 sl.finish_loading()
141 return sl
142 sl = self.screenlet(id=id, session=self, **keyword_args)
143 if sl:
144 self.instances.append(sl)
145
146 sl.x = sl.x
147 return sl
148 return None
149
151 """Delete the given instance with ID 'id' and remove its session file.
152 When the last instance within the session is removed, the session dir
153 is completely removed."""
154 sl = self.get_instance_by_id(id)
155 if sl:
156
157 self.instances.remove(sl)
158
159 try:
160 self.backend.delete_instance(id)
161 except Exception:
162 print "Failed to remove INI-file for instance (not critical)."
163
164 if len(self.instances) == 0:
165
166 print "Removing last instance from session"
167
168 print "TODO: remove self.path: %s" % self.path
169 try:
170 os.rmdir(self.path)
171 except:
172 print "Failed to remove session dir '%s' - not empty?" % self.name
173
174
175 sl.quit_on_close = True
176 else:
177 print "Removing instance from session but staying alive"
178 sl.quit_on_close = False
179
180 sl.close()
181 del sl
182 return True
183 return False
184
186 """Return the instance with the given id from within this session."""
187 for inst in self.instances:
188 if inst.id == id:
189 return inst
190 return None
191
193 """quit the given instance with ID 'id'"""
194
195 sl = self.get_instance_by_id(id)
196 if sl:
197 print self.instances
198
199
200
201 if len(self.instances) == 1:
202 sl.quit_on_close = True
203 else:
204 print "Removing instance from session but staying alive"
205 sl.quit_on_close = False
206 self.backend.flush()
207 sl.close()
208 self.instances.remove(sl)
209
210
211 return True
212 return False
213
214
216 """Start a new session (or restore an existing session) for the
217 current Screenlet-class. Creates a new instance when none is found.
218 Returns True if everything worked well, else False."""
219
220
221
222 sln = self.screenlet.__name__[:-9]
223 running = utils.list_running_screenlets()
224 if running and running.count(self.screenlet.__name__) > 0:
225
226 print "Found a running session of %s, adding new instance by service." % sln
227 srvc = services.get_service_by_name(sln)
228 if srvc:
229 print "Adding new instance through: %s" % str(srvc)
230 srvc.add('')
231 return False
232
233 self.__register_screenlet()
234
235 print "Loading instances in: %s" % self.path
236 if self.__load_instances():
237
238 print "Restored instances from session '%s' ..." % self.name
239
240
241 self.__run_session(self.instances[0])
242 else:
243
244 print 'No instance(s) found in session-path, creating new one.'
245 sl = self.screenlet(session=self, id=self.__get_next_id())
246 if sl:
247
248 self.instances.append(sl)
249
250
251 self.backend.save_option(sl.id, 'x', sl.x)
252
253 sl.finish_loading()
254
255
256 self.__run_session(sl)
257 else:
258 print 'Failed creating instance of: %s' % self.classobj.__name__
259
260 self.__unregister_screenlet()
261 return False
262
263 return True
264
266 """Create new entry for this session in the global TMP_FILE."""
267
268
269 if not self.__create_tempdir():
270 return False
271
272
273 running = utils.list_running_screenlets()
274 if running == None : running = []
275 if running.count(self.screenlet.__name__) == 0:
276
277 try:
278 f = open(self.tempfile, 'a')
279 except IOError, e:
280 print "Unable to open %s" % self.tempfile
281 return False
282 else:
283 print "Creating new entry for %s in %s" % (self.screenlet.__name__, self.tempfile)
284 f.write(self.screenlet.__name__ + '\n')
285 f.close()
286 else: print "Screenlet has already been added to %s" % self.tempfile
287
288
289 if self.daemon_iface:
290 self.daemon_iface.register_screenlet(self.screenlet.__name__)
291
293 """Create the global temporary file for saving screenlets. The file is
294 used for indicating which screnlets are currently running."""
295
296
297 if not os.path.isdir(TMP_DIR):
298 try:
299 if os.path.exists(TMP_DIR):
300
301 os.remove(TMP_DIR)
302
303 print "No global tempdir found, creating new one."
304 os.mkdir(TMP_DIR)
305
306
307 os.chmod(TMP_DIR, S_IRWXU | S_IRWXG | S_IRWXO)
308 print 'Temp directory %s created.' % TMP_DIR
309 except OSError, e:
310 print 'Error: Unable to create temp directory %s - screenlets-manager will not work properly.' % TMP_DIR
311 print "Error was: %s"%e
312 return False
313 return True
314
315
317 """Delete this session's entry from the gloabl tempfile (and delete the
318 entire file if no more running screenlets are set."""
319 if not name:
320 name = self.screenlet.__name__
321
322
323 if self.daemon_iface:
324 try:
325 self.daemon_iface.unregister_screenlet(name)
326 except Exception, ex:
327 print "Failed to unregister from daemon: %s" % ex
328
329
330 running = utils.list_running_screenlets()
331 if running and len(running) > 0:
332 pass
333 try:
334 running.remove(name)
335 except:
336
337 print "Entry not found. Will (obviously) not be removed."
338 return True
339
340 if running and len(running) > 0:
341
342 f = open(self.tempfile, 'w')
343 if f:
344 for r in running:
345 f.write(r + '\n')
346 f.close()
347 return True
348 else:
349 print "Error global tempfile not found. Some error before?"
350 return False
351 else:
352 print 'No more screenlets running.'
353 self.__delete_tempfile(name)
354 else:
355 print 'No screenlets running?'
356 return False
357
359 """Delete the tempfile for this session."""
360 if self.tempfile and os.path.isfile(self.tempfile):
361 print "Deleting global tempfile %s" % self.tempfile
362 try:
363 os.remove(self.tempfile)
364 return True
365 except:
366 print "Error: Failed to delete global tempfile"
367 return False
368
370 """Get the next ID for an instance of the assigned Screenlet."""
371 num = 1
372 sln = self.screenlet.__name__[:-9]
373 id = sln + str(num)
374 while self.get_instance_by_id(id) != None:
375 id = sln + str(num)
376 num += 1
377 return id
378
380 """Check for existing instances in the current session, create them
381 and store them into self.instances if any are found. Returns True if
382 at least one instance was found, else False."""
383 dirlst = glob.glob(self.path + '*')
384 tdlen = len(self.path)
385 for filename in dirlst:
386 filename = filename[tdlen:]
387 print 'Loaded config from: %s' % filename
388 if filename.endswith('.ini'):
389
390 sl = self.create_instance(id=filename[:-4], enable_saving=False)
391 if sl:
392
393 print "Set options in %s" % sl.__name__
394
395 self.__restore_options_from_backend(sl, self.path+filename)
396 sl.enable_saving(True)
397
398 sl.finish_loading()
399 else:
400 print "Failed to create instance of '%s'!" % filename[:-4]
401
402 if len(self.instances) > 0:
403 return True
404 return False
405
406
426
428 """Run the session by calling the main handler of the given Screenlet-
429 instance. Handles sigkill (?) and keyboard interrupts."""
430
431 import signal
432 def on_kill(*args):
433
434 pass
435 signal.signal(signal.SIGTERM, on_kill)
436
437 tempfile = self.screenlet.__name__
438
439 try:
440
441 main_instance.main()
442 except KeyboardInterrupt:
443
444 self.backend.flush()
445 print "Screenlet '%s' has been interrupted by keyboard. TODO: make this an event" % self.screenlet.__name__
446 except Exception, ex:
447 print "Exception in ScreenletSession: " + ex
448
449 self.__unregister_screenlet(name=tempfile)
450
452 """Check commandline args for "--session" argument and set session
453 name if found. Runs only once during __init__.
454 TODO: handle more arguments and maybe allow setting options by
455 commandline"""
456 import sys
457 for arg in sys.argv[1:]:
458
459 if arg.startswith('--session=') and len(arg)>10:
460 self.name = arg[10:]
461
462
463
465 """A very simple utility-function to easily create/start a new session."""
466
467 if threading:
468 import gtk
469 gtk.gdk.threads_init()
470 session = ScreenletSession(classobj, backend_type=backend)
471 session.start()
472