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
99
100
101
102
103
104
105
106
107 self.connect_daemon()
108
110 """Connect to org.screenlets.ScreenletsDaemon."""
111 self.daemon_iface = None
112 bus = dbus.SessionBus()
113 if bus:
114 try:
115 proxy_obj = bus.get_object(screenlets.DAEMON_BUS, screenlets.DAEMON_PATH)
116 if proxy_obj:
117 self.daemon_iface = dbus.Interface(proxy_obj, screenlets.DAEMON_IFACE)
118 except Exception, ex:
119 print "Error in screenlets.session.connect_daemon: %s" % ex
120
122 """Create a new instance with ID 'id' and add it to this session. The
123 function returns either the new Screenlet-instance or None."""
124
125 if id==None or id=='' or self.get_instance_by_id(id) != None:
126 print "ID is unset or already in use - creating new one!"
127 id = self.__get_next_id()
128 dirlst = glob.glob(self.path + '*')
129 tdlen = len(self.path)
130 for filename in dirlst:
131 filename = filename[tdlen:]
132 print 'Loaded config from: %s' % filename
133 if filename.endswith(id + '.ini'):
134
135 sl = self.create_instance(id=filename[:-4], enable_saving=False)
136 if sl:
137
138 print "Set options in %s" % sl.__name__
139
140 self.__restore_options_from_backend(sl, self.path+filename)
141 sl.enable_saving(True)
142
143 sl.finish_loading()
144 return sl
145 sl = self.screenlet(id=id, session=self, **keyword_args)
146 if sl:
147 self.instances.append(sl)
148
149 sl.x = sl.x
150 return sl
151 return None
152
154 """Delete the given instance with ID 'id' and remove its session file.
155 When the last instance within the session is removed, the session dir
156 is completely removed."""
157 sl = self.get_instance_by_id(id)
158 if sl:
159
160 self.instances.remove(sl)
161
162 try:
163 self.backend.delete_instance(id)
164 except Exception:
165 print "Failed to remove INI-file for instance (not critical)."
166
167 if len(self.instances) == 0:
168
169 print "Removing last instance from session"
170
171 print "TODO: remove self.path: %s" % self.path
172 try:
173 os.rmdir(self.path)
174 except:
175 print "Failed to remove session dir '%s' - not empty?" % self.name
176
177
178 sl.quit_on_close = True
179 else:
180 print "Removing instance from session but staying alive"
181 sl.quit_on_close = False
182
183 sl.close()
184 del sl
185 return True
186 return False
187
189 """Return the instance with the given id from within this session."""
190 for inst in self.instances:
191 if inst.id == id:
192 return inst
193 return None
194
196 """quit the given instance with ID 'id'"""
197
198 sl = self.get_instance_by_id(id)
199 if sl:
200 print self.instances
201
202
203
204 if len(self.instances) == 1:
205 sl.quit_on_close = True
206 else:
207 print "Removing instance from session but staying alive"
208 sl.quit_on_close = False
209 self.backend.flush()
210 sl.close()
211 self.instances.remove(sl)
212
213
214 return True
215 return False
216
217
219 """Start a new session (or restore an existing session) for the
220 current Screenlet-class. Creates a new instance when none is found.
221 Returns True if everything worked well, else False."""
222
223
224
225 sln = self.screenlet.__name__[:-9]
226 running = utils.list_running_screenlets()
227 if running and running.count(self.screenlet.__name__) > 0:
228
229 print "Found a running session of %s, adding new instance by service." % sln
230 srvc = services.get_service_by_name(sln)
231 if srvc:
232 print "Adding new instance through: %s" % str(srvc)
233 srvc.add('')
234 return False
235
236 self.__register_screenlet()
237
238 print "Loading instances in: %s" % self.path
239 if self.__load_instances():
240
241 print "Restored instances from session '%s' ..." % self.name
242
243
244 self.__run_session(self.instances[0])
245 else:
246
247 print 'No instance(s) found in session-path, creating new one.'
248 sl = self.screenlet(session=self, id=self.__get_next_id())
249 if sl:
250
251 self.instances.append(sl)
252
253
254 self.backend.save_option(sl.id, 'x', sl.x)
255
256 sl.finish_loading()
257
258
259 self.__run_session(sl)
260 else:
261 print 'Failed creating instance of: %s' % self.classobj.__name__
262
263 self.__unregister_screenlet()
264 return False
265
266 return True
267
269 """Create new entry for this session in the global TMP_FILE."""
270
271
272 if not self.__create_tempdir():
273 return False
274
275
276 running = utils.list_running_screenlets()
277 if running == None : running = []
278 if running.count(self.screenlet.__name__) == 0:
279
280 try:
281 f = open(self.tempfile, 'a')
282 except IOError, e:
283 print "Unable to open %s" % self.tempfile
284 return False
285 else:
286 print "Creating new entry for %s in %s" % (self.screenlet.__name__, self.tempfile)
287 f.write(self.screenlet.__name__ + '\n')
288 f.close()
289 else: print "Screenlet has already been added to %s" % self.tempfile
290
291
292 if self.daemon_iface:
293 self.daemon_iface.register_screenlet(self.screenlet.__name__)
294
296 """Create the global temporary file for saving screenlets. The file is
297 used for indicating which screnlets are currently running."""
298
299
300 if not os.path.isdir(TMP_DIR):
301 try:
302 if os.path.exists(TMP_DIR):
303
304 os.remove(TMP_DIR)
305
306 print "No global tempdir found, creating new one."
307 os.mkdir(TMP_DIR)
308
309
310 os.chmod(TMP_DIR, S_IRWXU | S_IRWXG | S_IRWXO)
311 print 'Temp directory %s created.' % TMP_DIR
312 except OSError, e:
313 print 'Error: Unable to create temp directory %s - screenlets-manager will not work properly.' % TMP_DIR
314 print "Error was: %s"%e
315 return False
316 return True
317
318
320 """Delete this session's entry from the gloabl tempfile (and delete the
321 entire file if no more running screenlets are set."""
322 if not name:
323 name = self.screenlet.__name__
324
325
326 if self.daemon_iface:
327 try:
328 self.daemon_iface.unregister_screenlet(name)
329 except Exception, ex:
330 print "Failed to unregister from daemon: %s" % ex
331
332
333 running = utils.list_running_screenlets()
334 if running and len(running) > 0:
335 pass
336 try:
337 running.remove(name)
338 except:
339
340 print "Entry not found. Will (obviously) not be removed."
341 return True
342
343 if running and len(running) > 0:
344
345 f = open(self.tempfile, 'w')
346 if f:
347 for r in running:
348 f.write(r + '\n')
349 f.close()
350 return True
351 else:
352 print "Error global tempfile not found. Some error before?"
353 return False
354 else:
355 print 'No more screenlets running.'
356 self.__delete_tempfile(name)
357 else:
358 print 'No screenlets running?'
359 return False
360
362 """Delete the tempfile for this session."""
363 if self.tempfile and os.path.isfile(self.tempfile):
364 print "Deleting global tempfile %s" % self.tempfile
365 try:
366 os.remove(self.tempfile)
367 return True
368 except:
369 print "Error: Failed to delete global tempfile"
370 return False
371
373 """Get the next ID for an instance of the assigned Screenlet."""
374 num = 1
375 sln = self.screenlet.__name__[:-9]
376 id = sln + str(num)
377 while self.get_instance_by_id(id) != None:
378 id = sln + str(num)
379 num += 1
380 return id
381
383 """Check for existing instances in the current session, create them
384 and store them into self.instances if any are found. Returns True if
385 at least one instance was found, else False."""
386 dirlst = glob.glob(self.path + '*')
387 tdlen = len(self.path)
388 for filename in dirlst:
389 filename = filename[tdlen:]
390 print 'Loaded config from: %s' % filename
391 if filename.endswith('.ini'):
392
393 sl = self.create_instance(id=filename[:-4], enable_saving=False)
394 if sl:
395
396 print "Set options in %s" % sl.__name__
397
398 self.__restore_options_from_backend(sl, self.path+filename)
399 sl.enable_saving(True)
400
401 sl.finish_loading()
402 else:
403 print "Failed to create instance of '%s'!" % filename[:-4]
404
405 if len(self.instances) > 0:
406 return True
407 return False
408
409
429
431 """Run the session by calling the main handler of the given Screenlet-
432 instance. Handles sigkill (?) and keyboard interrupts."""
433
434 import signal
435 def on_kill(*args):
436
437 pass
438 signal.signal(signal.SIGTERM, on_kill)
439
440 tempfile = self.screenlet.__name__
441
442 try:
443
444 main_instance.main()
445 except KeyboardInterrupt:
446
447 self.backend.flush()
448 print "Screenlet '%s' has been interrupted by keyboard. TODO: make this an event" % self.screenlet.__name__
449 except Exception, ex:
450 print "Exception in ScreenletSession: " + ex
451
452 self.__unregister_screenlet(name=tempfile)
453
455 """Check commandline args for "--session" argument and set session
456 name if found. Runs only once during __init__.
457 TODO: handle more arguments and maybe allow setting options by
458 commandline"""
459 import sys
460 for arg in sys.argv[1:]:
461
462 if arg.startswith('--session=') and len(arg)>10:
463 self.name = arg[10:]
464
465
466
468 """A very simple utility-function to easily create/start a new session."""
469
470 if threading:
471 import gtk
472 gtk.gdk.threads_init()
473 session = ScreenletSession(classobj, backend_type=backend)
474 session.start()
475