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 from distutils.version import LooseVersion
27 try:
28 import gnomevfs
29 except:
30 pass
32 return gettext.gettext(s)
33
34
35
36
37
38
40 """Returns the system autostart directory"""
41 desktop_environment = 'gnome'
42
43 if os.environ.get('KDE_FULL_SESSION') == 'true':
44 desktop_environment = 'kde'
45 elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
46 desktop_environment = 'gnome'
47 else:
48 try:
49 import commands
50 info = commands.getoutput('xprop -root _DT_SAVE_MODE')
51 if ' = "xfce4"' in info:
52 desktop_environment = 'xfce'
53 except (OSError, RuntimeError):
54 pass
55
56
57
58 if desktop_environment == 'kde':
59 return os.environ['HOME'] + '/.kde/Autostart/'
60 elif desktop_environment == 'gnome':
61 return os.environ['HOME'] + '/.config/autostart/'
62 elif desktop_environment == 'xfce':
63 return os.environ['HOME'] + '/.config/autostart/'
64
65 if os.geteuid()==0:
66
67 USER = 0
68 DIR_USER = screenlets.INSTALL_PREFIX + '/share/screenlets'
69 DIR_AUTOSTART = '/etc/xdg/autostart'
70 else:
71
72 USER = 1
73 DIR_USER = os.environ['HOME'] + '/.screenlets'
74 DIR_AUTOSTART = get_autostart_dir()
75
76
77
79 """checks if the one starting the screenlet is the screenlets manager"""
80 if str(sys.argv[0]).find('screenlets-manager') != -1:
81 return True
82 else:
83 return False
84
86 """Check whether 'str' contains ALL of the chars in 'set'"""
87 for c in set:
88 if c not in str: return 0;
89 return 1;
91 """Check whether 'str' contains ANY of the chars in 'set'"""
92 return 1 in [c in str for c in set]
93
95 """Create a .desktop-file for the screenlet with the given name in
96 $HOME/.config/autostart."""
97 if not os.path.isdir(DIR_AUTOSTART):
98
99 if screenlets.show_question(None,
100 _("There is no existing autostart directory for your user account yet. Do you want me to automatically create it for you?"),
101 _('Error')):
102 print "Auto-create autostart dir ..."
103 os.system('mkdir %s' % DIR_AUTOSTART)
104 if not os.path.isdir(DIR_AUTOSTART):
105 screenlets.show_error(None, _("Automatic creation failed. Please manually create the directory:\n%s") % DIR_AUTOSTART, _('Error'))
106 return False
107 else:
108 screenlets.show_message(None, _("Please manually create the directory:\n%s") % DIR_AUTOSTART)
109 return False
110 if name.endswith('Screenlet'):
111 name = name[:-9]
112 starter = '%s%sScreenlet.desktop' % (DIR_AUTOSTART, name)
113
114 for f in os.listdir(DIR_AUTOSTART):
115 a = f.find(name + 'Screenlet')
116 if a != -1:
117 print str(f) + ' duplicate entry'
118 os.system('rm %s%s' % (chr(34)+DIR_AUTOSTART,f+chr(34)))
119 print 'Removed duplicate entry'
120 if not os.path.isfile(starter) and not os.path.exists(os.environ['HOME'] + '/.config/autostart/CalendarScreenlet'):
121 path = find_first_screenlet_path(name)
122 if path:
123 print "Create autostarter for: %s/%sScreenlet.py" % (path, name)
124 code = ['[Desktop Entry]']
125 code.append('Name=%sScreenlet' % name)
126 code.append('Encoding=UTF-8')
127 code.append('Version=1.0')
128 code.append('Type=Application')
129 code.append('Exec= python -u %s/%sScreenlet.py' % (path, name))
130 code.append('X-GNOME-Autostart-enabled=true')
131
132 f = open(starter, 'w')
133 if f:
134 for l in code:
135 f.write(l + '\n')
136 f.close()
137 return True
138 print 'Failed to create autostarter for %s.' % name
139 return False
140 else:
141 print "Starter already exists."
142 return True
143
145 """Delete the autostart for the given screenlet."""
146 if name.endswith('Screenlet'):
147 name = name[:-9]
148 print 'Delete autostarter for %s.' % name
149 os.system('rm %s%sScreenlet.desktop' % (DIR_AUTOSTART, name))
150 for f in os.listdir(DIR_AUTOSTART):
151 a = f.find(name + 'Screenlet')
152 if a != -1:
153 print str(f) + ' duplicate entry'
154 os.system('rm %s%s' % (chr(34)+DIR_AUTOSTART,f+chr(34)))
155 print 'Removed duplicate entry'
156
158 """Returns screenlet name on form 'foobar-screenlet' by main screenlet class file path."""
159 return path.lower().replace(".py", "").split("/")[path.count("/")].replace("screenlet", "-screenlet")
160
162 """Returns screenlet name on form 'foobar-screenlet' by screenlet class name."""
163 return name.lower().replace("screenlet", "-screenlet")
164
166 """Returns screenlet name on form 'foobar-screenlet' by shortened screenlet class name."""
167 return name.lower() + "-screenlet"
168
170 """Internal function: Returns true if the given string contains one of the
171 Screenlets paths."""
172
173 for path in screenlets.SCREENLETS_PATH:
174 if string.find(path) > -1:
175 return True
176 return False
177
179 """Create the userdir for the screenlets."""
180 if not os.path.isdir(os.environ['HOME'] + '/.screenlets'):
181 try:
182 os.mkdir(os.environ['HOME'] + '/.screenlets')
183 except:
184 print 'coulnt create user dir'
185
186
188 """Scan the Screenlets paths for the occurence of screenlet "name" with the
189 highest version and return the full path to it. This function is used to get
190 the theme/data directories for a Screenlet and run the Screenlet."""
191 available_versions_paths = []
192
193 for dir in screenlets.SCREENLETS_PATH:
194 try:
195 for name in os.listdir(dir):
196 name_py = name + 'Screenlet.py'
197 path = dir + '/' + name
198 if not stat.S_ISDIR(os.stat(path).st_mode):
199 continue
200
201 if os.access(path + '/' + name_py, os.F_OK):
202 if name == screenlet_name:
203 available_versions_paths.append(path)
204 else:
205
206
207 pass
208 except OSError:
209 pass
210 if len(available_versions_paths) == 1:
211 return available_versions_paths[0]
212 elif len(available_versions_paths) > 1:
213 path_and_version = []
214 for version_path in available_versions_paths:
215 path_and_version.append({'version': get_screenlet_metadata_by_path(version_path)['version'], 'path': version_path})
216
217 sorted_versions = sorted(path_and_version, key=lambda x: LooseVersion(x["version"]), reverse=True)
218 return sorted_versions[0]['path']
219
220
221 return None
222
224 img = gtk.gdk.pixbuf_new_from_file_at_size(\
225 screenlets.INSTALL_PREFIX + '/share/screenlets-manager/noimage.svg',width,height)
226
227 for path in screenlets.SCREENLETS_PATH:
228 for ext in ['svg', 'png']:
229 img_path = "%s/%s/icon.%s" % (path, screenlet_name, ext)
230 if os.path.isfile(img_path):
231 try:
232 img = gtk.gdk.pixbuf_new_from_file_at_size(img_path,width,height)
233 except Exception, ex:
234 pass
235 return img
236
238 x = len(first)
239 begin = data.find(first) +x
240 end = data.find(last, begin)
241 return data[begin:end]
242
300
309
322
324 """Scan the Screenlets paths for all existing screenlets and return their
325 names (without trailing "Screenlet") as a list of strings."""
326 sls = []
327
328 refresh_available_screenlet_paths()
329
330 for dir in screenlets.SCREENLETS_PATH:
331 try:
332 for name in os.listdir(dir):
333 path = dir + '/' + name
334
335 if not stat.S_ISDIR(os.stat(path).st_mode):
336 continue
337
338 if os.access(path + '/' + name + 'Screenlet.py', os.F_OK):
339 if not sls.count(name):
340 sls.append(name)
341 else:
342 pass
343 except OSError:
344 pass
345 return sls
346
347 import session
349 """Returns a list with names of running screenlets or None if no
350 Screenlet is currently running. Function returns False if an error
351 happened!"""
352 running = []
353 tempfile = screenlets.TMP_DIR + '/' + screenlets.TMP_FILE
354 if not os.path.isfile(tempfile):
355 return None
356 f = open(tempfile, 'r')
357 if f:
358 running = f.readlines()
359 f.close()
360 for i in xrange(len(running)):
361 running[i] = running[i][:-1]
362
363 p = os.popen("ps aux | awk '/Screenlet.py/{ print $11, $12, $13, $14, $15, $16 }'")
364 lst = []
365 regex = re.compile('/([A-Za-z0-9]+)Screenlet.py ')
366 for line in p.readlines():
367 if not line.endswith('awk /Screenlet.py/{\n') and line != 'sh -c\n' \
368 and _contains_path(line):
369 slname = regex.findall(line)
370 if slname and type(slname) == list and len(slname) > 0:
371 lst.append(slname[0]+'Screenlet')
372 p.close()
373 for a in lst:
374 if a not in running:
375 running.append(a)
376 return running
377
378
379
381 """Returns a list with names of running screenlets. The list can be empty if
382 no Screenlet is currently running."""
383 p = os.popen("ps aux | awk '/Screenlet.py/{ print $11, $12, $13, $14, $15, $16 }'")
384 lst = []
385 regex = re.compile('/([A-Za-z0-9]+)Screenlet.py ')
386 for line in p.readlines():
387 if not line.endswith('awk /Screenlet.py/{\n') and line != 'sh -c\n' \
388 and _contains_path(line):
389 slname = regex.findall(line)
390 if slname and type(slname) == list and len(slname) > 0:
391 lst.append(slname[0]+'Screenlet')
392 p.close()
393 return lst
394
395
396
397
399 """Returns the PID of the given screenlet (if running) or None."""
400 p = os.popen("ps aux | awk '/[" + name[0] + "]" + name[1:] + \
401 "Screenlet.py/{ print $2, $11, $12, $13, $14, $15, $16 }'")
402 line = p.readlines()
403 p.close()
404
405 if len(line) and _contains_path(line[0]):
406 return int(line[0].split(' ')[0])
407 return None
408
410 """http://www.freedesktop.org/wiki/Software/xdg-user-dirs"""
411
412 user_dirs_dirs = os.path.expanduser("~/.config/user-dirs.dirs")
413 if os.path.exists(user_dirs_dirs):
414 f = open(user_dirs_dirs, "r")
415 for line in f.readlines():
416 if line.startswith(key):
417 return os.path.expandvars(line[len(key)+2:-2])
418 return default
419
421 """Check if the daemon is already running and return its interface."""
422 bus = dbus.SessionBus()
423 if bus:
424 try:
425 proxy_obj = bus.get_object(screenlets.DAEMON_BUS, screenlets.DAEMON_PATH)
426 if proxy_obj:
427 return dbus.Interface(proxy_obj, screenlets.DAEMON_IFACE)
428
429 except Exception, ex:
430 print "Error in ScreenletsManager.connect_daemon: %s" % ex
431 return None
432
434 """Returns desktop dir"""
435 desktop_dir = get_user_dir("XDG_DESKTOP_DIR", os.path.expanduser("~/Desktop"))
436 desktop_dir = urllib.unquote(desktop_dir)
437 return desktop_dir
438
440 """Returns filenames of window droped files"""
441 filename = ''
442 filenames = []
443
444 try:
445 txt = unicode.encode(sel_data.get_text(), 'utf-8')
446 except:
447 txt = sel_data.get_text()
448 txta = urllib.unquote(txt)
449 txta = str(txta).split('\n')
450
451 for txt in txta:
452 if txt and txt != '':
453
454 if txt.startswith('file://'):
455 filename = txt[7:]
456 else:
457 print 'Invalid string: %s.' % txt
458 else:
459
460 uris = sel_data.get_uris()
461 if uris and len(uris)>0:
462
463 filename = uris[0][7:]
464 if filename != '':
465 filenames.append(chr(34) +filename + chr(34))
466
467 return filenames
468
470 """Returns mount points in media"""
471 mountlist = os.popen('mount -l').read()
472 prog = re.compile("^/dev/.*?\son\s/media/(.*?) .*?(\[(.*?)\])?$", re.MULTILINE)
473 return prog.findall(mountlist)
474
476 """Returns gtk bookmarks """
477 _bookmarks_path = os.path.expanduser("~/.gtk-bookmarks")
478 _places = []
479 try:
480 for line in file(_bookmarks_path):
481 line = line.strip()
482
483 if " " in line:
484 uri, name = line.split(" ", 1)
485
486 else:
487 uri = line
488
489 path = urllib.splittype(uri)[1]
490 name = urllib.unquote(os.path.split(path)[1])
491
492 try:
493 if os.path.exists(uri):
494 continue
495
496 except TypeError:
497 continue
498
499 _places.append((uri, name))
500 return _places
501 except IOError, err:
502 print "Error loading GTK bookmarks:", err
503
510
522
529
531 """Reads fstab file"""
532 fstab = []
533 f = open(filename, 'r')
534 for line in f:
535 if (not line.isspace() and not line.startswith('#') and not line.lower().startswith('none')) :
536 fstabline = line.split()
537 if fstabline[1] != 'none' and fstabline[1] != '/proc': fstab.append(fstabline[1])
538
539 fstab.sort()
540 return fstab
541
543 """Reads a file"""
544 f = open(filename, 'r')
545 t = f.read()
546 f.close()
547 return t
548
549
551 """Strips HTML tags of a string"""
552 return re.sub(r"<.*?>|</.*?>","",string)
553
554
555
557 """Adds Screenlets-daemon to autostart if not already"""
558 if not os.path.isdir(DIR_AUTOSTART):
559
560 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')):
561 print "Auto-create autostart dir ..."
562 os.system('mkdir %s' % DIR_AUTOSTART)
563 if not os.path.isdir(DIR_AUTOSTART):
564 screenlets.show_error(None, _("Automatic creation failed. Please manually create the directory:\n%s") % DIR_AUTOSTART, _('Error'))
565 return False
566 else:
567 screenlets.show_message(None, _("Please manually create the directory:\n%s") % DIR_AUTOSTART)
568 return False
569 starter = '%sScreenlets Daemon.desktop' % (DIR_AUTOSTART)
570
571 if not os.path.isfile(starter) and os.path.isfile('%sscreenlets-daemon.desktop' % (DIR_AUTOSTART)) == False:
572 print "Create autostarter for: Screenlets Daemon"
573 code = ['[Desktop Entry]']
574 code.append('Encoding=UTF-8')
575 code.append('Version=1.0')
576 code.append('Name=Screenlets Daemon')
577 code.append('Type=Application')
578 code.append('Exec=%s/share/screenlets-manager/screenlets-daemon.py' % (screenlets.INSTALL_PREFIX))
579 code.append('X-GNOME-Autostart-enabled=true')
580 f = open(starter, 'w')
581 if f:
582 for l in code:
583 f.write(l + '\n')
584 f.close()
585 return True
586 print 'Failed to create autostarter for %s.' % name
587 return False
588 else:
589 print "Starter already exists."
590 return True
591
597
598
599
601 """Opens anything"""
602 os.system('xdg-open ' + name + ' &')
603
604
605
606
607
609 """A container with info about a screenlet."""
610
611 - def __init__ (self, name, lname, info, author, version, icon):
612 self.name = name
613 self.lname = lname
614 self.info = info.replace("\n", '').replace('\t', ' ')
615 self.author = author
616 self.version = version
617 self.icon = icon
618 self.active = False
619 self.system = not os.path.isfile('%s/%s/%sScreenlet.py' % (DIR_USER, name, name))
620 self.autostart = os.path.isfile(DIR_AUTOSTART + '/' + name + 'Screenlet.desktop')
621
622
623
625 '''
626 A simple wrapper around Gnome VFS file monitors. Emits created, deleted,
627 and changed events. Incoming events are queued, with the latest event
628 cancelling prior undelivered events.
629 '''
630
631
632 __gsignals__ = {
633 "event" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
634 (gobject.TYPE_STRING, gobject.TYPE_INT)),
635 "created" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)),
636 "deleted" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)),
637 "changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
638 }
639
641 gobject.GObject.__init__(self)
642
643 if os.path.isabs(path):
644 self.path = "file://" + path
645 else:
646 self.path = path
647 try:
648 self.type = gnomevfs.get_file_info(path).type
649 except gnomevfs.Error:
650 self.type = gnomevfs.MONITOR_FILE
651
652 self.monitor = None
653 self.pending_timeouts = {}
654
656 if not self.monitor:
657 if self.type == gnomevfs.FILE_TYPE_DIRECTORY:
658 monitor_type = gnomevfs.MONITOR_DIRECTORY
659 else:
660 monitor_type = gnomevfs.MONITOR_FILE
661 self.monitor = gnomevfs.monitor_add(self.path, monitor_type, self._queue_event)
662
664 try:
665 gobject.source_remove(self.pending_timeouts[info_uri])
666 del self.pending_timeouts[info_uri]
667 except KeyError:
668 pass
669
671 self._clear_timeout(info_uri)
672 self.pending_timeouts[info_uri] = \
673 gobject.timeout_add(250, self._timeout_cb, monitor_uri, info_uri, event)
674
677
679 gnomevfs.monitor_cancel(self.monitor)
680 self.monitor = None
681
683 if event in (gnomevfs.MONITOR_EVENT_METADATA_CHANGED,
684 gnomevfs.MONITOR_EVENT_CHANGED):
685 self.emit("changed", info_uri)
686 elif event == gnomevfs.MONITOR_EVENT_CREATED:
687 self.emit("created", info_uri)
688 elif event == gnomevfs.MONITOR_EVENT_DELETED:
689 self.emit("deleted", info_uri)
690 self.emit("event", info_uri, event)
691
692 self._clear_timeout(info_uri)
693 return False
694
695
697 """A simple config/ini-reader class. This is only used for reading the
698 theme.conf files yet, thus it only uses string-values.
699 TODO: add writing-functions and let backend use this, too"""
700
702 self.options = []
703 self.sections = {}
704
706 """Return all options (alternatively only from the given section)."""
707 if section != '':
708 return self.sections[section]
709 else:
710 return self.options
711
713 """Get a variable from the config (optional: only get vars from the
714 specified section)."""
715 if section != '':
716 l = self.sections[section]
717 else:
718 l = self.options
719 for o in l:
720 if o[0] == name:
721 return o[1]
722 return None
723
725 """Returns true if the given section exists."""
726 return self.sections.has_key(name)
727
728 - def load (self, filename):
729 """Load a config/ini-file and save vars in internal list."""
730 f=None
731 try:
732 f = open (filename, "r")
733 except:
734 print "File %s not found" % str(filename)
735 if f:
736 section_name = ''
737 for line in f.readlines():
738
739 line = line.lstrip().lstrip('\t')
740
741
742 if len(line) < 4 or line[0] in ("#", "\n", ";"):
743 pass
744 else:
745
746 tmp = line.split('=', 1)
747
748 if len(tmp) < 2 and len(line) > 5 and line[0] == '[':
749 section_name = line[:-1][1:-1]
750 self.sections[section_name] = []
751
752 else:
753
754 var = tmp[0].rstrip().rstrip('\t')
755 val = tmp[1][:-1].lstrip()
756
757
758 if var != '' and val != '':
759 o = [var, val]
760 self.options.append(o)
761 if section_name != '':
762 try:
763 self.sections[section_name].append(o)
764 except:
765 print "Section %s not found!" % section_name
766 f.close()
767 return True
768 else:
769 return False
770
771
772
774 """A simple and conveniet wrapper for the notification-service. Allows
775 screenlets to easily pop up notes with their own icon (if any)."""
776
778 self.bus = dbus.SessionBus()
779 self.notifications = dbus.Interface(\
780 self.bus.get_object('org.freedesktop.Notifications',
781 '/org/freedesktop/Notifications'), 'org.freedesktop.Notifications')
782 self.screenlet = screenlet
783
784 - def notify (self, message, title='', icon='', timeout=-1, screenlet=None):
785 """Send a notification to org.freedesktop.Notifications. The message
786 should contain the text you want to display, title may define a title
787 (summary) for the message, icon can be the full path to an icon,
788 timeout can be set to the desired displaying time in milliseconds."""
789 if self.bus and self.notifications:
790 if not screenlet:
791 screenlet = self.screenlet
792 if screenlet:
793 p = find_first_screenlet_path(screenlet.__class__.__name__[:-9])
794 if p:
795 icon = p + '/icon.svg'
796 title = screenlet.__name__
797 self.notifications.Notify('Screenlets', 0, icon, title, message,
798 [], {}, timeout)
799 return True
800 else:
801 print "Notify: No DBus running or notifications-daemon unavailable."
802 return False
803
804
805 if __name__ == '__main__':
806
807
808 print get_screenlet_metadata('Clock')
809
810
811 print "Find first occurence of a Screenlet:"
812 print find_first_screenlet_path('Clock')
813 print find_first_screenlet_path('Orloj')
814 print find_first_screenlet_path('Weather')
815 print find_first_screenlet_path('Foo')
816
817
818 print "\nList all installed Screenlets:"
819 avail = list_available_screenlets()
820 avail.sort()
821 print avail
822
823
824 print "\nTest INI-reader:"
825 ini = IniReader()
826 if not ini.load('/usr/share/screenlets/CPUMeter/themes/default/theme.conf'):
827 print "Error while loading ini-file"
828 else:
829
830 if ini.has_section('Theme'):
831
832 print ini.get_option('name', section='Theme')
833 print ini.get_option('info', section='Theme')
834
835 if ini.has_section('Options'):
836 for o in ini.list_options(section='Options'):
837 print o[0]
838
839
840 print "\nNotify-test:"
841 n = Notifier()
842 n.notify('Hi there! This is sent through screenlets.utils.Notifier.notify',
843 title='Test')
844 n.notify('A second note ..', title='Another note', timeout=2000)
845 n.notify('A second note ..', title='Another note', icon='/usr/share/screenlets/Notes/icon.svg')
846
847
848 print "\nRunning screenlets: "
849 print list_running_screenlets2()
850 print "\n"
851 print get_screenlet_process('Clock')
852 print get_screenlet_process('Ruler')
853 print get_screenlet_process('Webtest')
854