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
36
37
38
39
40
41
42
43
44
45
46 import os
47 import sys
48 from optparse import OptionParser
49
50 import gtk
51 import gettext
52 from xdg.BaseDirectory import *
53
54
55
56
57 try:
58 INSTALL_PREFIX = open("/etc/screenlets/prefix").read()[:-1]
59 except:
60 INSTALL_PREFIX = '/usr'
61
62
63 gettext.textdomain('screenlets')
64 gettext.bindtextdomain('screenlets', INSTALL_PREFIX + '/share/locale')
65
66
67
68
69
70
71
72
73
74 LOG_DISABLED = False
75 LOG_LEVEL = 4
76 LOG_OUTPUT = "FILE"
77 LOG_NAME = "screenlets"
78 LOG_FILE = "/tmp/%s.log" % os.path.basename(sys.argv[0])
79
80 SESSION_NAME = "default"
81 SESSION_REPLACE = "False"
82 SERVER_NAME = "none"
83
84
85 parser = OptionParser()
86
87 parser.add_option("-l", "--logging-level", dest = "LOG_LEVEL", default = LOG_LEVEL,
88 help = ("set logging level.\n0 - log disabled, 1 - only critical errors, 2 - all errors,\
89 3 - all errors and warnings, 4 - all errors, warnings, and info messages, 5 - all messages \
90 including debug output.\ndefault: %s") %(LOG_LEVEL))
91 parser.add_option("-f", "--logging-file", dest = "LOG_FILE", default = LOG_FILE,
92 help = ("write log to LOG_FILE. Default: %s") %(LOG_FILE))
93 parser.add_option("-s", "--server", dest = "SERVER_NAME", default = SERVER_NAME,
94 help = "server name. default options are Melange and Sidebar")
95 parser.add_option("-o", "--output", dest = "LOG_OUTPUT", default = LOG_OUTPUT,
96 help = ("set output. allowed outputs: FILE, STDOUT and STDERR. Default: %s") %(LOG_OUTPUT))
97 parser.add_option("-q", "--quiet", action="store_true", dest = "LOG_DISABLED",
98 default = LOG_DISABLED, help = "Disable log. The same as log level 0")
99 parser.add_option("-r", "--replace", action="store_true", dest = "SESSION_REPLACE",
100 default = SESSION_REPLACE, help = "Replace old session. Default: %s" %(SESSION_REPLACE))
101 parser.add_option("-e", "--session", action="store_true", dest = "SESSION_NAME",
102 default = SESSION_NAME, help = "Name of session. Default: %s" %(SESSION_NAME))
103
104 COMMAND_LINE_OPTIONS, COMMAND_LINE_ARGS = parser.parse_args()
105
106
107
108
109
110 import pygtk
111 pygtk.require('2.0')
112 import cairo, pango
113 import gobject
114 import glib
115 try:
116 import rsvg
117 except ImportError: print 'No module RSVG , graphics will not be so good'
118 import subprocess
119 import glob
120 import math
121 import time
122
123
124 from options import *
125 import services
126 import utils
127 import sensors
128
129 import menu
130 from menu import DefaultMenuItem, add_menuitem
131 from drawing import Drawing
132
133
134 import logger
135
137 return gettext.gettext(s)
138
139
140
141
142
143
144 APP_NAME = "Screenlets"
145
146
147 VERSION = "0.1.6"
148
149
150 COPYRIGHT = "(c) RYX (Rico Pfaus) <ryx@ryxperience.com>\nWhise (Helder Fraga) <helder.fraga@hotmail.com>\nNatan Yellin (Aantn) <aantny@gmail.com>\nGuido Tabbernuk <boamaod@gmail.com>"
151
152
153 AUTHORS = ["RYX (Rico Pfaus) <ryx@ryxperience.com>", "Whise (Helder Fraga) <helder.fraga@hotmail.com>", "Sorcerer (Hendrik Kaju)", "Natan Yellin (Aantn) <aantny@gmail.com>", "Guido Tabbernuk <boamaod@gmail.com>" ]
154
155
156 COMMENTS = "Screenlets is a widget framework that consists of small owner-drawn applications (written in Python, a very simple object-oriented programming-language) that can be described as 'the virtual representation of things lying/standing around on your desk'. Sticknotes, clocks, rulers, ... the possibilities are endless. Screenlet also tries to include some compatibility with other widget frameworks,like web widgets and super karamba themes"
157
158 DOCUMENTERS = ["Documentation generated by epydoc"]
159
160 ARTISTS = ["Some themes by RYX\nSome themes by Whise\nMonochrome icons by Tabbernuk"]
161
162 TRANSLATORS = "Special thanks for translators\nFull Translator list on https://translations.launchpad.net/screenlets/"
163
164
165 WEBSITE = 'http://www.screenlets.org'
166
167
168 THIRD_PARTY_DOWNLOAD = _("http://www.screenlets.org/index.php/Get_more_screenlets")
169
170
171
172
173
174 DIR_TMP = '/tmp/screenlets/'
175
176 TMP_DIR = DIR_TMP
177
178 TMP_FILE = 'screenlets.' + os.environ['USER'] + '.running'
179
180 DIR_USER_ROOT = screenlets.INSTALL_PREFIX + '/share/screenlets'
181
182 DIR_USER = os.path.join(os.environ['HOME'], '.screenlets')
183
184 DIR_CONFIG = os.path.join(xdg_config_home,'screenlets')
185 OLD_DIR_CONFIG = os.path.join(xdg_config_home,'Screenlets')
186
187 try:
188 if not os.path.exists(DIR_CONFIG) and os.path.exists(OLD_DIR_CONFIG):
189 os.rename(OLD_DIR_CONFIG, DIR_CONFIG)
190 except:
191 pass
192
193 try:
194 if not os.path.isdir(DIR_CONFIG):
195 os.system('mkdir %s' % DIR_CONFIG)
196 except:
197 pass
198 try:
199 if not os.path.isdir(DIR_USER):
200 os.system('mkdir %s' % DIR_USER)
201 except:
202 pass
203
204 CONFIG_FILE = os.path.join(DIR_CONFIG, "config.ini")
205 OLD_CONFIG_FILE = os.path.join(DIR_USER, "config.ini")
206
207 try:
208 if not os.path.exists(CONFIG_FILE) and os.path.exists(OLD_CONFIG_FILE):
209 os.rename(OLD_CONFIG_FILE, CONFIG_FILE)
210 except:
211 pass
212
213
214
215 SCREENLETS_PATH = [DIR_USER, DIR_USER_ROOT]
216
217 SCREENLETS_PACK_PREFIX = "screenlets-pack-"
218
219
220
221
222
223 DAEMON_BUS = 'org.screenlets.ScreenletsDaemon'
224
225 DAEMON_PATH = '/org/screenlets/ScreenletsDaemon'
226
227 DAEMON_IFACE = 'org.screenlets.ScreenletsDaemon'
228
229
230
231 DEBUG_MODE = True
232
233 DEBIAN = True
234 try:
235 subprocess.call(["dpkg"], stdout=open(os.devnull, 'w'), stderr=subprocess.STDOUT)
236 except OSError:
237 DEBIAN = False
238
239 UBUNTU = True
240 try:
241 subprocess.call(["apt-add-repository"], stdout=open(os.devnull, 'w'), stderr=subprocess.STDOUT)
242 except OSError:
243 UBUNTU = False
244
245
246
247
248
269
270
272 """ScreenletThemes are simple storages that allow loading files
273 as svg-handles within a theme-directory. Each Screenlet can have
274 its own theme-directory. It is up to the Screenlet-developer if he
275 wants to let his Screenlet support themes or not. Themes are
276 turned off by default - if your Screenlet uses Themes, just set the
277 attribute 'theme_name' to the name of the theme's dir you want to use.
278 TODO: remove dict-inheritance"""
279
280
281 __name__ = ''
282 __author__ = ''
283 __version__ = ''
284 __info__ = ''
285
286
287 path = ""
288 loaded = False
289 width = 0
290 height = 0
291 option_overrides = {}
292 p_fdesc = None
293 p_layout = None
294 tooltip = None
295 notify = None
296
297
307
309 if name in ("width", "height"):
310 if self.loaded and len(self)>0:
311 size=self[0].get_dimension_data()
312 if name=="width":
313 return size[0]
314 else:
315 return size[1]
316 else:
317 return object.__getattr__(self, name)
318
346
347 - def check_entry (self, filename):
348 """Checks if a file with filename is loaded in this theme."""
349 try:
350 if self[filename]:
351 return True
352 except:
353
354 return False
355
356 - def get_text_width(self, ctx, text, font):
357 """@DEPRECATED Moved to Screenlets class: Returns the pixel width of a given text"""
358 ctx.save()
359
360 if self.p_layout == None :
361
362 self.p_layout = ctx.create_layout()
363 else:
364
365 ctx.update_layout(self.p_layout)
366 self.p_fdesc = pango.FontDescription(font)
367 self.p_layout.set_font_description(self.p_fdesc)
368 self.p_layout.set_text(text)
369 extents, lextents = self.p_layout.get_pixel_extents()
370 ctx.restore()
371 return extents[2]
372
373 - def get_text_extents(self, ctx, text, font):
374 """@DEPRECATED Moved to Screenlets class: Returns the pixel extents of a given text"""
375 ctx.save()
376
377 if self.p_layout == None :
378
379 self.p_layout = ctx.create_layout()
380 else:
381
382 ctx.update_layout(self.p_layout)
383 self.p_fdesc = pango.FontDescription(font)
384 self.p_layout.set_font_description(self.p_fdesc)
385 self.p_layout.set_text(text)
386 extents, lextents = self.p_layout.get_pixel_extents()
387 ctx.restore()
388 return extents
389
390 - def draw_text(self, ctx, text, x, y, font, size, width, allignment, weight = 0, ellipsize = pango.ELLIPSIZE_NONE):
391 """@DEPRECATED Moved to Screenlets class: Draws text"""
392 ctx.save()
393 ctx.translate(x, y)
394 if self.p_layout == None :
395
396 self.p_layout = ctx.create_layout()
397 else:
398
399 ctx.update_layout(self.p_layout)
400 self.p_fdesc = pango.FontDescription()
401 self.p_fdesc.set_family_static(font)
402 self.p_fdesc.set_size(size * pango.SCALE)
403 self.p_fdesc.set_weight(weight)
404 self.p_layout.set_font_description(self.p_fdesc)
405 self.p_layout.set_width(width * pango.SCALE)
406 self.p_layout.set_alignment(allignment)
407 self.p_layout.set_ellipsize(ellipsize)
408 self.p_layout.set_markup(text)
409 ctx.show_layout(self.p_layout)
410 ctx.restore()
411
412
414 """@DEPRECATED Moved to Screenlets class: Draws a circule"""
415 ctx.save()
416 ctx.translate(x, y)
417 ctx.arc(width/2,height/2,min(height,width)/2,0,2*math.pi)
418 if fill: ctx.fill()
419 else: ctx.stroke()
420 ctx.restore()
421
422 - def draw_line(self,ctx,start_x,start_y,end_x,end_y,line_width = 1,close=False,preserve=False):
423 """@DEPRECATED Moved to Screenlets class: Draws a line"""
424 ctx.save()
425 ctx.move_to(start_x, start_y)
426 ctx.set_line_width(line_width)
427 ctx.rel_line_to(end_x, end_y)
428 if close : ctx.close_path()
429 if preserve: ctx.stroke_preserve()
430 else: ctx.stroke()
431 ctx.restore()
432
434 """@DEPRECATED Moved to Screenlets class: Draws a rectangle"""
435 ctx.save()
436 ctx.translate(x, y)
437 ctx.rectangle (0,0,width,height)
438 if fill:ctx.fill()
439 else: ctx.stroke()
440 ctx.restore()
441
443 """@DEPRECATED Moved to Screenlets class: Draws a rounded rectangle"""
444 ctx.save()
445 ctx.translate(x, y)
446 padding=0
447 rounded=rounded_angle
448 w = width
449 h = height
450
451
452 ctx.move_to(0+padding+rounded, 0+padding)
453
454
455 ctx.line_to(w-padding-rounded, 0+padding)
456 ctx.arc(w-padding-rounded, 0+padding+rounded, rounded, (math.pi/2 )+(math.pi) , 0)
457
458
459 ctx.line_to(w-padding, h-padding-rounded)
460 ctx.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
461
462
463 ctx.line_to(0+padding+rounded, h-padding)
464 ctx.arc(0+padding+rounded, h-padding-rounded, rounded,math.pi/2, math.pi)
465
466
467 ctx.line_to(0+padding, 0+padding+rounded)
468 ctx.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi, (math.pi/2 )+(math.pi))
469
470
471 if fill:ctx.fill()
472 else: ctx.stroke()
473 ctx.restore()
474
476 """@DEPRECATED Moved to Screenlets class: Gets a picture width and height"""
477
478 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
479 iw = pixbuf.get_width()
480 ih = pixbuf.get_height()
481 puxbuf = None
482 return iw,ih
483
485 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path"""
486
487 ctx.save()
488 ctx.translate(x, y)
489 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
490 format = cairo.FORMAT_RGB24
491 if pixbuf.get_has_alpha():
492 format = cairo.FORMAT_ARGB32
493
494 iw = pixbuf.get_width()
495 ih = pixbuf.get_height()
496 image = cairo.ImageSurface(format, iw, ih)
497 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
498
499 ctx.paint()
500 puxbuf = None
501 image = None
502 ctx.restore()
503
504
505
507 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path with a certain width and height"""
508
509 ctx.save()
510 ctx.translate(x, y)
511 pixbuf = gtk.gdk.pixbuf_new_from_file(pix).scale_simple(w,h,gtk.gdk.INTERP_HYPER)
512 format = cairo.FORMAT_RGB24
513 if pixbuf.get_has_alpha():
514 format = cairo.FORMAT_ARGB32
515
516 iw = pixbuf.get_width()
517 ih = pixbuf.get_height()
518 image = cairo.ImageSurface(format, iw, ih)
519
520 matrix = cairo.Matrix(xx=iw/w, yy=ih/h)
521 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
522 if image != None :image.set_matrix(matrix)
523 ctx.paint()
524 puxbuf = None
525 image = None
526 ctx.restore()
527
534
536 """@DEPRECATED Moved to Screenlets class: hide notification window"""
537 if self.notify != None:
538 self.notify.hide()
539 self.notify = None
540
549
555
557 """Check if this theme contains overrides for options."""
558 return len(self.option_overrides) > 0
559
561 """Load a config-file from this theme's dir and save vars in list."""
562 ini = utils.IniReader()
563 if ini.load(filename):
564 if ini.has_section('Theme'):
565 self.__name__ = ini.get_option('name', section='Theme')
566 self.__author__ = ini.get_option('author', section='Theme')
567 self.__version__ = ini.get_option('version', section='Theme')
568 self.__info__ = ini.get_option('info', section='Theme')
569 if ini.has_section('Options'):
570 opts = ini.list_options(section='Options')
571 if opts:
572 for o in opts:
573 self.option_overrides[o[0]] = o[1]
574 print "Loaded theme config from:", filename
575 print "\tName: " + str(self.__name__)
576 print "\tAuthor: " +str(self.__author__)
577 print "\tVersion: " +str(self.__version__)
578 print "\tInfo: " +str(self.__info__)
579 else:
580 print "Failed to theme config from", filename
581
582
584 """Load an SVG-file into this theme and reference it as ref_name."""
585 if self.has_key(filename):
586 del self[filename]
587 try:
588 self[filename] = rsvg.Handle(self.path + "/" + filename)
589 self.svgs[filename[:-4]] = self[filename]
590 if self[filename] != None:
591
592 size=self[filename].get_dimension_data()
593 if size:
594 self.width = size[0]
595 self.height = size[1]
596 return True
597 except NameError, ex:
598 self[filename] = gtk.gdk.pixbuf_new_from_file(self.path + '/' + filename)
599 self.svgs[filename[:-4]] = self[filename]
600 if self[filename] != None:
601
602 self.width = self[filename].get_width()
603 self.height = self[filename].get_height()
604 print str(ex)
605 return True
606
607 else:
608 return False
609
610
612 """Load a PNG-file into this theme and reference it as ref_name."""
613 if self.has_key(filename):
614 del self[filename]
615 self[filename] = cairo.ImageSurface.create_from_png(self.path +
616 "/" + filename)
617 self.pngs[filename[:-4]] = self[filename]
618 if self[filename] != None:
619 return True
620 else:
621 return False
622
623
625 """Load all files in the theme's path. Currently only loads SVGs and
626 PNGs."""
627
628
629
630 dirlst = glob.glob(self.path + '/*')
631 if len(dirlst)==0:
632 return False
633 plen = len(self.path) + 1
634 for file in dirlst:
635 fname = file[plen:]
636 if fname.endswith('.svg'):
637
638 if self.load_svg(fname) == False:
639 return False
640 elif fname.endswith('.png'):
641
642 if self.load_png(fname) == False:
643 return False
644 elif fname == "theme.conf":
645 print "theme.conf found! Loading option-overrides."
646
647 if self.load_conf(file) == False:
648 return False
649
650 return True
651
653 """Re-Load all files in the theme's path."""
654 self.free()
655 self.__load_all()
656
657
659 """Deletes the Theme's contents and frees all rsvg-handles.
660 TODO: freeing rsvg-handles does NOT work for some reason"""
661 self.option_overrides.clear()
662 for filename in self:
663 try:
664 self[filename].free()
665 except AttributeError:pass
666
667 del filename
668 self.clear()
669
670
671
672
673 - def render (self, ctx, name):
674 """Render an image from within this theme to the given context. This
675 function can EITHER use png OR svg images, so it is possible to
676 create themes using both image-formats when a Screenlet uses this
677 function for drawing its images. The image name has to be defined
678 without the extension and the function will automatically select
679 the available one (SVG is prefered over PNG)."""
680
681
682 if os.path.isfile (self.path + '/' + name + '.svg'):
683
684 try:
685 self.svgs[name].render_cairo(ctx)
686 except:
687 try:
688 ctx.set_source_pixbuf(self.svgs[name], 0, 0)
689
690 ctx.paint()
691 pixbuf = None
692 except TypeError:
693 ctx.set_source_surface(self.pngs[name], 0, 0)
694 ctx.paint()
695
696 elif os.path.isfile (self.path + '/' + name + '.png'):
697 ctx.set_source_surface(self.pngs[name], 0, 0)
698 ctx.paint()
699
700
701
703
704 ctx.set_source_rgba(color[0], color[1], color[2], color[3])
705 ctx.set_source_surface(self.pngs[name], 0, 0)
706 ctx.mask_surface(image, 0, 0)
707 ctx.stroke()
708
709
710
711 -class Screenlet (gobject.GObject, EditableOptions, Drawing):
712 """A Screenlet is a (i.e. contains a) shaped gtk-window that is
713 fully invisible by default. Subclasses of Screenlet can render
714 their owner-drawn graphics on fully transparent background."""
715
716
717 __name__ = _('No name set for this Screenlet')
718 __version__ = '0.0'
719 __author__ = _('No author defined for this Screenlet')
720 __desc__ = _('No info set for this Screenlet')
721 __requires__ = []
722
723
724
725
726
727 id = ''
728 window = None
729 theme = None
730 uses_theme = True
731 draw_buttons = True
732 show_buttons = True
733 menu = None
734 is_dragged = False
735 quit_on_close = True
736 saving_enabled = True
737 dragging_over = False
738 disable_updates = False
739 p_context = None
740 p_layout = None
741
742
743 x = None
744 y = None
745 mousex = 0
746 mousey = 0
747 mouse_is_over = False
748 width = 100
749 height = 100
750 scale = 1.0
751 opacity = 1.0
752 theme_name = ""
753 is_visible = True
754 is_sticky = False
755 is_widget = False
756 keep_above = False
757 keep_below = True
758 skip_pager = True
759 first_run = False
760 skip_taskbar = True
761 lock_position = False
762 allow_option_override = True
763 ask_on_option_override = True
764 ignore_requirements = False
765 resize_on_scroll = True
766 has_started = False
767 has_focus = False
768
769 gtk_icon_theme = None
770 __lastx = 0
771 __lasty = 0
772 p_fdesc = None
773 p_layout = None
774 tooltip = None
775 notify = None
776
777
778 __mi_keep_above = None
779 __mi_keep_below = None
780 __mi_widget = None
781 __mi_sticky = None
782 __mi_lock = None
783
784 __gsignals__ = dict(screenlet_removed=(gobject.SIGNAL_RUN_FIRST,
785 gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)))
786
787 - def __init__ (self, id='', width=100, height=100, parent_window=None,
788 show_window=True, is_widget=False, is_sticky=False,
789 uses_theme=True, draw_buttons=True,path=os.getcwd(), drag_drop=False, session=None,
790 enable_saving=True, service_class=services.ScreenletService,
791 uses_pango=False, is_sizable=True,resize_on_scroll=True, ask_on_option_override=False):
792 """Constructor - should only be subclassed"""
793
794
795 super(Screenlet, self).__init__()
796 EditableOptions.__init__(self)
797
798 self.id = id
799 self.session = session
800 self.service = None
801 self.__desc__ = self.__doc__
802
803
804 if self.id and service_class:
805 self.register_service(service_class)
806
807 self.service.instance_added(self.id)
808 self.width = width
809 self.height = height
810 self.is_dragged = False
811 self.__path__ = path
812 self.saving_enabled = enable_saving
813
814 self.__dict__['theme_name'] = ""
815 self.__dict__['is_widget'] = is_widget
816 self.__dict__['is_sticky'] = is_sticky
817 self.__dict__['draw_buttons'] = draw_buttons
818 self.resize_on_scroll = resize_on_scroll
819 self.__dict__['x'] = gtk.gdk.screen_width()/2 - self.width/2
820 self.__dict__['y'] = gtk.gdk.screen_height()/2 - self.height/2
821
822
823
824
825 self.__shape_bitmap = None
826 self.__shape_bitmap_width = 0
827 self.__shape_bitmap_height = 0
828
829 self.add_options_group('Screenlet',
830 _('The basic settings for this Screenlet-instance.'))
831
832
833
834 self.gtk_icon_theme = gtk.icon_theme_get_default()
835 self.load_buttons(None)
836 self.gtk_icon_theme.connect("changed", self.load_buttons)
837 if draw_buttons: self.draw_buttons = True
838 else: self.draw_buttons = False
839 if uses_theme:
840 self.uses_theme = True
841 self.add_option(StringOption('Screenlet', 'theme_name',
842 default='default', hidden=True))
843
844 self.add_option(IntOption('Screenlet', 'x',
845 default=self.x, label=_('X-Position'),
846 desc=_('The X-position of this Screenlet ...'),
847 min=0, max=gtk.gdk.screen_width()))
848 self.add_option(IntOption('Screenlet', 'y',
849 default=self.y, label=_('Y-Position'),
850 desc=_('The Y-position of this Screenlet ...'),
851 min=0, max=gtk.gdk.screen_height()))
852 self.add_option(IntOption('Screenlet', 'width',
853 default=width, label=_('Width'),
854 desc=_('The width of this Screenlet ...'),
855 min=16, max=1000, hidden=True))
856 self.add_option(IntOption('Screenlet', 'height',
857 default=height, label=_('Height'),
858 desc=_('The height of this Screenlet ...'),
859 min=16, max=1000, hidden=True))
860 self.add_option(FloatOption('Screenlet', 'scale',
861 default=self.scale, label=_('Scale'),
862 desc=_('The scale-factor of this Screenlet ...'),
863 min=0.1, max=10.0, digits=2, increment=0.1))
864 self.add_option(FloatOption('Screenlet', 'opacity',
865 default=self.opacity, label=_('Opacity'),
866 desc=_('The opacity of the Screenlet window ...'),
867 min=0.1, max=1.0, digits=2, increment=0.1))
868 self.add_option(BoolOption('Screenlet', 'is_sticky',
869 default=is_sticky, label=_('Stick to Desktop'),
870 desc=_('Show this Screenlet on all workspaces ...')))
871 self.add_option(BoolOption('Screenlet', 'is_widget',
872 default=is_widget, label=_('Treat as Widget'),
873 desc=_('Treat this Screenlet as a "Widget" ...')))
874 self.add_option(BoolOption('Screenlet', 'is_dragged',
875 default=self.is_dragged, label="Is the screenlet dragged",
876 desc="Is the screenlet dragged", hidden=True))
877 self.add_option(BoolOption('Screenlet', 'is_sizable',
878 default=is_sizable, label="Can the screenlet be resized",
879 desc="is_sizable", hidden=True))
880 self.add_option(BoolOption('Screenlet', 'is_visible',
881 default=self.is_visible, label="Usefull to use screenlets as gnome panel applets",
882 desc="is_visible", hidden=True))
883 self.add_option(BoolOption('Screenlet', 'lock_position',
884 default=self.lock_position, label=_('Lock position'),
885 desc=_('Stop the screenlet from being moved...')))
886 self.add_option(BoolOption('Screenlet', 'keep_above',
887 default=self.keep_above, label=_('Keep above'),
888 desc=_('Keep this Screenlet above other windows ...')))
889 self.add_option(BoolOption('Screenlet', 'keep_below',
890 default=self.keep_below, label=_('Keep below'),
891 desc=_('Keep this Screenlet below other windows ...')))
892 self.add_option(BoolOption('Screenlet', 'draw_buttons',
893 default=self.draw_buttons, label=_('Draw button controls'),
894 desc=_('Draw buttons in top right corner')))
895 self.add_option(BoolOption('Screenlet', 'skip_pager',
896 default=self.skip_pager, label=_('Skip Pager'),
897 desc=_('Set this Screenlet to show/hide in pagers ...')))
898 self.add_option(BoolOption('Screenlet', 'skip_taskbar',
899 default=self.skip_pager, label=_('Skip Taskbar'),
900 desc=_('Set this Screenlet to show/hide in taskbars ...')))
901 self.add_option(BoolOption('Screenlet', 'resize_on_scroll',
902 default=self.resize_on_scroll, label=_("Resize on mouse scroll"),
903 desc="resize_on_scroll"))
904 self.add_option(BoolOption('Screenlet', 'ignore_requirements',
905 self.ignore_requirements, _('Ignore requirements'),
906 _('Set this Screenlet to ignore/demand DEB requirements ...')))
907 if uses_theme:
908 self.ask_on_option_override = ask_on_option_override
909 self.add_option(BoolOption('Screenlet', 'allow_option_override',
910 default=self.allow_option_override, label=_('Allow overriding Options'),
911 desc=_('Allow themes to override options in this screenlet ...')))
912 self.add_option(BoolOption('Screenlet', 'ask_on_option_override',
913 default=self.ask_on_option_override, label=_('Ask on Override'),
914 desc=_('Show a confirmation-dialog when a theme wants to override ')+\
915 _('the current options of this Screenlet ...')))
916
917 self.disable_option('width')
918 self.disable_option('height')
919
920 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
921 self.window.set_position(gtk.WIN_POS_CENTER)
922 self.window.set_accept_focus(True)
923 if parent_window:
924 self.window.set_parent_window(parent_window)
925 self.window.set_transient_for(parent_window)
926 self.window.set_destroy_with_parent(True)
927 self.window.resize(width, height)
928 self.window.set_decorated(False)
929
930 self.window.set_role(self.id)
931 try:
932 self.window.set_property('has-resize-grip', False)
933 except TypeError:
934 pass
935 self.window.set_app_paintable(True)
936
937 if uses_pango:
938 self.p_context = self.window.get_pango_context()
939 if self.p_context:
940 self.p_layout = pango.Layout(self.p_context)
941 self.p_layout.set_font_description(\
942 pango.FontDescription("Sans 12"))
943
944
945 if str(sensors.sys_get_window_manager()).lower() == 'kwin':
946 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
947
948 elif str(sensors.sys_get_window_manager()).lower() == 'sawfish':
949 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
950 else:
951
952
953
954
955 if os.environ.get('DESKTOP_SESSION') == "ubuntu":
956 self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
957
958
959
960
961 else:
962 self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
963
964
965 self.window.set_keep_above(self.keep_above)
966 self.window.set_keep_below(self.keep_below)
967 self.window.set_skip_taskbar_hint(True)
968 self.window.set_skip_pager_hint(True)
969 if is_sticky:
970 self.window.stick()
971 self.alpha_screen_changed(self.window)
972 self.update_shape()
973
974 self.window.set_events(gtk.gdk.ALL_EVENTS_MASK)
975 self.window.connect("composited-changed", self.composite_changed)
976 self.window.connect("delete_event", self.delete_event)
977 self.window.connect("destroy", self.destroy)
978 self.window.connect("expose_event", self.expose)
979 self.window.connect("button-press-event", self.button_press)
980 self.window.connect("button-release-event", self.button_release)
981 self.window.connect("configure-event", self.configure_event)
982 self.window.connect("screen-changed", self.alpha_screen_changed)
983 self.window.connect("realize", self.realize_event)
984 self.window.connect("enter-notify-event", self.enter_notify_event)
985 self.window.connect("leave-notify-event", self.leave_notify_event)
986 self.window.connect("focus-in-event", self.focus_in_event)
987 self.window.connect("focus-out-event", self.focus_out_event)
988 self.window.connect("scroll-event", self.scroll_event)
989 self.window.connect("motion-notify-event",self.motion_notify_event)
990 self.window.connect("map-event", self.map_event)
991 self.window.connect("unmap-event", self.unmap_event)
992
993 self.window.connect("key-press-event", self.key_press)
994
995 if drag_drop:
996 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
997 gtk.DEST_DEFAULT_DROP,
998 [("text/plain", 0, 0),
999 ("image", 0, 1),
1000 ("text/uri-list", 0, 2)],
1001 gtk.gdk.ACTION_COPY)
1002 self.window.connect("drag_data_received", self.drag_data_received)
1003 self.window.connect("drag-begin", self.drag_begin)
1004 self.window.connect("drag-end", self.drag_end)
1005 self.window.connect("drag-motion", self.drag_motion)
1006 self.window.connect("drag-leave", self.drag_leave)
1007
1008 self.menu = gtk.Menu()
1009
1010
1011
1012 if show_window:
1013 self.window.show()
1014 if self.__name__.endswith("Screenlet"):
1015 short_name = self.__name__[:-9]
1016 else:
1017 short_name = self.__name__
1018 if not os.path.exists(DIR_CONFIG + '/' + short_name + '/default/'+ self.id + '.ini'):
1019 self.first_run = True
1020 self.window.hide()
1021
1022
1023 if not self.window.is_composited () :
1024 self.disable_option('opacity')
1025
1027
1028 self.on_before_set_atribute(name, value)
1029 gobject.GObject.__setattr__(self, name, value)
1030
1031 if name=="x" or name=="y":
1032 if self.has_started:
1033 self.window.move(self.x, self.y)
1034 elif name == 'opacity':
1035 self.window.set_opacity(value)
1036 elif name == 'scale':
1037 self.window.resize(int(self.width * self.scale),
1038 int(self.height * self.scale))
1039
1040 self.on_scale()
1041 self.redraw_canvas()
1042 self.update_shape()
1043
1044
1045 elif name == "theme_name":
1046
1047
1048
1049 print "Theme set to: '%s'" % value
1050 path = self.find_theme(value)
1051 if path:
1052 self.load_theme(path)
1053
1054 self.redraw_canvas()
1055 self.update_shape()
1056 elif name in ("width", "height"):
1057
1058 if self.window:
1059 self.window.resize(int(self.width*self.scale), int(self.height*self.scale))
1060
1061 self.update_shape()
1062 elif name == "is_widget":
1063 if self.has_started:
1064 self.set_is_widget(value)
1065 elif name == "is_visible":
1066 if self.has_started:
1067 if value == True:
1068 self.reshow()
1069 else:
1070 self.window.hide()
1071 elif name == "is_sticky":
1072 if value == True:
1073 self.window.stick()
1074 else:
1075 self.window.unstick()
1076
1077
1078 elif name == "keep_above":
1079 if self.has_started == True:
1080 self.window.set_keep_above(bool(value))
1081
1082 elif name == "keep_below":
1083 if self.has_started == True:
1084 self.window.set_keep_below(bool(value))
1085
1086 elif name == "skip_pager":
1087 if self.window.window:
1088 self.window.window.set_skip_pager_hint(bool(value))
1089 elif name == "skip_taskbar":
1090 if self.window.window:
1091 self.window.window.set_skip_taskbar_hint(bool(value))
1092
1093
1094 if self.saving_enabled:
1095 o = self.get_option_by_name(name)
1096 if o != None:
1097 self.session.backend.save_option(self.id, o.name,
1098 o.on_export(value))
1099 self.on_after_set_atribute(name, value)
1100
1101
1102
1103
1104
1105
1107 '''Checks if required DEB packages are installed'''
1108
1109 req_feedback = ""
1110 fail = False
1111
1112
1113
1114 commandstr = 'LANG=C apt-cache policy %s 2>/dev/null | sed -n "2 p" | grep -v ":[ \t]*([a-z \t]*)" | sed -r -e "s/(\s*[^\s]+:\s*)(.*)/\\2/"'
1115 for req in self.__requires__:
1116 operator = None
1117
1118 if req.find('(') != -1:
1119
1120 pos = req.find('(')
1121 package = req[:pos].strip()
1122 version_str = req[pos+1:]
1123 version_str = version_str[:version_str.find(')')]
1124 while version_str.find(' ') != -1:
1125 version_str = req.replace(' ', ' ')
1126 res = version_str.split(' ')
1127 version = res[1]
1128 operator = res[0]
1129 else:
1130
1131 package = req
1132
1133 version = _("?")
1134
1135 installed_version = os.popen(commandstr % package).readline().replace('\n', '')
1136
1137 if len(installed_version) < 1:
1138 req_feedback += _("\n%(package)s %(version)s required, NOT INSTALLED!") % {"package":package, "version":version}
1139 fail = True
1140 else:
1141 req_feedback += _("\n%(package)s %(version)s installed, req %(required)s.") % {"package":package, "version":installed_version, "required":version}
1142
1143
1144
1145 if operator is not None:
1146 comp_command = "dpkg --compare-versions \"" + installed_version + "\" \"" + operator + "\" \"" + version + "\""
1147
1148 if subprocess.call(comp_command, shell=True) != 0:
1149 fail = True
1150 if fail:
1151 screenlets.show_message (self,_("Requirements for the Screenlet are not satisfied! Use the package manager of your system to install required packages.\n\nREQUIREMENTS:\n%s") % req_feedback, "Requirements not satisfied")
1152
1154 """Appends the default menu-items to self.menu. You can add on OR'ed
1155 flag with DefaultMenuItems you want to add."""
1156 if not self.has_started: print 'WARNING - add_default_menuitems and add_menuitems should be set in on_init ,menu values will be displayed incorrectly'
1157
1158 menu = self.menu
1159
1160
1161 if len(menu.get_children()) > 0:
1162 self.add_menuitem("", "-")
1163
1164 if flags & DefaultMenuItem.XML:
1165
1166 xfile = self.get_screenlet_dir() + "/menu.xml"
1167 xmlmenu = screenlets.menu.create_menu_from_file(xfile,
1168 self.menuitem_callback)
1169 if xmlmenu:
1170 self.menu = xmlmenu
1171
1172 if flags & DefaultMenuItem.SIZE:
1173 size_item = gtk.MenuItem(_("Size"))
1174 size_item.show()
1175 size_menu = gtk.Menu()
1176 menu.append(size_item)
1177 size_item.set_submenu(size_menu)
1178
1179 for i in (0.2,0.3,0.4, 0.5,0.6, 0.7,0.8,0.9, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 7.5, 10):
1180 s = str(int(i * 100))
1181 item = gtk.MenuItem(s + " %")
1182 item.connect("activate", self.menuitem_callback,
1183 "scale:"+str(i))
1184 item.show()
1185 size_menu.append(item)
1186
1187 if flags & DefaultMenuItem.THEMES:
1188 themes_item = gtk.MenuItem(_("Theme"))
1189 themes_item.show()
1190 themes_menu = gtk.Menu()
1191 menu.append(themes_item)
1192 themes_item.set_submenu(themes_menu)
1193
1194 lst = self.get_available_themes()
1195 for tname in lst:
1196 item = gtk.MenuItem(tname)
1197 item.connect("activate", self.menuitem_callback, "theme:"+tname)
1198 item.show()
1199 themes_menu.append(item)
1200
1201
1202 if flags & DefaultMenuItem.WINDOW_MENU:
1203 winmenu_item = gtk.MenuItem(_("Window"))
1204 winmenu_item.show()
1205 winmenu_menu = gtk.Menu()
1206 menu.append(winmenu_item)
1207 winmenu_item.set_submenu(winmenu_menu)
1208
1209 self.__mi_lock = item = gtk.CheckMenuItem(_("Lock"))
1210 item.set_active(self.lock_position)
1211 item.connect("activate", self.menuitem_callback,
1212 "option:lock")
1213 item.show()
1214 winmenu_menu.append(item)
1215
1216 self.__mi_sticky = item = gtk.CheckMenuItem(_("Sticky"))
1217 item.set_active(self.is_sticky)
1218 item.connect("activate", self.menuitem_callback,
1219 "option:sticky")
1220 item.show()
1221 winmenu_menu.append(item)
1222
1223 self.__mi_widget = item = gtk.CheckMenuItem(_("Widget"))
1224 item.set_active(self.is_widget)
1225 item.connect("activate", self.menuitem_callback,
1226 "option:widget")
1227 item.show()
1228 winmenu_menu.append(item)
1229
1230 self.__mi_keep_above = item = gtk.CheckMenuItem(_("Keep above"))
1231 item.set_active(self.keep_above)
1232 item.connect("activate", self.menuitem_callback,
1233 "option:keep_above")
1234 item.show()
1235 winmenu_menu.append(item)
1236
1237 self.__mi_keep_below = item = gtk.CheckMenuItem(_("Keep below"))
1238 item.set_active(self.keep_below)
1239 item.connect("activate", self.menuitem_callback,
1240 "option:keep_below")
1241 item.show()
1242 winmenu_menu.append(item)
1243
1244
1245 if flags & DefaultMenuItem.PROPERTIES:
1246 add_menuitem(menu, "-", self.menuitem_callback, "")
1247 add_menuitem(menu, _("Properties..."), self.menuitem_callback, "options")
1248
1249 if flags & DefaultMenuItem.INFO:
1250 add_menuitem(menu, _("Info..."), self.menuitem_callback, "info")
1251
1252 if flags & DefaultMenuItem.ADD:
1253 add_menuitem(menu, "-", self.menuitem_callback, "")
1254 add_menuitem(menu, _("Add one more %s") % self.get_short_name(), self.menuitem_callback, "add")
1255
1256 if flags & DefaultMenuItem.DELETE:
1257 add_menuitem(menu, _("Delete this %s") % self.get_short_name(), self.menuitem_callback, "delete")
1258
1259 if flags & DefaultMenuItem.QUIT:
1260 add_menuitem(menu, "-", self.menuitem_callback, "")
1261 add_menuitem(menu, _("Quit this %s") % self.get_short_name(), self.menuitem_callback, "quit_instance")
1262
1263 if flags & DefaultMenuItem.QUIT_ALL:
1264 add_menuitem(menu, _("Quit all %ss") % self.get_short_name(), self.menuitem_callback, "quit")
1265
1267 """Simple way to add menuitems to a right-click menu.
1268 This function wraps screenlets.menu.add_menuitem.
1269 For backwards compatibility, the order of the parameters
1270 to this function is switched."""
1271 if not self.has_started: print 'WARNING - add_default_menuitems and add_menuitems should be set in on_init ,menu values will be displayed incorrectly'
1272 if callback is None:
1273 callback = self.menuitem_callback
1274
1275 return add_menuitem(self.menu, label, callback, id)
1276
1278 """Simple way to add submenuitems to the right-click menu through a list."""
1279 if not self.has_started: print 'WARNING - add_default_menuitems and add_menuitems should be set in on_init ,menu values will be displayed incorrectly'
1280
1281 submenu = gtk.MenuItem(label)
1282 submenu.show()
1283 sub_menu = gtk.Menu()
1284 self.menu.append(submenu)
1285 submenu.set_submenu(sub_menu)
1286
1287
1288 for tname in lst:
1289 item = gtk.MenuItem(tname)
1290 item.connect("activate", self.menuitem_callback,
1291 tname)
1292 item.show()
1293 sub_menu.append(item)
1294
1295 return submenu
1296
1297
1298
1302
1323
1324 - def clear_cairo_context (self, ctx):
1325 """Fills the given cairo.Context with fully transparent white."""
1326 ctx.save()
1327 ctx.set_source_rgba(1, 1, 1, 0)
1328 ctx.set_operator (cairo.OPERATOR_SOURCE)
1329 ctx.paint()
1330 ctx.restore()
1331
1333 """Close this Screenlet
1334 TODO: send close-notify instead of destroying window?"""
1335
1336 self.window.unmap()
1337 self.window.destroy()
1338
1339
1341 """Create drag-icon and -mask for drag-operation. Returns a 2-tuple
1342 with the icon and the mask. To supply your own icon you can use the
1343 on_create_drag_icon-handler and return the icon/mask as 2-tuple."""
1344 w = self.width
1345 h = self.height
1346 icon, mask = self.on_create_drag_icon()
1347 if icon == None:
1348
1349 icon = gtk.gdk.Pixmap(self.window.window, w, h)
1350 ctx = icon.cairo_create()
1351 self.clear_cairo_context(ctx)
1352 self.on_draw(ctx)
1353 if mask == None:
1354
1355 mask = gtk.gdk.Pixmap(self.window.window, w, h)
1356 ctx = mask.cairo_create()
1357 self.clear_cairo_context(ctx)
1358 self.on_draw_shape(ctx)
1359 return (icon, mask)
1360
1362 """Enable/Disable realtime-saving of options."""
1363 self.saving_enabled = enabled
1364
1374
1376 """Return the short name of this screenlet. This returns the classname
1377 of the screenlet without trailing "Screenlet". Please always use
1378 this function if you want to retrieve the short name of a Screenlet."""
1379 return self.__class__.__name__[:-9]
1380
1382 """Return the name of this screenlet's personal directory."""
1383 p = utils.find_first_screenlet_path(self.get_short_name())
1384 if p:
1385 return p
1386 else:
1387 if self.__path__ != '':
1388 return self.__path__
1389 else:
1390 return os.getcwd()
1391
1393 """Return the name of this screenlet's personal theme-dir.
1394 (Only returns the dir under the screenlet's location"""
1395 return self.get_screenlet_dir() + "/themes/"
1396
1398 """Returns a list with the names of all available themes in this
1399 Screenlet's theme-directories."""
1400 lst = []
1401 utils.refresh_available_screenlet_paths()
1402 for p in SCREENLETS_PATH:
1403 d = p + '/' + self.get_short_name() + '/themes/'
1404 if os.path.isdir(d):
1405
1406 dirlst = glob.glob(d + '*')
1407 dirlst.sort()
1408 tdlen = len(d)
1409 for fname in dirlst:
1410 if os.path.isdir(fname):
1411 dname = fname[tdlen:]
1412 if not dname in lst:
1413 lst.append(dname)
1414 return lst
1415
1429
1431 """Called when screenlet finishes loading"""
1432
1433
1434
1435 if DEBIAN and not self.ignore_requirements:
1436 self.check_requirements()
1437
1438 self.window.present()
1439 self.show()
1440
1441 self.has_started = True
1442 self.is_dragged = False
1443 self.keep_above= self.keep_above
1444 self.keep_below= self.keep_below
1445 self.is_sticky = self.is_sticky
1446 self.skip_taskbar = self.skip_taskbar
1447 self.window.set_skip_taskbar_hint(self.skip_taskbar)
1448 self.window.set_keep_above(self.keep_above)
1449 self.window.set_keep_below(self.keep_below)
1450
1451 self.on_init()
1452 if self.is_widget:
1453 self.set_is_widget(True)
1454 self.has_focus = False
1455 ini = utils.IniReader()
1456 if ini.load (DIR_CONFIG + '/config.ini') and self.first_run:
1457
1458 if ini.get_option('Lock', section='Options') == 'True':
1459 self.lock_position = True
1460 elif ini.get_option('Lock', section='Options') == 'False':
1461 self.lock_position = False
1462 if ini.get_option('Sticky', section='Options') == 'True':
1463 self.is_sticky = True
1464 elif ini.get_option('Sticky', section='Options') == 'False':
1465 self.is_sticky = False
1466 if ini.get_option('Widget', section='Options') == 'True':
1467 self.is_widget = True
1468 elif ini.get_option('Widget', section='Options') == 'False':
1469 self.is_widget = False
1470 if ini.get_option('Keep_above', section='Options') == 'True':
1471 self.keep_above = True
1472 elif ini.get_option('Keep_above', section='Options') == 'False':
1473 self.keep_above = False
1474 if ini.get_option('Keep_below', section='Options') == 'True':
1475 self.keep_below = True
1476 elif ini.get_option('Keep_below', section='Options') == 'False':
1477 self.keep_below = False
1478 if ini.get_option('draw_buttons', section='Options') == 'True':
1479 self.draw_buttons = True
1480 elif ini.get_option('draw_buttons', section='Options') == 'False':
1481 self.draw_buttons = False
1482
1484 """Hides this Screenlet's underlying gtk.Window"""
1485 self.window.hide()
1486 self.on_hide()
1487
1488
1489
1490
1514
1515
1517 """If the Screenlet runs as stand-alone app, starts gtk.main()"""
1518 gtk.main()
1519
1521 """Register or create the given ScreenletService-(sub)class as the new
1522 service for this Screenlet. If self is not the first instance in the
1523 current session, the service from the first instance will be used
1524 instead and no new service is created."""
1525 if self.session:
1526 if len(self.session.instances) == 0:
1527
1528 if service_classobj==services.ScreenletService:
1529 self.service = service_classobj(self, self.get_short_name())
1530 else:
1531
1532 self.service = service_classobj(self)
1533 else:
1534 self.service = self.session.instances[0].service
1535
1536 return True
1537 return False
1538
1558
1560 """Show this Screenlet's underlying gtk.Window"""
1561
1562 while True and os.environ.get('DESKTOP_SESSION') == "ubuntu":
1563 if os.system("pgrep -fl unity-panel-service | grep -v pgrep") == 0:
1564 print "PANEL-SERVICE OK"
1565 break
1566 print "WAITING..."
1567 time.sleep(1)
1568 self.window.move(self.x, self.y)
1569 self.window.show()
1570 self.on_show()
1571
1573 """Show the EditableSettingsDialog for this Screenlet."""
1574 se = OptionsDialog(490, 450)
1575 img = gtk.Image()
1576 try:
1577 d = self.get_screenlet_dir()
1578 if os.path.isfile(d + '/icon.svg'):
1579 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.svg')
1580 elif os.path.isfile(d + '/icon.png'):
1581 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.png')
1582 img.set_from_pixbuf(icn)
1583 except:
1584 img.set_from_stock(gtk.STOCK_PROPERTIES, 5)
1585 se.set_title(self.__name__)
1586 se.set_info(self.__name__, glib.markup_escape_text(self.__desc__), '(c) ' + glib.markup_escape_text(self.__author__),
1587 version='v' + self.__version__, icon=img)
1588 se.show_options_for_object(self)
1589 resp = se.run()
1590 if resp == gtk.RESPONSE_REJECT:
1591 se.reset_to_defaults()
1592 else:
1593 self.update_shape()
1594 se.destroy()
1595
1597 """Redraw the entire Screenlet's window area.
1598 TODO: store window alloaction in class and change when size changes."""
1599
1600 if self.disable_updates:
1601 return
1602 if self.window:
1603 x, y, w, h = self.window.get_allocation()
1604 rect = gtk.gdk.Rectangle(x, y, w, h)
1605 if self.window.window:
1606 self.window.window.invalidate_rect(rect, True)
1607 self.window.window.process_updates(True)
1608
1609
1610
1611
1623
1625 """Removed shaped window , in case the nom composited shape has been set"""
1626 if self.window.window:
1627 self.window.window.shape_combine_mask(None,0,0)
1628
1629 w = self.window.allocation.width
1630 h = self.window.allocation.height
1631
1632
1633 if w==0 or h==0: return False
1634
1635 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1636 self.__shape_bitmap = screenlets.create_empty_bitmap(w, h)
1637 self.__shape_bitmap_width = w
1638 self.__shape_bitmap_height = h
1639
1640
1641 ctx = self.__shape_bitmap.cairo_create()
1642 self.clear_cairo_context(ctx)
1643
1644
1645 if self.window.is_composited():
1646
1647 self.on_draw_shape(ctx)
1648
1649 else:
1650 try:
1651 self.on_draw_shape(ctx)
1652 except:
1653 self.on_draw(ctx)
1654
1655
1656
1658 """Update window shape (only call this when shape has changed
1659 because it is very ressource intense if ran too often)."""
1660
1661 if self.disable_updates:
1662 return
1663
1664
1665
1666
1667
1668 w = int(self.width * self.scale)
1669 h = int(self.height * self.scale)
1670
1671 if w==0: w = 100
1672 if h==0: h = 100
1673
1674 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1675 data = ''.zfill(w*h)
1676 self.__shape_bitmap = gtk.gdk.bitmap_create_from_data(None, data,
1677 w, h)
1678 self.__shape_bitmap_width = w
1679 self.__shape_bitmap_height = h
1680
1681 ctx = self.__shape_bitmap.cairo_create()
1682 self.clear_cairo_context(ctx)
1683 if self.has_focus and self.draw_buttons and self.show_buttons:
1684 ctx.save()
1685
1686
1687
1688
1689
1690
1691
1692
1693 ctx.translate((self.width*self.scale)-16,0)
1694 ctx.set_source_pixbuf(self.closeb, 0, 0)
1695 ctx.paint()
1696 ctx.restore()
1697 ctx.save()
1698 ctx.translate((self.width*self.scale)-32,0)
1699 ctx.set_source_pixbuf(self.prop, 0, 0)
1700 ctx.paint()
1701 ctx.restore()
1702
1703
1704 if self.window.is_composited():
1705
1706 self.on_draw_shape(ctx)
1707
1708 self.window.input_shape_combine_mask(self.__shape_bitmap, 0, 0)
1709 else:
1710 try: self.on_draw(ctx)
1711 except: self.on_draw_shape(ctx)
1712
1713 self.window.shape_combine_mask(self.__shape_bitmap,0,0)
1714 self.on_update_shape()
1715
1717 """TEST: This function is intended to shape the window whenever no
1718 composited environment can be found. (NOT WORKING YET!!!!)"""
1719
1720
1721 w = int(self.width * self.scale)
1722 h = int(self.height * self.scale)
1723
1724 if w==0: w = 100
1725 if h==0: h = 100
1726
1727 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1728 data = ''.zfill(w*h)
1729 self.__shape_bitmap = gtk.gdk.pixbuf_new_from_data(data,
1730 gtk.gdk.COLORSPACE_RGB, True, 1, w, h, w)
1731 self.__shape_bitmap_width = w
1732 self.__shape_bitmap_height = h
1733
1734
1735 if self.__shape_bitmap:
1736
1737 (pixmap,mask) = self.__shape_bitmap.render_pixmap_and_mask(255)
1738
1739 self.window.shape_combine_mask(mask)
1740
1744
1745
1746
1747
1748
1750 """Called when the Screenlet gets deleted. Return True to cancel.
1751 TODO: sometimes not properly called"""
1752 return not show_question(self, _("To quit all %s's, use 'Quit' instead. ") % self.__class__.__name__ +\
1753 _('Really delete this %s and its settings?') % self.get_short_name())
1754 """return not show_question(self, 'Deleting this instance of the '+\
1755 self.__name__ + ' will also delete all your personal '+\
1756 'changes you made to it!! If you just want to close the '+\
1757 'application, use "Quit" instead. Are you sure you want to '+\
1758 'delete this instance?')
1759 return False"""
1760
1761
1762
1763
1765 """Called after setting screenlet atributes"""
1766 pass
1767
1769 """Called before setting screenlet atributes"""
1770 pass
1771
1772
1774 """Called when the screenlet's drag-icon is created. You can supply
1775 your own icon and mask by returning them as a 2-tuple."""
1776 return (None, None)
1777
1779 """Called when screenlet was mapped"""
1780 pass
1781
1783 """Called when screenlet was unmapped"""
1784 pass
1785
1787 """Called when composite state has changed"""
1788 pass
1789
1790
1792 """Called when the Screenlet gets dragged."""
1793 pass
1794
1796 """Called when something gets dragged into the Screenlets area."""
1797 pass
1798
1800 """Called when something gets dragged out of the Screenlets area."""
1801 pass
1802
1804 """Callback for drawing the Screenlet's window - override
1805 in subclasses to implement your own drawing."""
1806 pass
1807
1809 """Callback for drawing the Screenlet's shape - override
1810 in subclasses to draw the window's input-shape-mask."""
1811 pass
1812
1813 - def on_drop (self, x, y, sel_data, timestamp):
1814 """Called when a selection is dropped on this Screenlet."""
1815 return False
1816
1818 """Called when the Screenlet's window receives focus."""
1819 pass
1820
1822 """Called when the Screenlet gets hidden."""
1823 pass
1824
1826 """Called when the Screenlet's options have been applied and the
1827 screenlet finished its initialization. If you want to have your
1828 Screenlet do things on startup you should use this handler."""
1829 pass
1830
1831 - def on_key_down (self, keycode, keyvalue, event=None):
1832 """Called when a key is pressed within the screenlet's window."""
1833 pass
1834
1836 """Called when the theme is reloaded (after loading, before redraw)."""
1837 pass
1838
1840 """Called when a menuitem is selected."""
1841 pass
1842
1844 """Called when a buttonpress-event occured in Screenlet's window.
1845 Returning True causes the event to be not further propagated."""
1846 return False
1847
1849 """Called when the mouse enters the Screenlet's window."""
1850 pass
1851
1853 """Called when the mouse leaves the Screenlet's window."""
1854 pass
1855
1857 """Called when the mouse moves in the Screenlet's window."""
1858 pass
1859
1861 """Called when a buttonrelease-event occured in Screenlet's window.
1862 Returning True causes the event to be not further propagated."""
1863 return False
1864
1866 """Callback for handling destroy-event. Perform your cleanup here!"""
1867 return True
1868
1870 """"Callback for handling the realize-event."""
1871
1873 """Called when Screenlet.scale is changed."""
1874 pass
1875
1879
1883
1885 """Called when the Screenlet gets shown after being hidden."""
1886 pass
1887
1891
1893 """Called when the Screenlet's window loses focus."""
1894 pass
1895
1897 """Called when the Screenlet's window is updating shape"""
1898 pass
1899
1900
1901
1902
1904 """set colormap for window"""
1905 if screen==None:
1906 screen = window.get_screen()
1907 map = screen.get_rgba_colormap()
1908 if map:
1909 pass
1910 else:
1911 map = screen.get_rgb_colormap()
1912 window.set_colormap(map)
1913
1952
1961
1988
1989
2007
2009
2010 print "delete_event"
2011 if self.on_delete() == True:
2012 print "Cancel delete_event"
2013 return True
2014 else:
2015 self.close()
2016 return False
2017
2018 - def destroy (self, widget, data=None):
2030
2035
2036
2038 return self.on_drop(x, y, sel_data, timestamp)
2039
2040 - def drag_end (self, widget, drag_context):
2041 print "End drag"
2042 self.is_dragged = False
2043 return False
2044
2045 - def drag_motion (self, widget, drag_context, x, y, timestamp):
2051
2052 - def drag_leave (self, widget, drag_context, timestamp):
2056
2058
2059 self.__dict__['mouse_is_over'] = True
2060 self.on_mouse_enter(event)
2061
2062
2063
2064 - def expose (self, widget, event):
2082
2093
2094
2095
2096
2103
2104
2105
2107 """Handle keypress events, needed for in-place editing."""
2108 self.on_key_down(event.keyval, event.string, event)
2109
2111
2112
2113 self.__dict__['mouse_is_over'] = False
2114 self.on_mouse_leave(event)
2115
2116
2117
2190
2193
2196
2198 self.__dict__['mousex'] = event.x / self.scale
2199 self.__dict__['mousey'] = event.y / self.scale
2200
2201 self.on_mouse_move(event)
2202
2209
2218
2219
2226
2228 """hide notification window"""
2229 if self.notify != None:
2230 self.notify.hide()
2231 self.notify = None
2232
2246
2247
2253
2254
2336
2338 __gtype_name__ = 'WrapLabel'
2339
2341 gtk.Label.__init__(self)
2342
2343 self.__wrap_width = 0
2344 self.layout = self.get_layout()
2345 self.layout.set_wrap(pango.WRAP_WORD_CHAR)
2346
2347 if str != None:
2348 self.set_text(str)
2349
2350 self.set_alignment(0.0, 0.0)
2351
2357
2361
2362 - def set_text(self, str):
2363 gtk.Label.set_text(self, str)
2364 self.__set_wrap_width(self.__wrap_width)
2365
2369
2371 if width == 0:
2372 return
2373 layout = self.get_layout()
2374 layout.set_width(width * pango.SCALE)
2375 if self.__wrap_width != width:
2376 self.__wrap_width = width
2377 self.queue_resize()
2378
2475
2477 """A window that displays a text and serves as Notification (very basic yet)."""
2478
2479
2480 __timeout = None
2481
2482
2483 text = ''
2484 font_name = 'FreeSans 9'
2485 width = 200
2486 height = 100
2487 x = 0
2488 y = 0
2489 gradient = cairo.LinearGradient(0, 100,0, 0)
2490
2512
2520
2527
2532
2537
2544
2547
2549 if screen == None:
2550 screen = window.get_screen()
2551 map = screen.get_rgba_colormap()
2552 if not map:
2553 map = screen.get_rgb_colormap()
2554 window.set_colormap(map)
2555
2556 - def expose (self, widget, event):
2557 ctx = self.window.window.cairo_create()
2558 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL)
2559
2560 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2561 ctx.clip()
2562
2563 ctx.set_source_rgba(1, 1, 1, 0)
2564 ctx.set_operator (cairo.OPERATOR_SOURCE)
2565 ctx.paint()
2566
2567 self.gradient.add_color_stop_rgba(1,0.3, 0.3, 0.3, 0.9)
2568 self.gradient.add_color_stop_rgba(0.3, 0, 0, 0, 0.9)
2569 ctx.set_source(self.gradient)
2570 ctx.rectangle(0, 0, self.width, self.height)
2571 ctx.fill()
2572
2573 ctx.save()
2574 ctx.translate(3, 3)
2575 ctx.set_source_rgba(1, 1, 1, 1)
2576 ctx.show_layout(self.p_layout)
2577 ctx.fill()
2578 ctx.restore()
2579 ctx.rectangle(0, 0, self.width, self.height)
2580 ctx.set_source_rgba(0, 0, 0, 0.7)
2581 ctx.stroke()
2582
2583
2584 """class TestWidget(ShapedWidget):
2585
2586 def __init__(self, width, height):
2587 #ShapedWidget.__init__(self, width, height)
2588 super(TestWidget, self).__init__(width, height)
2589
2590 def draw(self, ctx):
2591 if self.mouse_inside:
2592 ctx.set_source_rgba(1, 0, 0, 0.8)
2593 else:
2594 ctx.set_source_rgba(1, 1, 0, 0.8)
2595 ctx.rectangle(0, 0, 32, 32)
2596 ctx.fill()
2597 """
2598
2599
2600
2601
2602
2603
2604
2606 """Launch a screenlet, either through its service or by launching a new
2607 process of the given screenlet. Name has to be the name of the Screenlet's
2608 class without trailing 'Screenlet'.
2609 NOTE: we could only launch the file here"""
2610
2611 if services.service_is_running(name):
2612
2613 srvc = services.get_service_by_name(name)
2614 if srvc:
2615 try:
2616 srvc.add('')
2617 return True
2618 except Exception, ex:
2619 print "Error while adding instance by service: %s" % ex
2620
2621 path = utils.find_first_screenlet_path(name)
2622 if path:
2623
2624 slfile = path + '/' + name + 'Screenlet.py'
2625
2626 print "Launching Screenlet from: %s" % slfile
2627 if debug:
2628 print "Logging output goes to: "+DIR_CONFIG+"/%sScreenlet.log" % name
2629 out = DIR_CONFIG+'/%sScreenlet.log' % name
2630 else:
2631 out = '/dev/null'
2632 os.system('python -u %s > %s &' % (slfile, out))
2633 return True
2634 else:
2635 print "Screenlet '%s' could not be launched." % name
2636 return False
2637
2639 """Show a message for the given Screenlet (may contain Pango-Markup).
2640 If screenlet is None, this function can be used by other objects as well."""
2641 if screenlet == None:
2642 md = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,
2643 buttons=gtk.BUTTONS_OK)
2644 md.set_title(title)
2645 else:
2646 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_INFO,
2647 buttons=gtk.BUTTONS_OK)
2648 md.set_title(screenlet.__name__)
2649 md.set_markup(message)
2650 md.run()
2651 md.destroy()
2652
2654 """Show a question for the given Screenlet (may contain Pango-Markup)."""
2655 if screenlet == None:
2656 md = gtk.MessageDialog(None, type=gtk.MESSAGE_QUESTION,
2657 buttons=gtk.BUTTONS_YES_NO)
2658 md.set_title(title)
2659 else:
2660 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_QUESTION,
2661 buttons=gtk.BUTTONS_YES_NO)
2662 md.set_title(screenlet.__name__)
2663 md.set_markup(message)
2664 response = md.run()
2665 md.destroy()
2666 if response == gtk.RESPONSE_YES:
2667 return True
2668 return False
2669
2670 -def show_error (screenlet, message, title='Error'):
2671 """Show an error for the given Screenlet (may contain Pango-Markup)."""
2672 if screenlet == None:
2673 md = gtk.MessageDialog(None, type=gtk.MESSAGE_ERROR,
2674 buttons=gtk.BUTTONS_OK)
2675 md.set_title(title)
2676 else:
2677 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_ERROR,
2678 buttons=gtk.BUTTONS_OK)
2679 md.set_title(screenlet.__name__)
2680 md.set_markup(message)
2681 md.run()
2682 md.destroy()
2683
2685 """Raise a fatal error to stdout and stderr and exit with an errorcode."""
2686 import sys
2687 msg = 'FATAL ERROR: %s\n' % message
2688 sys.stdout.write(msg)
2689 sys.stderr.write(msg)
2690 sys.exit(1)
2691
2692
2693
2695 fatal_error("This screenlet seems to be written for an older version of the framework. Please download a newer version of the %s." % name)
2696