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