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 import os
37 import sys
38 from optparse import OptionParser
39
40 import gtk
41 import gettext
42
43
44
45
46
47 try:
48 INSTALL_PREFIX = open("/etc/screenlets/prefix").read()[:-1]
49 except:
50 INSTALL_PREFIX = '/usr'
51
52
53 gettext.textdomain('screenlets')
54 gettext.bindtextdomain('screenlets', INSTALL_PREFIX + '/share/locale')
55
56
57
58
59
60
61
62
63
64 LOG_DISABLED = False
65 LOG_LEVEL = 4
66 LOG_OUTPUT = "FILE"
67 LOG_NAME = "screenlets"
68 LOG_FILE = "/tmp/%s.log" % os.path.basename(sys.argv[0])
69
70 SESSION_NAME = "default"
71 SESSION_REPLACE = "False"
72 SERVER_NAME = "none"
73
74
75 parser = OptionParser()
76
77 parser.add_option("-l", "--logging-level", dest = "LOG_LEVEL", default = LOG_LEVEL,
78 help = ("set logging level.\n0 - log disabled, 1 - only critical errors, 2 - all errors,\
79 3 - all errors and warnings, 4 - all errors, warnings, and info messages, 5 - all messages \
80 including debug output.\ndefault: %s") %(LOG_LEVEL))
81 parser.add_option("-f", "--logging-file", dest = "LOG_FILE", default = LOG_FILE,
82 help = ("write log to LOG_FILE. Default: %s") %(LOG_FILE))
83 parser.add_option("-s", "--server", dest = "SERVER_NAME", default = SERVER_NAME,
84 help = "server name. default options are Melange and Sidebar")
85 parser.add_option("-o", "--output", dest = "LOG_OUTPUT", default = LOG_OUTPUT,
86 help = ("set output. allowed outputs: FILE, STDOUT and STDERR. Default: %s") %(LOG_OUTPUT))
87 parser.add_option("-q", "--quiet", action="store_true", dest = "LOG_DISABLED",
88 default = LOG_DISABLED, help = "Disable log. The same as log level 0")
89 parser.add_option("-r", "--replace", action="store_true", dest = "SESSION_REPLACE",
90 default = SESSION_REPLACE, help = "Replace old session. Default: %s" %(SESSION_REPLACE))
91 parser.add_option("-e", "--session", action="store_true", dest = "SESSION_NAME",
92 default = SESSION_NAME, help = "Name of session. Default: %s" %(SESSION_NAME))
93
94 COMMAND_LINE_OPTIONS, COMMAND_LINE_ARGS = parser.parse_args()
95
96
97
98
99
100 import pygtk
101 pygtk.require('2.0')
102 import cairo, pango
103 import gobject
104 import glib
105 try:
106 import rsvg
107 except ImportError: print 'No module RSVG , graphics will not be so good'
108 import subprocess
109 import glob
110 import math
111
112
113 from options import *
114 import services
115 import utils
116 import sensors
117
118 import menu
119 from menu import DefaultMenuItem, add_menuitem
120 from drawing import Drawing
121
122
123 import logger
124
126 return gettext.gettext(s)
127
128
129
130
131
132
133 APP_NAME = "Screenlets"
134
135
136 VERSION = "0.1.4"
137
138
139 COPYRIGHT = "(c) RYX (Rico Pfaus) <ryx@ryxperience.com>\nWhise (Helder Fraga) <helder.fraga@hotmail.com>"
140
141
142 AUTHORS = ["RYX (Rico Pfaus) <ryx@ryxperience.com>", "Whise (Helder Fraga)<helder.fraga@hotmail.com>","Sorcerer (Hendrik Kaju)"]
143
144
145 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"
146
147 DOCUMENTERS = ["Documentation generated by epydoc"]
148
149 ARTISTS = ["ODD radio screenlet theme by ODDie\nPasodoble mail theme by jEsuSdA\nSome themes by RYX\nSome themes by Whise\nMore to come..."]
150
151 TRANSLATORS = "Special thanks for translators\nFull Translator list on https://translations.launchpad.net/screenlets/"
152
153
154 WEBSITE = 'http://www.screenlets.org'
155
156
157 THIRD_PARTY_DOWNLOAD = _("http://www.screenlets.org/index.php/Get_more_screenlets")
158
159
160
161
162
163 DIR_TMP = '/tmp/screenlets/'
164
165 TMP_DIR = DIR_TMP
166
167 TMP_FILE = 'screenlets.' + os.environ['USER'] + '.running'
168
169 DIR_USER_ROOT = screenlets.INSTALL_PREFIX + '/share/screenlets'
170
171 DIR_USER = os.environ['HOME'] + '/.screenlets'
172
173 DIR_CONFIG = os.environ['HOME'] + '/.config/Screenlets'
174
175
176
177 SCREENLETS_PATH = [DIR_USER, DIR_USER_ROOT]
178
179 SCREENLETS_PACK_PREFIX = "screenlets-pack-"
180
181
182
183
184
185 DAEMON_BUS = 'org.screenlets.ScreenletsDaemon'
186
187 DAEMON_PATH = '/org/screenlets/ScreenletsDaemon'
188
189 DAEMON_IFACE = 'org.screenlets.ScreenletsDaemon'
190
191
192
193 DEBUG_MODE = True
194
195 DEBIAN = True
196 try:
197 subprocess.call(["dpkg"], stdout=open(os.devnull, 'w'), stderr=subprocess.STDOUT)
198 except OSError:
199 DEBIAN = False
200
201 UBUNTU = True
202 try:
203 subprocess.call(["apt-add-repository"], stdout=open(os.devnull, 'w'), stderr=subprocess.STDOUT)
204 except OSError:
205 UBUNTU = False
206
207
208
209
210
231
232
234 """ScreenletThemes are simple storages that allow loading files
235 as svg-handles within a theme-directory. Each Screenlet can have
236 its own theme-directory. It is up to the Screenlet-developer if he
237 wants to let his Screenlet support themes or not. Themes are
238 turned off by default - if your Screenlet uses Themes, just set the
239 attribute 'theme_name' to the name of the theme's dir you want to use.
240 TODO: remove dict-inheritance"""
241
242
243 __name__ = ''
244 __author__ = ''
245 __version__ = ''
246 __info__ = ''
247
248
249 path = ""
250 loaded = False
251 width = 0
252 height = 0
253 option_overrides = {}
254 p_fdesc = None
255 p_layout = None
256 tooltip = None
257 notify = None
258
259
269
271 if name in ("width", "height"):
272 if self.loaded and len(self)>0:
273 size=self[0].get_dimension_data()
274 if name=="width":
275 return size[0]
276 else:
277 return size[1]
278 else:
279 return object.__getattr__(self, name)
280
308
309 - def check_entry (self, filename):
310 """Checks if a file with filename is loaded in this theme."""
311 try:
312 if self[filename]:
313 return True
314 except:
315
316 return False
317
318 - def get_text_width(self, ctx, text, font):
319 """@DEPRECATED Moved to Screenlets class: Returns the pixel width of a given text"""
320 ctx.save()
321
322 if self.p_layout == None :
323
324 self.p_layout = ctx.create_layout()
325 else:
326
327 ctx.update_layout(self.p_layout)
328 self.p_fdesc = pango.FontDescription(font)
329 self.p_layout.set_font_description(self.p_fdesc)
330 self.p_layout.set_text(text)
331 extents, lextents = self.p_layout.get_pixel_extents()
332 ctx.restore()
333 return extents[2]
334
335 - def get_text_extents(self, ctx, text, font):
336 """@DEPRECATED Moved to Screenlets class: Returns the pixel extents of a given text"""
337 ctx.save()
338
339 if self.p_layout == None :
340
341 self.p_layout = ctx.create_layout()
342 else:
343
344 ctx.update_layout(self.p_layout)
345 self.p_fdesc = pango.FontDescription(font)
346 self.p_layout.set_font_description(self.p_fdesc)
347 self.p_layout.set_text(text)
348 extents, lextents = self.p_layout.get_pixel_extents()
349 ctx.restore()
350 return extents
351
352 - def draw_text(self, ctx, text, x, y, font, size, width, allignment, weight = 0, ellipsize = pango.ELLIPSIZE_NONE):
353 """@DEPRECATED Moved to Screenlets class: Draws text"""
354 ctx.save()
355 ctx.translate(x, y)
356 if self.p_layout == None :
357
358 self.p_layout = ctx.create_layout()
359 else:
360
361 ctx.update_layout(self.p_layout)
362 self.p_fdesc = pango.FontDescription()
363 self.p_fdesc.set_family_static(font)
364 self.p_fdesc.set_size(size * pango.SCALE)
365 self.p_fdesc.set_weight(weight)
366 self.p_layout.set_font_description(self.p_fdesc)
367 self.p_layout.set_width(width * pango.SCALE)
368 self.p_layout.set_alignment(allignment)
369 self.p_layout.set_ellipsize(ellipsize)
370 self.p_layout.set_markup(text)
371 ctx.show_layout(self.p_layout)
372 ctx.restore()
373
374
376 """@DEPRECATED Moved to Screenlets class: Draws a circule"""
377 ctx.save()
378 ctx.translate(x, y)
379 ctx.arc(width/2,height/2,min(height,width)/2,0,2*math.pi)
380 if fill: ctx.fill()
381 else: ctx.stroke()
382 ctx.restore()
383
384 - def draw_line(self,ctx,start_x,start_y,end_x,end_y,line_width = 1,close=False,preserve=False):
385 """@DEPRECATED Moved to Screenlets class: Draws a line"""
386 ctx.save()
387 ctx.move_to(start_x, start_y)
388 ctx.set_line_width(line_width)
389 ctx.rel_line_to(end_x, end_y)
390 if close : ctx.close_path()
391 if preserve: ctx.stroke_preserve()
392 else: ctx.stroke()
393 ctx.restore()
394
396 """@DEPRECATED Moved to Screenlets class: Draws a rectangle"""
397 ctx.save()
398 ctx.translate(x, y)
399 ctx.rectangle (0,0,width,height)
400 if fill:ctx.fill()
401 else: ctx.stroke()
402 ctx.restore()
403
405 """@DEPRECATED Moved to Screenlets class: Draws a rounded rectangle"""
406 ctx.save()
407 ctx.translate(x, y)
408 padding=0
409 rounded=rounded_angle
410 w = width
411 h = height
412
413
414 ctx.move_to(0+padding+rounded, 0+padding)
415
416
417 ctx.line_to(w-padding-rounded, 0+padding)
418 ctx.arc(w-padding-rounded, 0+padding+rounded, rounded, (math.pi/2 )+(math.pi) , 0)
419
420
421 ctx.line_to(w-padding, h-padding-rounded)
422 ctx.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
423
424
425 ctx.line_to(0+padding+rounded, h-padding)
426 ctx.arc(0+padding+rounded, h-padding-rounded, rounded,math.pi/2, math.pi)
427
428
429 ctx.line_to(0+padding, 0+padding+rounded)
430 ctx.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi, (math.pi/2 )+(math.pi))
431
432
433 if fill:ctx.fill()
434 else: ctx.stroke()
435 ctx.restore()
436
438 """@DEPRECATED Moved to Screenlets class: Gets a picture width and height"""
439
440 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
441 iw = pixbuf.get_width()
442 ih = pixbuf.get_height()
443 puxbuf = None
444 return iw,ih
445
447 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path"""
448
449 ctx.save()
450 ctx.translate(x, y)
451 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
452 format = cairo.FORMAT_RGB24
453 if pixbuf.get_has_alpha():
454 format = cairo.FORMAT_ARGB32
455
456 iw = pixbuf.get_width()
457 ih = pixbuf.get_height()
458 image = cairo.ImageSurface(format, iw, ih)
459 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
460
461 ctx.paint()
462 puxbuf = None
463 image = None
464 ctx.restore()
465
466
467
469 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path with a certain width and height"""
470
471 ctx.save()
472 ctx.translate(x, y)
473 pixbuf = gtk.gdk.pixbuf_new_from_file(pix).scale_simple(w,h,gtk.gdk.INTERP_HYPER)
474 format = cairo.FORMAT_RGB24
475 if pixbuf.get_has_alpha():
476 format = cairo.FORMAT_ARGB32
477
478 iw = pixbuf.get_width()
479 ih = pixbuf.get_height()
480 image = cairo.ImageSurface(format, iw, ih)
481
482 matrix = cairo.Matrix(xx=iw/w, yy=ih/h)
483 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
484 if image != None :image.set_matrix(matrix)
485 ctx.paint()
486 puxbuf = None
487 image = None
488 ctx.restore()
489
496
498 """@DEPRECATED Moved to Screenlets class: hide notification window"""
499 if self.notify != None:
500 self.notify.hide()
501 self.notify = None
502
511
517
519 """Check if this theme contains overrides for options."""
520 return len(self.option_overrides) > 0
521
523 """Load a config-file from this theme's dir and save vars in list."""
524 ini = utils.IniReader()
525 if ini.load(filename):
526 if ini.has_section('Theme'):
527 self.__name__ = ini.get_option('name', section='Theme')
528 self.__author__ = ini.get_option('author', section='Theme')
529 self.__version__ = ini.get_option('version', section='Theme')
530 self.__info__ = ini.get_option('info', section='Theme')
531 if ini.has_section('Options'):
532 opts = ini.list_options(section='Options')
533 if opts:
534 for o in opts:
535 self.option_overrides[o[0]] = o[1]
536 print "Loaded theme config from:", filename
537 print "\tName: " + str(self.__name__)
538 print "\tAuthor: " +str(self.__author__)
539 print "\tVersion: " +str(self.__version__)
540 print "\tInfo: " +str(self.__info__)
541 else:
542 print "Failed to theme config from", filename
543
544
546 """Load an SVG-file into this theme and reference it as ref_name."""
547 if self.has_key(filename):
548 del self[filename]
549 try:
550 self[filename] = rsvg.Handle(self.path + "/" + filename)
551 self.svgs[filename[:-4]] = self[filename]
552 if self[filename] != None:
553
554 size=self[filename].get_dimension_data()
555 if size:
556 self.width = size[0]
557 self.height = size[1]
558 return True
559 except NameError, ex:
560 self[filename] = gtk.gdk.pixbuf_new_from_file(self.path + '/' + filename)
561 self.svgs[filename[:-4]] = self[filename]
562 if self[filename] != None:
563
564 self.width = self[filename].get_width()
565 self.height = self[filename].get_height()
566 print str(ex)
567 return True
568
569 else:
570 return False
571
572
574 """Load a PNG-file into this theme and reference it as ref_name."""
575 if self.has_key(filename):
576 del self[filename]
577 self[filename] = cairo.ImageSurface.create_from_png(self.path +
578 "/" + filename)
579 self.pngs[filename[:-4]] = self[filename]
580 if self[filename] != None:
581 return True
582 else:
583 return False
584
585
587 """Load all files in the theme's path. Currently only loads SVGs and
588 PNGs."""
589
590
591
592 dirlst = glob.glob(self.path + '/*')
593 if len(dirlst)==0:
594 return False
595 plen = len(self.path) + 1
596 for file in dirlst:
597 fname = file[plen:]
598 if fname.endswith('.svg'):
599
600 if self.load_svg(fname) == False:
601 return False
602 elif fname.endswith('.png'):
603
604 if self.load_png(fname) == False:
605 return False
606 elif fname == "theme.conf":
607 print "theme.conf found! Loading option-overrides."
608
609 if self.load_conf(file) == False:
610 return False
611
612 return True
613
615 """Re-Load all files in the theme's path."""
616 self.free()
617 self.__load_all()
618
619
621 """Deletes the Theme's contents and frees all rsvg-handles.
622 TODO: freeing rsvg-handles does NOT work for some reason"""
623 self.option_overrides.clear()
624 for filename in self:
625 try:
626 self[filename].free()
627 except AttributeError:pass
628
629 del filename
630 self.clear()
631
632
633
634
635 - def render (self, ctx, name):
636 """Render an image from within this theme to the given context. This
637 function can EITHER use png OR svg images, so it is possible to
638 create themes using both image-formats when a Screenlet uses this
639 function for drawing its images. The image name has to be defined
640 without the extension and the function will automatically select
641 the available one (SVG is prefered over PNG)."""
642
643
644 if os.path.isfile (self.path + '/' + name + '.svg'):
645
646 try:
647 self.svgs[name].render_cairo(ctx)
648 except:
649 try:
650 ctx.set_source_pixbuf(self.svgs[name], 0, 0)
651
652 ctx.paint()
653 pixbuf = None
654 except TypeError:
655 ctx.set_source_surface(self.pngs[name], 0, 0)
656 ctx.paint()
657
658 elif os.path.isfile (self.path + '/' + name + '.png'):
659 ctx.set_source_surface(self.pngs[name], 0, 0)
660 ctx.paint()
661
662
663
665
666 ctx.set_source_rgba(color[0], color[1], color[2], color[3])
667 ctx.set_source_surface(self.pngs[name], 0, 0)
668 ctx.mask_surface(image, 0, 0)
669 ctx.stroke()
670
671
672
673 -class Screenlet (gobject.GObject, EditableOptions, Drawing):
674 """A Screenlet is a (i.e. contains a) shaped gtk-window that is
675 fully invisible by default. Subclasses of Screenlet can render
676 their owner-drawn graphics on fully transparent background."""
677
678
679 __name__ = _('No name set for this Screenlet')
680 __version__ = '0.0'
681 __author__ = _('No author defined for this Screenlet')
682 __desc__ = _('No info set for this Screenlet')
683 __requires__ = []
684
685
686
687
688
689 id = ''
690 window = None
691 theme = None
692 uses_theme = True
693 draw_buttons = True
694 show_buttons = True
695 menu = None
696 is_dragged = False
697 quit_on_close = True
698 saving_enabled = True
699 dragging_over = False
700 disable_updates = False
701 p_context = None
702 p_layout = None
703
704
705 x = 200
706 y = 150
707 mousex = 0
708 mousey = 0
709 mouse_is_over = False
710 width = 100
711 height = 100
712 scale = 1.0
713 opacity = 1.0
714 theme_name = ""
715 is_visible = True
716 is_sticky = False
717 is_widget = False
718 keep_above = False
719 keep_below = True
720 skip_pager = True
721 first_run = False
722 skip_taskbar = True
723 lock_position = False
724 allow_option_override = True
725 ask_on_option_override = True
726 ignore_requirements = False
727 resize_on_scroll = True
728 has_started = False
729 has_focus = False
730
731 gtk_icon_theme = None
732 __lastx = 0
733 __lasty = 0
734 p_fdesc = None
735 p_layout = None
736 tooltip = None
737 notify = None
738
739
740 __mi_keep_above = None
741 __mi_keep_below = None
742 __mi_widget = None
743 __mi_sticky = None
744 __mi_lock = None
745
746 __gsignals__ = dict(screenlet_removed=(gobject.SIGNAL_RUN_FIRST,
747 gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)))
748
749 - def __init__ (self, id='', width=100, height=100, parent_window=None,
750 show_window=True, is_widget=False, is_sticky=False,
751 uses_theme=True, draw_buttons=True,path=os.getcwd(), drag_drop=False, session=None,
752 enable_saving=True, service_class=services.ScreenletService,
753 uses_pango=False, is_sizable=True,resize_on_scroll=True, ask_on_option_override=False):
754 """Constructor - should only be subclassed"""
755
756
757 super(Screenlet, self).__init__()
758 EditableOptions.__init__(self)
759
760 self.id = id
761 self.session = session
762 self.service = None
763 self.__desc__ = self.__doc__
764
765
766 if self.id and service_class:
767 self.register_service(service_class)
768
769 self.service.instance_added(self.id)
770 self.width = width
771 self.height = height
772 self.is_dragged = False
773 self.__path__ = path
774 self.saving_enabled = enable_saving
775
776 self.__dict__['theme_name'] = ""
777 self.__dict__['is_widget'] = is_widget
778 self.__dict__['is_sticky'] = is_sticky
779 self.__dict__['draw_buttons'] = draw_buttons
780 self.resize_on_scroll = resize_on_scroll
781 self.__dict__['x'] = 200
782 self.__dict__['y'] = 150
783
784
785
786
787 self.__shape_bitmap = None
788 self.__shape_bitmap_width = 0
789 self.__shape_bitmap_height = 0
790
791 self.add_options_group('Screenlet',
792 _('The basic settings for this Screenlet-instance.'))
793
794
795
796 self.gtk_icon_theme = gtk.icon_theme_get_default()
797 self.load_buttons(None)
798 self.gtk_icon_theme.connect("changed", self.load_buttons)
799 if draw_buttons: self.draw_buttons = True
800 else: self.draw_buttons = False
801 if uses_theme:
802 self.uses_theme = True
803 self.add_option(StringOption('Screenlet', 'theme_name',
804 default='default', hidden=True))
805
806 self.add_option(IntOption('Screenlet', 'x',
807 default=200, label=_('X-Position'),
808 desc=_('The X-position of this Screenlet ...'),
809 min=0, max=gtk.gdk.screen_width()))
810 self.add_option(IntOption('Screenlet', 'y',
811 default=150, label=_('Y-Position'),
812 desc=_('The Y-position of this Screenlet ...'),
813 min=0, max=gtk.gdk.screen_height()))
814 self.add_option(IntOption('Screenlet', 'width',
815 default=width, label=_('Width'),
816 desc=_('The width of this Screenlet ...'),
817 min=16, max=1000, hidden=True))
818 self.add_option(IntOption('Screenlet', 'height',
819 default=height, label=_('Height'),
820 desc=_('The height of this Screenlet ...'),
821 min=16, max=1000, hidden=True))
822 self.add_option(FloatOption('Screenlet', 'scale',
823 default=self.scale, label=_('Scale'),
824 desc=_('The scale-factor of this Screenlet ...'),
825 min=0.1, max=10.0, digits=2, increment=0.1))
826 self.add_option(FloatOption('Screenlet', 'opacity',
827 default=self.opacity, label=_('Opacity'),
828 desc=_('The opacity of the Screenlet window ...'),
829 min=0.1, max=1.0, digits=2, increment=0.1))
830 self.add_option(BoolOption('Screenlet', 'is_sticky',
831 default=is_sticky, label=_('Stick to Desktop'),
832 desc=_('Show this Screenlet on all workspaces ...')))
833 self.add_option(BoolOption('Screenlet', 'is_widget',
834 default=is_widget, label=_('Treat as Widget'),
835 desc=_('Treat this Screenlet as a "Widget" ...')))
836 self.add_option(BoolOption('Screenlet', 'is_dragged',
837 default=self.is_dragged, label="Is the screenlet dragged",
838 desc="Is the screenlet dragged", hidden=True))
839 self.add_option(BoolOption('Screenlet', 'is_sizable',
840 default=is_sizable, label="Can the screenlet be resized",
841 desc="is_sizable", hidden=True))
842 self.add_option(BoolOption('Screenlet', 'is_visible',
843 default=self.is_visible, label="Usefull to use screenlets as gnome panel applets",
844 desc="is_visible", hidden=True))
845 self.add_option(BoolOption('Screenlet', 'lock_position',
846 default=self.lock_position, label=_('Lock position'),
847 desc=_('Stop the screenlet from being moved...')))
848 self.add_option(BoolOption('Screenlet', 'keep_above',
849 default=self.keep_above, label=_('Keep above'),
850 desc=_('Keep this Screenlet above other windows ...')))
851 self.add_option(BoolOption('Screenlet', 'keep_below',
852 default=self.keep_below, label=_('Keep below'),
853 desc=_('Keep this Screenlet below other windows ...')))
854 self.add_option(BoolOption('Screenlet', 'draw_buttons',
855 default=self.draw_buttons, label=_('Draw button controls'),
856 desc=_('Draw buttons in top right corner')))
857 self.add_option(BoolOption('Screenlet', 'skip_pager',
858 default=self.skip_pager, label=_('Skip Pager'),
859 desc=_('Set this Screenlet to show/hide in pagers ...')))
860 self.add_option(BoolOption('Screenlet', 'skip_taskbar',
861 default=self.skip_pager, label=_('Skip Taskbar'),
862 desc=_('Set this Screenlet to show/hide in taskbars ...')))
863 self.add_option(BoolOption('Screenlet', 'resize_on_scroll',
864 default=self.resize_on_scroll, label=_("Resize on mouse scroll"),
865 desc="resize_on_scroll"))
866 self.add_option(BoolOption('Screenlet', 'ignore_requirements',
867 self.ignore_requirements, _('Ignore requirements'),
868 _('Set this Screenlet to ignore/demand DEB requirements ...')))
869 if uses_theme:
870 self.ask_on_option_override = ask_on_option_override
871 self.add_option(BoolOption('Screenlet', 'allow_option_override',
872 default=self.allow_option_override, label=_('Allow overriding Options'),
873 desc=_('Allow themes to override options in this screenlet ...')))
874 self.add_option(BoolOption('Screenlet', 'ask_on_option_override',
875 default=self.ask_on_option_override, label=_('Ask on Override'),
876 desc=_('Show a confirmation-dialog when a theme wants to override ')+\
877 _('the current options of this Screenlet ...')))
878
879 self.disable_option('width')
880 self.disable_option('height')
881
882 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
883 if parent_window:
884 self.window.set_parent_window(parent_window)
885 self.window.set_transient_for(parent_window)
886 self.window.set_destroy_with_parent(True)
887 self.window.resize(width, height)
888 self.window.set_decorated(False)
889 try:
890 self.window.set_property('has-resize-grip', False)
891 except TypeError:
892 pass
893 self.window.set_app_paintable(True)
894
895 if uses_pango:
896 self.p_context = self.window.get_pango_context()
897 if self.p_context:
898 self.p_layout = pango.Layout(self.p_context)
899 self.p_layout.set_font_description(\
900 pango.FontDescription("Sans 12"))
901
902
903 if str(sensors.sys_get_window_manager()).lower() == 'kwin':
904 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
905
906 elif str(sensors.sys_get_window_manager()).lower() == 'sawfish':
907 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
908 else:
909 self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_TOOLBAR)
910 self.window.set_keep_above(self.keep_above)
911 self.window.set_keep_below(self.keep_below)
912 self.window.set_skip_taskbar_hint(True)
913 self.window.set_skip_pager_hint(True)
914 if is_sticky:
915 self.window.stick()
916 self.alpha_screen_changed(self.window)
917 self.update_shape()
918
919 self.window.set_events(gtk.gdk.ALL_EVENTS_MASK)
920 self.window.connect("composited-changed", self.composite_changed)
921 self.window.connect("delete_event", self.delete_event)
922 self.window.connect("destroy", self.destroy)
923 self.window.connect("expose_event", self.expose)
924 self.window.connect("button-press-event", self.button_press)
925 self.window.connect("button-release-event", self.button_release)
926 self.window.connect("configure-event", self.configure_event)
927 self.window.connect("screen-changed", self.alpha_screen_changed)
928 self.window.connect("realize", self.realize_event)
929 self.window.connect("enter-notify-event", self.enter_notify_event)
930 self.window.connect("leave-notify-event", self.leave_notify_event)
931 self.window.connect("focus-in-event", self.focus_in_event)
932 self.window.connect("focus-out-event", self.focus_out_event)
933 self.window.connect("scroll-event", self.scroll_event)
934 self.window.connect("motion-notify-event",self.motion_notify_event)
935 self.window.connect("map-event", self.map_event)
936 self.window.connect("unmap-event", self.unmap_event)
937
938 self.window.connect("key-press-event", self.key_press)
939
940 if drag_drop:
941 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
942 gtk.DEST_DEFAULT_DROP,
943 [("text/plain", 0, 0),
944 ("image", 0, 1),
945 ("text/uri-list", 0, 2)],
946 gtk.gdk.ACTION_COPY)
947 self.window.connect("drag_data_received", self.drag_data_received)
948 self.window.connect("drag-begin", self.drag_begin)
949 self.window.connect("drag-end", self.drag_end)
950 self.window.connect("drag-motion", self.drag_motion)
951 self.window.connect("drag-leave", self.drag_leave)
952
953 self.menu = gtk.Menu()
954
955
956
957 if show_window:
958 self.window.show()
959 if self.__name__.endswith("Screenlet"):
960 short_name = self.__name__[:-9]
961 else:
962 short_name = self.__name__
963 if not os.path.exists(os.environ['HOME'] + '/.config/Screenlets/' + short_name + '/default/'+ self.id + '.ini'):
964 self.first_run = True
965 self.window.hide()
966
967
968 if not self.window.is_composited () :
969 self.disable_option('opacity')
970
972
973 self.on_before_set_atribute(name, value)
974 gobject.GObject.__setattr__(self, name, value)
975
976 if name=="x" or name=="y":
977 if self.has_started:
978 self.window.move(self.x, self.y)
979 elif name == 'opacity':
980 self.window.set_opacity(value)
981 elif name == 'scale':
982 self.window.resize(int(self.width * self.scale),
983 int(self.height * self.scale))
984
985 self.on_scale()
986 self.redraw_canvas()
987 self.update_shape()
988
989
990 elif name == "theme_name":
991
992
993
994 print "Theme set to: '%s'" % value
995 path = self.find_theme(value)
996 if path:
997 self.load_theme(path)
998
999 self.redraw_canvas()
1000 self.update_shape()
1001 elif name in ("width", "height"):
1002
1003 if self.window:
1004 self.window.resize(int(self.width*self.scale), int(self.height*self.scale))
1005
1006 self.update_shape()
1007 elif name == "is_widget":
1008 if self.has_started:
1009 self.set_is_widget(value)
1010 elif name == "is_visible":
1011 if self.has_started:
1012 if value == True:
1013 self.reshow()
1014 else:
1015 self.window.hide()
1016 elif name == "is_sticky":
1017 if value == True:
1018 self.window.stick()
1019 else:
1020 self.window.unstick()
1021
1022
1023 elif name == "keep_above":
1024 if self.has_started == True:
1025 self.window.set_keep_above(bool(value))
1026
1027 elif name == "keep_below":
1028 if self.has_started == True:
1029 self.window.set_keep_below(bool(value))
1030
1031 elif name == "skip_pager":
1032 if self.window.window:
1033 self.window.window.set_skip_pager_hint(bool(value))
1034 elif name == "skip_taskbar":
1035 if self.window.window:
1036 self.window.window.set_skip_taskbar_hint(bool(value))
1037
1038
1039 if self.saving_enabled:
1040 o = self.get_option_by_name(name)
1041 if o != None:
1042 self.session.backend.save_option(self.id, o.name,
1043 o.on_export(value))
1044 self.on_after_set_atribute(name, value)
1045
1046
1047
1048
1049
1050
1052 '''Checks if required DEB packages are installed'''
1053
1054 req_feedback = ""
1055 fail = False
1056
1057
1058
1059 commandstr = '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/"'
1060 for req in self.__requires__:
1061 operator = None
1062
1063 if req.find('(') != -1:
1064
1065 pos = req.find('(')
1066 package = req[:pos].strip()
1067 version_str = req[pos+1:]
1068 version_str = version_str[:version_str.find(')')]
1069 while version_str.find(' ') != -1:
1070 version_str = req.replace(' ', ' ')
1071 res = version_str.split(' ')
1072 version = res[1]
1073 operator = res[0]
1074 else:
1075
1076 package = req
1077
1078 version = _("?")
1079
1080 installed_version = os.popen(commandstr % package).readline().replace('\n', '')
1081
1082 if len(installed_version) < 1:
1083 req_feedback += _("\n%(package)s %(version)s required, NOT INSTALLED!") % {"package":package, "version":version}
1084 fail = True
1085 else:
1086 req_feedback += _("\n%(package)s %(version)s installed, req %(required)s.") % {"package":package, "version":installed_version, "required":version}
1087
1088
1089
1090 if operator is not None:
1091 comp_command = "dpkg --compare-versions \"" + installed_version + "\" \"" + operator + "\" \"" + version + "\""
1092
1093 if subprocess.call(comp_command, shell=True) != 0:
1094 fail = True
1095 if fail:
1096 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")
1097
1099 """Appends the default menu-items to self.menu. You can add on OR'ed
1100 flag with DefaultMenuItems you want to add."""
1101 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'
1102
1103 menu = self.menu
1104
1105
1106 if len(menu.get_children()) > 0:
1107 self.add_menuitem("", "-")
1108
1109 if flags & DefaultMenuItem.XML:
1110
1111 xfile = self.get_screenlet_dir() + "/menu.xml"
1112 xmlmenu = screenlets.menu.create_menu_from_file(xfile,
1113 self.menuitem_callback)
1114 if xmlmenu:
1115 self.menu = xmlmenu
1116
1117 if flags & DefaultMenuItem.SIZE:
1118 size_item = gtk.MenuItem(_("Size"))
1119 size_item.show()
1120 size_menu = gtk.Menu()
1121 menu.append(size_item)
1122 size_item.set_submenu(size_menu)
1123
1124 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):
1125 s = str(int(i * 100))
1126 item = gtk.MenuItem(s + " %")
1127 item.connect("activate", self.menuitem_callback,
1128 "scale:"+str(i))
1129 item.show()
1130 size_menu.append(item)
1131
1132 if flags & DefaultMenuItem.THEMES:
1133 themes_item = gtk.MenuItem(_("Theme"))
1134 themes_item.show()
1135 themes_menu = gtk.Menu()
1136 menu.append(themes_item)
1137 themes_item.set_submenu(themes_menu)
1138
1139 lst = self.get_available_themes()
1140 for tname in lst:
1141 item = gtk.MenuItem(tname)
1142 item.connect("activate", self.menuitem_callback, "theme:"+tname)
1143 item.show()
1144 themes_menu.append(item)
1145
1146
1147 if flags & DefaultMenuItem.WINDOW_MENU:
1148 winmenu_item = gtk.MenuItem(_("Window"))
1149 winmenu_item.show()
1150 winmenu_menu = gtk.Menu()
1151 menu.append(winmenu_item)
1152 winmenu_item.set_submenu(winmenu_menu)
1153
1154 self.__mi_lock = item = gtk.CheckMenuItem(_("Lock"))
1155 item.set_active(self.lock_position)
1156 item.connect("activate", self.menuitem_callback,
1157 "option:lock")
1158 item.show()
1159 winmenu_menu.append(item)
1160
1161 self.__mi_sticky = item = gtk.CheckMenuItem(_("Sticky"))
1162 item.set_active(self.is_sticky)
1163 item.connect("activate", self.menuitem_callback,
1164 "option:sticky")
1165 item.show()
1166 winmenu_menu.append(item)
1167
1168 self.__mi_widget = item = gtk.CheckMenuItem(_("Widget"))
1169 item.set_active(self.is_widget)
1170 item.connect("activate", self.menuitem_callback,
1171 "option:widget")
1172 item.show()
1173 winmenu_menu.append(item)
1174
1175 self.__mi_keep_above = item = gtk.CheckMenuItem(_("Keep above"))
1176 item.set_active(self.keep_above)
1177 item.connect("activate", self.menuitem_callback,
1178 "option:keep_above")
1179 item.show()
1180 winmenu_menu.append(item)
1181
1182 self.__mi_keep_below = item = gtk.CheckMenuItem(_("Keep below"))
1183 item.set_active(self.keep_below)
1184 item.connect("activate", self.menuitem_callback,
1185 "option:keep_below")
1186 item.show()
1187 winmenu_menu.append(item)
1188
1189
1190 if flags & DefaultMenuItem.PROPERTIES:
1191 add_menuitem(menu, "-", self.menuitem_callback, "")
1192 add_menuitem(menu, _("Properties..."), self.menuitem_callback, "options")
1193
1194 if flags & DefaultMenuItem.INFO:
1195 add_menuitem(menu, _("Info..."), self.menuitem_callback, "info")
1196
1197 if flags & DefaultMenuItem.ADD:
1198 add_menuitem(menu, "-", self.menuitem_callback, "")
1199 add_menuitem(menu, _("Add one more %s") % self.get_short_name(), self.menuitem_callback, "add")
1200
1201 if flags & DefaultMenuItem.DELETE:
1202 add_menuitem(menu, _("Delete this %s") % self.get_short_name(), self.menuitem_callback, "delete")
1203
1204 if flags & DefaultMenuItem.QUIT:
1205 add_menuitem(menu, "-", self.menuitem_callback, "")
1206 add_menuitem(menu, _("Quit this %s") % self.get_short_name(), self.menuitem_callback, "quit_instance")
1207
1208 if flags & DefaultMenuItem.QUIT_ALL:
1209 add_menuitem(menu, _("Quit all %ss") % self.get_short_name(), self.menuitem_callback, "quit")
1210
1212 """Simple way to add menuitems to a right-click menu.
1213 This function wraps screenlets.menu.add_menuitem.
1214 For backwards compatibility, the order of the parameters
1215 to this function is switched."""
1216 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'
1217 if callback is None:
1218 callback = self.menuitem_callback
1219
1220 return add_menuitem(self.menu, label, callback, id)
1221
1223 """Simple way to add submenuitems to the right-click menu through a list."""
1224 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'
1225
1226 submenu = gtk.MenuItem(label)
1227 submenu.show()
1228 sub_menu = gtk.Menu()
1229 self.menu.append(submenu)
1230 submenu.set_submenu(sub_menu)
1231
1232
1233 for tname in lst:
1234 item = gtk.MenuItem(tname)
1235 item.connect("activate", self.menuitem_callback,
1236 tname)
1237 item.show()
1238 sub_menu.append(item)
1239
1240 return submenu
1241
1242
1243
1247
1268
1269 - def clear_cairo_context (self, ctx):
1270 """Fills the given cairo.Context with fully transparent white."""
1271 ctx.save()
1272 ctx.set_source_rgba(1, 1, 1, 0)
1273 ctx.set_operator (cairo.OPERATOR_SOURCE)
1274 ctx.paint()
1275 ctx.restore()
1276
1278 """Close this Screenlet
1279 TODO: send close-notify instead of destroying window?"""
1280
1281 self.window.unmap()
1282 self.window.destroy()
1283
1284
1286 """Create drag-icon and -mask for drag-operation. Returns a 2-tuple
1287 with the icon and the mask. To supply your own icon you can use the
1288 on_create_drag_icon-handler and return the icon/mask as 2-tuple."""
1289 w = self.width
1290 h = self.height
1291 icon, mask = self.on_create_drag_icon()
1292 if icon == None:
1293
1294 icon = gtk.gdk.Pixmap(self.window.window, w, h)
1295 ctx = icon.cairo_create()
1296 self.clear_cairo_context(ctx)
1297 self.on_draw(ctx)
1298 if mask == None:
1299
1300 mask = gtk.gdk.Pixmap(self.window.window, w, h)
1301 ctx = mask.cairo_create()
1302 self.clear_cairo_context(ctx)
1303 self.on_draw_shape(ctx)
1304 return (icon, mask)
1305
1307 """Enable/Disable realtime-saving of options."""
1308 self.saving_enabled = enabled
1309
1319
1321 """Return the short name of this screenlet. This returns the classname
1322 of the screenlet without trailing "Screenlet". Please always use
1323 this function if you want to retrieve the short name of a Screenlet."""
1324 return self.__class__.__name__[:-9]
1325
1327 """Return the name of this screenlet's personal directory."""
1328 p = utils.find_first_screenlet_path(self.get_short_name())
1329 if p:
1330 return p
1331 else:
1332 if self.__path__ != '':
1333 return self.__path__
1334 else:
1335 return os.getcwd()
1336
1338 """Return the name of this screenlet's personal theme-dir.
1339 (Only returns the dir under the screenlet's location"""
1340 return self.get_screenlet_dir() + "/themes/"
1341
1343 """Returns a list with the names of all available themes in this
1344 Screenlet's theme-directories."""
1345 lst = []
1346 utils.refresh_available_screenlet_paths()
1347 for p in SCREENLETS_PATH:
1348 d = p + '/' + self.get_short_name() + '/themes/'
1349 if os.path.isdir(d):
1350
1351 dirlst = glob.glob(d + '*')
1352 dirlst.sort()
1353 tdlen = len(d)
1354 for fname in dirlst:
1355 if os.path.isdir(fname):
1356 dname = fname[tdlen:]
1357 if not dname in lst:
1358 lst.append(dname)
1359 return lst
1360
1374
1376 """Called when screenlet finishes loading"""
1377
1378
1379 self.window.present()
1380
1381
1382
1383 self.window.hide()
1384 self.window.move(self.x, self.y)
1385
1386 if DEBIAN and not self.ignore_requirements:
1387 self.check_requirements()
1388
1389 self.window.show()
1390 self.has_started = True
1391 self.is_dragged = False
1392 self.keep_above= self.keep_above
1393 self.keep_below= self.keep_below
1394 self.is_sticky = self.is_sticky
1395 self.skip_taskbar = self.skip_taskbar
1396 self.window.set_skip_taskbar_hint(self.skip_taskbar)
1397 self.window.set_keep_above(self.keep_above)
1398 self.window.set_keep_below(self.keep_below)
1399
1400 self.on_init()
1401 if self.is_widget:
1402 self.set_is_widget(True)
1403 self.has_focus = False
1404 ini = utils.IniReader()
1405 if ini.load (os.environ['HOME'] + '/.screenlets' + '/config.ini') and self.first_run:
1406
1407 if ini.get_option('Lock', section='Options') == 'True':
1408 self.lock_position = True
1409 elif ini.get_option('Lock', section='Options') == 'False':
1410 self.lock_position = False
1411 if ini.get_option('Sticky', section='Options') == 'True':
1412 self.is_sticky = True
1413 elif ini.get_option('Sticky', section='Options') == 'False':
1414 self.is_sticky = False
1415 if ini.get_option('Widget', section='Options') == 'True':
1416 self.is_widget = True
1417 elif ini.get_option('Widget', section='Options') == 'False':
1418 self.is_widget = False
1419 if ini.get_option('Keep_above', section='Options') == 'True':
1420 self.keep_above = True
1421 elif ini.get_option('Keep_above', section='Options') == 'False':
1422 self.keep_above = False
1423 if ini.get_option('Keep_below', section='Options') == 'True':
1424 self.keep_below = True
1425 elif ini.get_option('Keep_below', section='Options') == 'False':
1426 self.keep_below = False
1427 if ini.get_option('draw_buttons', section='Options') == 'True':
1428 self.draw_buttons = True
1429 elif ini.get_option('draw_buttons', section='Options') == 'False':
1430 self.draw_buttons = False
1431
1433 """Hides this Screenlet's underlying gtk.Window"""
1434 self.window.hide()
1435 self.on_hide()
1436
1437
1438
1439
1463
1464
1466 """If the Screenlet runs as stand-alone app, starts gtk.main()"""
1467 gtk.main()
1468
1470 """Register or create the given ScreenletService-(sub)class as the new
1471 service for this Screenlet. If self is not the first instance in the
1472 current session, the service from the first instance will be used
1473 instead and no new service is created."""
1474 if self.session:
1475 if len(self.session.instances) == 0:
1476
1477 if service_classobj==services.ScreenletService:
1478 self.service = service_classobj(self, self.get_short_name())
1479 else:
1480
1481 self.service = service_classobj(self)
1482 else:
1483 self.service = self.session.instances[0].service
1484
1485 return True
1486 return False
1487
1507
1509 """Show this Screenlet's underlying gtk.Window"""
1510 self.window.show()
1511 self.window.move(self.x, self.y)
1512 self.on_show()
1513
1515 """Show the EditableSettingsDialog for this Screenlet."""
1516 se = OptionsDialog(490, 450)
1517 img = gtk.Image()
1518 try:
1519 d = self.get_screenlet_dir()
1520 if os.path.isfile(d + '/icon.svg'):
1521 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.svg')
1522 elif os.path.isfile(d + '/icon.png'):
1523 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.png')
1524 img.set_from_pixbuf(icn)
1525 except:
1526 img.set_from_stock(gtk.STOCK_PROPERTIES, 5)
1527 se.set_title(self.__name__)
1528 se.set_info(self.__name__, glib.markup_escape_text(self.__desc__), '(c) ' + glib.markup_escape_text(self.__author__),
1529 version='v' + self.__version__, icon=img)
1530 se.show_options_for_object(self)
1531 resp = se.run()
1532 if resp == gtk.RESPONSE_REJECT:
1533 se.reset_to_defaults()
1534 else:
1535 self.update_shape()
1536 se.destroy()
1537
1539 """Redraw the entire Screenlet's window area.
1540 TODO: store window alloaction in class and change when size changes."""
1541
1542 if self.disable_updates:
1543 return
1544 if self.window:
1545 x, y, w, h = self.window.get_allocation()
1546 rect = gtk.gdk.Rectangle(x, y, w, h)
1547 if self.window.window:
1548 self.window.window.invalidate_rect(rect, True)
1549 self.window.window.process_updates(True)
1550
1551
1552
1553
1565
1567 """Removed shaped window , in case the nom composited shape has been set"""
1568 if self.window.window:
1569 self.window.window.shape_combine_mask(None,0,0)
1570
1571 w = self.window.allocation.width
1572 h = self.window.allocation.height
1573
1574
1575 if w==0 or h==0: return False
1576
1577 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1578 self.__shape_bitmap = screenlets.create_empty_bitmap(w, h)
1579 self.__shape_bitmap_width = w
1580 self.__shape_bitmap_height = h
1581
1582
1583 ctx = self.__shape_bitmap.cairo_create()
1584 self.clear_cairo_context(ctx)
1585
1586
1587 if self.window.is_composited():
1588
1589 self.on_draw_shape(ctx)
1590
1591 else:
1592 try:
1593 self.on_draw_shape(ctx)
1594 except:
1595 self.on_draw(ctx)
1596
1597
1598
1600 """Update window shape (only call this when shape has changed
1601 because it is very ressource intense if ran too often)."""
1602
1603 if self.disable_updates:
1604 return
1605
1606
1607
1608
1609
1610 w = int(self.width * self.scale)
1611 h = int(self.height * self.scale)
1612
1613 if w==0: w = 100
1614 if h==0: h = 100
1615
1616 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1617 data = ''.zfill(w*h)
1618 self.__shape_bitmap = gtk.gdk.bitmap_create_from_data(None, data,
1619 w, h)
1620 self.__shape_bitmap_width = w
1621 self.__shape_bitmap_height = h
1622
1623 ctx = self.__shape_bitmap.cairo_create()
1624 self.clear_cairo_context(ctx)
1625 if self.has_focus and self.draw_buttons and self.show_buttons:
1626 ctx.save()
1627
1628
1629
1630
1631
1632
1633
1634
1635 ctx.translate((self.width*self.scale)-16,0)
1636 ctx.set_source_pixbuf(self.closeb, 0, 0)
1637 ctx.paint()
1638 ctx.restore()
1639 ctx.save()
1640 ctx.translate((self.width*self.scale)-32,0)
1641 ctx.set_source_pixbuf(self.prop, 0, 0)
1642 ctx.paint()
1643 ctx.restore()
1644
1645
1646 if self.window.is_composited():
1647
1648 self.on_draw_shape(ctx)
1649
1650 self.window.input_shape_combine_mask(self.__shape_bitmap, 0, 0)
1651 else:
1652 try: self.on_draw(ctx)
1653 except: self.on_draw_shape(ctx)
1654
1655 self.window.shape_combine_mask(self.__shape_bitmap,0,0)
1656 self.on_update_shape()
1657
1659 """TEST: This function is intended to shape the window whenever no
1660 composited environment can be found. (NOT WORKING YET!!!!)"""
1661
1662
1663 w = int(self.width * self.scale)
1664 h = int(self.height * self.scale)
1665
1666 if w==0: w = 100
1667 if h==0: h = 100
1668
1669 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1670 data = ''.zfill(w*h)
1671 self.__shape_bitmap = gtk.gdk.pixbuf_new_from_data(data,
1672 gtk.gdk.COLORSPACE_RGB, True, 1, w, h, w)
1673 self.__shape_bitmap_width = w
1674 self.__shape_bitmap_height = h
1675
1676
1677 if self.__shape_bitmap:
1678
1679 (pixmap,mask) = self.__shape_bitmap.render_pixmap_and_mask(255)
1680
1681 self.window.shape_combine_mask(mask)
1682
1686
1687
1688
1689
1690
1692 """Called when the Screenlet gets deleted. Return True to cancel.
1693 TODO: sometimes not properly called"""
1694 return not show_question(self, _("To quit all %s's, use 'Quit' instead. ") % self.__class__.__name__ +\
1695 _('Really delete this %s and its settings?') % self.get_short_name())
1696 """return not show_question(self, 'Deleting this instance of the '+\
1697 self.__name__ + ' will also delete all your personal '+\
1698 'changes you made to it!! If you just want to close the '+\
1699 'application, use "Quit" instead. Are you sure you want to '+\
1700 'delete this instance?')
1701 return False"""
1702
1703
1704
1705
1707 """Called after setting screenlet atributes"""
1708 pass
1709
1711 """Called before setting screenlet atributes"""
1712 pass
1713
1714
1716 """Called when the screenlet's drag-icon is created. You can supply
1717 your own icon and mask by returning them as a 2-tuple."""
1718 return (None, None)
1719
1721 """Called when screenlet was mapped"""
1722 pass
1723
1725 """Called when screenlet was unmapped"""
1726 pass
1727
1729 """Called when composite state has changed"""
1730 pass
1731
1732
1734 """Called when the Screenlet gets dragged."""
1735 pass
1736
1738 """Called when something gets dragged into the Screenlets area."""
1739 pass
1740
1742 """Called when something gets dragged out of the Screenlets area."""
1743 pass
1744
1746 """Callback for drawing the Screenlet's window - override
1747 in subclasses to implement your own drawing."""
1748 pass
1749
1751 """Callback for drawing the Screenlet's shape - override
1752 in subclasses to draw the window's input-shape-mask."""
1753 pass
1754
1755 - def on_drop (self, x, y, sel_data, timestamp):
1756 """Called when a selection is dropped on this Screenlet."""
1757 return False
1758
1760 """Called when the Screenlet's window receives focus."""
1761 pass
1762
1764 """Called when the Screenlet gets hidden."""
1765 pass
1766
1768 """Called when the Screenlet's options have been applied and the
1769 screenlet finished its initialization. If you want to have your
1770 Screenlet do things on startup you should use this handler."""
1771 pass
1772
1773 - def on_key_down (self, keycode, keyvalue, event=None):
1774 """Called when a key is pressed within the screenlet's window."""
1775 pass
1776
1778 """Called when the theme is reloaded (after loading, before redraw)."""
1779 pass
1780
1782 """Called when a menuitem is selected."""
1783 pass
1784
1786 """Called when a buttonpress-event occured in Screenlet's window.
1787 Returning True causes the event to be not further propagated."""
1788 return False
1789
1791 """Called when the mouse enters the Screenlet's window."""
1792 pass
1793
1795 """Called when the mouse leaves the Screenlet's window."""
1796 pass
1797
1799 """Called when the mouse moves in the Screenlet's window."""
1800 pass
1801
1803 """Called when a buttonrelease-event occured in Screenlet's window.
1804 Returning True causes the event to be not further propagated."""
1805 return False
1806
1808 """Callback for handling destroy-event. Perform your cleanup here!"""
1809 return True
1810
1812 """"Callback for handling the realize-event."""
1813
1815 """Called when Screenlet.scale is changed."""
1816 pass
1817
1821
1825
1827 """Called when the Screenlet gets shown after being hidden."""
1828 pass
1829
1833
1835 """Called when the Screenlet's window loses focus."""
1836 pass
1837
1839 """Called when the Screenlet's window is updating shape"""
1840 pass
1841
1842
1843
1844
1846 """set colormap for window"""
1847 if screen==None:
1848 screen = window.get_screen()
1849 map = screen.get_rgba_colormap()
1850 if map:
1851 pass
1852 else:
1853 map = screen.get_rgb_colormap()
1854 window.set_colormap(map)
1855
1894
1903
1930
1931
1949
1951
1952 print "delete_event"
1953 if self.on_delete() == True:
1954 print "Cancel delete_event"
1955 return True
1956 else:
1957 self.close()
1958 return False
1959
1960 - def destroy (self, widget, data=None):
1972
1977
1978
1980 return self.on_drop(x, y, sel_data, timestamp)
1981
1982 - def drag_end (self, widget, drag_context):
1983 print "End drag"
1984 self.is_dragged = False
1985 return False
1986
1987 - def drag_motion (self, widget, drag_context, x, y, timestamp):
1993
1994 - def drag_leave (self, widget, drag_context, timestamp):
1998
2000
2001 self.__dict__['mouse_is_over'] = True
2002 self.on_mouse_enter(event)
2003
2004
2005
2006 - def expose (self, widget, event):
2024
2035
2036
2037
2038
2045
2046
2047
2049 """Handle keypress events, needed for in-place editing."""
2050 self.on_key_down(event.keyval, event.string, event)
2051
2053
2054
2055 self.__dict__['mouse_is_over'] = False
2056 self.on_mouse_leave(event)
2057
2058
2059
2132
2135
2138
2140 self.__dict__['mousex'] = event.x / self.scale
2141 self.__dict__['mousey'] = event.y / self.scale
2142
2143 self.on_mouse_move(event)
2144
2151
2160
2161
2168
2170 """hide notification window"""
2171 if self.notify != None:
2172 self.notify.hide()
2173 self.notify = None
2174
2188
2189
2195
2196
2278
2280 __gtype_name__ = 'WrapLabel'
2281
2283 gtk.Label.__init__(self)
2284
2285 self.__wrap_width = 0
2286 self.layout = self.get_layout()
2287 self.layout.set_wrap(pango.WRAP_WORD_CHAR)
2288
2289 if str != None:
2290 self.set_text(str)
2291
2292 self.set_alignment(0.0, 0.0)
2293
2299
2303
2304 - def set_text(self, str):
2305 gtk.Label.set_text(self, str)
2306 self.__set_wrap_width(self.__wrap_width)
2307
2311
2313 if width == 0:
2314 return
2315 layout = self.get_layout()
2316 layout.set_width(width * pango.SCALE)
2317 if self.__wrap_width != width:
2318 self.__wrap_width = width
2319 self.queue_resize()
2320
2417
2419 """A window that displays a text and serves as Notification (very basic yet)."""
2420
2421
2422 __timeout = None
2423
2424
2425 text = ''
2426 font_name = 'FreeSans 9'
2427 width = 200
2428 height = 100
2429 x = 0
2430 y = 0
2431 gradient = cairo.LinearGradient(0, 100,0, 0)
2432
2454
2462
2469
2474
2479
2486
2489
2491 if screen == None:
2492 screen = window.get_screen()
2493 map = screen.get_rgba_colormap()
2494 if not map:
2495 map = screen.get_rgb_colormap()
2496 window.set_colormap(map)
2497
2498 - def expose (self, widget, event):
2499 ctx = self.window.window.cairo_create()
2500 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL)
2501
2502 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2503 ctx.clip()
2504
2505 ctx.set_source_rgba(1, 1, 1, 0)
2506 ctx.set_operator (cairo.OPERATOR_SOURCE)
2507 ctx.paint()
2508
2509 self.gradient.add_color_stop_rgba(1,0.3, 0.3, 0.3, 0.9)
2510 self.gradient.add_color_stop_rgba(0.3, 0, 0, 0, 0.9)
2511 ctx.set_source(self.gradient)
2512 ctx.rectangle(0, 0, self.width, self.height)
2513 ctx.fill()
2514
2515 ctx.save()
2516 ctx.translate(3, 3)
2517 ctx.set_source_rgba(1, 1, 1, 1)
2518 ctx.show_layout(self.p_layout)
2519 ctx.fill()
2520 ctx.restore()
2521 ctx.rectangle(0, 0, self.width, self.height)
2522 ctx.set_source_rgba(0, 0, 0, 0.7)
2523 ctx.stroke()
2524
2525
2526 """class TestWidget(ShapedWidget):
2527
2528 def __init__(self, width, height):
2529 #ShapedWidget.__init__(self, width, height)
2530 super(TestWidget, self).__init__(width, height)
2531
2532 def draw(self, ctx):
2533 if self.mouse_inside:
2534 ctx.set_source_rgba(1, 0, 0, 0.8)
2535 else:
2536 ctx.set_source_rgba(1, 1, 0, 0.8)
2537 ctx.rectangle(0, 0, 32, 32)
2538 ctx.fill()
2539 """
2540
2541
2542
2543
2544
2545
2546
2548 """Launch a screenlet, either through its service or by launching a new
2549 process of the given screenlet. Name has to be the name of the Screenlet's
2550 class without trailing 'Screenlet'.
2551 NOTE: we could only launch the file here"""
2552
2553 if services.service_is_running(name):
2554
2555 srvc = services.get_service_by_name(name)
2556 if srvc:
2557 try:
2558 srvc.add('')
2559 return True
2560 except Exception, ex:
2561 print "Error while adding instance by service: %s" % ex
2562
2563 path = utils.find_first_screenlet_path(name)
2564 if path:
2565
2566 slfile = path + '/' + name + 'Screenlet.py'
2567
2568 print "Launching Screenlet from: %s" % slfile
2569 if debug:
2570 print "Logging output goes to: $HOME/.config/Screenlets/%sScreenlet.log" % name
2571 out = '$HOME/.config/Screenlets/%sScreenlet.log' % name
2572 else:
2573 out = '/dev/null'
2574 os.system('python -u %s > %s &' % (slfile, out))
2575 return True
2576 else:
2577 print "Screenlet '%s' could not be launched." % name
2578 return False
2579
2581 """Show a message for the given Screenlet (may contain Pango-Markup).
2582 If screenlet is None, this function can be used by other objects as well."""
2583 if screenlet == None:
2584 md = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,
2585 buttons=gtk.BUTTONS_OK)
2586 md.set_title(title)
2587 else:
2588 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_INFO,
2589 buttons=gtk.BUTTONS_OK)
2590 md.set_title(screenlet.__name__)
2591 md.set_markup(message)
2592 md.run()
2593 md.destroy()
2594
2596 """Show a question for the given Screenlet (may contain Pango-Markup)."""
2597 if screenlet == None:
2598 md = gtk.MessageDialog(None, type=gtk.MESSAGE_QUESTION,
2599 buttons=gtk.BUTTONS_YES_NO)
2600 md.set_title(title)
2601 else:
2602 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_QUESTION,
2603 buttons=gtk.BUTTONS_YES_NO)
2604 md.set_title(screenlet.__name__)
2605 md.set_markup(message)
2606 response = md.run()
2607 md.destroy()
2608 if response == gtk.RESPONSE_YES:
2609 return True
2610 return False
2611
2612 -def show_error (screenlet, message, title='Error'):
2613 """Show an error for the given Screenlet (may contain Pango-Markup)."""
2614 if screenlet == None:
2615 md = gtk.MessageDialog(None, type=gtk.MESSAGE_ERROR,
2616 buttons=gtk.BUTTONS_OK)
2617 md.set_title(title)
2618 else:
2619 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_ERROR,
2620 buttons=gtk.BUTTONS_OK)
2621 md.set_title(screenlet.__name__)
2622 md.set_markup(message)
2623 md.run()
2624 md.destroy()
2625
2627 """Raise a fatal error to stdout and stderr and exit with an errorcode."""
2628 import sys
2629 msg = 'FATAL ERROR: %s\n' % message
2630 sys.stdout.write(msg)
2631 sys.stderr.write(msg)
2632 sys.exit(1)
2633
2634
2635
2637 fatal_error("This screenlet seems to be written for an older version of the framework. Please download a newer version of the %s." % name)
2638