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 try:
33 INSTALL_PREFIX = open("/etc/screenlets/prefix").read()[:-1]
34 except:
35 INSTALL_PREFIX = '/usr'
36
37 import pygtk
38 pygtk.require('2.0')
39 import gtk
40 import cairo, pango
41 import gobject
42 try:
43 import rsvg
44 except ImportError: print 'No module RSVG , graphics will not be so good'
45 import os
46 import glob
47 import gettext
48 import math
49
50
51 from options import *
52 import services
53 import utils
54 import sensors
55
56 import menu
57 from menu import DefaultMenuItem, add_menuitem
58 from drawing import Drawing
59
60
61
62
63
64
65
66
67 APP_NAME = "Screenlets"
68
69
70 VERSION = "0.1.2"
71
72
73 COPYRIGHT = "(c) RYX (Rico Pfaus) <ryx@ryxperience.com>\nWhise (Helder Fraga) <helder.fraga@hotmail.com>"
74
75
76 AUTHORS = ["RYX (Rico Pfaus) <ryx@ryxperience.com>", "Whise (Helder Fraga)<helder.fraga@hotmail.com>","Sorcerer (Hendrik Kaju)"]
77
78
79 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"
80
81 DOCUMENTERS = ["Documentation generated by epydoc"]
82
83 ARTISTS = ["ODD radio screenlet theme by ODDie\nPasodoble mail theme by jEsuSdA\nSome themes by RYX\nSome themes by Whise\nMore to come..."]
84
85 TRANSLATORS = "Special thanks for translators\nFull Translator list on https://translations.launchpad.net/screenlets/"
86
87
88 WEBSITE = 'http://www.screenlets.org'
89
90
91 THIRD_PARTY_DOWNLOAD = "http://screenlets.org/index.php/Category:UserScreenlets"
92
93
94
95
96
97 DIR_TMP = '/tmp/screenlets/'
98
99 TMP_DIR = DIR_TMP
100
101 TMP_FILE = 'screenlets.' + os.environ['USER'] + '.running'
102
103 DIR_USER_ROOT = screenlets.INSTALL_PREFIX + '/share/screenlets'
104
105 DIR_USER = os.environ['HOME'] + '/.screenlets'
106
107 DIR_CONFIG = os.environ['HOME'] + '/.config/Screenlets'
108
109 SCREENLETS_PATH = [DIR_USER,DIR_USER_ROOT]
110
111
112
113
114
115
116 DAEMON_BUS = 'org.screenlets.ScreenletsDaemon'
117
118 DAEMON_PATH = '/org/screenlets/ScreenletsDaemon'
119
120 DAEMON_IFACE = 'org.screenlets.ScreenletsDaemon'
121
122
123
124 DEBUG_MODE = True
125
126
127 gettext.textdomain('screenlets')
128 gettext.bindtextdomain('screenlets', INSTALL_PREFIX + '/share/locale')
129
131 return gettext.gettext(s)
132
133
134
135
136
137
157
158
160 """ScreenletThemes are simple storages that allow loading files
161 as svg-handles within a theme-directory. Each Screenlet can have
162 its own theme-directory. It is up to the Screenlet-developer if he
163 wants to let his Screenlet support themes or not. Themes are
164 turned off by default - if your Screenlet uses Themes, just set the
165 attribute 'theme_name' to the name of the theme's dir you want to use.
166 TODO: remove dict-inheritance"""
167
168
169 __name__ = ''
170 __author__ = ''
171 __version__ = ''
172 __info__ = ''
173
174
175 path = ""
176 loaded = False
177 width = 0
178 height = 0
179 option_overrides = {}
180 p_fdesc = None
181 p_layout = None
182 tooltip = None
183 notify = None
184
185
195
197 if name in ("width", "height"):
198 if self.loaded and len(self)>0:
199 size=self[0].get_dimension_data()
200 if name=="width":
201 return size[0]
202 else:
203 return size[1]
204 else:
205 return object.__getattr__(self, name)
206
234
235 - def check_entry (self, filename):
236 """Checks if a file with filename is loaded in this theme."""
237 try:
238 if self[filename]:
239 return True
240 except:
241
242 return False
243
244 - def get_text_width(self, ctx, text, font):
245 """@DEPRECATED Moved to Screenlets class: Returns the pixel width of a given text"""
246 ctx.save()
247
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(font)
255 self.p_layout.set_font_description(self.p_fdesc)
256 self.p_layout.set_text(text)
257 extents, lextents = self.p_layout.get_pixel_extents()
258 ctx.restore()
259 return extents[2]
260
261 - def get_text_extents(self, ctx, text, font):
262 """@DEPRECATED Moved to Screenlets class: Returns the pixel extents of a given text"""
263 ctx.save()
264
265 if self.p_layout == None :
266
267 self.p_layout = ctx.create_layout()
268 else:
269
270 ctx.update_layout(self.p_layout)
271 self.p_fdesc = pango.FontDescription(font)
272 self.p_layout.set_font_description(self.p_fdesc)
273 self.p_layout.set_text(text)
274 extents, lextents = self.p_layout.get_pixel_extents()
275 ctx.restore()
276 return extents
277
278 - def draw_text(self, ctx, text, x, y, font, size, width, allignment, weight = 0, ellipsize = pango.ELLIPSIZE_NONE):
279 """@DEPRECATED Moved to Screenlets class: Draws text"""
280 ctx.save()
281 ctx.translate(x, y)
282 if self.p_layout == None :
283
284 self.p_layout = ctx.create_layout()
285 else:
286
287 ctx.update_layout(self.p_layout)
288 self.p_fdesc = pango.FontDescription()
289 self.p_fdesc.set_family_static(font)
290 self.p_fdesc.set_size(size * pango.SCALE)
291 self.p_fdesc.set_weight(weight)
292 self.p_layout.set_font_description(self.p_fdesc)
293 self.p_layout.set_width(width * pango.SCALE)
294 self.p_layout.set_alignment(allignment)
295 self.p_layout.set_ellipsize(ellipsize)
296 self.p_layout.set_markup(text)
297 ctx.show_layout(self.p_layout)
298 ctx.restore()
299
300
302 """@DEPRECATED Moved to Screenlets class: Draws a circule"""
303 ctx.save()
304 ctx.translate(x, y)
305 ctx.arc(width/2,height/2,min(height,width)/2,0,2*math.pi)
306 if fill:ctx.fill()
307 else: ctx.stroke()
308 ctx.restore()
309
310 - def draw_line(self,ctx,start_x,start_y,end_x,end_y,line_width = 1,close=False,preserve=False):
311 """@DEPRECATED Moved to Screenlets class: Draws a line"""
312 ctx.save()
313 ctx.move_to(start_x, start_y)
314 ctx.set_line_width(line_width)
315 ctx.rel_line_to(end_x, end_y)
316 if close : ctx.close_path()
317 if preserve: ctx.stroke_preserve()
318 else: ctx.stroke()
319 ctx.restore()
320
322 """@DEPRECATED Moved to Screenlets class: Draws a rectangle"""
323 ctx.save()
324 ctx.translate(x, y)
325 ctx.rectangle (0,0,width,height)
326 if fill:ctx.fill()
327 else: ctx.stroke()
328 ctx.restore()
329
331 """@DEPRECATED Moved to Screenlets class: Draws a rounded rectangle"""
332 ctx.save()
333 ctx.translate(x, y)
334 padding=0
335 rounded=rounded_angle
336 w = width
337 h = height
338
339
340 ctx.move_to(0+padding+rounded, 0+padding)
341
342
343 ctx.line_to(w-padding-rounded, 0+padding)
344 ctx.arc(w-padding-rounded, 0+padding+rounded, rounded, (math.pi/2 )+(math.pi) , 0)
345
346
347 ctx.line_to(w-padding, h-padding-rounded)
348 ctx.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
349
350
351 ctx.line_to(0+padding+rounded, h-padding)
352 ctx.arc(0+padding+rounded, h-padding-rounded, rounded,math.pi/2, math.pi)
353
354
355 ctx.line_to(0+padding, 0+padding+rounded)
356 ctx.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi, (math.pi/2 )+(math.pi))
357
358
359 if fill:ctx.fill()
360 else: ctx.stroke()
361 ctx.restore()
362
364 """@DEPRECATED Moved to Screenlets class: Gets a picture width and height"""
365
366 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
367 iw = pixbuf.get_width()
368 ih = pixbuf.get_height()
369 puxbuf = None
370 return iw,ih
371
373 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path"""
374
375 ctx.save()
376 ctx.translate(x, y)
377 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
378 format = cairo.FORMAT_RGB24
379 if pixbuf.get_has_alpha():
380 format = cairo.FORMAT_ARGB32
381
382 iw = pixbuf.get_width()
383 ih = pixbuf.get_height()
384 image = cairo.ImageSurface(format, iw, ih)
385 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
386
387 ctx.paint()
388 puxbuf = None
389 image = None
390 ctx.restore()
391
392
393
395 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path with a certain width and height"""
396
397 ctx.save()
398 ctx.translate(x, y)
399 pixbuf = gtk.gdk.pixbuf_new_from_file(pix).scale_simple(w,h,gtk.gdk.INTERP_HYPER)
400 format = cairo.FORMAT_RGB24
401 if pixbuf.get_has_alpha():
402 format = cairo.FORMAT_ARGB32
403
404 iw = pixbuf.get_width()
405 ih = pixbuf.get_height()
406 image = cairo.ImageSurface(format, iw, ih)
407
408 matrix = cairo.Matrix(xx=iw/w, yy=ih/h)
409 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
410 if image != None :image.set_matrix(matrix)
411 ctx.paint()
412 puxbuf = None
413 image = None
414 ctx.restore()
415
422
424 """@DEPRECATED Moved to Screenlets class: hide notification window"""
425 if self.notify != None:
426 self.notify.hide()
427 self.notify = None
428
437
443
445 """Check if this theme contains overrides for options."""
446 return len(self.option_overrides) > 0
447
469
470
472 """Load an SVG-file into this theme and reference it as ref_name."""
473 if self.has_key(filename):
474 del self[filename]
475 try:
476 self[filename] = rsvg.Handle(self.path + "/" + filename)
477 self.svgs[filename[:-4]] = self[filename]
478 if self[filename] != None:
479
480 size=self[filename].get_dimension_data()
481 if size:
482 self.width = size[0]
483 self.height = size[1]
484 return True
485 except NameError, ex:
486 self[filename] = gtk.gdk.pixbuf_new_from_file(self.path + '/' + filename)
487 self.svgs[filename[:-4]] = self[filename]
488 if self[filename] != None:
489
490 self.width = self[filename].get_width()
491 self.height = self[filename].get_height()
492 print str(ex)
493 return True
494
495 else:
496 return False
497
498
500 """Load a PNG-file into this theme and reference it as ref_name."""
501 if self.has_key(filename):
502 del self[filename]
503 self[filename] = cairo.ImageSurface.create_from_png(self.path +
504 "/" + filename)
505 self.pngs[filename[:-4]] = self[filename]
506 if self[filename] != None:
507 return True
508 else:
509 return False
510
511
513 """Load all files in the theme's path. Currently only loads SVGs and
514 PNGs."""
515
516
517
518 dirlst = glob.glob(self.path + '/*')
519 if len(dirlst)==0:
520 return False
521 plen = len(self.path) + 1
522 for file in dirlst:
523 fname = file[plen:]
524 if fname.endswith('.svg'):
525
526 if self.load_svg(fname) == False:
527 return False
528 elif fname.endswith('.png'):
529
530 if self.load_png(fname) == False:
531 return False
532 elif fname == "theme.conf":
533 print _("theme.conf found! Loading option-overrides.")
534
535 if self.load_conf(file) == False:
536 return False
537 return True
538
540 """Re-Load all files in the theme's path."""
541 self.free()
542 self.__load_all()
543
544
546 """Deletes the Theme's contents and frees all rsvg-handles.
547 TODO: freeing rsvg-handles does NOT work for some reason"""
548 self.option_overrides.clear()
549 for filename in self:
550 try:
551 self[filename].free()
552 except AttributeError:pass
553
554 del filename
555 self.clear()
556
557
558
559
560 - def render (self, ctx, name):
561 """Render an image from within this theme to the given context. This
562 function can EITHER use png OR svg images, so it is possible to
563 create themes using both image-formats when a Screenlet uses this
564 function for drawing its images. The image name has to be defined
565 without the extension and the function will automatically select
566 the available one (SVG is prefered over PNG)."""
567
568
569 if os.path.isfile (self.path + '/' + name + '.svg'):
570
571 try:
572 self.svgs[name].render_cairo(ctx)
573 except:
574 try:
575 ctx.set_source_pixbuf(self.svgs[name], 0, 0)
576
577 ctx.paint()
578 pixbuf = None
579 except TypeError:
580 ctx.set_source_surface(self.pngs[name], 0, 0)
581 ctx.paint()
582
583 elif os.path.isfile (self.path + '/' + name + '.png'):
584 ctx.set_source_surface(self.pngs[name], 0, 0)
585 ctx.paint()
586
587
588
590
591 ctx.set_source_rgba(color[0], color[1], color[2], color[3])
592 ctx.set_source_surface(self.pngs[name], 0, 0)
593 ctx.mask_surface(image, 0, 0)
594 ctx.stroke()
595
596
597
598 -class Screenlet (gobject.GObject, EditableOptions, Drawing):
599 """A Screenlet is a (i.e. contains a) shaped gtk-window that is
600 fully invisible by default. Subclasses of Screenlet can render
601 their owner-drawn graphics on fully transparent background."""
602
603
604 __name__ = _('No name set for this Screenlet')
605 __version__ = '0.0'
606 __author__ = _('No author defined for this Screenlet')
607 __desc__ = _('No info set for this Screenlet')
608 __requires__ = []
609
610
611
612
613
614 id = ''
615 window = None
616 theme = None
617 uses_theme = True
618 draw_buttons = True
619 show_buttons = True
620 menu = None
621 is_dragged = False
622 quit_on_close = True
623 saving_enabled = True
624 dragging_over = False
625 disable_updates = False
626 p_context = None
627 p_layout = None
628
629
630 x = 0
631 y = 0
632 mousex = 0
633 mousey = 0
634 mouse_is_over = False
635 width = 100
636 height = 100
637 scale = 1.0
638 opacity = 1.0
639 theme_name = ""
640 is_visible = True
641 is_sticky = False
642 is_widget = False
643 keep_above = True
644 keep_below = False
645 skip_pager = True
646 first_run = False
647 skip_taskbar = True
648 lock_position = False
649 allow_option_override = True
650 ask_on_option_override = True
651 resize_on_scroll = True
652 has_started = False
653 has_focus = False
654
655 gtk_icon_theme = None
656 __lastx = 0
657 __lasty = 0
658 p_fdesc = None
659 p_layout = None
660 tooltip = None
661 notify = None
662
663
664 __mi_keep_above = None
665 __mi_keep_below = None
666 __mi_widget = None
667 __mi_sticky = None
668 __mi_lock = None
669
670 __gsignals__ = dict(screenlet_removed=(gobject.SIGNAL_RUN_FIRST,
671 gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)))
672
673 - def __init__ (self, id='', width=100, height=100, parent_window=None,
674 show_window=True, is_widget=False, is_sticky=False,
675 uses_theme=True, draw_buttons=True,path=os.getcwd(), drag_drop=False, session=None,
676 enable_saving=True, service_class=services.ScreenletService,
677 uses_pango=False, is_sizable=True,resize_on_scroll=True, ask_on_option_override=False):
678 """Constructor - should only be subclassed"""
679
680
681 super(Screenlet, self).__init__()
682 EditableOptions.__init__(self)
683
684 self.id = id
685 self.session = session
686 self.service = None
687
688 if self.id and service_class:
689 self.register_service(service_class)
690
691 self.service.instance_added(self.id)
692 self.width = width
693 self.height = height
694 self.is_dragged = False
695 self.__path__ = path
696 self.saving_enabled = enable_saving
697
698 self.__dict__['theme_name'] = ""
699 self.__dict__['is_widget'] = is_widget
700 self.__dict__['is_sticky'] = is_sticky
701 self.__dict__['draw_buttons'] = draw_buttons
702 self.resize_on_scroll = resize_on_scroll
703 self.__dict__['x'] = 0
704 self.__dict__['y'] = 0
705
706
707
708
709 self.__shape_bitmap = None
710 self.__shape_bitmap_width = 0
711 self.__shape_bitmap_height = 0
712
713 self.add_options_group('Screenlet',
714 _('The basic settings for this Screenlet-instance.'))
715
716
717
718 self.gtk_icon_theme = gtk.icon_theme_get_default()
719 self.load_buttons(None)
720 self.gtk_icon_theme.connect("changed", self.load_buttons)
721 if draw_buttons: self.draw_buttons = True
722 else: self.draw_buttons = False
723 if uses_theme:
724 self.uses_theme = True
725 self.add_option(StringOption('Screenlet', 'theme_name',
726 'default', '', '', hidden=True))
727
728 self.add_option(IntOption('Screenlet', 'x',
729 0, _('X-Position'), _('The X-position of this Screenlet ...'),
730 min=0, max=gtk.gdk.screen_width()))
731 self.add_option(IntOption('Screenlet', 'y',
732 0, _('Y-Position'), _('The Y-position of this Screenlet ...'),
733 min=0, max=gtk.gdk.screen_height()))
734 self.add_option(IntOption('Screenlet', 'width',
735 width, _('Width'), _('The width of this Screenlet ...'),
736 min=16, max=1000, hidden=True))
737 self.add_option(IntOption('Screenlet', 'height',
738 height, _('Height'), _('The height of this Screenlet ...'),
739 min=16, max=1000, hidden=True))
740 self.add_option(FloatOption('Screenlet', 'scale',
741 self.scale, _('Scale'), _('The scale-factor of this Screenlet ...'),
742 min=0.1, max=10.0, digits=2, increment=0.1))
743 self.add_option(FloatOption('Screenlet', 'opacity',
744 self.opacity, _('Opacity'), _('The opacity of the Screenlet window ...'),
745 min=0.1, max=1.0, digits=2, increment=0.1))
746 self.add_option(BoolOption('Screenlet', 'is_sticky',
747 is_sticky, _('Stick to Desktop'),
748 _('Show this Screenlet on all workspaces ...')))
749 self.add_option(BoolOption('Screenlet', 'is_widget',
750 is_widget, _('Treat as Widget'),
751 _('Treat this Screenlet as a "Widget" ...')))
752 self.add_option(BoolOption('Screenlet', 'is_dragged',
753 self.is_dragged, "Is the screenlet dragged","Is the screenlet dragged", hidden=True))
754 self.add_option(BoolOption('Screenlet', 'is_sizable',
755 is_sizable, "Can the screenlet be resized","is_sizable", hidden=True))
756 self.add_option(BoolOption('Screenlet', 'is_visible',
757 self.is_visible, "Usefull to use screenlets as gnome panel applets","is_visible", hidden=True))
758 self.add_option(BoolOption('Screenlet', 'lock_position',
759 self.lock_position, _('Lock position'),
760 _('Stop the screenlet from being moved...')))
761 self.add_option(BoolOption('Screenlet', 'keep_above',
762 self.keep_above, _('Keep above'),
763 _('Keep this Screenlet above other windows ...')))
764 self.add_option(BoolOption('Screenlet', 'keep_below',
765 self.keep_below, _('Keep below'),
766 _('Keep this Screenlet below other windows ...')))
767 self.add_option(BoolOption('Screenlet', 'draw_buttons',
768 self.draw_buttons, _('Draw button controls'),
769 _('Draw buttons in top right corner')))
770 self.add_option(BoolOption('Screenlet', 'skip_pager',
771 self.skip_pager, _('Skip Pager'),
772 _('Set this Screenlet to show/hide in pagers ...')))
773 self.add_option(BoolOption('Screenlet', 'skip_taskbar',
774 self.skip_pager, _('Skip Taskbar'),
775 _('Set this Screenlet to show/hide in taskbars ...')))
776 self.add_option(BoolOption('Screenlet', 'resize_on_scroll',
777 self.resize_on_scroll, _("Resize on mouse scroll"),"resize_on_scroll"))
778 if uses_theme:
779 self.ask_on_option_override = ask_on_option_override
780 self.add_option(BoolOption('Screenlet', 'allow_option_override',
781 self.allow_option_override, _('Allow overriding Options'),
782 _('Allow themes to override options in this screenlet ...')))
783 self.add_option(BoolOption('Screenlet', 'ask_on_option_override',
784 self.ask_on_option_override, _('Ask on Override'),
785 _('Show a confirmation-dialog when a theme wants to override ')+\
786 _('the current options of this Screenlet ...')))
787
788 self.disable_option('width')
789 self.disable_option('height')
790
791 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
792 if parent_window:
793 self.window.set_parent_window(parent_window)
794 self.window.set_transient_for(parent_window)
795 self.window.set_destroy_with_parent(True)
796 self.window.resize(width, height)
797 self.window.set_decorated(False)
798 self.window.set_app_paintable(True)
799
800 if uses_pango:
801 self.p_context = self.window.get_pango_context()
802 if self.p_context:
803 self.p_layout = pango.Layout(self.p_context)
804 self.p_layout.set_font_description(\
805 pango.FontDescription("Sans 12"))
806
807
808 if str(sensors.sys_get_window_manager()).lower() == 'kwin':
809 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
810
811 elif str(sensors.sys_get_window_manager()).lower() == 'sawfish':
812 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
813 else:
814 self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_TOOLBAR)
815 self.window.set_keep_above(True)
816 self.window.set_skip_taskbar_hint(True)
817 self.window.set_skip_pager_hint(True)
818 if is_sticky:
819 self.window.stick()
820 self.alpha_screen_changed(self.window)
821 self.update_shape()
822
823 self.window.set_events(gtk.gdk.ALL_EVENTS_MASK)
824 self.window.connect("composited-changed", self.composite_changed)
825 self.window.connect("delete_event", self.delete_event)
826 self.window.connect("destroy", self.destroy)
827 self.window.connect("expose_event", self.expose)
828 self.window.connect("button-press-event", self.button_press)
829 self.window.connect("button-release-event", self.button_release)
830 self.window.connect("configure-event", self.configure_event)
831 self.window.connect("screen-changed", self.alpha_screen_changed)
832 self.window.connect("realize", self.realize_event)
833 self.window.connect("enter-notify-event", self.enter_notify_event)
834 self.window.connect("leave-notify-event", self.leave_notify_event)
835 self.window.connect("focus-in-event", self.focus_in_event)
836 self.window.connect("focus-out-event", self.focus_out_event)
837 self.window.connect("scroll-event", self.scroll_event)
838 self.window.connect("motion-notify-event",self.motion_notify_event)
839 self.window.connect("map-event", self.map_event)
840 self.window.connect("unmap-event", self.unmap_event)
841
842 self.window.connect("key-press-event", self.key_press)
843
844 if drag_drop:
845 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
846 gtk.DEST_DEFAULT_DROP,
847 [("text/plain", 0, 0),
848 ("image", 0, 1),
849 ("text/uri-list", 0, 2)],
850 gtk.gdk.ACTION_COPY)
851 self.window.connect("drag_data_received", self.drag_data_received)
852 self.window.connect("drag-begin", self.drag_begin)
853 self.window.connect("drag-end", self.drag_end)
854 self.window.connect("drag-motion", self.drag_motion)
855 self.window.connect("drag-leave", self.drag_leave)
856
857 self.menu = gtk.Menu()
858
859
860
861 if show_window:
862 self.window.show()
863 print os.environ['HOME'] + '/.config/Screenlets/' + self.__name__[:-9] + '/default/'+ self.id
864 if not os.path.exists(os.environ['HOME'] + '/.config/Screenlets/' + self.__name__[:-9] + '/default/'+ self.id + '.ini'):
865 self.first_run = True
866 self.window.hide()
867
869
870 self.on_before_set_atribute(name, value)
871 gobject.GObject.__setattr__(self, name, value)
872
873 if name=="x" or name=="y":
874 if self.has_started:
875 self.window.move(self.x, self.y)
876 elif name == 'opacity':
877 self.window.set_opacity(value)
878 elif name == 'scale':
879 self.window.resize(int(self.width * self.scale),
880 int(self.height * self.scale))
881
882 self.on_scale()
883 self.redraw_canvas()
884 self.update_shape()
885
886
887 elif name == "theme_name":
888
889 print _("LOAD NEW THEME: ") + value
890 print _("FOUND: ") + str(self.find_theme(value))
891
892
893 path = self.find_theme(value)
894 if path:
895 self.load_theme(path)
896
897 self.redraw_canvas()
898 self.update_shape()
899 elif name in ("width", "height"):
900
901 if self.window:
902 self.window.resize(int(self.width*self.scale), int(self.height*self.scale))
903
904 self.update_shape()
905 elif name == "is_widget":
906 if self.has_started:
907 self.set_is_widget(value)
908 elif name == "is_visible":
909 if self.has_started:
910 if value == True:
911 self.reshow()
912 else:
913 self.window.hide()
914 elif name == "is_sticky":
915 if value == True:
916 self.window.stick()
917 else:
918 self.window.unstick()
919
920
921 elif name == "keep_above":
922 if self.has_started == True:
923 self.window.set_keep_above(bool(value))
924
925 elif name == "keep_below":
926 if self.has_started == True:
927 self.window.set_keep_below(bool(value))
928
929 elif name == "skip_pager":
930 if self.window.window:
931 self.window.window.set_skip_pager_hint(bool(value))
932 elif name == "skip_taskbar":
933 if self.window.window:
934 self.window.window.set_skip_taskbar_hint(bool(value))
935
936
937 if self.saving_enabled:
938 o = self.get_option_by_name(name)
939 if o != None:
940 self.session.backend.save_option(self.id, o.name,
941 o.on_export(value))
942 self.on_after_set_atribute(name, value)
943
944
945
946
947
948
950 """Appends the default menu-items to self.menu. You can add on OR'ed
951 flag with DefaultMenuItems you want to add."""
952 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'
953
954 menu = self.menu
955
956
957 if len(menu.get_children()) > 0:
958 self.add_menuitem("", "-")
959
960 if flags & DefaultMenuItem.XML:
961
962 xfile = self.get_screenlet_dir() + "/menu.xml"
963 xmlmenu = screenlets.menu.create_menu_from_file(xfile,
964 self.menuitem_callback)
965 if xmlmenu:
966 self.menu = xmlmenu
967
968 if flags & DefaultMenuItem.SIZE:
969 size_item = gtk.MenuItem(_("Size"))
970 size_item.show()
971 size_menu = gtk.Menu()
972 menu.append(size_item)
973 size_item.set_submenu(size_menu)
974
975 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):
976 s = str(int(i * 100))
977 item = gtk.MenuItem(s + " %")
978 item.connect("activate", self.menuitem_callback,
979 "scale:"+str(i))
980 item.show()
981 size_menu.append(item)
982
983 if flags & DefaultMenuItem.THEMES:
984 themes_item = gtk.MenuItem(_("Theme"))
985 themes_item.show()
986 themes_menu = gtk.Menu()
987 menu.append(themes_item)
988 themes_item.set_submenu(themes_menu)
989
990 lst = self.get_available_themes()
991 for tname in lst:
992 item = gtk.MenuItem(tname)
993 item.connect("activate", self.menuitem_callback, "theme:"+tname)
994 item.show()
995 themes_menu.append(item)
996
997
998 if flags & DefaultMenuItem.WINDOW_MENU:
999 winmenu_item = gtk.MenuItem(_("Window"))
1000 winmenu_item.show()
1001 winmenu_menu = gtk.Menu()
1002 menu.append(winmenu_item)
1003 winmenu_item.set_submenu(winmenu_menu)
1004
1005 self.__mi_lock = item = gtk.CheckMenuItem(_("Lock"))
1006 item.set_active(self.lock_position)
1007 item.connect("activate", self.menuitem_callback,
1008 "option:lock")
1009 item.show()
1010 winmenu_menu.append(item)
1011
1012 self.__mi_sticky = item = gtk.CheckMenuItem(_("Sticky"))
1013 item.set_active(self.is_sticky)
1014 item.connect("activate", self.menuitem_callback,
1015 "option:sticky")
1016 item.show()
1017 winmenu_menu.append(item)
1018
1019 self.__mi_widget = item = gtk.CheckMenuItem(_("Widget"))
1020 item.set_active(self.is_widget)
1021 item.connect("activate", self.menuitem_callback,
1022 "option:widget")
1023 item.show()
1024 winmenu_menu.append(item)
1025
1026 self.__mi_keep_above = item = gtk.CheckMenuItem(_("Keep above"))
1027 item.set_active(self.keep_above)
1028 item.connect("activate", self.menuitem_callback,
1029 "option:keep_above")
1030 item.show()
1031 winmenu_menu.append(item)
1032
1033 self.__mi_keep_below = item = gtk.CheckMenuItem(_("Keep below"))
1034 item.set_active(self.keep_below)
1035 item.connect("activate", self.menuitem_callback,
1036 "option:keep_below")
1037 item.show()
1038 winmenu_menu.append(item)
1039
1040
1041 if flags & DefaultMenuItem.PROPERTIES:
1042 add_menuitem(menu, "-", self.menuitem_callback, "")
1043 add_menuitem(menu, _("Properties..."), self.menuitem_callback, "options")
1044
1045 if flags & DefaultMenuItem.INFO:
1046 add_menuitem(menu, "-", self.menuitem_callback, "")
1047 add_menuitem(menu, _("Info..."), self.menuitem_callback, "info")
1048
1049 if flags & DefaultMenuItem.DELETE:
1050 add_menuitem(menu, "-", self.menuitem_callback, "")
1051 add_menuitem(menu, _("Delete Screenlet ..."), self.menuitem_callback, "delete")
1052
1053 if flags & DefaultMenuItem.QUIT:
1054 add_menuitem(menu, "-", self.menuitem_callback, "")
1055 add_menuitem(menu, _("Quit this %s ...") % self.get_short_name(), self.menuitem_callback, "quit_instance")
1056
1057 if flags & DefaultMenuItem.QUIT_ALL:
1058 add_menuitem(menu, "-", self.menuitem_callback, "")
1059 add_menuitem(menu, _("Quit all %ss ...") % self.get_short_name(), self.menuitem_callback, "quit")
1060
1062 """Simple way to add menuitems to a right-click menu.
1063 This function wraps screenlets.menu.add_menuitem.
1064 For backwards compatibility, the order of the parameters
1065 to this function is switched."""
1066 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'
1067 if callback is None:
1068 callback = self.menuitem_callback
1069
1070 return add_menuitem(self.menu, label, callback, id)
1071
1073 """Simple way to add submenuitems to the right-click menu through a list."""
1074 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'
1075
1076 submenu = gtk.MenuItem(label)
1077 submenu.show()
1078 sub_menu = gtk.Menu()
1079 self.menu.append(submenu)
1080 submenu.set_submenu(sub_menu)
1081
1082
1083 for tname in lst:
1084 item = gtk.MenuItem(tname)
1085 item.connect("activate", self.menuitem_callback,
1086 tname)
1087 item.show()
1088 sub_menu.append(item)
1089
1090 return submenu
1091
1092
1093
1097
1118
1119 - def clear_cairo_context (self, ctx):
1120 """Fills the given cairo.Context with fully transparent white."""
1121 ctx.save()
1122 ctx.set_source_rgba(1, 1, 1, 0)
1123 ctx.set_operator (cairo.OPERATOR_SOURCE)
1124 ctx.paint()
1125 ctx.restore()
1126
1128 """Close this Screenlet
1129 TODO: send close-notify instead of destroying window?"""
1130
1131 self.window.unmap()
1132 self.window.destroy()
1133
1134
1136 """Create drag-icon and -mask for drag-operation. Returns a 2-tuple
1137 with the icon and the mask. To supply your own icon you can use the
1138 on_create_drag_icon-handler and return the icon/mask as 2-tuple."""
1139 w = self.width
1140 h = self.height
1141 icon, mask = self.on_create_drag_icon()
1142 if icon == None:
1143
1144 icon = gtk.gdk.Pixmap(self.window.window, w, h)
1145 ctx = icon.cairo_create()
1146 self.clear_cairo_context(ctx)
1147 self.on_draw(ctx)
1148 if mask == None:
1149
1150 mask = gtk.gdk.Pixmap(self.window.window, w, h)
1151 ctx = mask.cairo_create()
1152 self.clear_cairo_context(ctx)
1153 self.on_draw_shape(ctx)
1154 return (icon, mask)
1155
1157 """Enable/Disable realtime-saving of options."""
1158 self.saving_enabled = enabled
1159
1161 """Find the first occurence of a theme and return its global path."""
1162 sn = self.get_short_name()
1163 for p in SCREENLETS_PATH:
1164 fpath = p + '/' + sn + '/themes/' + name
1165 if os.path.isdir(fpath):
1166 return fpath
1167 return None
1168
1170 """Return the short name of this screenlet. This returns the classname
1171 of the screenlet without trailing "Screenlet". Please always use
1172 this function if you want to retrieve the short name of a Screenlet."""
1173 return self.__class__.__name__[:-9]
1174
1176 """Return the name of this screenlet's personal directory."""
1177 p = utils.find_first_screenlet_path(self.get_short_name())
1178 if p:
1179 return p
1180 else:
1181 if self.__path__ != '':
1182 return self.__path__
1183 else:
1184 return os.getcwd()
1185
1187 """Return the name of this screenlet's personal theme-dir.
1188 (Only returns the dir under the screenlet's location"""
1189 return self.get_screenlet_dir() + "/themes/"
1190
1192 """Returns a list with the names of all available themes in this
1193 Screenlet's theme-directory."""
1194 lst = []
1195 for p in SCREENLETS_PATH:
1196 d = p + '/' + self.get_short_name() + '/themes/'
1197 if os.path.isdir(d):
1198
1199 dirlst = glob.glob(d + '*')
1200 dirlst.sort()
1201 tdlen = len(d)
1202 for fname in dirlst:
1203 dname = fname[tdlen:]
1204
1205 lst.append(dname)
1206 return lst
1207
1221
1223 """Called when screenlet finishes loading"""
1224
1225
1226 self.window.present()
1227
1228
1229
1230 self.window.hide()
1231 self.window.move(self.x, self.y)
1232 self.window.show()
1233 self.has_started = True
1234 self.is_dragged = False
1235 self.keep_above= self.keep_above
1236 self.keep_below= self.keep_below
1237 self.is_sticky = self.is_sticky
1238 self.skip_taskbar = self.skip_taskbar
1239 self.window.set_skip_taskbar_hint(self.skip_taskbar)
1240 self.window.set_keep_above(self.keep_above)
1241 self.window.set_keep_below(self.keep_below)
1242
1243 self.on_init()
1244 if self.is_widget:
1245 self.set_is_widget(True)
1246 self.has_focus = False
1247 ini = utils.IniReader()
1248 if ini.load (os.environ['HOME'] + '/.screenlets' + '/config.ini') and self.first_run:
1249
1250 if ini.get_option('Lock', section='Options') == 'True':
1251 self.lock_position = True
1252 elif ini.get_option('Lock', section='Options') == 'False':
1253 self.lock_position = False
1254 if ini.get_option('Sticky', section='Options') == 'True':
1255 self.is_sticky = True
1256 elif ini.get_option('Sticky', section='Options') == 'False':
1257 self.is_sticky = False
1258 if ini.get_option('Widget', section='Options') == 'True':
1259 self.is_widget = True
1260 elif ini.get_option('Widget', section='Options') == 'False':
1261 self.is_widget = False
1262 if ini.get_option('Keep_above', section='Options') == 'True':
1263 self.keep_above = True
1264 elif ini.get_option('Keep_above', section='Options') == 'False':
1265 self.keep_above = False
1266 if ini.get_option('Keep_below', section='Options') == 'True':
1267 self.keep_below = True
1268 elif ini.get_option('Keep_below', section='Options') == 'False':
1269 self.keep_below = False
1270 if ini.get_option('draw_buttons', section='Options') == 'True':
1271 self.draw_buttons = True
1272 elif ini.get_option('draw_buttons', section='Options') == 'False':
1273 self.draw_buttons = False
1274
1276 """Hides this Screenlet's underlying gtk.Window"""
1277 self.window.hide()
1278 self.on_hide()
1279
1280
1281
1282
1306
1307
1309 """If the Screenlet runs as stand-alone app, starts gtk.main()"""
1310 gtk.main()
1311
1313 """Register or create the given ScreenletService-(sub)class as the new
1314 service for this Screenlet. If self is not the first instance in the
1315 current session, the service from the first instance will be used
1316 instead and no new service is created."""
1317 if self.session:
1318 if len(self.session.instances) == 0:
1319
1320 if service_classobj==services.ScreenletService:
1321 self.service = service_classobj(self, self.get_short_name())
1322 else:
1323
1324 self.service = service_classobj(self)
1325 else:
1326 self.service = self.session.instances[0].service
1327
1328 return True
1329 return False
1330
1350
1352 """Show this Screenlet's underlying gtk.Window"""
1353 self.window.show()
1354 self.window.move(self.x, self.y)
1355 self.on_show()
1356
1358 """Show the EditableSettingsDialog for this Screenlet."""
1359 se = OptionsDialog(490, 450)
1360 img = gtk.Image()
1361 try:
1362 d = self.get_screenlet_dir()
1363 if os.path.isfile(d + '/icon.svg'):
1364 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.svg')
1365 elif os.path.isfile(d + '/icon.png'):
1366 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.png')
1367 img.set_from_pixbuf(icn)
1368 except:
1369 img.set_from_stock(gtk.STOCK_PROPERTIES, 5)
1370 se.set_title(self.__name__)
1371 se.set_info(self.__name__, self.__desc__, '(c) ' + self.__author__,
1372 version='v' + self.__version__, icon=img)
1373 se.show_options_for_object(self)
1374 resp = se.run()
1375 if resp == gtk.RESPONSE_REJECT:
1376 se.reset_to_defaults()
1377 else:
1378 self.update_shape()
1379 se.destroy()
1380
1382 """Redraw the entire Screenlet's window area.
1383 TODO: store window alloaction in class and change when size changes."""
1384
1385 if self.disable_updates:
1386 return
1387 if self.window:
1388 x, y, w, h = self.window.get_allocation()
1389 rect = gtk.gdk.Rectangle(x, y, w, h)
1390 if self.window.window:
1391 self.window.window.invalidate_rect(rect, True)
1392 self.window.window.process_updates(True)
1393
1394
1395
1396
1408
1410 """Removed shaped window , in case the nom composited shape has been set"""
1411 if self.window.window:
1412 self.window.window.shape_combine_mask(None,0,0)
1413
1415 """Update window shape (only call this when shape has changed
1416 because it is very ressource intense if ran too often)."""
1417
1418 if self.disable_updates:
1419 return
1420
1421
1422
1423
1424
1425 w = int(self.width * self.scale)
1426 h = int(self.height * self.scale)
1427
1428 if w==0: w = 100
1429 if h==0: h = 100
1430
1431 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1432 data = ''.zfill(w*h)
1433 self.__shape_bitmap = gtk.gdk.bitmap_create_from_data(None, data,
1434 w, h)
1435 self.__shape_bitmap_width = w
1436 self.__shape_bitmap_height = h
1437
1438 ctx = self.__shape_bitmap.cairo_create()
1439 self.clear_cairo_context(ctx)
1440 if self.has_focus and self.draw_buttons and self.show_buttons:
1441 ctx.save()
1442
1443
1444
1445
1446
1447
1448
1449
1450 ctx.translate((self.width*self.scale)-16,0)
1451 ctx.set_source_pixbuf(self.closeb, 0, 0)
1452 ctx.paint()
1453 ctx.restore()
1454 ctx.save()
1455 ctx.translate((self.width*self.scale)-32,0)
1456 ctx.set_source_pixbuf(self.prop, 0, 0)
1457 ctx.paint()
1458 ctx.restore()
1459
1460
1461 if self.window.is_composited():
1462
1463 self.on_draw_shape(ctx)
1464
1465 self.window.input_shape_combine_mask(self.__shape_bitmap, 0, 0)
1466 else:
1467 try: self.on_draw(ctx)
1468 except: self.on_draw_shape(ctx)
1469
1470 self.window.shape_combine_mask(self.__shape_bitmap,0,0)
1471 self.on_update_shape()
1472
1474 """TEST: This function is intended to shape the window whenever no
1475 composited environment can be found. (NOT WORKING YET!!!!)"""
1476
1477
1478 w = int(self.width * self.scale)
1479 h = int(self.height * self.scale)
1480
1481 if w==0: w = 100
1482 if h==0: h = 100
1483
1484 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1485 data = ''.zfill(w*h)
1486 self.__shape_bitmap = gtk.gdk.pixbuf_new_from_data(data,
1487 gtk.gdk.COLORSPACE_RGB, True, 1, w, h, w)
1488 self.__shape_bitmap_width = w
1489 self.__shape_bitmap_height = h
1490
1491
1492 if self.__shape_bitmap:
1493
1494 (pixmap,mask) = self.__shape_bitmap.render_pixmap_and_mask(255)
1495
1496 self.window.shape_combine_mask(mask)
1497
1498
1499
1500
1501
1503 """Called when the Screenlet gets deleted. Return True to cancel.
1504 TODO: sometimes not properly called"""
1505 return not show_question(self, _("To quit all %s's, use 'Quit' instead. ") % self.__class__.__name__ +\
1506 _('Really delete this %s and its settings?') % self.get_short_name())
1507 """return not show_question(self, 'Deleting this instance of the '+\
1508 self.__name__ + ' will also delete all your personal '+\
1509 'changes you made to it!! If you just want to close the '+\
1510 'application, use "Quit" instead. Are you sure you want to '+\
1511 'delete this instance?')
1512 return False"""
1513
1514
1515
1516
1518 """Called after setting screenlet atributes"""
1519 pass
1520
1522 """Called before setting screenlet atributes"""
1523 pass
1524
1525
1527 """Called when the screenlet's drag-icon is created. You can supply
1528 your own icon and mask by returning them as a 2-tuple."""
1529 return (None, None)
1530
1532 """Called when screenlet was mapped"""
1533 pass
1534
1536 """Called when screenlet was unmapped"""
1537 pass
1538
1540 """Called when composite state has changed"""
1541 pass
1542
1543
1545 """Called when the Screenlet gets dragged."""
1546 pass
1547
1549 """Called when something gets dragged into the Screenlets area."""
1550 pass
1551
1553 """Called when something gets dragged out of the Screenlets area."""
1554 pass
1555
1557 """Callback for drawing the Screenlet's window - override
1558 in subclasses to implement your own drawing."""
1559 pass
1560
1562 """Callback for drawing the Screenlet's shape - override
1563 in subclasses to draw the window's input-shape-mask."""
1564 pass
1565
1566 - def on_drop (self, x, y, sel_data, timestamp):
1567 """Called when a selection is dropped on this Screenlet."""
1568 return False
1569
1571 """Called when the Screenlet's window receives focus."""
1572 pass
1573
1575 """Called when the Screenlet gets hidden."""
1576 pass
1577
1579 """Called when the Screenlet's options have been applied and the
1580 screenlet finished its initialization. If you want to have your
1581 Screenlet do things on startup you should use this handler."""
1582 pass
1583
1584 - def on_key_down (self, keycode, keyvalue, event=None):
1585 """Called when a key is pressed within the screenlet's window."""
1586 pass
1587
1589 """Called when the theme is reloaded (after loading, before redraw)."""
1590 pass
1591
1593 """Called when a menuitem is selected."""
1594 pass
1595
1597 """Called when a buttonpress-event occured in Screenlet's window.
1598 Returning True causes the event to be not further propagated."""
1599 return False
1600
1602 """Called when the mouse enters the Screenlet's window."""
1603 pass
1604
1606 """Called when the mouse leaves the Screenlet's window."""
1607 pass
1608
1610 """Called when the mouse moves in the Screenlet's window."""
1611 pass
1612
1614 """Called when a buttonrelease-event occured in Screenlet's window.
1615 Returning True causes the event to be not further propagated."""
1616 return False
1617
1619 """Callback for handling destroy-event. Perform your cleanup here!"""
1620 return True
1621
1623 """"Callback for handling the realize-event."""
1624
1626 """Called when Screenlet.scale is changed."""
1627 pass
1628
1632
1636
1638 """Called when the Screenlet gets shown after being hidden."""
1639 pass
1640
1644
1646 """Called when the Screenlet's window loses focus."""
1647 pass
1648
1650 """Called when the Screenlet's window is updating shape"""
1651 pass
1652
1653
1654
1655
1657 """set colormap for window"""
1658 if screen==None:
1659 screen = window.get_screen()
1660 map = screen.get_rgba_colormap()
1661 if map:
1662 pass
1663 else:
1664 map = screen.get_rgb_colormap()
1665 window.set_colormap(map)
1666
1705
1714
1737
1738
1756
1758
1759 print "delete_event"
1760 if self.on_delete() == True:
1761 print _("Cancel delete_event")
1762 return True
1763 else:
1764 self.close()
1765 return False
1766
1767 - def destroy (self, widget, data=None):
1779
1784
1785
1787 return self.on_drop(x, y, sel_data, timestamp)
1788
1789 - def drag_end (self, widget, drag_context):
1790 print _("End drag")
1791 self.is_dragged = False
1792 return False
1793
1794 - def drag_motion (self, widget, drag_context, x, y, timestamp):
1800
1801 - def drag_leave (self, widget, drag_context, timestamp):
1805
1807
1808 self.__dict__['mouse_is_over'] = True
1809 self.on_mouse_enter(event)
1810
1811
1812
1813 - def expose (self, widget, event):
1831
1842
1843
1844
1845
1852
1853
1854
1856 """Handle keypress events, needed for in-place editing."""
1857 self.on_key_down(event.keyval, event.string, event)
1858
1860
1861
1862 self.__dict__['mouse_is_over'] = False
1863 self.on_mouse_leave(event)
1864
1865
1866
1937
1940
1943
1945 self.__dict__['mousex'] = event.x / self.scale
1946 self.__dict__['mousey'] = event.y / self.scale
1947
1948 self.on_mouse_move(event)
1949
1956
1965
1966
1973
1975 """hide notification window"""
1976 if self.notify != None:
1977 self.notify.hide()
1978 self.notify = None
1979
1993
1994
2000
2001
2083
2196
2198 """A window that displays a text and serves as Notification (very basic yet)."""
2199
2200
2201 __timeout = None
2202
2203
2204 text = ''
2205 font_name = 'FreeSans 9'
2206 width = 200
2207 height = 100
2208 x = 0
2209 y = 0
2210 gradient = cairo.LinearGradient(0, 100,0, 0)
2211
2233
2235 self.__dict__[name] = value
2236 if name in ('text'):
2237 if name == 'text':
2238 self.p_layout.set_markup(value)
2239 ink_rect, logical_rect = self.p_layout.get_pixel_extents()
2240 self.window.queue_draw()
2241
2248
2253
2258
2265
2268
2270 if screen == None:
2271 screen = window.get_screen()
2272 map = screen.get_rgba_colormap()
2273 if not map:
2274 map = screen.get_rgb_colormap()
2275 window.set_colormap(map)
2276
2277 - def expose (self, widget, event):
2278 ctx = self.window.window.cairo_create()
2279 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL)
2280
2281 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2282 ctx.clip()
2283
2284 ctx.set_source_rgba(1, 1, 1, 0)
2285 ctx.set_operator (cairo.OPERATOR_SOURCE)
2286 ctx.paint()
2287
2288 self.gradient.add_color_stop_rgba(1,0.3, 0.3, 0.3, 0.9)
2289 self.gradient.add_color_stop_rgba(0.3, 0, 0, 0, 0.9)
2290 ctx.set_source(self.gradient)
2291 ctx.rectangle(0, 0, self.width, self.height)
2292 ctx.fill()
2293
2294 ctx.save()
2295 ctx.translate(3, 3)
2296 ctx.set_source_rgba(1, 1, 1, 1)
2297 ctx.show_layout(self.p_layout)
2298 ctx.fill()
2299 ctx.restore()
2300 ctx.rectangle(0, 0, self.width, self.height)
2301 ctx.set_source_rgba(0, 0, 0, 0.7)
2302 ctx.stroke()
2303
2304
2305 """class TestWidget(ShapedWidget):
2306
2307 def __init__(self, width, height):
2308 #ShapedWidget.__init__(self, width, height)
2309 super(TestWidget, self).__init__(width, height)
2310
2311 def draw(self, ctx):
2312 if self.mouse_inside:
2313 ctx.set_source_rgba(1, 0, 0, 0.8)
2314 else:
2315 ctx.set_source_rgba(1, 1, 0, 0.8)
2316 ctx.rectangle(0, 0, 32, 32)
2317 ctx.fill()
2318 """
2319
2320
2321
2322
2323
2324
2325
2327 """Launch a screenlet, either through its service or by launching a new
2328 process of the given screenlet. Name has to be the name of the Screenlet's
2329 class without trailing 'Screenlet'.
2330 NOTE: we could only launch the file here"""
2331
2332 if services.service_is_running(name):
2333
2334 srvc = services.get_service_by_name(name)
2335 if srvc:
2336 try:
2337 srvc.add('')
2338 return True
2339 except Exception, ex:
2340 print "Error while adding instance by service: %s" % ex
2341
2342 path = utils.find_first_screenlet_path(name)
2343 if path:
2344
2345 slfile = path + '/' + name + 'Screenlet.py'
2346
2347 print "Launching Screenlet from: %s" % slfile
2348 if debug:
2349 print "Logging output goes to: $HOME/.config/Screenlets/%sScreenlet.log" % name
2350 out = '$HOME/.config/Screenlets/%sScreenlet.log' % name
2351 else:
2352 out = '/dev/null'
2353 os.system('python -u %s > %s &' % (slfile, out))
2354 return True
2355 else:
2356 print "Screenlet '%s' could not be launched." % name
2357 return False
2358
2360 """Show a message for the given Screenlet (may contain Pango-Markup).
2361 If screenlet is None, this function can be used by other objects as well."""
2362 if screenlet == None:
2363 md = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,
2364 buttons=gtk.BUTTONS_OK)
2365 md.set_title(title)
2366 else:
2367 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_INFO,
2368 buttons=gtk.BUTTONS_OK)
2369 md.set_title(screenlet.__name__)
2370 md.set_markup(message)
2371 md.run()
2372 md.destroy()
2373
2375 """Show a question for the given Screenlet (may contain Pango-Markup)."""
2376 if screenlet == None:
2377 md = gtk.MessageDialog(None, type=gtk.MESSAGE_QUESTION,
2378 buttons=gtk.BUTTONS_YES_NO)
2379 md.set_title(title)
2380 else:
2381 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_QUESTION,
2382 buttons=gtk.BUTTONS_YES_NO)
2383 md.set_title(screenlet.__name__)
2384 md.set_markup(message)
2385 response = md.run()
2386 md.destroy()
2387 if response == gtk.RESPONSE_YES:
2388 return True
2389 return False
2390
2391 -def show_error (screenlet, message, title='Error'):
2392 """Show an error for the given Screenlet (may contain Pango-Markup)."""
2393 if screenlet == None:
2394 md = gtk.MessageDialog(None, type=gtk.MESSAGE_ERROR,
2395 buttons=gtk.BUTTONS_OK)
2396 md.set_title(title)
2397 else:
2398 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_ERROR,
2399 buttons=gtk.BUTTONS_OK)
2400 md.set_title(screenlet.__name__)
2401 md.set_markup(message)
2402 md.run()
2403 md.destroy()
2404
2406 """Raise a fatal error to stdout and stderr and exit with an errorcode."""
2407 import sys
2408 msg = 'FATAL ERROR: %s\n' % message
2409 sys.stdout.write(msg)
2410 sys.stderr.write(msg)
2411 sys.exit(1)
2412
2413
2414
2416 fatal_error("This screenlet seems to be written for an older version of the framework. Please download a newer version of the %s." % name)
2417