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 import pygtk
32 pygtk.require('2.0')
33 import gtk
34 import cairo, pango
35 import gobject
36 import rsvg
37 import os
38 import glob
39 import gettext
40 import math
41
42
43 from options import *
44 import services
45 import utils
46 import sensors
47
48 import XmlMenu
49
50
51
52
53
54
55
56
57 APP_NAME = "Screenlets"
58
59
60 VERSION = "0.1.1"
61
62
63 COPYRIGHT = "(c) RYX (Rico Pfaus) <ryx@ryxperience.com>\nWhise (Helder Fraga) <helder.fraga@hotmail.com>"
64
65
66 AUTHORS = ["RYX (Rico Pfaus) <ryx@ryxperience.com>", "Whise (Helder Fraga)<helder.fraga@hotmail.com>","Sorcerer (Hendrik Kaju)"]
67
68
69 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"
70
71 DOCUMENTERS = ["Documentation generated by epydoc"]
72
73 ARTISTS = ["More to come..."]
74
75 TRANSLATORS = "Special thanks for translators, credits on https://translations.launchpad.net/screenlets/"
76
77
78 WEBSITE = 'http://www.screenlets.org'
79
80
81 THIRD_PARTY_DOWNLOAD = "http://screenlets.org/index.php/Category:UserScreenlets"
82
83
84 INSTALL_PREFIX = '/usr'
85
86
87 PATH = INSTALL_PREFIX + '/share/screenlets'
88
89
90
91
92
93 SCREENLETS_PATH = [os.environ['HOME'] + '/.screenlets', PATH]
94
95
96 gettext.textdomain('screenlets')
97 gettext.bindtextdomain('screenlets', '/usr/share/locale')
98
100 return gettext.gettext(s)
101
102
103
104
105
106
123
124
126 """ScreenletThemes are simple storages that allow loading files
127 as svg-handles within a theme-directory. Each Screenlet can have
128 its own theme-directory. It is up to the Screenlet-developer if he
129 wants to let his Screenlet support themes or not. Themes are
130 turned off by default - if your Screenlet uses Themes, just set the
131 attribute 'theme_name' to the name of the theme's dir you want to use.
132 TODO: remove dict-inheritance"""
133
134
135 __name__ = ''
136 __author__ = ''
137 __version__ = ''
138 __info__ = ''
139
140
141 path = ""
142 loaded = False
143 width = 0
144 height = 0
145 option_overrides = {}
146 p_fdesc = None
147 p_layout = None
148 tooltip = None
149 notify = None
150
151
161
163 if name in ("width", "height"):
164 if self.loaded and len(self)>0:
165 size=self[0].get_dimension_data()
166 if name=="width":
167 return size[0]
168 else:
169 return size[1]
170 else:
171 return object.__getattr__(self, name)
172
200
201 - def check_entry (self, filename):
202 """Checks if a file with filename is loaded in this theme."""
203 try:
204 if self[filename]:
205 return True
206 except:
207
208 return False
209
210 - def get_text_width(self, ctx, text, font):
211 """@DEPRECATED Moved to Screenlets class: Returns the pixel width of a given text"""
212 ctx.save()
213
214 if self.p_layout == None :
215
216 self.p_layout = ctx.create_layout()
217 else:
218
219 ctx.update_layout(self.p_layout)
220 self.p_fdesc = pango.FontDescription(font)
221 self.p_layout.set_font_description(self.p_fdesc)
222 self.p_layout.set_text(text)
223 extents, lextents = self.p_layout.get_pixel_extents()
224 ctx.restore()
225 return extents[2]
226
227 - def get_text_extents(self, ctx, text, font):
228 """@DEPRECATED Moved to Screenlets class: Returns the pixel extents of a given text"""
229 ctx.save()
230
231 if self.p_layout == None :
232
233 self.p_layout = ctx.create_layout()
234 else:
235
236 ctx.update_layout(self.p_layout)
237 self.p_fdesc = pango.FontDescription(font)
238 self.p_layout.set_font_description(self.p_fdesc)
239 self.p_layout.set_text(text)
240 extents, lextents = self.p_layout.get_pixel_extents()
241 ctx.restore()
242 return extents
243
244 - def draw_text(self, ctx, text, x, y, font, size, width, allignment, weight = 0, ellipsize = pango.ELLIPSIZE_NONE):
245 """@DEPRECATED Moved to Screenlets class: Draws text"""
246 ctx.save()
247 ctx.translate(x, y)
248 if self.p_layout == None :
249
250 self.p_layout = ctx.create_layout()
251 else:
252
253 ctx.update_layout(self.p_layout)
254 self.p_fdesc = pango.FontDescription()
255 self.p_fdesc.set_family_static(font)
256 self.p_fdesc.set_size(size * pango.SCALE)
257 self.p_fdesc.set_weight(weight)
258 self.p_layout.set_font_description(self.p_fdesc)
259 self.p_layout.set_width(width * pango.SCALE)
260 self.p_layout.set_alignment(allignment)
261 self.p_layout.set_ellipsize(ellipsize)
262 self.p_layout.set_markup(text)
263 ctx.show_layout(self.p_layout)
264 ctx.restore()
265
266
268 """@DEPRECATED Moved to Screenlets class: Draws a circule"""
269 ctx.save()
270 ctx.translate(x, y)
271 ctx.arc(width/2,height/2,min(height,width)/2,0,2*math.pi)
272 if fill:ctx.fill()
273 else: ctx.stroke()
274 ctx.restore()
275
276 - def draw_line(self,ctx,start_x,start_y,end_x,end_y,line_width = 1,close=False,preserve=False):
277 """@DEPRECATED Moved to Screenlets class: Draws a line"""
278 ctx.save()
279 ctx.move_to(start_x, start_y)
280 ctx.set_line_width(line_width)
281 ctx.rel_line_to(end_x, end_y)
282 if close : ctx.close_path()
283 if preserve: ctx.stroke_preserve()
284 else: ctx.stroke()
285 ctx.restore()
286
288 """@DEPRECATED Moved to Screenlets class: Draws a rectangle"""
289 ctx.save()
290 ctx.translate(x, y)
291 ctx.rectangle (0,0,width,height)
292 if fill:ctx.fill()
293 else: ctx.stroke()
294 ctx.restore()
295
297 """@DEPRECATED Moved to Screenlets class: Draws a rounded rectangle"""
298 ctx.save()
299 ctx.translate(x, y)
300 padding=0
301 rounded=rounded_angle
302 w = width
303 h = height
304
305
306 ctx.move_to(0+padding+rounded, 0+padding)
307
308
309 ctx.line_to(w-padding-rounded, 0+padding)
310 ctx.arc(w-padding-rounded, 0+padding+rounded, rounded, (math.pi/2 )+(math.pi) , 0)
311
312
313 ctx.line_to(w-padding, h-padding-rounded)
314 ctx.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
315
316
317 ctx.line_to(0+padding+rounded, h-padding)
318 ctx.arc(0+padding+rounded, h-padding-rounded, rounded,math.pi/2, math.pi)
319
320
321 ctx.line_to(0+padding, 0+padding+rounded)
322 ctx.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi, (math.pi/2 )+(math.pi))
323
324
325 if fill:ctx.fill()
326 else: ctx.stroke()
327 ctx.restore()
328
330 """@DEPRECATED Moved to Screenlets class: Gets a picture width and height"""
331
332 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
333 iw = pixbuf.get_width()
334 ih = pixbuf.get_height()
335 puxbuf = None
336 return iw,ih
337
339 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path"""
340
341 ctx.save()
342 ctx.translate(x, y)
343 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
344 format = cairo.FORMAT_RGB24
345 if pixbuf.get_has_alpha():
346 format = cairo.FORMAT_ARGB32
347
348 iw = pixbuf.get_width()
349 ih = pixbuf.get_height()
350 image = cairo.ImageSurface(format, iw, ih)
351 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
352
353 ctx.paint()
354 puxbuf = None
355 image = None
356 ctx.restore()
357
358
359
361 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path with a certain width and height"""
362
363 ctx.save()
364 ctx.translate(x, y)
365 pixbuf = gtk.gdk.pixbuf_new_from_file(pix).scale_simple(w,h,gtk.gdk.INTERP_HYPER)
366 format = cairo.FORMAT_RGB24
367 if pixbuf.get_has_alpha():
368 format = cairo.FORMAT_ARGB32
369
370 iw = pixbuf.get_width()
371 ih = pixbuf.get_height()
372 image = cairo.ImageSurface(format, iw, ih)
373
374 matrix = cairo.Matrix(xx=iw/w, yy=ih/h)
375 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
376 if image != None :image.set_matrix(matrix)
377 ctx.paint()
378 puxbuf = None
379 image = None
380 ctx.restore()
381
388
390 """@DEPRECATED Moved to Screenlets class: hide notification window"""
391 if self.notify != None:
392 self.notify.hide()
393 self.notify = None
394
403
409
411 """Check if this theme contains overrides for options."""
412 return len(self.option_overrides) > 0
413
415 """Load a config-file from this theme's dir and save vars in list."""
416 ini = utils.IniReader()
417 if ini.load(filename):
418 if ini.has_section('Theme'):
419 self.__name__ = ini.get_option('name', section='Theme')
420 self.__author__ = ini.get_option('author', section='Theme')
421 self.__version__ = ini.get_option('version', section='Theme')
422 self.__info__ = ini.get_option('info', section='Theme')
423 if ini.has_section('Options'):
424 opts = ini.list_options(section='Options')
425 if opts:
426 for o in opts:
427 self.option_overrides[o[0]] = o[1]
428 print _("theme.conf loaded: ")
429 print _("Name: ") + str(self.__name__)
430 print _("Author: ") +str(self.__author__)
431 print _("Version: ") +str(self.__version__)
432 print _("Info: ") +str(self.__info__)
433 else:
434 print _("Failed to load theme.conf")
435
436
438 """Load an SVG-file into this theme and reference it as ref_name."""
439 if self.has_key(filename):
440 del self[filename]
441 self[filename] = rsvg.Handle(self.path + "/" + filename)
442 self.svgs[filename[:-4]] = self[filename]
443 if self[filename] != None:
444
445 size=self[filename].get_dimension_data()
446 if size:
447 self.width = size[0]
448 self.height = size[1]
449 return True
450 else:
451 return False
452 self[filename] = None
453
455 """Load a PNG-file into this theme and reference it as ref_name."""
456 if self.has_key(filename):
457 del self[filename]
458 self[filename] = cairo.ImageSurface.create_from_png(self.path +
459 "/" + filename)
460 self.pngs[filename[:-4]] = self[filename]
461 if self[filename] != None:
462 return True
463 else:
464 return False
465 self[filename] = None
466
468 """Load all files in the theme's path. Currently only loads SVGs and
469 PNGs."""
470
471
472
473 dirlst = glob.glob(self.path + '/*')
474 if len(dirlst)==0:
475 return False
476 plen = len(self.path) + 1
477 for file in dirlst:
478 fname = file[plen:]
479 if fname.endswith('.svg'):
480
481 if self.load_svg(fname) == False:
482 return False
483 elif fname.endswith('.png'):
484
485 if self.load_png(fname) == False:
486 return False
487 elif fname == "theme.conf":
488 print _("theme.conf found! Loading option-overrides.")
489
490 if self.load_conf(file) == False:
491 return False
492 return True
493
495 """Re-Load all files in the theme's path."""
496 self.free()
497 self.__load_all()
498
499
501 """Deletes the Theme's contents and frees all rsvg-handles.
502 TODO: freeing rsvg-handles does NOT work for some reason"""
503 self.option_overrides.clear()
504 for filename in self:
505
506 del filename
507 self.clear()
508
509
510
511
512 - def render (self, ctx, name):
513 """Render an image from within this theme to the given context. This
514 function can EITHER use png OR svg images, so it is possible to
515 create themes using both image-formats when a Screenlet uses this
516 function for drawing its images. The image name has to be defined
517 without the extension and the function will automatically select
518 the available one (SVG is prefered over PNG)."""
519 """if self.has_key(name + '.svg'):
520 self[name + '.svg'].render_cairo(ctx)
521 else:
522 ctx.set_source_surface(self[name + '.png'], 0, 0)
523 ctx.paint()"""
524 try:
525
526 self.svgs[name].render_cairo(ctx)
527 except:
528
529 ctx.set_source_surface(self.pngs[name], 0, 0)
530 ctx.paint()
531
532
533
534
535
536
537 -class Screenlet (gobject.GObject, EditableOptions):
538 """A Screenlet is a (i.e. contains a) shaped gtk-window that is
539 fully invisible by default. Subclasses of Screenlet can render
540 their owner-drawn graphics on fully transparent background."""
541
542
543 __name__ = _('No name set for this Screenlet')
544 __version__ = '0.0'
545 __author__ = _('No author defined for this Screenlet')
546 __desc__ = _('No info set for this Screenlet')
547 __requires__ = []
548
549
550
551
552
553 id = ''
554 window = None
555 theme = None
556 uses_theme = True
557 draw_buttons = True
558 show_buttons = True
559 menu = None
560 is_dragged = False
561 quit_on_close = True
562 saving_enabled = True
563 dragging_over = False
564 disable_updates = False
565 p_context = None
566 p_layout = None
567
568
569 x = 0
570 y = 0
571 mousex = 0
572 mousey = 0
573 mouse_is_over = False
574 width = 100
575 height = 100
576 scale = 1.0
577 opacity = 1.0
578 theme_name = ""
579 is_visible = True
580 is_sticky = False
581 is_widget = False
582 keep_above = True
583 keep_below = False
584 skip_pager = True
585 first_run = False
586 skip_taskbar = True
587 lock_position = False
588 allow_option_override = True
589 ask_on_option_override = True
590 has_started = False
591 has_focus = False
592
593 __lastx = 0
594 __lasty = 0
595 p_fdesc = None
596 p_layout = None
597 tooltip = None
598 notify = None
599
600
601 __mi_keep_above = None
602 __mi_keep_below = None
603 __mi_widget = None
604 __mi_sticky = None
605 __mi_lock = None
606
607 __gsignals__ = dict(screenlet_removed=(gobject.SIGNAL_RUN_FIRST,
608 gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)))
609
610 - def __init__ (self, id='', width=100, height=100, parent_window=None,
611 show_window=True, is_widget=False, is_sticky=False,
612 uses_theme=True, draw_buttons=True,path=os.getcwd(), drag_drop=False, session=None,
613 enable_saving=True, service_class=services.ScreenletService,
614 uses_pango=False, is_sizable=True, ask_on_option_override=True):
615 """Constructor - should only be subclassed"""
616
617
618 super(Screenlet, self).__init__()
619 EditableOptions.__init__(self)
620
621 self.id = id
622 self.session = session
623 self.service = None
624
625 if self.id and service_class:
626 self.register_service(service_class)
627
628 self.service.instance_added(self.id)
629 self.width = width
630 self.height = height
631 self.is_dragged = False
632 self.__path__ = path
633 self.saving_enabled = enable_saving
634
635 self.__dict__['theme_name'] = ""
636 self.__dict__['is_widget'] = is_widget
637 self.__dict__['is_sticky'] = is_sticky
638 self.__dict__['draw_buttons'] = draw_buttons
639 self.__dict__['x'] = 0
640 self.__dict__['y'] = 0
641
642
643
644
645 self.__shape_bitmap = None
646 self.__shape_bitmap_width = 0
647 self.__shape_bitmap_height = 0
648
649 self.add_options_group('Screenlet',
650 _('The basic settings for this Screenlet-instance.'))
651
652
653
654 if draw_buttons: self.draw_buttons = True
655 else: self.draw_buttons = False
656 if uses_theme:
657 self.uses_theme = True
658 self.add_option(StringOption('Screenlet', 'theme_name',
659 'default', '', '', hidden=True))
660
661 self.add_option(IntOption('Screenlet', 'x',
662 0, _('X-Position'), _('The X-position of this Screenlet ...'),
663 min=0, max=gtk.gdk.screen_width()))
664 self.add_option(IntOption('Screenlet', 'y',
665 0, _('Y-Position'), _('The Y-position of this Screenlet ...'),
666 min=0, max=gtk.gdk.screen_height()))
667 self.add_option(IntOption('Screenlet', 'width',
668 width, _('Width'), _('The width of this Screenlet ...'),
669 min=16, max=1000, hidden=True))
670 self.add_option(IntOption('Screenlet', 'height',
671 height, _('Height'), _('The height of this Screenlet ...'),
672 min=16, max=1000, hidden=True))
673 self.add_option(FloatOption('Screenlet', 'scale',
674 self.scale, _('Scale'), _('The scale-factor of this Screenlet ...'),
675 min=0.1, max=10.0, digits=2, increment=0.1))
676 self.add_option(FloatOption('Screenlet', 'opacity',
677 self.opacity, _('Opacity'), _('The opacity of the Screenlet window ...'),
678 min=0.1, max=1.0, digits=2, increment=0.1))
679 self.add_option(BoolOption('Screenlet', 'is_sticky',
680 is_sticky, _('Stick to Desktop'),
681 _('Show this Screenlet on all workspaces ...')))
682 self.add_option(BoolOption('Screenlet', 'is_widget',
683 is_widget, _('Treat as Widget'),
684 _('Treat this Screenlet as a "Widget" ...')))
685 self.add_option(BoolOption('Screenlet', 'is_dragged',
686 self.is_dragged, "Is the screenlet dragged","Is the screenlet dragged", hidden=True))
687 self.add_option(BoolOption('Screenlet', 'is_sizable',
688 is_sizable, "Can the screenlet be resized","is_sizable", hidden=True))
689 self.add_option(BoolOption('Screenlet', 'is_visible',
690 self.is_visible, "Usefull to use screenlets as gnome panel applets","is_visible", hidden=True))
691 self.add_option(BoolOption('Screenlet', 'lock_position',
692 self.lock_position, _('Lock position'),
693 _('Stop the screenlet from being moved...')))
694 self.add_option(BoolOption('Screenlet', 'keep_above',
695 self.keep_above, _('Keep above'),
696 _('Keep this Screenlet above other windows ...')))
697 self.add_option(BoolOption('Screenlet', 'keep_below',
698 self.keep_below, _('Keep below'),
699 _('Keep this Screenlet below other windows ...')))
700 self.add_option(BoolOption('Screenlet', 'draw_buttons',
701 self.draw_buttons, _('Draw button controls'),
702 _('Draw buttons in top right corner')))
703 self.add_option(BoolOption('Screenlet', 'skip_pager',
704 self.skip_pager, _('Skip Pager'),
705 _('Set this Screenlet to show/hide in pagers ...')))
706 self.add_option(BoolOption('Screenlet', 'skip_taskbar',
707 self.skip_pager, _('Skip Taskbar'),
708 _('Set this Screenlet to show/hide in taskbars ...')))
709 if uses_theme:
710 self.ask_on_option_override = ask_on_option_override
711 self.add_option(BoolOption('Screenlet', 'allow_option_override',
712 self.allow_option_override, _('Allow overriding Options'),
713 _('Allow themes to override options in this screenlet ...')))
714 self.add_option(BoolOption('Screenlet', 'ask_on_option_override',
715 self.ask_on_option_override, _('Ask on Override'),
716 _('Show a confirmation-dialog when a theme wants to override ')+\
717 _('the current options of this Screenlet ...')))
718
719 self.disable_option('width')
720 self.disable_option('height')
721
722 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
723 if parent_window:
724 self.window.set_parent_window(parent_window)
725 self.window.set_transient_for(parent_window)
726 self.window.set_destroy_with_parent(True)
727 self.window.resize(width, height)
728 self.window.set_decorated(False)
729 self.window.set_app_paintable(True)
730
731 if uses_pango:
732 self.p_context = self.window.get_pango_context()
733 if self.p_context:
734 self.p_layout = pango.Layout(self.p_context)
735 self.p_layout.set_font_description(\
736 pango.FontDescription("Sans 12"))
737
738
739 if str(sensors.sys_get_window_manager()).lower() == 'kwin':
740 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
741
742 elif str(sensors.sys_get_window_manager()).lower() == 'sawfish':
743 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
744 else:
745 self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_TOOLBAR)
746 self.window.set_keep_above(True)
747 self.window.set_skip_taskbar_hint(True)
748 self.window.set_skip_pager_hint(True)
749 if is_sticky:
750 self.window.stick()
751 self.alpha_screen_changed(self.window)
752 self.update_shape()
753
754 self.window.set_events(gtk.gdk.ALL_EVENTS_MASK)
755 self.window.connect("composited-changed", self.composite_changed)
756 self.window.connect("delete_event", self.delete_event)
757 self.window.connect("destroy", self.destroy)
758 self.window.connect("expose_event", self.expose)
759 self.window.connect("button-press-event", self.button_press)
760 self.window.connect("button-release-event", self.button_release)
761 self.window.connect("configure-event", self.configure_event)
762 self.window.connect("screen-changed", self.alpha_screen_changed)
763 self.window.connect("realize", self.realize_event)
764 self.window.connect("enter-notify-event", self.enter_notify_event)
765 self.window.connect("leave-notify-event", self.leave_notify_event)
766 self.window.connect("focus-in-event", self.focus_in_event)
767 self.window.connect("focus-out-event", self.focus_out_event)
768 self.window.connect("scroll-event", self.scroll_event)
769 self.window.connect("motion-notify-event",self.motion_notify_event)
770 self.window.connect("map-event", self.map_event)
771 self.window.connect("unmap-event", self.unmap_event)
772
773 self.window.connect("key-press-event", self.key_press)
774
775 if drag_drop:
776 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
777 gtk.DEST_DEFAULT_DROP,
778 [("text/plain", 0, 0),
779 ("image", 0, 1),
780 ("text/uri-list", 0, 2)],
781 gtk.gdk.ACTION_COPY)
782 self.window.connect("drag_data_received", self.drag_data_received)
783 self.window.connect("drag-begin", self.drag_begin)
784 self.window.connect("drag-end", self.drag_end)
785 self.window.connect("drag-motion", self.drag_motion)
786 self.window.connect("drag-leave", self.drag_leave)
787
788 self.menu = gtk.Menu()
789
790
791
792 if show_window:
793 self.window.show()
794 print os.environ['HOME'] + '/.config/Screenlets/' + self.__name__[:-9] + '/default/'+ self.id
795 if not os.path.exists(os.environ['HOME'] + '/.config/Screenlets/' + self.__name__[:-9] + '/default/'+ self.id + '.ini'):
796 self.first_run = True
797 self.window.hide()
798
800
801 self.on_before_set_atribute(name, value)
802 gobject.GObject.__setattr__(self, name, value)
803
804 if name=="x" or name=="y":
805 if self.has_started:
806 self.window.move(self.x, self.y)
807 elif name == 'opacity':
808 self.window.set_opacity(value)
809 elif name == 'scale':
810 self.window.resize(int(self.width * self.scale),
811 int(self.height * self.scale))
812
813 self.on_scale()
814 self.redraw_canvas()
815 self.update_shape()
816
817
818 elif name == "theme_name":
819
820 print _("LOAD NEW THEME: ") + value
821 print _("FOUND: ") + str(self.find_theme(value))
822
823
824 path = self.find_theme(value)
825 if path:
826 self.load_theme(path)
827
828 self.redraw_canvas()
829 self.update_shape()
830 elif name in ("width", "height"):
831
832 if self.window:
833 self.window.resize(int(self.width*self.scale), int(self.height*self.scale))
834
835 self.update_shape()
836 elif name == "is_widget":
837 if self.has_started:
838 self.set_is_widget(value)
839 elif name == "is_visible":
840 if self.has_started:
841 if value == True:
842 self.reshow()
843 else:
844 self.window.hide()
845 elif name == "is_sticky":
846 if value == True:
847 self.window.stick()
848 else:
849 self.window.unstick()
850
851
852 elif name == "keep_above":
853 if self.has_started == True:
854 self.window.set_keep_above(bool(value))
855
856 elif name == "keep_below":
857 if self.has_started == True:
858 self.window.set_keep_below(bool(value))
859
860 elif name == "skip_pager":
861 if self.window.window:
862 self.window.window.set_skip_pager_hint(bool(value))
863 elif name == "skip_taskbar":
864 if self.window.window:
865 self.window.window.set_skip_taskbar_hint(bool(value))
866
867
868 if self.saving_enabled:
869 o = self.get_option_by_name(name)
870 if o != None:
871 self.session.backend.save_option(self.id, o.name,
872 o.on_export(value))
873 self.on_after_set_atribute(name, value)
874
875
876
877
878
879
880
881
883 """Appends the default menu-items to self.menu. You can add on OR'ed
884 flag with DefaultMenuItems you want to add."""
885 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'
886
887 if len(self.menu.get_children()) > 0:
888 self.add_menuitem("", "-")
889
890
891
892
893 menu = self.menu
894
895 if flags & DefaultMenuItem.XML:
896
897 xfile = self.get_screenlet_dir() + "/menu.xml"
898 xmlmenu = XmlMenu.create_menu_from_file(xfile,
899 self.menuitem_callback)
900 if xmlmenu:
901 self.menu = xmlmenu
902 pass
903
904 if flags & DefaultMenuItem.SIZE:
905 size_item = gtk.MenuItem(_("Size"))
906 size_item.show()
907 size_menu = gtk.Menu()
908 menu.append(size_item)
909 size_item.set_submenu(size_menu)
910
911 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):
912 s = str(int(i * 100))
913 item = gtk.MenuItem(s + " %")
914 item.connect("activate", self.menuitem_callback,
915 "scale:"+str(i))
916 item.show()
917 size_menu.append(item)
918
919 if flags & DefaultMenuItem.THEMES:
920 themes_item = gtk.MenuItem(_("Theme"))
921 themes_item.show()
922 themes_menu = gtk.Menu()
923 menu.append(themes_item)
924 themes_item.set_submenu(themes_menu)
925
926 lst = self.get_available_themes()
927 for tname in lst:
928 item = gtk.MenuItem(tname)
929 item.connect("activate", self.menuitem_callback,
930 "theme:"+tname)
931 item.show()
932 themes_menu.append(item)
933
934 if flags & DefaultMenuItem.WINDOW_MENU:
935 winmenu_item = gtk.MenuItem(_("Window"))
936 winmenu_item.show()
937 winmenu_menu = gtk.Menu()
938 menu.append(winmenu_item)
939 winmenu_item.set_submenu(winmenu_menu)
940
941 self.__mi_lock = item = gtk.CheckMenuItem(_("Lock"))
942 item.set_active(self.lock_position)
943 item.connect("activate", self.menuitem_callback,
944 "option:lock")
945 item.show()
946 winmenu_menu.append(item)
947
948 self.__mi_sticky = item = gtk.CheckMenuItem(_("Sticky"))
949 item.set_active(self.is_sticky)
950 item.connect("activate", self.menuitem_callback,
951 "option:sticky")
952 item.show()
953 winmenu_menu.append(item)
954
955 self.__mi_widget = item = gtk.CheckMenuItem(_("Widget"))
956 item.set_active(self.is_widget)
957 item.connect("activate", self.menuitem_callback,
958 "option:widget")
959 item.show()
960 winmenu_menu.append(item)
961
962 self.__mi_keep_above = item = gtk.CheckMenuItem(_("Keep above"))
963 item.set_active(self.keep_above)
964 item.connect("activate", self.menuitem_callback,
965 "option:keep_above")
966 item.show()
967 winmenu_menu.append(item)
968
969 self.__mi_keep_below = item = gtk.CheckMenuItem(_("Keep below"))
970 item.set_active(self.keep_below)
971 item.connect("activate", self.menuitem_callback,
972 "option:keep_below")
973 item.show()
974 winmenu_menu.append(item)
975
976 if flags & DefaultMenuItem.PROPERTIES:
977 self.add_menuitem("", "-")
978 self.add_menuitem("options", _("Properties..."))
979
980 if flags & DefaultMenuItem.INFO:
981 self.add_menuitem("", "-")
982 self.add_menuitem("info", _("Info..."))
983
984 if flags & DefaultMenuItem.DELETE:
985 self.add_menuitem("", "-")
986 self.add_menuitem("delete", _("Delete Screenlet ..."))
987
988 self.add_menuitem("", "-")
989 self.add_menuitem("quit_instance", _("Quit this %s ...") % self.get_short_name())
990
991 self.add_menuitem("", "-")
992 self.add_menuitem("quit", _("Quit all %ss ...") % self.get_short_name())
993
995 """Simple way to add menuitems to the right-click menu."""
996 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'
997 if callback == None:
998 callback = self.menuitem_callback
999 if label == "-":
1000 menu_item = gtk.SeparatorMenuItem()
1001 else:
1002 menu_item = gtk.MenuItem(label)
1003 menu_item.connect("activate", callback, id)
1004 self.menu.append(menu_item)
1005 menu_item.show()
1006 return menu_item
1007
1030
1031 - def clear_cairo_context (self, ctx):
1032 """Fills the given cairo.Context with fully transparent white."""
1033 ctx.save()
1034 ctx.set_source_rgba(1, 1, 1, 0)
1035 ctx.set_operator (cairo.OPERATOR_SOURCE)
1036 ctx.paint()
1037 ctx.restore()
1038
1040 """Close this Screenlet
1041 TODO: send close-notify instead of destroying window?"""
1042
1043 self.window.unmap()
1044 self.window.destroy()
1045
1046
1048 """Create drag-icon and -mask for drag-operation. Returns a 2-tuple
1049 with the icon and the mask. To supply your own icon you can use the
1050 on_create_drag_icon-handler and return the icon/mask as 2-tuple."""
1051 w = self.width
1052 h = self.height
1053 icon, mask = self.on_create_drag_icon()
1054 if icon == None:
1055
1056 icon = gtk.gdk.Pixmap(self.window.window, w, h)
1057 ctx = icon.cairo_create()
1058 self.clear_cairo_context(ctx)
1059 self.on_draw(ctx)
1060 if mask == None:
1061
1062 mask = gtk.gdk.Pixmap(self.window.window, w, h)
1063 ctx = mask.cairo_create()
1064 self.clear_cairo_context(ctx)
1065 self.on_draw_shape(ctx)
1066 return (icon, mask)
1067
1069 """Enable/Disable realtime-saving of options."""
1070 self.saving_enabled = enabled
1071
1073 """Find the first occurence of a theme and return its global path."""
1074 sn = self.get_short_name()
1075 for p in SCREENLETS_PATH:
1076 fpath = p + '/' + sn + '/themes/' + name
1077 if os.path.isdir(fpath):
1078 return fpath
1079 return None
1080
1082 """Return the short name of this screenlet. This returns the classname
1083 of the screenlet without trailing "Screenlet". Please always use
1084 this function if you want to retrieve the short name of a Screenlet."""
1085 return self.__class__.__name__[:-9]
1086
1088 """Return the name of this screenlet's personal directory."""
1089 p = utils.find_first_screenlet_path(self.get_short_name())
1090 if p:
1091 return p
1092 else:
1093 if self.__path__ != '':
1094 return self.__path__
1095 else:
1096 return os.getcwd()
1097
1099 """Return the name of this screenlet's personal theme-dir.
1100 (Only returns the dir under the screenlet's location"""
1101 return self.get_screenlet_dir() + "/themes/"
1102
1104 """Returns a list with the names of all available themes in this
1105 Screenlet's theme-directory."""
1106 lst = []
1107 for p in SCREENLETS_PATH:
1108 d = p + '/' + self.get_short_name() + '/themes/'
1109 if os.path.isdir(d):
1110
1111 dirlst = glob.glob(d + '*')
1112 dirlst.sort()
1113 tdlen = len(d)
1114 for fname in dirlst:
1115 dname = fname[tdlen:]
1116
1117 lst.append(dname)
1118 return lst
1119
1133
1135 """Called when screenlet finishes loading"""
1136
1137
1138 self.window.present()
1139
1140
1141
1142 self.window.hide()
1143 self.window.move(self.x, self.y)
1144 self.window.present()
1145 self.has_started = True
1146 self.is_dragged = False
1147 self.keep_above= self.keep_above
1148 self.keep_below= self.keep_below
1149 self.skip_taskbar = self.skip_taskbar
1150 self.window.set_skip_taskbar_hint(self.skip_taskbar)
1151 self.window.set_keep_above(self.keep_above)
1152 self.window.set_keep_below(self.keep_below)
1153
1154 self.on_init()
1155 if self.is_widget:
1156 self.set_is_widget(True)
1157 self.has_focus = False
1158 ini = utils.IniReader()
1159 if ini.load (os.environ['HOME'] + '/.screenlets' + '/config.ini') and self.first_run:
1160
1161 if ini.get_option('Lock', section='Options') == 'True':
1162 self.lock_position = True
1163 elif ini.get_option('Lock', section='Options') == 'False':
1164 self.lock_position = False
1165 if ini.get_option('Sticky', section='Options') == 'True':
1166 self.is_sticky = True
1167 elif ini.get_option('Sticky', section='Options') == 'False':
1168 self.is_sticky = False
1169 if ini.get_option('Widget', section='Options') == 'True':
1170 self.is_widget = True
1171 elif ini.get_option('Widget', section='Options') == 'False':
1172 self.is_widget = False
1173 if ini.get_option('Keep_above', section='Options') == 'True':
1174 self.keep_above = True
1175 elif ini.get_option('Keep_above', section='Options') == 'False':
1176 self.keep_above = False
1177 if ini.get_option('Keep_below', section='Options') == 'True':
1178 self.keep_below = True
1179 elif ini.get_option('Keep_below', section='Options') == 'False':
1180 self.keep_below = False
1181 if ini.get_option('draw_buttons', section='Options') == 'True':
1182 self.draw_buttons = True
1183 elif ini.get_option('draw_buttons', section='Options') == 'False':
1184 self.draw_buttons = False
1185
1187 """Hides this Screenlet's underlying gtk.Window"""
1188 self.window.hide()
1189 self.on_hide()
1190
1191
1192
1193
1217
1218
1220 """If the Screenlet runs as stand-alone app, starts gtk.main()"""
1221 gtk.main()
1222
1224 """Register or create the given ScreenletService-(sub)class as the new
1225 service for this Screenlet. If self is not the first instance in the
1226 current session, the service from the first instance will be used
1227 instead and no new service is created."""
1228 if self.session:
1229 if len(self.session.instances) == 0:
1230
1231 if service_classobj==services.ScreenletService:
1232 self.service = service_classobj(self, self.get_short_name())
1233 else:
1234
1235 self.service = service_classobj(self)
1236 else:
1237 self.service = self.session.instances[0].service
1238
1239 return True
1240 return False
1241
1261
1263 """Show this Screenlet's underlying gtk.Window"""
1264 self.window.show()
1265 self.window.move(self.x, self.y)
1266 self.on_show()
1267
1269 """Show the EditableSettingsDialog for this Screenlet."""
1270 se = OptionsDialog(490, 450)
1271 img = gtk.Image()
1272 try:
1273 d = self.get_screenlet_dir()
1274 if os.path.isfile(d + '/icon.svg'):
1275 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.svg')
1276 elif os.path.isfile(d + '/icon.png'):
1277 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.png')
1278 img.set_from_pixbuf(icn)
1279 except:
1280 img.set_from_stock(gtk.STOCK_PROPERTIES, 5)
1281 se.set_title(self.__name__)
1282 se.set_info(self.__name__, self.__desc__, '(c) ' + self.__author__,
1283 version='v' + self.__version__, icon=img)
1284 se.show_options_for_object(self)
1285 resp = se.run()
1286 if resp == gtk.RESPONSE_REJECT:
1287 se.reset_to_defaults()
1288 else:
1289 self.update_shape()
1290 se.destroy()
1291
1306
1307
1319
1321 """Removed shaped window , in case the nom composited shape has been set"""
1322 if self.window.window:
1323 self.window.window.shape_combine_mask(None,0,0)
1324
1326 """Update window shape (only call this when shape has changed
1327 because it is very ressource intense if ran too often)."""
1328
1329 if self.disable_updates:
1330 return
1331 print _("UPDATING SHAPE")
1332
1333
1334
1335
1336 w = int(self.width * self.scale)
1337 h = int(self.height * self.scale)
1338
1339 if w==0: w = 100
1340 if h==0: h = 100
1341
1342 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1343 data = ''.zfill(w*h)
1344 self.__shape_bitmap = gtk.gdk.bitmap_create_from_data(None, data,
1345 w, h)
1346 self.__shape_bitmap_width = w
1347 self.__shape_bitmap_height = h
1348
1349 ctx = self.__shape_bitmap.cairo_create()
1350 self.clear_cairo_context(ctx)
1351 if self.has_focus and self.draw_buttons and self.show_buttons:
1352 ctx.save()
1353 theme1 = gtk.icon_theme_get_default()
1354
1355
1356 close = theme1.load_icon ("gtk-close", 16, 0)
1357 prop = theme1.load_icon ("gtk-properties", 16, 0)
1358
1359
1360
1361
1362 ctx.translate((self.width*self.scale)-16,0)
1363 ctx.set_source_pixbuf(close, 0, 0)
1364 ctx.paint()
1365 ctx.restore()
1366 ctx.save()
1367 ctx.translate((self.width*self.scale)-32,0)
1368 ctx.set_source_pixbuf(prop, 0, 0)
1369 ctx.paint()
1370 ctx.restore()
1371
1372
1373 if self.window.is_composited():
1374
1375 self.on_draw_shape(ctx)
1376
1377 self.window.input_shape_combine_mask(self.__shape_bitmap, 0, 0)
1378 else:
1379 try: self.on_draw(ctx)
1380 except: self.on_draw_shape(ctx)
1381
1382 self.window.shape_combine_mask(self.__shape_bitmap,0,0)
1383 self.on_update_shape()
1384
1386 """TEST: This function is intended to shape the window whenever no
1387 composited environment can be found. (NOT WORKING YET!!!!)"""
1388
1389
1390 w = int(self.width * self.scale)
1391 h = int(self.height * self.scale)
1392
1393 if w==0: w = 100
1394 if h==0: h = 100
1395
1396 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1397 data = ''.zfill(w*h)
1398 self.__shape_bitmap = gtk.gdk.pixbuf_new_from_data(data,
1399 gtk.gdk.COLORSPACE_RGB, True, 1, w, h, w)
1400 self.__shape_bitmap_width = w
1401 self.__shape_bitmap_height = h
1402
1403
1404 if self.__shape_bitmap:
1405
1406 (pixmap,mask) = self.__shape_bitmap.render_pixmap_and_mask(255)
1407
1408 self.window.shape_combine_mask(mask)
1409
1410
1411
1412
1413
1415 """Called when the Screenlet gets deleted. Return True to cancel.
1416 TODO: sometimes not properly called"""
1417 return not show_question(self, _("To quit all %s's, use 'Quit' instead. ") % self.__class__.__name__ +\
1418 _('Really delete this %s and its settings?') % self.get_short_name())
1419 """return not show_question(self, 'Deleting this instance of the '+\
1420 self.__name__ + ' will also delete all your personal '+\
1421 'changes you made to it!! If you just want to close the '+\
1422 'application, use "Quit" instead. Are you sure you want to '+\
1423 'delete this instance?')
1424 return False"""
1425
1426
1427
1428
1430 """Called after setting screenlet atributes"""
1431 pass
1432
1434 """Called before setting screenlet atributes"""
1435 pass
1436
1437
1439 """Called when the screenlet's drag-icon is created. You can supply
1440 your own icon and mask by returning them as a 2-tuple."""
1441 return (None, None)
1442
1444 """Called when screenlet was mapped"""
1445 pass
1446
1448 """Called when screenlet was unmapped"""
1449 pass
1450
1452 """Called when composite state has changed"""
1453 pass
1454
1455
1457 """Called when the Screenlet gets dragged."""
1458 pass
1459
1461 """Called when something gets dragged into the Screenlets area."""
1462 pass
1463
1465 """Called when something gets dragged out of the Screenlets area."""
1466 pass
1467
1469 """Callback for drawing the Screenlet's window - override
1470 in subclasses to implement your own drawing."""
1471 pass
1472
1474 """Callback for drawing the Screenlet's shape - override
1475 in subclasses to draw the window's input-shape-mask."""
1476 pass
1477
1478 - def on_drop (self, x, y, sel_data, timestamp):
1479 """Called when a selection is dropped on this Screenlet."""
1480 return False
1481
1483 """Called when the Screenlet's window receives focus."""
1484 pass
1485
1487 """Called when the Screenlet gets hidden."""
1488 pass
1489
1491 """Called when the Screenlet's options have been applied and the
1492 screenlet finished its initialization. If you want to have your
1493 Screenlet do things on startup you should use this handler."""
1494 pass
1495
1496 - def on_key_down (self, keycode, keyvalue, event=None):
1497 """Called when a key is pressed within the screenlet's window."""
1498 pass
1499
1501 """Called when the theme is reloaded (after loading, before redraw)."""
1502 pass
1503
1505 """Called when a menuitem is selected."""
1506 pass
1507
1509 """Called when a buttonpress-event occured in Screenlet's window.
1510 Returning True causes the event to be not further propagated."""
1511 return False
1512
1514 """Called when the mouse enters the Screenlet's window."""
1515 pass
1516
1518 """Called when the mouse leaves the Screenlet's window."""
1519 pass
1520
1522 """Called when the mouse moves in the Screenlet's window."""
1523 pass
1524
1526 """Called when a buttonrelease-event occured in Screenlet's window.
1527 Returning True causes the event to be not further propagated."""
1528 return False
1529
1531 """Callback for handling destroy-event. Perform your cleanup here!"""
1532 return True
1533
1535 """"Callback for handling the realize-event."""
1536
1538 """Called when Screenlet.scale is changed."""
1539 pass
1540
1544
1548
1550 """Called when the Screenlet gets shown after being hidden."""
1551 pass
1552
1556
1558 """Called when the Screenlet's window loses focus."""
1559 pass
1560
1562 """Called when the Screenlet's window is updating shape"""
1563 pass
1564
1565
1566
1567
1569 """set colormap for window"""
1570 if screen==None:
1571 screen = window.get_screen()
1572 map = screen.get_rgba_colormap()
1573 if map:
1574 pass
1575 else:
1576 map = screen.get_rgb_colormap()
1577 window.set_colormap(map)
1578
1617
1624
1647
1648
1666
1668
1669 print "delete_event"
1670 if self.on_delete() == True:
1671 print _("Cancel delete_event")
1672 return True
1673 else:
1674 self.close()
1675 return False
1676
1677 - def destroy (self, widget, data=None):
1689
1694
1695
1697 return self.on_drop(x, y, sel_data, timestamp)
1698
1699 - def drag_end (self, widget, drag_context):
1700 print _("End drag")
1701 self.is_dragged = False
1702 return False
1703
1704 - def drag_motion (self, widget, drag_context, x, y, timestamp):
1710
1711 - def drag_leave (self, widget, drag_context, timestamp):
1715
1717
1718 self.__dict__['mouse_is_over'] = True
1719 self.on_mouse_enter(event)
1720
1721
1722
1723 - def expose (self, widget, event):
1724 ctx = widget.window.cairo_create()
1725
1726 self.clear_cairo_context(ctx)
1727
1728 ctx.rectangle(event.area.x, event.area.y,
1729 event.area.width, event.area.height)
1730 ctx.clip()
1731
1732
1733
1734
1735 self.on_draw(ctx)
1736
1737 del ctx
1738 return False
1739
1745
1746
1747
1748
1754
1755
1756
1758 """Handle keypress events, needed for in-place editing."""
1759 self.on_key_down(event.keyval, event.string, event)
1760
1762
1763
1764 self.__dict__['mouse_is_over'] = False
1765 self.on_mouse_leave(event)
1766
1767
1768
1839
1842
1845
1847 self.__dict__['mousex'] = event.x / self.scale
1848 self.__dict__['mousey'] = event.y / self.scale
1849
1850 self.on_mouse_move(event)
1851
1858
1865
1866
1867
1868
1869
1870
1871
1872
1873 - def get_text_width(self, ctx, text, font):
1874 """Returns the pixel width of a given text"""
1875 ctx.save()
1876 if self.p_layout == None :
1877
1878 self.p_layout = ctx.create_layout()
1879 else:
1880
1881 ctx.update_layout(self.p_layout)
1882 if self.p_fdesc == None:self.p_fdesc = pango.FontDescription()
1883 else: pass
1884 self.p_fdesc.set_family_static(font)
1885 self.p_layout.set_font_description(self.p_fdesc)
1886 self.p_layout.set_text(text)
1887 extents, lextents = self.p_layout.get_pixel_extents()
1888 ctx.restore()
1889 return extents[2]
1890
1891 - def get_text_extents(self, ctx, text, font):
1892 """Returns the pixel extents of a given text"""
1893 ctx.save()
1894 if self.p_layout == None :
1895
1896 self.p_layout = ctx.create_layout()
1897 else:
1898
1899 ctx.update_layout(self.p_layout)
1900 if self.p_fdesc == None:self.p_fdesc = pango.FontDescription()
1901 else: pass
1902 self.p_fdesc.set_family_static(font)
1903 self.p_layout.set_font_description(self.p_fdesc)
1904 self.p_layout.set_text(text)
1905 extents, lextents = self.p_layout.get_pixel_extents()
1906 ctx.restore()
1907 return extents
1908
1910 try:
1911 icontheme = gtk.icon_theme_get_default()
1912 image = icontheme.load_icon (icon,32,32)
1913 image = None
1914 icontheme = None
1915 return True
1916 except:
1917 return False
1918
1919 - def draw_text(self, ctx, text, x, y, font, size, width, allignment=pango.ALIGN_LEFT,weight = 0, ellipsize = pango.ELLIPSIZE_NONE):
1920 """Draws text"""
1921 ctx.save()
1922 ctx.translate(x, y)
1923 if self.p_layout == None :
1924
1925 self.p_layout = ctx.create_layout()
1926 else:
1927
1928 ctx.update_layout(self.p_layout)
1929 if self.p_fdesc == None:self.p_fdesc = pango.FontDescription()
1930 else: pass
1931 self.p_fdesc.set_family_static(font)
1932 self.p_fdesc.set_size(size * pango.SCALE)
1933 self.p_fdesc.set_weight(weight)
1934 self.p_layout.set_font_description(self.p_fdesc)
1935 self.p_layout.set_width(width * pango.SCALE)
1936 self.p_layout.set_alignment(allignment)
1937 self.p_layout.set_ellipsize(ellipsize)
1938 self.p_layout.set_markup(text)
1939 ctx.show_layout(self.p_layout)
1940 ctx.restore()
1941
1942
1943 - def draw_circle(self,ctx,x,y,width,height,fill=True):
1944 """Draws a circule"""
1945 ctx.save()
1946 ctx.translate(x, y)
1947 ctx.arc(width/2,height/2,min(height,width)/2,0,2*math.pi)
1948 if fill:ctx.fill()
1949 else: ctx.stroke()
1950 ctx.restore()
1951
1952
1954 """Draws a circule"""
1955 ctx.save()
1956 ctx.translate(x, y)
1957 ctx.move_to(width-(width/3), height/3)
1958 ctx.line_to(width,height)
1959 ctx.rel_line_to(-(width-(width/3)), 0)
1960 ctx.close_path()
1961 if fill:ctx.fill()
1962 else: ctx.stroke()
1963 ctx.restore()
1964
1965 - def draw_line(self,ctx,start_x,start_y,end_x,end_y,line_width = 1,close=False,preserve=False):
1966 """Draws a line"""
1967 ctx.save()
1968 ctx.move_to(start_x, start_y)
1969 ctx.set_line_width(line_width)
1970 ctx.rel_line_to(end_x, end_y)
1971 if close : ctx.close_path()
1972 if preserve: ctx.stroke_preserve()
1973 else: ctx.stroke()
1974 ctx.restore()
1975
1977 """Draws a rectangle"""
1978 ctx.save()
1979 ctx.translate(x, y)
1980 ctx.rectangle (0,0,width,height)
1981 if fill:ctx.fill()
1982 else: ctx.stroke()
1983 ctx.restore()
1984
1985
1986 - def draw_rectangle_advanced (self, ctx, x, y, width, height, rounded_angles=(0,0,0,0), fill=True, border_size=0, border_color=(0,0,0,1), shadow_size=0, shadow_color=(0,0,0,0.5)):
1987 '''with this funktion you can create a rectangle in advanced mode'''
1988 ctx.save()
1989 ctx.translate(x, y)
1990 s = shadow_size
1991 w = width
1992 h = height
1993 rounded = rounded_angles
1994 if shadow_size > 0:
1995 ctx.save()
1996
1997 gradient = cairo.LinearGradient(0,s,0,0)
1998 gradient.add_color_stop_rgba(0,*shadow_color)
1999 gradient.add_color_stop_rgba(1,shadow_color[0], shadow_color[1], shadow_color[2], 0)
2000 ctx.set_source(gradient)
2001 ctx.rectangle(s+rounded[0],0, w-rounded[0]-rounded[1], s)
2002 ctx.fill()
2003
2004
2005 gradient = cairo.LinearGradient(0, s+h, 0, h+(s*2))
2006 gradient.add_color_stop_rgba(0,*shadow_color)
2007 gradient.add_color_stop_rgba(1,shadow_color[0], shadow_color[1], shadow_color[2], 0)
2008 ctx.set_source(gradient)
2009 ctx.rectangle(s+rounded[2], s+h, w-rounded[2]-rounded[3], s)
2010 ctx.fill()
2011
2012
2013 gradient = cairo.LinearGradient(s, 0, 0, 0)
2014 gradient.add_color_stop_rgba(0,*shadow_color)
2015 gradient.add_color_stop_rgba(1,shadow_color[0], shadow_color[1], shadow_color[2], 0)
2016 ctx.set_source(gradient)
2017 ctx.rectangle(0, s+rounded[0], s, h-rounded[0]-rounded[2])
2018 ctx.fill()
2019
2020
2021 gradient = cairo.LinearGradient(s+w, 0, (s*2)+w, 0)
2022 gradient.add_color_stop_rgba(0,*shadow_color)
2023 gradient.add_color_stop_rgba(1,shadow_color[0], shadow_color[1], shadow_color[2], 0)
2024 ctx.set_source(gradient)
2025 ctx.rectangle(s+w, s+rounded[1], s, h-rounded[1]-rounded[3])
2026 ctx.fill()
2027 ctx.restore
2028
2029
2030 gradient = cairo.RadialGradient(s+rounded[0], s+rounded[0], rounded[0], s+rounded[0], s+rounded[0], s+rounded[0])
2031 gradient.add_color_stop_rgba(0,*shadow_color)
2032 gradient.add_color_stop_rgba(1,shadow_color[0], shadow_color[1], shadow_color[2], 0)
2033 ctx.set_source(gradient)
2034 ctx.new_sub_path()
2035 ctx.arc(s,s,s, -math.pi, -math.pi/2)
2036 ctx.line_to(s+rounded[0],0)
2037 ctx.line_to(s+rounded[0],s)
2038 ctx.arc_negative(s+rounded[0],s+rounded[0],rounded[0], -math.pi/2, math.pi)
2039 ctx.line_to(0, s+rounded[0])
2040 ctx.close_path()
2041 ctx.fill()
2042
2043
2044 gradient = cairo.RadialGradient(w+s-rounded[1], s+rounded[1], rounded[1], w+s-rounded[1], s+rounded[1], s+rounded[1])
2045 gradient.add_color_stop_rgba(0,*shadow_color)
2046 gradient.add_color_stop_rgba(1,shadow_color[0], shadow_color[1], shadow_color[2], 0)
2047 ctx.set_source(gradient)
2048 ctx.new_sub_path()
2049 ctx.arc(w+s,s,s, -math.pi/2, 0)
2050 ctx.line_to(w+(s*2), s+rounded[1])
2051 ctx.line_to(w+s, s+rounded[1])
2052 ctx.arc_negative(w+s-rounded[1], s+rounded[1], rounded[1], 0, -math.pi/2)
2053 ctx.line_to(w+s-rounded[1], 0)
2054 ctx.close_path()
2055 ctx.fill()
2056
2057
2058 gradient = cairo.RadialGradient(s+rounded[2], h+s-rounded[2], rounded[2], s+rounded[2], h+s-rounded[2], s+rounded[2])
2059 gradient.add_color_stop_rgba(0,*shadow_color)
2060 gradient.add_color_stop_rgba(1,shadow_color[0], shadow_color[1], shadow_color[2], 0)
2061 ctx.set_source(gradient)
2062 ctx.new_sub_path()
2063 ctx.arc(s,h+s,s, math.pi/2, math.pi)
2064 ctx.line_to(0, h+s-rounded[2])
2065 ctx.line_to(s, h+s-rounded[2])
2066 ctx.arc_negative(s+rounded[2], h+s-rounded[2], rounded[2], -math.pi, math.pi/2)
2067 ctx.line_to(s+rounded[2], h+(s*2))
2068 ctx.close_path()
2069 ctx.fill()
2070
2071
2072 gradient = cairo.RadialGradient(w+s-rounded[3], h+s-rounded[3], rounded[3], w+s-rounded[3], h+s-rounded[3], s+rounded[3])
2073 gradient.add_color_stop_rgba(0,*shadow_color)
2074 gradient.add_color_stop_rgba(1,shadow_color[0], shadow_color[1], shadow_color[2], 0)
2075 ctx.set_source(gradient)
2076 ctx.new_sub_path()
2077 ctx.arc(w+s,h+s,s, 0, math.pi/2)
2078 ctx.line_to(w+s-rounded[3], h+(s*2))
2079 ctx.line_to(w+s-rounded[3], h+s)
2080 ctx.arc_negative(s+w-rounded[3], s+h-rounded[3], rounded[3], math.pi/2, 0)
2081 ctx.line_to((s*2)+w, s+h-rounded[3])
2082 ctx.close_path()
2083 ctx.fill()
2084 ctx.restore()
2085
2086
2087 ctx.translate(s, s)
2088 else:
2089 ctx.translate(border_size, border_size)
2090
2091
2092 if fill:
2093 ctx.line_to(0, rounded[0])
2094 ctx.arc(rounded[0], rounded[0], rounded[0], math.pi, -math.pi/2)
2095 ctx.line_to(w-rounded[1], 0)
2096 ctx.arc(w-rounded[1], rounded[1], rounded[1], -math.pi/2, 0)
2097 ctx.line_to(w, h-rounded[3])
2098 ctx.arc(w-rounded[3], h-rounded[3], rounded[3], 0, math.pi/2)
2099 ctx.line_to(rounded[2], h)
2100 ctx.arc(rounded[2], h-rounded[2], rounded[2], math.pi/2, -math.pi)
2101 ctx.close_path()
2102 ctx.fill()
2103
2104 if border_size > 0:
2105 ctx.save()
2106 ctx.line_to(0, rounded[0])
2107 ctx.arc(rounded[0], rounded[0], rounded[0], math.pi, -math.pi/2)
2108 ctx.line_to(w-rounded[1], 0)
2109 ctx.arc(w-rounded[1], rounded[1], rounded[1], -math.pi/2, 0)
2110 ctx.line_to(w, h-rounded[3])
2111 ctx.arc(w-rounded[3], h-rounded[3], rounded[3], 0, math.pi/2)
2112 ctx.line_to(rounded[2], h)
2113 ctx.arc(rounded[2], h-rounded[2], rounded[2], math.pi/2, -math.pi)
2114 ctx.close_path()
2115 ctx.set_source_rgba(*border_color)
2116 ctx.set_line_width(border_size)
2117 ctx.stroke()
2118 ctx.restore()
2119 ctx.restore()
2120
2121 - def draw_rounded_rectangle(self,ctx,x,y,rounded_angle,width,height,round_top_left = True ,round_top_right = True,round_bottom_left = True,round_bottom_right = True, fill=True):
2122 """Draws a rounded rectangle"""
2123 ctx.save()
2124 ctx.translate(x, y)
2125 padding=0
2126 rounded=rounded_angle
2127 w = width
2128 h = height
2129
2130
2131 ctx.move_to(0+padding+rounded, 0+padding)
2132
2133
2134 if round_top_right:
2135 ctx.line_to(w-padding-rounded, 0+padding)
2136 ctx.arc(w-padding-rounded, 0+padding+rounded, rounded, (math.pi/2 )+(math.pi) , 0)
2137 else:
2138 ctx.line_to(w-padding, 0+padding)
2139
2140
2141 if round_bottom_right:
2142 ctx.line_to(w-padding, h-padding-rounded)
2143 ctx.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
2144 else:
2145 ctx.line_to(w-padding, h-padding)
2146
2147 if round_bottom_left:
2148 ctx.line_to(0+padding+rounded, h-padding)
2149 ctx.arc(0+padding+rounded, h-padding-rounded, rounded,math.pi/2, math.pi)
2150 else:
2151 ctx.line_to(0+padding, h-padding)
2152
2153 if round_top_left:
2154 ctx.line_to(0+padding, 0+padding+rounded)
2155 ctx.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi, (math.pi/2 )+(math.pi))
2156 else:
2157 ctx.line_to(0+padding, 0+padding)
2158
2159 if fill:ctx.fill()
2160 else: ctx.stroke()
2161 ctx.restore()
2162
2164 gradient = cairo.RadialGradient(x,y,from_r,x,y,to_r)
2165 gradient.add_color_stop_rgba(0,col[0],col[1],col[2],col[3])
2166 gradient.add_color_stop_rgba(1,col[0],col[1],col[2],0)
2167 ctx.set_source(gradient)
2168 ctx.new_sub_path()
2169 if quad==0: ctx.arc(x,y,to_r, -math.pi, -math.pi/2)
2170 elif quad==1: ctx.arc(x,y,to_r, -math.pi/2, 0)
2171 elif quad==2: ctx.arc(x,y,to_r, math.pi/2, math.pi)
2172 elif quad==3: ctx.arc(x,y,to_r, 0, math.pi/2)
2173 ctx.line_to(x,y)
2174 ctx.close_path()
2175 ctx.fill()
2176
2177
2179 gradient = None
2180 if side==0:
2181 gradient = cairo.LinearGradient(x+w,y,x,y)
2182 elif side==1:
2183 gradient = cairo.LinearGradient(x,y,x+w,y)
2184 elif side==2:
2185 gradient = cairo.LinearGradient(x,y+h,x,y)
2186 elif side==3:
2187 gradient = cairo.LinearGradient(x,y,x,y+h)
2188 if gradient:
2189 gradient.add_color_stop_rgba(0,col[0],col[1],col[2],col[3])
2190 gradient.add_color_stop_rgba(1,col[0],col[1],col[2],0)
2191 ctx.set_source(gradient)
2192 ctx.rectangle(x,y,w,h)
2193 ctx.fill()
2194
2195 - def draw_shadow(self, ctx, x, y, w, h, shadow_size, col):
2196 s = shadow_size
2197
2198 r = s
2199 rr = r+s
2200 h = h-r
2201 if h < 2*r: h = 2*r
2202
2203
2204
2205 ctx.save()
2206 ctx.translate(x,y)
2207
2208
2209 self.draw_quadrant_shadow(ctx, rr, rr, 0, rr, 0, col)
2210
2211 self.draw_side_shadow(ctx, 0, rr, r+s, h-2*r, 0, col)
2212
2213 self.draw_quadrant_shadow(ctx, rr, h-r+s, 0, rr, 2, col)
2214
2215 self.draw_side_shadow(ctx, rr, h-r+s, w-2*r, s+r, 3, col)
2216
2217 self.draw_quadrant_shadow(ctx, w-r+s, h-r+s, 0, rr, 3, col)
2218
2219 self.draw_side_shadow(ctx, w-r+s, rr, s+r, h-2*r, 1, col)
2220
2221 self.draw_quadrant_shadow(ctx, w-r+s, rr, 0, rr, 1, col)
2222
2223 self.draw_side_shadow(ctx, rr, 0, w-2*r, s+r, 2, col)
2224
2225 ctx.restore()
2226
2227
2228
2230 """Gets a picture width and height"""
2231
2232 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
2233 iw = pixbuf.get_width()
2234 ih = pixbuf.get_height()
2235 puxbuf = None
2236 return iw,ih
2237
2239 """Draws a picture from specified path"""
2240
2241 ctx.save()
2242 ctx.translate(x, y)
2243 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
2244 format = cairo.FORMAT_RGB24
2245 if pixbuf.get_has_alpha():
2246 format = cairo.FORMAT_ARGB32
2247
2248 iw = pixbuf.get_width()
2249 ih = pixbuf.get_height()
2250 image = cairo.ImageSurface(format, iw, ih)
2251 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
2252
2253 ctx.paint()
2254 puxbuf = None
2255 image = None
2256 ctx.restore()
2257
2258 - def draw_icon(self,ctx,x,y, pix,width=32,height=32):
2259 """Draws a gtk icon """
2260
2261 ctx.save()
2262 ctx.translate(x, y)
2263 icontheme = gtk.icon_theme_get_default()
2264 image = icontheme.load_icon (pix,width,height)
2265 ctx.set_source_pixbuf(image, 0, 0)
2266 ctx.paint()
2267 icontheme = None
2268 image = None
2269 ctx.restore()
2270
2272 """Draws a picture from specified path with a certain width and height"""
2273
2274 ctx.save()
2275 ctx.translate(x, y)
2276 pixbuf = gtk.gdk.pixbuf_new_from_file(pix).scale_simple(w,h,gtk.gdk.INTERP_HYPER)
2277 format = cairo.FORMAT_RGB24
2278 if pixbuf.get_has_alpha():
2279 format = cairo.FORMAT_ARGB32
2280
2281 iw = pixbuf.get_width()
2282 ih = pixbuf.get_height()
2283 image = cairo.ImageSurface(format, iw, ih)
2284
2285 matrix = cairo.Matrix(xx=iw/w, yy=ih/h)
2286 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
2287 if image != None :image.set_matrix(matrix)
2288 ctx.paint()
2289 puxbuf = None
2290 image = None
2291 ctx.restore()
2292
2299
2301 """hide notification window"""
2302 if self.notify != None:
2303 self.notify.hide()
2304 self.notify = None
2305
2314
2320
2321
2403
2516
2518 """A window that displays a text and serves as Notification (very basic yet)."""
2519
2520
2521 __timeout = None
2522
2523
2524 text = ''
2525 font_name = 'FreeSans 9'
2526 width = 200
2527 height = 100
2528 x = 0
2529 y = 0
2530 gradient = cairo.LinearGradient(0, 100,0, 0)
2531
2553
2555 self.__dict__[name] = value
2556 if name in ('text'):
2557 if name == 'text':
2558 self.p_layout.set_markup(value)
2559 ink_rect, logical_rect = self.p_layout.get_pixel_extents()
2560 self.window.queue_draw()
2561
2568
2573
2578
2585
2588
2590 if screen == None:
2591 screen = window.get_screen()
2592 map = screen.get_rgba_colormap()
2593 if not map:
2594 map = screen.get_rgb_colormap()
2595 window.set_colormap(map)
2596
2597 - def expose (self, widget, event):
2598 ctx = self.window.window.cairo_create()
2599 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL)
2600
2601 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2602 ctx.clip()
2603
2604 ctx.set_source_rgba(1, 1, 1, 0)
2605 ctx.set_operator (cairo.OPERATOR_SOURCE)
2606 ctx.paint()
2607
2608 self.gradient.add_color_stop_rgba(1,0.3, 0.3, 0.3, 0.9)
2609 self.gradient.add_color_stop_rgba(0.3, 0, 0, 0, 0.9)
2610 ctx.set_source(self.gradient)
2611 ctx.rectangle(0, 0, self.width, self.height)
2612 ctx.fill()
2613
2614 ctx.save()
2615 ctx.translate(3, 3)
2616 ctx.set_source_rgba(1, 1, 1, 1)
2617 ctx.show_layout(self.p_layout)
2618 ctx.fill()
2619 ctx.restore()
2620 ctx.rectangle(0, 0, self.width, self.height)
2621 ctx.set_source_rgba(0, 0, 0, 0.7)
2622 ctx.stroke()
2623
2624
2625 """class TestWidget(ShapedWidget):
2626
2627 def __init__(self, width, height):
2628 #ShapedWidget.__init__(self, width, height)
2629 super(TestWidget, self).__init__(width, height)
2630
2631 def draw(self, ctx):
2632 if self.mouse_inside:
2633 ctx.set_source_rgba(1, 0, 0, 0.8)
2634 else:
2635 ctx.set_source_rgba(1, 1, 0, 0.8)
2636 ctx.rectangle(0, 0, 32, 32)
2637 ctx.fill()
2638 """
2639
2640
2641
2642
2643
2644
2645
2647 """Launch a screenlet, either through its service or by launching a new
2648 process of the given screenlet. Name has to be the name of the Screenlet's
2649 class without trailing 'Screenlet'.
2650 NOTE: we could only launch the file here"""
2651
2652 if services.service_is_running(name):
2653
2654 srvc = services.get_service_by_name(name)
2655 if srvc:
2656 try:
2657 srvc.add('')
2658 return True
2659 except Exception, ex:
2660 print "Error while adding instance by service: %s" % ex
2661
2662 path = utils.find_first_screenlet_path(name)
2663 if path:
2664
2665 slfile = path + '/' + name + 'Screenlet.py'
2666
2667 print "Launching Screenlet from: %s" % slfile
2668 if debug:
2669 print "Logging output goes to: $HOME/.config/Screenlets/%sScreenlet.log" % name
2670 out = '$HOME/.config/Screenlets/%sScreenlet.log' % name
2671 else:
2672 out = '/dev/null'
2673 os.system('python -u %s > %s &' % (slfile, out))
2674 return True
2675 else:
2676 print "Screenlet '%s' could not be launched." % name
2677 return False
2678
2680 """Show a message for the given Screenlet (may contain Pango-Markup).
2681 If screenlet is None, this function can be used by other objects as well."""
2682 if screenlet == None:
2683 md = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,
2684 buttons=gtk.BUTTONS_OK)
2685 md.set_title(title)
2686 else:
2687 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_INFO,
2688 buttons=gtk.BUTTONS_OK)
2689 md.set_title(screenlet.__name__)
2690 md.set_markup(message)
2691 md.run()
2692 md.destroy()
2693
2695 """Show a question for the given Screenlet (may contain Pango-Markup)."""
2696 if screenlet == None:
2697 md = gtk.MessageDialog(None, type=gtk.MESSAGE_QUESTION,
2698 buttons=gtk.BUTTONS_YES_NO)
2699 md.set_title(title)
2700 else:
2701 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_QUESTION,
2702 buttons=gtk.BUTTONS_YES_NO)
2703 md.set_title(screenlet.__name__)
2704 md.set_markup(message)
2705 response = md.run()
2706 md.destroy()
2707 if response == gtk.RESPONSE_YES:
2708 return True
2709 return False
2710
2711 -def show_error (screenlet, message, title='Error'):
2712 """Show an error for the given Screenlet (may contain Pango-Markup)."""
2713 if screenlet == None:
2714 md = gtk.MessageDialog(None, type=gtk.MESSAGE_ERROR,
2715 buttons=gtk.BUTTONS_OK)
2716 md.set_title(title)
2717 else:
2718 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_ERROR,
2719 buttons=gtk.BUTTONS_OK)
2720 md.set_title(screenlet.__name__)
2721 md.set_markup(message)
2722 md.run()
2723 md.destroy()
2724
2726 """Raise a fatal error to stdout and stderr and exit with an errorcode."""
2727 import sys
2728 msg = 'FATAL ERROR: %s\n' % message
2729 sys.stdout.write(msg)
2730 sys.stderr.write(msg)
2731 sys.exit(1)
2732
2733
2734
2736 fatal_error("This screenlet seems to be written for an older version of the framework. Please download a newer version of the %s." % name)
2737