1
2
3
4
5
6
7
8
9
10
11
12
13
14 import screenlets
15 import gtk
16 import dbus
17 import os
18 import sys
19 import stat
20 import gettext
21 import re
22 import urllib
23 gettext.textdomain('screenlets')
24 gettext.bindtextdomain('screenlets', screenlets.INSTALL_PREFIX + '/share/locale')
25 import gobject
26 try:
27 import gnomevfs
28 except:
29 pass
31 return gettext.gettext(s)
32
33
34
35
36
37
39 """Returns the system autostart directory"""
40 desktop_environment = 'gnome'
41
42 if os.environ.get('KDE_FULL_SESSION') == 'true':
43 desktop_environment = 'kde'
44 elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
45 desktop_environment = 'gnome'
46 else:
47 try:
48 import commands
49 info = commands.getoutput('xprop -root _DT_SAVE_MODE')
50 if ' = "xfce4"' in info:
51 desktop_environment = 'xfce'
52 except (OSError, RuntimeError):
53 pass
54
55
56
57 if desktop_environment == 'kde':
58 return os.environ['HOME'] + '/.kde/Autostart/'
59 elif desktop_environment == 'gnome':
60 return os.environ['HOME'] + '/.config/autostart/'
61 elif desktop_environment == 'xfce':
62 return os.environ['HOME'] + '/.config/autostart/'
63
64 if os.geteuid()==0:
65
66 USER = 0
67 DIR_USER = screenlets.INSTALL_PREFIX + '/share/screenlets'
68 DIR_AUTOSTART = '/etc/xdg/autostart'
69 else:
70
71 USER = 1
72 DIR_USER = os.environ['HOME'] + '/.screenlets'
73 DIR_AUTOSTART = get_autostart_dir()
74
75
76
78 """checks if the one starting the screenlet is the screenlets manager"""
79 if str(sys.argv[0]).find('screenlets-manager') != -1:
80 return True
81 else:
82 return False
83
85 """Check whether 'str' contains ALL of the chars in 'set'"""
86 for c in set:
87 if c not in str: return 0;
88 return 1;
90 """Check whether 'str' contains ANY of the chars in 'set'"""
91 return 1 in [c in str for c in set]
92
94 """Create a .desktop-file for the screenlet with the given name in
95 $HOME/.config/autostart."""
96 if not os.path.isdir(DIR_AUTOSTART):
97
98 if screenlets.show_question(None,
99 _("There is no existing autostart directory for your user account yet. Do you want me to automatically create it for you?"),
100 _('Error')):
101 print _("Auto-create autostart dir ...")
102 os.system('mkdir %s' % DIR_AUTOSTART)
103 if not os.path.isdir(DIR_AUTOSTART):
104 screenlets.show_error(None, _("Automatic creation failed. Please manually create the directory:\n%s") % DIR_AUTOSTART, _('Error'))
105 return False
106 else:
107 screenlets.show_message(None, _("Please manually create the directory:\n%s") % DIR_AUTOSTART)
108 return False
109 if name.endswith('Screenlet'):
110 name = name[:-9]
111 starter = '%s%sScreenlet.desktop' % (DIR_AUTOSTART, name)
112
113 for f in os.listdir(DIR_AUTOSTART):
114 a = f.find(name + 'Screenlet')
115 if a != -1:
116 print str(f) + ' duplicate entry'
117 os.system('rm %s%s' % (chr(34)+DIR_AUTOSTART,f+chr(34)))
118 print _('Removed duplicate entry')
119 if not os.path.isfile(starter) and not os.path.exists(os.environ['HOME'] + '/.config/autostart/CalendarScreenlet'):
120 path = find_first_screenlet_path(name)
121 if path:
122 print _("Create autostarter for: %s/%sScreenlet.py") % (path, name)
123 code = ['[Desktop Entry]']
124 code.append('Name=%sScreenlet' % name)
125 code.append('Encoding=UTF-8')
126 code.append('Version=1.0')
127 code.append('Type=Application')
128 code.append('Exec= python -u %s/%sScreenlet.py' % (path, name))
129 code.append('X-GNOME-Autostart-enabled=true')
130
131 f = open(starter, 'w')
132 if f:
133 for l in code:
134 f.write(l + '\n')
135 f.close()
136 return True
137 print _('Failed to create autostarter for %s.') % name
138 return False
139 else:
140 print _("Starter already exists.")
141 return True
142
144 """Delete the autostart for the given screenlet."""
145 if name.endswith('Screenlet'):
146 name = name[:-9]
147 print _('Delete autostarter for %s.') % name
148 os.system('rm %s%sScreenlet.desktop' % (DIR_AUTOSTART, name))
149 for f in os.listdir(DIR_AUTOSTART):
150 a = f.find(name + 'Screenlet')
151 if a != -1:
152 print str(f) + ' duplicate entry'
153 os.system('rm %s%s' % (chr(34)+DIR_AUTOSTART,f+chr(34)))
154 print _('Removed duplicate entry')
155
157 """Internal function: Returns true if the given string contains one of the
158 SCREENLETS_PATH entries."""
159 for p in screenlets.SCREENLETS_PATH:
160 if string.find(p) > -1:
161 return True
162 return False
163
165 """Create the userdir for the screenlets."""
166 if not os.path.isdir(os.environ['HOME'] + '/.screenlets'):
167 try:
168 os.mkdir(os.environ['HOME'] + '/.screenlets')
169 except:
170 print 'coulnt create user dir'
171
172
174 """Scan the SCREENLETS_PATH for the first occurence of screenlet "name" and
175 return the full path to it. This function is used to get the theme/data
176 directories for a Screenlet."""
177 for dir in screenlets.SCREENLETS_PATH:
178 try:
179 for name in os.listdir(dir):
180 name_py = name + 'Screenlet.py'
181 path = dir + '/' + name
182 if not stat.S_ISDIR(os.stat(path).st_mode):
183 continue
184
185 if os.access(path + '/' + name_py, os.F_OK):
186 if name == screenlet_name:
187 return path
188 else:
189
190
191 pass
192 except OSError:
193 pass
194
195 return None
196
198 img = gtk.gdk.pixbuf_new_from_file_at_size(\
199 screenlets.INSTALL_PREFIX + '/share/screenlets-manager/noimage.svg',width,height)
200 for path in screenlets.SCREENLETS_PATH:
201 for ext in ['svg', 'png']:
202 img_path = "%s/%s/icon.%s" % (path, screenlet_name, ext)
203 if os.path.isfile(img_path):
204 try:
205 img = gtk.gdk.pixbuf_new_from_file_at_size(img_path,width,height)
206 except Exception, ex:
207 pass
208 return img
209
211 x = len(first)
212 begin = data.find(first) +x
213 end = data.find(last, begin)
214 return data[begin:end]
215
264
266 """Scan the SCREENLETS_PATHs for all existing screenlets and return their
267 names (without trailing "Screenlet") as a list of strings."""
268 sls = []
269 for dir in screenlets.SCREENLETS_PATH:
270 try:
271 for name in os.listdir(dir):
272 path = dir + '/' + name
273
274 if not stat.S_ISDIR(os.stat(path).st_mode):
275 continue
276
277 if os.access(path + '/' + name + 'Screenlet.py', os.F_OK):
278 if not sls.count(name):
279 sls.append(name)
280 else:
281 pass
282 except OSError:
283 pass
284 return sls
285
286 import session
288 """Returns a list with names of running screenlets or None if no
289 Screenlet is currently running. Function returns False if an error
290 happened!"""
291 running = []
292 tempfile = screenlets.TMP_DIR + '/' + screenlets.TMP_FILE
293 if not os.path.isfile(tempfile):
294 return None
295 f = open(tempfile, 'r')
296 if f:
297 running = f.readlines()
298 f.close()
299 for i in xrange(len(running)):
300 running[i] = running[i][:-1]
301
302 p = os.popen("ps aux | awk '/Screenlet.py/{ print $11, $12, $13, $14, $15, $16 }'")
303 lst = []
304 regex = re.compile('/([A-Za-z0-9]+)Screenlet.py ')
305 for line in p.readlines():
306 if not line.endswith('awk /Screenlet.py/{\n') and line != 'sh -c\n' \
307 and _contains_path(line):
308 slname = regex.findall(line)
309 if slname and type(slname) == list and len(slname) > 0:
310 lst.append(slname[0]+'Screenlet')
311 p.close()
312 for a in lst:
313 if a not in running:
314 running.append(a)
315 return running
316
317
318
320 """Returns a list with names of running screenlets. The list can be empty if
321 no Screenlet is currently running."""
322 p = os.popen("ps aux | awk '/Screenlet.py/{ print $11, $12, $13, $14, $15, $16 }'")
323 lst = []
324 regex = re.compile('/([A-Za-z0-9]+)Screenlet.py ')
325 for line in p.readlines():
326 if not line.endswith('awk /Screenlet.py/{\n') and line != 'sh -c\n' \
327 and _contains_path(line):
328 slname = regex.findall(line)
329 if slname and type(slname) == list and len(slname) > 0:
330 lst.append(slname[0]+'Screenlet')
331 p.close()
332 return lst
333
334
335
336
338 """Returns the PID of the given screenlet (if running) or None."""
339 p = os.popen("ps aux | awk '/[" + name[0] + "]" + name[1:] + \
340 "Screenlet.py/{ print $2, $11, $12, $13, $14, $15, $16 }'")
341 line = p.readlines()
342 p.close()
343
344 if len(line) and _contains_path(line[0]):
345 return int(line[0].split(' ')[0])
346 return None
347
349 """http://www.freedesktop.org/wiki/Software/xdg-user-dirs"""
350
351 user_dirs_dirs = os.path.expanduser("~/.config/user-dirs.dirs")
352 if os.path.exists(user_dirs_dirs):
353 f = open(user_dirs_dirs, "r")
354 for line in f.readlines():
355 if line.startswith(key):
356 return os.path.expandvars(line[len(key)+2:-2])
357 return default
358
360 """Check if the daemon is already running and return its interface."""
361 bus = dbus.SessionBus()
362 if bus:
363 try:
364 proxy_obj = bus.get_object(screenlets.DAEMON_BUS, screenlets.DAEMON_PATH)
365 if proxy_obj:
366 return dbus.Interface(proxy_obj, screenlets.DAEMON_IFACE)
367
368 except Exception, ex:
369 print _("Error in ScreenletsManager.connect_daemon: %s") % ex
370 return None
371
373 """Returns desktop dir"""
374 desktop_dir = get_user_dir("XDG_DESKTOP_DIR", os.path.expanduser("~/Desktop"))
375 desktop_dir = urllib.unquote(desktop_dir)
376 return desktop_dir
377
379 """Returns filenames of window droped files"""
380 filename = ''
381 filenames = []
382
383 try:
384 txt = unicode.encode(sel_data.get_text(), 'utf-8')
385 except:
386 txt = sel_data.get_text()
387 txta = urllib.unquote(txt)
388 txta = str(txta).split('\n')
389
390 for txt in txta:
391 if txt and txt != '':
392
393 if txt.startswith('file://'):
394 filename = txt[7:]
395 else:
396 print 'Invalid string: %s.' % txt
397 else:
398
399 uris = sel_data.get_uris()
400 if uris and len(uris)>0:
401
402 filename = uris[0][7:]
403 if filename != '':
404 filenames.append(chr(34) +filename + chr(34))
405
406 return filenames
407
409 """Returns mount points in media"""
410 mountlist = os.popen('mount -l').read()
411 prog = re.compile("^/dev/.*?\son\s/media/(.*?) .*?(\[(.*?)\])?$", re.MULTILINE)
412 return prog.findall(mountlist)
413
415 """Returns gtk bookmarks """
416 _bookmarks_path = os.path.expanduser("~/.gtk-bookmarks")
417 _places = []
418 try:
419 for line in file(_bookmarks_path):
420 line = line.strip()
421
422 if " " in line:
423 uri, name = line.split(" ", 1)
424
425 else:
426 uri = line
427
428 path = urllib.splittype(uri)[1]
429 name = urllib.unquote(os.path.split(path)[1])
430
431 try:
432 if os.path.exists(uri):
433 continue
434
435 except TypeError:
436 continue
437
438 _places.append((uri, name))
439 return _places
440 except IOError, err:
441 print "Error loading GTK bookmarks:", err
442
449
461
468
470 """Reads fstab file"""
471 fstab = []
472 f = open(filename, 'r')
473 for line in f:
474 if (not line.isspace() and not line.startswith('#') and not line.lower().startswith('none')) :
475 fstabline = line.split()
476 if fstabline[1] != 'none' and fstabline[1] != '/proc': fstab.append(fstabline[1])
477
478 fstab.sort()
479 return fstab
480
482 """Reads a file"""
483 f = open(filename, 'r')
484 t = f.read()
485 f.close()
486 return t
487
488
490 """Strips HTML tags of a string"""
491 return re.sub(r"<.*?>|</.*?>","",string)
492
493
494
496 """Adds Screenlets-daemon to autostart if not already"""
497 if not os.path.isdir(DIR_AUTOSTART):
498
499 if screenlets.show_question(None, _("There is no existing autostart directory for your user account yet. Do you want me to automatically create it for you?"), _('Error')):
500 print _("Auto-create autostart dir ...")
501 os.system('mkdir %s' % DIR_AUTOSTART)
502 if not os.path.isdir(DIR_AUTOSTART):
503 screenlets.show_error(None, _("Automatic creation failed. Please manually create the directory:\n%s") % DIR_AUTOSTART, _('Error'))
504 return False
505 else:
506 screenlets.show_message(None, _("Please manually create the directory:\n%s") % DIR_AUTOSTART)
507 return False
508 starter = '%sScreenlets Daemon.desktop' % (DIR_AUTOSTART)
509
510 if not os.path.isfile(starter) and os.path.isfile('%sscreenlets-daemon.desktop' % (DIR_AUTOSTART)) == False:
511 print _("Create autostarter for: Screenlets Daemon")
512 code = ['[Desktop Entry]']
513 code.append('Encoding=UTF-8')
514 code.append('Version=1.0')
515 code.append('Name=Screenlets Daemon')
516 code.append('Type=Application')
517 code.append('Exec=%s/share/screenlets-manager/screenlets-daemon.py' % (screenlets.INSTALL_PREFIX))
518 code.append('X-GNOME-Autostart-enabled=true')
519 f = open(starter, 'w')
520 if f:
521 for l in code:
522 f.write(l + '\n')
523 f.close()
524 return True
525 print _('Failed to create autostarter for %s.') % name
526 return False
527 else:
528 print _("Starter already exists.")
529 return True
530
536
537
538
540 """Opens anything"""
541 os.system('xdg-open ' + name + ' &')
542
543
544
545
546
548 """A container with info about a screenlet."""
549
550 - def __init__ (self, name, lname, info, author, version, icon):
551 self.name = name
552 self.lname = lname
553 self.info = info.replace("\n", '').replace('\t', ' ')
554 self.author = author
555 self.version = version
556 self.icon = icon
557 self.active = False
558 self.system = not os.path.isfile('%s/%s/%sScreenlet.py' % (DIR_USER, name, name))
559 self.autostart = os.path.isfile(DIR_AUTOSTART + '/' + name + 'Screenlet.desktop')
560
561
562
564 '''
565 A simple wrapper around Gnome VFS file monitors. Emits created, deleted,
566 and changed events. Incoming events are queued, with the latest event
567 cancelling prior undelivered events.
568 '''
569
570
571 __gsignals__ = {
572 "event" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
573 (gobject.TYPE_STRING, gobject.TYPE_INT)),
574 "created" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)),
575 "deleted" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)),
576 "changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
577 }
578
580 gobject.GObject.__init__(self)
581
582 if os.path.isabs(path):
583 self.path = "file://" + path
584 else:
585 self.path = path
586 try:
587 self.type = gnomevfs.get_file_info(path).type
588 except gnomevfs.Error:
589 self.type = gnomevfs.MONITOR_FILE
590
591 self.monitor = None
592 self.pending_timeouts = {}
593
595 if not self.monitor:
596 if self.type == gnomevfs.FILE_TYPE_DIRECTORY:
597 monitor_type = gnomevfs.MONITOR_DIRECTORY
598 else:
599 monitor_type = gnomevfs.MONITOR_FILE
600 self.monitor = gnomevfs.monitor_add(self.path, monitor_type, self._queue_event)
601
603 try:
604 gobject.source_remove(self.pending_timeouts[info_uri])
605 del self.pending_timeouts[info_uri]
606 except KeyError:
607 pass
608
610 self._clear_timeout(info_uri)
611 self.pending_timeouts[info_uri] = \
612 gobject.timeout_add(250, self._timeout_cb, monitor_uri, info_uri, event)
613
616
618 gnomevfs.monitor_cancel(self.monitor)
619 self.monitor = None
620
622 if event in (gnomevfs.MONITOR_EVENT_METADATA_CHANGED,
623 gnomevfs.MONITOR_EVENT_CHANGED):
624 self.emit("changed", info_uri)
625 elif event == gnomevfs.MONITOR_EVENT_CREATED:
626 self.emit("created", info_uri)
627 elif event == gnomevfs.MONITOR_EVENT_DELETED:
628 self.emit("deleted", info_uri)
629 self.emit("event", info_uri, event)
630
631 self._clear_timeout(info_uri)
632 return False
633
634
636 """A simple config/ini-reader class. This is only used for reading the
637 theme.conf files yet, thus it only uses string-values.
638 TODO: add writing-functions and let backend use this, too"""
639
641 self.options = []
642 self.sections = {}
643
645 """Return all options (alternatively only from the given section)."""
646 if section != '':
647 return self.sections[section]
648 else:
649 return self.options
650
652 """Get a variable from the config (optional: only get vars from the
653 specified section)."""
654 if section != '':
655 l = self.sections[section]
656 else:
657 l = self.options
658 for o in l:
659 if o[0] == name:
660 return o[1]
661 return None
662
664 """Returns true if the given section exists."""
665 return self.sections.has_key(name)
666
667 - def load (self, filename):
668 """Load a config/ini-file and save vars in internal list."""
669 f=None
670 try:
671 f = open (filename, "r")
672 except:
673 print _("File %s not found") % str(filename)
674 if f:
675 section_name = ''
676 for line in f.readlines():
677
678 line = line.lstrip().lstrip('\t')
679
680
681 if len(line) < 4 or line[0] in ("#", "\n", ";"):
682 pass
683 else:
684
685 tmp = line.split('=', 1)
686
687 if len(tmp) < 2 and len(line) > 5 and line[0] == '[':
688 section_name = line[:-1][1:-1]
689 self.sections[section_name] = []
690
691 else:
692
693 var = tmp[0].rstrip().rstrip('\t')
694 val = tmp[1][:-1].lstrip()
695
696
697 if var != '' and val != '':
698 o = [var, val]
699 self.options.append(o)
700 if section_name != '':
701 try:
702 self.sections[section_name].append(o)
703 except:
704 print _("Section %s not found!") % section_name
705 f.close()
706 return True
707 else:
708 return False
709
710
711
713 """A simple and conveniet wrapper for the notification-service. Allows
714 screenlets to easily pop up notes with their own icon (if any)."""
715
717 self.bus = dbus.SessionBus()
718 self.notifications = dbus.Interface(\
719 self.bus.get_object('org.freedesktop.Notifications',
720 '/org/freedesktop/Notifications'), 'org.freedesktop.Notifications')
721 self.screenlet = screenlet
722
723 - def notify (self, message, title='', icon='', timeout=-1, screenlet=None):
724 """Send a notification to org.freedesktop.Notifications. The message
725 should contain the text you want to display, title may define a title
726 (summary) for the message, icon can be the full path to an icon,
727 timeout can be set to the desired displaying time in milliseconds."""
728 if self.bus and self.notifications:
729 if not screenlet:
730 screenlet = self.screenlet
731 if screenlet:
732 p = find_first_screenlet_path(screenlet.__class__.__name__[:-9])
733 if p:
734 icon = p + '/icon.svg'
735 title = screenlet.__name__
736 self.notifications.Notify('Screenlets', 0, icon, title, message,
737 [], {}, timeout)
738 return True
739 else:
740 print _("Notify: No DBus running or notifications-daemon unavailable.")
741 return False
742
743
744 if __name__ == '__main__':
745
746
747 print get_screenlet_metadata('Clock')
748
749
750 print "Find first occurence of a Screenlet:"
751 print find_first_screenlet_path('Clock')
752 print find_first_screenlet_path('Orloj')
753 print find_first_screenlet_path('Weather')
754 print find_first_screenlet_path('Foo')
755
756
757 print "\nList all installed Screenlets:"
758 avail = list_available_screenlets()
759 avail.sort()
760 print avail
761
762
763 print "\nTest INI-reader:"
764 ini = IniReader()
765 if not ini.load('/usr/share/screenlets/CPUMeter/themes/default/theme.conf'):
766 print "Error while loading ini-file"
767 else:
768
769 if ini.has_section('Theme'):
770
771 print ini.get_option('name', section='Theme')
772 print ini.get_option('info', section='Theme')
773
774 if ini.has_section('Options'):
775 for o in ini.list_options(section='Options'):
776 print o[0]
777
778
779 print "\nNotify-test:"
780 n = Notifier()
781 n.notify('Hi there! This is sent through screenlets.utils.Notifier.notify',
782 title='Test')
783 n.notify('A second note ..', title='Another note', timeout=2000)
784 n.notify('A second note ..', title='Another note', icon='/usr/share/screenlets/Notes/icon.svg')
785
786
787 print "\nRunning screenlets: "
788 print list_running_screenlets2()
789 print "\n"
790 print get_screenlet_process('Clock')
791 print get_screenlet_process('Ruler')
792 print get_screenlet_process('Webtest')
793