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 import glib
43 try:
44 import rsvg
45 except ImportError: print 'No module RSVG , graphics will not be so good'
46 import os
47 import subprocess
48 import glob
49 import gettext
50 import math
51
52
53 from options import *
54 import services
55 import utils
56 import sensors
57
58 import menu
59 from menu import DefaultMenuItem, add_menuitem
60 from drawing import Drawing
61
62
63
64 gettext.textdomain('screenlets')
65 gettext.bindtextdomain('screenlets', INSTALL_PREFIX + '/share/locale')
66
68 return gettext.gettext(s)
69
70
71
72
73
74
75 APP_NAME = "Screenlets"
76
77
78 VERSION = "0.1.3"
79
80
81 COPYRIGHT = "(c) RYX (Rico Pfaus) <ryx@ryxperience.com>\nWhise (Helder Fraga) <helder.fraga@hotmail.com>"
82
83
84 AUTHORS = ["RYX (Rico Pfaus) <ryx@ryxperience.com>", "Whise (Helder Fraga)<helder.fraga@hotmail.com>","Sorcerer (Hendrik Kaju)"]
85
86
87 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"
88
89 DOCUMENTERS = ["Documentation generated by epydoc"]
90
91 ARTISTS = ["ODD radio screenlet theme by ODDie\nPasodoble mail theme by jEsuSdA\nSome themes by RYX\nSome themes by Whise\nMore to come..."]
92
93 TRANSLATORS = "Special thanks for translators\nFull Translator list on https://translations.launchpad.net/screenlets/"
94
95
96 WEBSITE = 'http://www.screenlets.org'
97
98
99 THIRD_PARTY_DOWNLOAD = _("http://www.screenlets.org/index.php/Get_more_screenlets")
100
101
102
103
104
105 DIR_TMP = '/tmp/screenlets/'
106
107 TMP_DIR = DIR_TMP
108
109 TMP_FILE = 'screenlets.' + os.environ['USER'] + '.running'
110
111 DIR_USER_ROOT = screenlets.INSTALL_PREFIX + '/share/screenlets'
112
113 DIR_USER = os.environ['HOME'] + '/.screenlets'
114
115 DIR_CONFIG = os.environ['HOME'] + '/.config/Screenlets'
116
117
118
119 SCREENLETS_PATH = [DIR_USER, DIR_USER_ROOT]
120
121 SCREENLETS_PACK_PREFIX = "screenlets-pack-"
122
123
124
125
126
127 DAEMON_BUS = 'org.screenlets.ScreenletsDaemon'
128
129 DAEMON_PATH = '/org/screenlets/ScreenletsDaemon'
130
131 DAEMON_IFACE = 'org.screenlets.ScreenletsDaemon'
132
133
134
135 DEBUG_MODE = True
136
137 DEBIAN = True
138 try:
139 subprocess.call(["dpkg"], stdout=open(os.devnull, 'w'), stderr=subprocess.STDOUT)
140 except OSError:
141 DEBIAN = False
142
143 UBUNTU = True
144 try:
145 subprocess.call(["apt-add-repository"], stdout=open(os.devnull, 'w'), stderr=subprocess.STDOUT)
146 except OSError:
147 UBUNTU = False
148
149
150
151
152
173
174
176 """ScreenletThemes are simple storages that allow loading files
177 as svg-handles within a theme-directory. Each Screenlet can have
178 its own theme-directory. It is up to the Screenlet-developer if he
179 wants to let his Screenlet support themes or not. Themes are
180 turned off by default - if your Screenlet uses Themes, just set the
181 attribute 'theme_name' to the name of the theme's dir you want to use.
182 TODO: remove dict-inheritance"""
183
184
185 __name__ = ''
186 __author__ = ''
187 __version__ = ''
188 __info__ = ''
189
190
191 path = ""
192 loaded = False
193 width = 0
194 height = 0
195 option_overrides = {}
196 p_fdesc = None
197 p_layout = None
198 tooltip = None
199 notify = None
200
201
211
213 if name in ("width", "height"):
214 if self.loaded and len(self)>0:
215 size=self[0].get_dimension_data()
216 if name=="width":
217 return size[0]
218 else:
219 return size[1]
220 else:
221 return object.__getattr__(self, name)
222
250
251 - def check_entry (self, filename):
252 """Checks if a file with filename is loaded in this theme."""
253 try:
254 if self[filename]:
255 return True
256 except:
257
258 return False
259
260 - def get_text_width(self, ctx, text, font):
261 """@DEPRECATED Moved to Screenlets class: Returns the pixel width of a given text"""
262 ctx.save()
263
264 if self.p_layout == None :
265
266 self.p_layout = ctx.create_layout()
267 else:
268
269 ctx.update_layout(self.p_layout)
270 self.p_fdesc = pango.FontDescription(font)
271 self.p_layout.set_font_description(self.p_fdesc)
272 self.p_layout.set_text(text)
273 extents, lextents = self.p_layout.get_pixel_extents()
274 ctx.restore()
275 return extents[2]
276
277 - def get_text_extents(self, ctx, text, font):
278 """@DEPRECATED Moved to Screenlets class: Returns the pixel extents of a given text"""
279 ctx.save()
280
281 if self.p_layout == None :
282
283 self.p_layout = ctx.create_layout()
284 else:
285
286 ctx.update_layout(self.p_layout)
287 self.p_fdesc = pango.FontDescription(font)
288 self.p_layout.set_font_description(self.p_fdesc)
289 self.p_layout.set_text(text)
290 extents, lextents = self.p_layout.get_pixel_extents()
291 ctx.restore()
292 return extents
293
294 - def draw_text(self, ctx, text, x, y, font, size, width, allignment, weight = 0, ellipsize = pango.ELLIPSIZE_NONE):
295 """@DEPRECATED Moved to Screenlets class: Draws text"""
296 ctx.save()
297 ctx.translate(x, y)
298 if self.p_layout == None :
299
300 self.p_layout = ctx.create_layout()
301 else:
302
303 ctx.update_layout(self.p_layout)
304 self.p_fdesc = pango.FontDescription()
305 self.p_fdesc.set_family_static(font)
306 self.p_fdesc.set_size(size * pango.SCALE)
307 self.p_fdesc.set_weight(weight)
308 self.p_layout.set_font_description(self.p_fdesc)
309 self.p_layout.set_width(width * pango.SCALE)
310 self.p_layout.set_alignment(allignment)
311 self.p_layout.set_ellipsize(ellipsize)
312 self.p_layout.set_markup(text)
313 ctx.show_layout(self.p_layout)
314 ctx.restore()
315
316
318 """@DEPRECATED Moved to Screenlets class: Draws a circule"""
319 ctx.save()
320 ctx.translate(x, y)
321 ctx.arc(width/2,height/2,min(height,width)/2,0,2*math.pi)
322 if fill:ctx.fill()
323 else: ctx.stroke()
324 ctx.restore()
325
326 - def draw_line(self,ctx,start_x,start_y,end_x,end_y,line_width = 1,close=False,preserve=False):
327 """@DEPRECATED Moved to Screenlets class: Draws a line"""
328 ctx.save()
329 ctx.move_to(start_x, start_y)
330 ctx.set_line_width(line_width)
331 ctx.rel_line_to(end_x, end_y)
332 if close : ctx.close_path()
333 if preserve: ctx.stroke_preserve()
334 else: ctx.stroke()
335 ctx.restore()
336
338 """@DEPRECATED Moved to Screenlets class: Draws a rectangle"""
339 ctx.save()
340 ctx.translate(x, y)
341 ctx.rectangle (0,0,width,height)
342 if fill:ctx.fill()
343 else: ctx.stroke()
344 ctx.restore()
345
347 """@DEPRECATED Moved to Screenlets class: Draws a rounded rectangle"""
348 ctx.save()
349 ctx.translate(x, y)
350 padding=0
351 rounded=rounded_angle
352 w = width
353 h = height
354
355
356 ctx.move_to(0+padding+rounded, 0+padding)
357
358
359 ctx.line_to(w-padding-rounded, 0+padding)
360 ctx.arc(w-padding-rounded, 0+padding+rounded, rounded, (math.pi/2 )+(math.pi) , 0)
361
362
363 ctx.line_to(w-padding, h-padding-rounded)
364 ctx.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
365
366
367 ctx.line_to(0+padding+rounded, h-padding)
368 ctx.arc(0+padding+rounded, h-padding-rounded, rounded,math.pi/2, math.pi)
369
370
371 ctx.line_to(0+padding, 0+padding+rounded)
372 ctx.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi, (math.pi/2 )+(math.pi))
373
374
375 if fill:ctx.fill()
376 else: ctx.stroke()
377 ctx.restore()
378
380 """@DEPRECATED Moved to Screenlets class: Gets a picture width and height"""
381
382 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
383 iw = pixbuf.get_width()
384 ih = pixbuf.get_height()
385 puxbuf = None
386 return iw,ih
387
389 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path"""
390
391 ctx.save()
392 ctx.translate(x, y)
393 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
394 format = cairo.FORMAT_RGB24
395 if pixbuf.get_has_alpha():
396 format = cairo.FORMAT_ARGB32
397
398 iw = pixbuf.get_width()
399 ih = pixbuf.get_height()
400 image = cairo.ImageSurface(format, iw, ih)
401 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
402
403 ctx.paint()
404 puxbuf = None
405 image = None
406 ctx.restore()
407
408
409
411 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path with a certain width and height"""
412
413 ctx.save()
414 ctx.translate(x, y)
415 pixbuf = gtk.gdk.pixbuf_new_from_file(pix).scale_simple(w,h,gtk.gdk.INTERP_HYPER)
416 format = cairo.FORMAT_RGB24
417 if pixbuf.get_has_alpha():
418 format = cairo.FORMAT_ARGB32
419
420 iw = pixbuf.get_width()
421 ih = pixbuf.get_height()
422 image = cairo.ImageSurface(format, iw, ih)
423
424 matrix = cairo.Matrix(xx=iw/w, yy=ih/h)
425 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
426 if image != None :image.set_matrix(matrix)
427 ctx.paint()
428 puxbuf = None
429 image = None
430 ctx.restore()
431
438
440 """@DEPRECATED Moved to Screenlets class: hide notification window"""
441 if self.notify != None:
442 self.notify.hide()
443 self.notify = None
444
453
459
461 """Check if this theme contains overrides for options."""
462 return len(self.option_overrides) > 0
463
465 """Load a config-file from this theme's dir and save vars in list."""
466 ini = utils.IniReader()
467 if ini.load(filename):
468 if ini.has_section('Theme'):
469 self.__name__ = ini.get_option('name', section='Theme')
470 self.__author__ = ini.get_option('author', section='Theme')
471 self.__version__ = ini.get_option('version', section='Theme')
472 self.__info__ = ini.get_option('info', section='Theme')
473 if ini.has_section('Options'):
474 opts = ini.list_options(section='Options')
475 if opts:
476 for o in opts:
477 self.option_overrides[o[0]] = o[1]
478 print "Loaded theme config from:", filename
479 print "\tName: " + str(self.__name__)
480 print "\tAuthor: " +str(self.__author__)
481 print "\tVersion: " +str(self.__version__)
482 print "\tInfo: " +str(self.__info__)
483 else:
484 print "Failed to theme config from", filename
485
486
488 """Load an SVG-file into this theme and reference it as ref_name."""
489 if self.has_key(filename):
490 del self[filename]
491 try:
492 self[filename] = rsvg.Handle(self.path + "/" + filename)
493 self.svgs[filename[:-4]] = self[filename]
494 if self[filename] != None:
495
496 size=self[filename].get_dimension_data()
497 if size:
498 self.width = size[0]
499 self.height = size[1]
500 return True
501 except NameError, ex:
502 self[filename] = gtk.gdk.pixbuf_new_from_file(self.path + '/' + filename)
503 self.svgs[filename[:-4]] = self[filename]
504 if self[filename] != None:
505
506 self.width = self[filename].get_width()
507 self.height = self[filename].get_height()
508 print str(ex)
509 return True
510
511 else:
512 return False
513
514
516 """Load a PNG-file into this theme and reference it as ref_name."""
517 if self.has_key(filename):
518 del self[filename]
519 self[filename] = cairo.ImageSurface.create_from_png(self.path +
520 "/" + filename)
521 self.pngs[filename[:-4]] = self[filename]
522 if self[filename] != None:
523 return True
524 else:
525 return False
526
527
529 """Load all files in the theme's path. Currently only loads SVGs and
530 PNGs."""
531
532
533
534 dirlst = glob.glob(self.path + '/*')
535 if len(dirlst)==0:
536 return False
537 plen = len(self.path) + 1
538 for file in dirlst:
539 fname = file[plen:]
540 if fname.endswith('.svg'):
541
542 if self.load_svg(fname) == False:
543 return False
544 elif fname.endswith('.png'):
545
546 if self.load_png(fname) == False:
547 return False
548 elif fname == "theme.conf":
549 print "theme.conf found! Loading option-overrides."
550
551 if self.load_conf(file) == False:
552 return False
553
554 return True
555
557 """Re-Load all files in the theme's path."""
558 self.free()
559 self.__load_all()
560
561
563 """Deletes the Theme's contents and frees all rsvg-handles.
564 TODO: freeing rsvg-handles does NOT work for some reason"""
565 self.option_overrides.clear()
566 for filename in self:
567 try:
568 self[filename].free()
569 except AttributeError:pass
570
571 del filename
572 self.clear()
573
574
575
576
577 - def render (self, ctx, name):
578 """Render an image from within this theme to the given context. This
579 function can EITHER use png OR svg images, so it is possible to
580 create themes using both image-formats when a Screenlet uses this
581 function for drawing its images. The image name has to be defined
582 without the extension and the function will automatically select
583 the available one (SVG is prefered over PNG)."""
584
585
586 if os.path.isfile (self.path + '/' + name + '.svg'):
587
588 try:
589 self.svgs[name].render_cairo(ctx)
590 except:
591 try:
592 ctx.set_source_pixbuf(self.svgs[name], 0, 0)
593
594 ctx.paint()
595 pixbuf = None
596 except TypeError:
597 ctx.set_source_surface(self.pngs[name], 0, 0)
598 ctx.paint()
599
600 elif os.path.isfile (self.path + '/' + name + '.png'):
601 ctx.set_source_surface(self.pngs[name], 0, 0)
602 ctx.paint()
603
604
605
607
608 ctx.set_source_rgba(color[0], color[1], color[2], color[3])
609 ctx.set_source_surface(self.pngs[name], 0, 0)
610 ctx.mask_surface(image, 0, 0)
611 ctx.stroke()
612
613
614
615 -class Screenlet (gobject.GObject, EditableOptions, Drawing):
616 """A Screenlet is a (i.e. contains a) shaped gtk-window that is
617 fully invisible by default. Subclasses of Screenlet can render
618 their owner-drawn graphics on fully transparent background."""
619
620
621 __name__ = _('No name set for this Screenlet')
622 __version__ = '0.0'
623 __author__ = _('No author defined for this Screenlet')
624 __desc__ = _('No info set for this Screenlet')
625 __requires__ = []
626
627
628
629
630
631 id = ''
632 window = None
633 theme = None
634 uses_theme = True
635 draw_buttons = True
636 show_buttons = True
637 menu = None
638 is_dragged = False
639 quit_on_close = True
640 saving_enabled = True
641 dragging_over = False
642 disable_updates = False
643 p_context = None
644 p_layout = None
645
646
647 x = 0
648 y = 0
649 mousex = 0
650 mousey = 0
651 mouse_is_over = False
652 width = 100
653 height = 100
654 scale = 1.0
655 opacity = 1.0
656 theme_name = ""
657 is_visible = True
658 is_sticky = False
659 is_widget = False
660 keep_above = True
661 keep_below = False
662 skip_pager = True
663 first_run = False
664 skip_taskbar = True
665 lock_position = False
666 allow_option_override = True
667 ask_on_option_override = True
668 ignore_requirements = False
669 resize_on_scroll = True
670 has_started = False
671 has_focus = False
672
673 gtk_icon_theme = None
674 __lastx = 0
675 __lasty = 0
676 p_fdesc = None
677 p_layout = None
678 tooltip = None
679 notify = None
680
681
682 __mi_keep_above = None
683 __mi_keep_below = None
684 __mi_widget = None
685 __mi_sticky = None
686 __mi_lock = None
687
688 __gsignals__ = dict(screenlet_removed=(gobject.SIGNAL_RUN_FIRST,
689 gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)))
690
691 - def __init__ (self, id='', width=100, height=100, parent_window=None,
692 show_window=True, is_widget=False, is_sticky=False,
693 uses_theme=True, draw_buttons=True,path=os.getcwd(), drag_drop=False, session=None,
694 enable_saving=True, service_class=services.ScreenletService,
695 uses_pango=False, is_sizable=True,resize_on_scroll=True, ask_on_option_override=False):
696 """Constructor - should only be subclassed"""
697
698
699 super(Screenlet, self).__init__()
700 EditableOptions.__init__(self)
701
702 self.id = id
703 self.session = session
704 self.service = None
705 self.__desc__ = self.__doc__
706
707
708 if self.id and service_class:
709 self.register_service(service_class)
710
711 self.service.instance_added(self.id)
712 self.width = width
713 self.height = height
714 self.is_dragged = False
715 self.__path__ = path
716 self.saving_enabled = enable_saving
717
718 self.__dict__['theme_name'] = ""
719 self.__dict__['is_widget'] = is_widget
720 self.__dict__['is_sticky'] = is_sticky
721 self.__dict__['draw_buttons'] = draw_buttons
722 self.resize_on_scroll = resize_on_scroll
723 self.__dict__['x'] = 0
724 self.__dict__['y'] = 0
725
726
727
728
729 self.__shape_bitmap = None
730 self.__shape_bitmap_width = 0
731 self.__shape_bitmap_height = 0
732
733 self.add_options_group('Screenlet',
734 _('The basic settings for this Screenlet-instance.'))
735
736
737
738 self.gtk_icon_theme = gtk.icon_theme_get_default()
739 self.load_buttons(None)
740 self.gtk_icon_theme.connect("changed", self.load_buttons)
741 if draw_buttons: self.draw_buttons = True
742 else: self.draw_buttons = False
743 if uses_theme:
744 self.uses_theme = True
745 self.add_option(StringOption('Screenlet', 'theme_name',
746 'default', '', '', hidden=True))
747
748 self.add_option(IntOption('Screenlet', 'x',
749 0, _('X-Position'), _('The X-position of this Screenlet ...'),
750 min=0, max=gtk.gdk.screen_width()))
751 self.add_option(IntOption('Screenlet', 'y',
752 0, _('Y-Position'), _('The Y-position of this Screenlet ...'),
753 min=0, max=gtk.gdk.screen_height()))
754 self.add_option(IntOption('Screenlet', 'width',
755 width, _('Width'), _('The width of this Screenlet ...'),
756 min=16, max=1000, hidden=True))
757 self.add_option(IntOption('Screenlet', 'height',
758 height, _('Height'), _('The height of this Screenlet ...'),
759 min=16, max=1000, hidden=True))
760 self.add_option(FloatOption('Screenlet', 'scale',
761 self.scale, _('Scale'), _('The scale-factor of this Screenlet ...'),
762 min=0.1, max=10.0, digits=2, increment=0.1))
763 self.add_option(FloatOption('Screenlet', 'opacity',
764 self.opacity, _('Opacity'), _('The opacity of the Screenlet window ...'),
765 min=0.1, max=1.0, digits=2, increment=0.1))
766 self.add_option(BoolOption('Screenlet', 'is_sticky',
767 is_sticky, _('Stick to Desktop'),
768 _('Show this Screenlet on all workspaces ...')))
769 self.add_option(BoolOption('Screenlet', 'is_widget',
770 is_widget, _('Treat as Widget'),
771 _('Treat this Screenlet as a "Widget" ...')))
772 self.add_option(BoolOption('Screenlet', 'is_dragged',
773 self.is_dragged, "Is the screenlet dragged","Is the screenlet dragged", hidden=True))
774 self.add_option(BoolOption('Screenlet', 'is_sizable',
775 is_sizable, "Can the screenlet be resized","is_sizable", hidden=True))
776 self.add_option(BoolOption('Screenlet', 'is_visible',
777 self.is_visible, "Usefull to use screenlets as gnome panel applets","is_visible", hidden=True))
778 self.add_option(BoolOption('Screenlet', 'lock_position',
779 self.lock_position, _('Lock position'),
780 _('Stop the screenlet from being moved...')))
781 self.add_option(BoolOption('Screenlet', 'keep_above',
782 self.keep_above, _('Keep above'),
783 _('Keep this Screenlet above other windows ...')))
784 self.add_option(BoolOption('Screenlet', 'keep_below',
785 self.keep_below, _('Keep below'),
786 _('Keep this Screenlet below other windows ...')))
787 self.add_option(BoolOption('Screenlet', 'draw_buttons',
788 self.draw_buttons, _('Draw button controls'),
789 _('Draw buttons in top right corner')))
790 self.add_option(BoolOption('Screenlet', 'skip_pager',
791 self.skip_pager, _('Skip Pager'),
792 _('Set this Screenlet to show/hide in pagers ...')))
793 self.add_option(BoolOption('Screenlet', 'skip_taskbar',
794 self.skip_pager, _('Skip Taskbar'),
795 _('Set this Screenlet to show/hide in taskbars ...')))
796 self.add_option(BoolOption('Screenlet', 'resize_on_scroll',
797 self.resize_on_scroll, _("Resize on mouse scroll"),"resize_on_scroll"))
798 self.add_option(BoolOption('Screenlet', 'ignore_requirements',
799 self.ignore_requirements, _('Ignore requirements'),
800 _('Set this Screenlet to ignore/demand DEB requirements ...')))
801 if uses_theme:
802 self.ask_on_option_override = ask_on_option_override
803 self.add_option(BoolOption('Screenlet', 'allow_option_override',
804 self.allow_option_override, _('Allow overriding Options'),
805 _('Allow themes to override options in this screenlet ...')))
806 self.add_option(BoolOption('Screenlet', 'ask_on_option_override',
807 self.ask_on_option_override, _('Ask on Override'),
808 _('Show a confirmation-dialog when a theme wants to override ')+\
809 _('the current options of this Screenlet ...')))
810
811 self.disable_option('width')
812 self.disable_option('height')
813
814 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
815 if parent_window:
816 self.window.set_parent_window(parent_window)
817 self.window.set_transient_for(parent_window)
818 self.window.set_destroy_with_parent(True)
819 self.window.resize(width, height)
820 self.window.set_decorated(False)
821 self.window.set_app_paintable(True)
822
823 if uses_pango:
824 self.p_context = self.window.get_pango_context()
825 if self.p_context:
826 self.p_layout = pango.Layout(self.p_context)
827 self.p_layout.set_font_description(\
828 pango.FontDescription("Sans 12"))
829
830
831 if str(sensors.sys_get_window_manager()).lower() == 'kwin':
832 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
833
834 elif str(sensors.sys_get_window_manager()).lower() == 'sawfish':
835 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
836 else:
837 self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_TOOLBAR)
838 self.window.set_keep_above(True)
839 self.window.set_skip_taskbar_hint(True)
840 self.window.set_skip_pager_hint(True)
841 if is_sticky:
842 self.window.stick()
843 self.alpha_screen_changed(self.window)
844 self.update_shape()
845
846 self.window.set_events(gtk.gdk.ALL_EVENTS_MASK)
847 self.window.connect("composited-changed", self.composite_changed)
848 self.window.connect("delete_event", self.delete_event)
849 self.window.connect("destroy", self.destroy)
850 self.window.connect("expose_event", self.expose)
851 self.window.connect("button-press-event", self.button_press)
852 self.window.connect("button-release-event", self.button_release)
853 self.window.connect("configure-event", self.configure_event)
854 self.window.connect("screen-changed", self.alpha_screen_changed)
855 self.window.connect("realize", self.realize_event)
856 self.window.connect("enter-notify-event", self.enter_notify_event)
857 self.window.connect("leave-notify-event", self.leave_notify_event)
858 self.window.connect("focus-in-event", self.focus_in_event)
859 self.window.connect("focus-out-event", self.focus_out_event)
860 self.window.connect("scroll-event", self.scroll_event)
861 self.window.connect("motion-notify-event",self.motion_notify_event)
862 self.window.connect("map-event", self.map_event)
863 self.window.connect("unmap-event", self.unmap_event)
864
865 self.window.connect("key-press-event", self.key_press)
866
867 if drag_drop:
868 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
869 gtk.DEST_DEFAULT_DROP,
870 [("text/plain", 0, 0),
871 ("image", 0, 1),
872 ("text/uri-list", 0, 2)],
873 gtk.gdk.ACTION_COPY)
874 self.window.connect("drag_data_received", self.drag_data_received)
875 self.window.connect("drag-begin", self.drag_begin)
876 self.window.connect("drag-end", self.drag_end)
877 self.window.connect("drag-motion", self.drag_motion)
878 self.window.connect("drag-leave", self.drag_leave)
879
880 self.menu = gtk.Menu()
881
882
883
884 if show_window:
885 self.window.show()
886
887 if not os.path.exists(os.environ['HOME'] + '/.config/Screenlets/' + self.__name__[:-9] + '/default/'+ self.id + '.ini'):
888 self.first_run = True
889 self.window.hide()
890
891
892 if not self.window.is_composited () :
893 self.disable_option('opacity')
894
896
897 self.on_before_set_atribute(name, value)
898 gobject.GObject.__setattr__(self, name, value)
899
900 if name=="x" or name=="y":
901 if self.has_started:
902 self.window.move(self.x, self.y)
903 elif name == 'opacity':
904 self.window.set_opacity(value)
905 elif name == 'scale':
906 self.window.resize(int(self.width * self.scale),
907 int(self.height * self.scale))
908
909 self.on_scale()
910 self.redraw_canvas()
911 self.update_shape()
912
913
914 elif name == "theme_name":
915
916
917
918 print "Theme set to: '%s'" % value
919 path = self.find_theme(value)
920 if path:
921 self.load_theme(path)
922
923 self.redraw_canvas()
924 self.update_shape()
925 elif name in ("width", "height"):
926
927 if self.window:
928 self.window.resize(int(self.width*self.scale), int(self.height*self.scale))
929
930 self.update_shape()
931 elif name == "is_widget":
932 if self.has_started:
933 self.set_is_widget(value)
934 elif name == "is_visible":
935 if self.has_started:
936 if value == True:
937 self.reshow()
938 else:
939 self.window.hide()
940 elif name == "is_sticky":
941 if value == True:
942 self.window.stick()
943 else:
944 self.window.unstick()
945
946
947 elif name == "keep_above":
948 if self.has_started == True:
949 self.window.set_keep_above(bool(value))
950
951 elif name == "keep_below":
952 if self.has_started == True:
953 self.window.set_keep_below(bool(value))
954
955 elif name == "skip_pager":
956 if self.window.window:
957 self.window.window.set_skip_pager_hint(bool(value))
958 elif name == "skip_taskbar":
959 if self.window.window:
960 self.window.window.set_skip_taskbar_hint(bool(value))
961
962
963 if self.saving_enabled:
964 o = self.get_option_by_name(name)
965 if o != None:
966 self.session.backend.save_option(self.id, o.name,
967 o.on_export(value))
968 self.on_after_set_atribute(name, value)
969
970
971
972
973
974
976 '''Checks if required DEB packages are installed'''
977
978 req_feedback = ""
979 fail = False
980
981
982
983 commandstr = 'apt-cache policy %s 2>/dev/null | sed -n "2 p" | grep -v ":[ \t]*([a-z \t]*)" | sed -r -e "s/(\s*[^\s]+:\s*)(.*)/\\2/"'
984 for req in self.__requires__:
985 operator = None
986
987 if req.find('(') != -1:
988
989 pos = req.find('(')
990 package = req[:pos].strip()
991 version_str = req[pos+1:]
992 version_str = version_str[:version_str.find(')')]
993 while version_str.find(' ') != -1:
994 version_str = req.replace(' ', ' ')
995 res = version_str.split(' ')
996 version = res[1]
997 operator = res[0]
998 else:
999
1000 package = req
1001
1002 version = _("?")
1003
1004 installed_version = os.popen(commandstr % package).readline().replace('\n', '')
1005
1006 if len(installed_version) < 1:
1007 req_feedback += _("\n%(package)s %(version)s required, NOT INSTALLED!") % {"package":package, "version":version}
1008 fail = True
1009 else:
1010 req_feedback += _("\n%(package)s %(version)s installed, req %(required)s.") % {"package":package, "version":installed_version, "required":version}
1011
1012
1013
1014 if operator is not None:
1015 comp_command = "dpkg --compare-versions \"" + installed_version + "\" \"" + operator + "\" \"" + version + "\""
1016
1017 if subprocess.call(comp_command, shell=True) != 0:
1018 fail = True
1019 if fail:
1020 screenlets.show_message (self,_("Requirements for the Screenlet are not satisfied! Use the package manager of your system to install required packages.\n\nREQUIREMENTS:\n%s") % req_feedback, "Requirements not satisfied")
1021
1023 """Appends the default menu-items to self.menu. You can add on OR'ed
1024 flag with DefaultMenuItems you want to add."""
1025 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'
1026
1027 menu = self.menu
1028
1029
1030 if len(menu.get_children()) > 0:
1031 self.add_menuitem("", "-")
1032
1033 if flags & DefaultMenuItem.XML:
1034
1035 xfile = self.get_screenlet_dir() + "/menu.xml"
1036 xmlmenu = screenlets.menu.create_menu_from_file(xfile,
1037 self.menuitem_callback)
1038 if xmlmenu:
1039 self.menu = xmlmenu
1040
1041 if flags & DefaultMenuItem.SIZE:
1042 size_item = gtk.MenuItem(_("Size"))
1043 size_item.show()
1044 size_menu = gtk.Menu()
1045 menu.append(size_item)
1046 size_item.set_submenu(size_menu)
1047
1048 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):
1049 s = str(int(i * 100))
1050 item = gtk.MenuItem(s + " %")
1051 item.connect("activate", self.menuitem_callback,
1052 "scale:"+str(i))
1053 item.show()
1054 size_menu.append(item)
1055
1056 if flags & DefaultMenuItem.THEMES:
1057 themes_item = gtk.MenuItem(_("Theme"))
1058 themes_item.show()
1059 themes_menu = gtk.Menu()
1060 menu.append(themes_item)
1061 themes_item.set_submenu(themes_menu)
1062
1063 lst = self.get_available_themes()
1064 for tname in lst:
1065 item = gtk.MenuItem(tname)
1066 item.connect("activate", self.menuitem_callback, "theme:"+tname)
1067 item.show()
1068 themes_menu.append(item)
1069
1070
1071 if flags & DefaultMenuItem.WINDOW_MENU:
1072 winmenu_item = gtk.MenuItem(_("Window"))
1073 winmenu_item.show()
1074 winmenu_menu = gtk.Menu()
1075 menu.append(winmenu_item)
1076 winmenu_item.set_submenu(winmenu_menu)
1077
1078 self.__mi_lock = item = gtk.CheckMenuItem(_("Lock"))
1079 item.set_active(self.lock_position)
1080 item.connect("activate", self.menuitem_callback,
1081 "option:lock")
1082 item.show()
1083 winmenu_menu.append(item)
1084
1085 self.__mi_sticky = item = gtk.CheckMenuItem(_("Sticky"))
1086 item.set_active(self.is_sticky)
1087 item.connect("activate", self.menuitem_callback,
1088 "option:sticky")
1089 item.show()
1090 winmenu_menu.append(item)
1091
1092 self.__mi_widget = item = gtk.CheckMenuItem(_("Widget"))
1093 item.set_active(self.is_widget)
1094 item.connect("activate", self.menuitem_callback,
1095 "option:widget")
1096 item.show()
1097 winmenu_menu.append(item)
1098
1099 self.__mi_keep_above = item = gtk.CheckMenuItem(_("Keep above"))
1100 item.set_active(self.keep_above)
1101 item.connect("activate", self.menuitem_callback,
1102 "option:keep_above")
1103 item.show()
1104 winmenu_menu.append(item)
1105
1106 self.__mi_keep_below = item = gtk.CheckMenuItem(_("Keep below"))
1107 item.set_active(self.keep_below)
1108 item.connect("activate", self.menuitem_callback,
1109 "option:keep_below")
1110 item.show()
1111 winmenu_menu.append(item)
1112
1113
1114 if flags & DefaultMenuItem.PROPERTIES:
1115 add_menuitem(menu, "-", self.menuitem_callback, "")
1116 add_menuitem(menu, _("Properties..."), self.menuitem_callback, "options")
1117
1118 if flags & DefaultMenuItem.INFO:
1119 add_menuitem(menu, _("Info..."), self.menuitem_callback, "info")
1120
1121 if flags & DefaultMenuItem.ADD:
1122 add_menuitem(menu, "-", self.menuitem_callback, "")
1123 add_menuitem(menu, _("Add one more %s") % self.get_short_name(), self.menuitem_callback, "add")
1124
1125 if flags & DefaultMenuItem.DELETE:
1126 add_menuitem(menu, _("Delete this %s") % self.get_short_name(), self.menuitem_callback, "delete")
1127
1128 if flags & DefaultMenuItem.QUIT:
1129 add_menuitem(menu, "-", self.menuitem_callback, "")
1130 add_menuitem(menu, _("Quit this %s") % self.get_short_name(), self.menuitem_callback, "quit_instance")
1131
1132 if flags & DefaultMenuItem.QUIT_ALL:
1133 add_menuitem(menu, _("Quit all %ss") % self.get_short_name(), self.menuitem_callback, "quit")
1134
1136 """Simple way to add menuitems to a right-click menu.
1137 This function wraps screenlets.menu.add_menuitem.
1138 For backwards compatibility, the order of the parameters
1139 to this function is switched."""
1140 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'
1141 if callback is None:
1142 callback = self.menuitem_callback
1143
1144 return add_menuitem(self.menu, label, callback, id)
1145
1147 """Simple way to add submenuitems to the right-click menu through a list."""
1148 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'
1149
1150 submenu = gtk.MenuItem(label)
1151 submenu.show()
1152 sub_menu = gtk.Menu()
1153 self.menu.append(submenu)
1154 submenu.set_submenu(sub_menu)
1155
1156
1157 for tname in lst:
1158 item = gtk.MenuItem(tname)
1159 item.connect("activate", self.menuitem_callback,
1160 tname)
1161 item.show()
1162 sub_menu.append(item)
1163
1164 return submenu
1165
1166
1167
1171
1192
1193 - def clear_cairo_context (self, ctx):
1194 """Fills the given cairo.Context with fully transparent white."""
1195 ctx.save()
1196 ctx.set_source_rgba(1, 1, 1, 0)
1197 ctx.set_operator (cairo.OPERATOR_SOURCE)
1198 ctx.paint()
1199 ctx.restore()
1200
1202 """Close this Screenlet
1203 TODO: send close-notify instead of destroying window?"""
1204
1205 self.window.unmap()
1206 self.window.destroy()
1207
1208
1210 """Create drag-icon and -mask for drag-operation. Returns a 2-tuple
1211 with the icon and the mask. To supply your own icon you can use the
1212 on_create_drag_icon-handler and return the icon/mask as 2-tuple."""
1213 w = self.width
1214 h = self.height
1215 icon, mask = self.on_create_drag_icon()
1216 if icon == None:
1217
1218 icon = gtk.gdk.Pixmap(self.window.window, w, h)
1219 ctx = icon.cairo_create()
1220 self.clear_cairo_context(ctx)
1221 self.on_draw(ctx)
1222 if mask == None:
1223
1224 mask = gtk.gdk.Pixmap(self.window.window, w, h)
1225 ctx = mask.cairo_create()
1226 self.clear_cairo_context(ctx)
1227 self.on_draw_shape(ctx)
1228 return (icon, mask)
1229
1231 """Enable/Disable realtime-saving of options."""
1232 self.saving_enabled = enabled
1233
1243
1245 """Return the short name of this screenlet. This returns the classname
1246 of the screenlet without trailing "Screenlet". Please always use
1247 this function if you want to retrieve the short name of a Screenlet."""
1248 return self.__class__.__name__[:-9]
1249
1251 """Return the name of this screenlet's personal directory."""
1252 p = utils.find_first_screenlet_path(self.get_short_name())
1253 if p:
1254 return p
1255 else:
1256 if self.__path__ != '':
1257 return self.__path__
1258 else:
1259 return os.getcwd()
1260
1262 """Return the name of this screenlet's personal theme-dir.
1263 (Only returns the dir under the screenlet's location"""
1264 return self.get_screenlet_dir() + "/themes/"
1265
1267 """Returns a list with the names of all available themes in this
1268 Screenlet's theme-directories."""
1269 lst = []
1270 utils.refresh_available_screenlet_paths()
1271 for p in SCREENLETS_PATH:
1272 d = p + '/' + self.get_short_name() + '/themes/'
1273 if os.path.isdir(d):
1274
1275 dirlst = glob.glob(d + '*')
1276 dirlst.sort()
1277 tdlen = len(d)
1278 for fname in dirlst:
1279 if os.path.isdir(fname):
1280 dname = fname[tdlen:]
1281 if not dname in lst:
1282 lst.append(dname)
1283 return lst
1284
1298
1300 """Called when screenlet finishes loading"""
1301
1302
1303 self.window.present()
1304
1305
1306
1307 self.window.hide()
1308 self.window.move(self.x, self.y)
1309
1310 if DEBIAN and not self.ignore_requirements:
1311 self.check_requirements()
1312
1313 self.window.show()
1314 self.has_started = True
1315 self.is_dragged = False
1316 self.keep_above= self.keep_above
1317 self.keep_below= self.keep_below
1318 self.is_sticky = self.is_sticky
1319 self.skip_taskbar = self.skip_taskbar
1320 self.window.set_skip_taskbar_hint(self.skip_taskbar)
1321 self.window.set_keep_above(self.keep_above)
1322 self.window.set_keep_below(self.keep_below)
1323
1324 self.on_init()
1325 if self.is_widget:
1326 self.set_is_widget(True)
1327 self.has_focus = False
1328 ini = utils.IniReader()
1329 if ini.load (os.environ['HOME'] + '/.screenlets' + '/config.ini') and self.first_run:
1330
1331 if ini.get_option('Lock', section='Options') == 'True':
1332 self.lock_position = True
1333 elif ini.get_option('Lock', section='Options') == 'False':
1334 self.lock_position = False
1335 if ini.get_option('Sticky', section='Options') == 'True':
1336 self.is_sticky = True
1337 elif ini.get_option('Sticky', section='Options') == 'False':
1338 self.is_sticky = False
1339 if ini.get_option('Widget', section='Options') == 'True':
1340 self.is_widget = True
1341 elif ini.get_option('Widget', section='Options') == 'False':
1342 self.is_widget = False
1343 if ini.get_option('Keep_above', section='Options') == 'True':
1344 self.keep_above = True
1345 elif ini.get_option('Keep_above', section='Options') == 'False':
1346 self.keep_above = False
1347 if ini.get_option('Keep_below', section='Options') == 'True':
1348 self.keep_below = True
1349 elif ini.get_option('Keep_below', section='Options') == 'False':
1350 self.keep_below = False
1351 if ini.get_option('draw_buttons', section='Options') == 'True':
1352 self.draw_buttons = True
1353 elif ini.get_option('draw_buttons', section='Options') == 'False':
1354 self.draw_buttons = False
1355
1357 """Hides this Screenlet's underlying gtk.Window"""
1358 self.window.hide()
1359 self.on_hide()
1360
1361
1362
1363
1387
1388
1390 """If the Screenlet runs as stand-alone app, starts gtk.main()"""
1391 gtk.main()
1392
1394 """Register or create the given ScreenletService-(sub)class as the new
1395 service for this Screenlet. If self is not the first instance in the
1396 current session, the service from the first instance will be used
1397 instead and no new service is created."""
1398 if self.session:
1399 if len(self.session.instances) == 0:
1400
1401 if service_classobj==services.ScreenletService:
1402 self.service = service_classobj(self, self.get_short_name())
1403 else:
1404
1405 self.service = service_classobj(self)
1406 else:
1407 self.service = self.session.instances[0].service
1408
1409 return True
1410 return False
1411
1431
1433 """Show this Screenlet's underlying gtk.Window"""
1434 self.window.show()
1435 self.window.move(self.x, self.y)
1436 self.on_show()
1437
1439 """Show the EditableSettingsDialog for this Screenlet."""
1440 se = OptionsDialog(490, 450)
1441 img = gtk.Image()
1442 try:
1443 d = self.get_screenlet_dir()
1444 if os.path.isfile(d + '/icon.svg'):
1445 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.svg')
1446 elif os.path.isfile(d + '/icon.png'):
1447 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.png')
1448 img.set_from_pixbuf(icn)
1449 except:
1450 img.set_from_stock(gtk.STOCK_PROPERTIES, 5)
1451 se.set_title(self.__name__)
1452 se.set_info(self.__name__, glib.markup_escape_text(self.__desc__), '(c) ' + glib.markup_escape_text(self.__author__),
1453 version='v' + self.__version__, icon=img)
1454 se.show_options_for_object(self)
1455 resp = se.run()
1456 if resp == gtk.RESPONSE_REJECT:
1457 se.reset_to_defaults()
1458 else:
1459 self.update_shape()
1460 se.destroy()
1461
1463 """Redraw the entire Screenlet's window area.
1464 TODO: store window alloaction in class and change when size changes."""
1465
1466 if self.disable_updates:
1467 return
1468 if self.window:
1469 x, y, w, h = self.window.get_allocation()
1470 rect = gtk.gdk.Rectangle(x, y, w, h)
1471 if self.window.window:
1472 self.window.window.invalidate_rect(rect, True)
1473 self.window.window.process_updates(True)
1474
1475
1476
1477
1489
1491 """Removed shaped window , in case the nom composited shape has been set"""
1492 if self.window.window:
1493 self.window.window.shape_combine_mask(None,0,0)
1494
1495 w = self.window.allocation.width
1496 h = self.window.allocation.height
1497
1498
1499 if w==0 or h==0: return False
1500
1501 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1502 self.__shape_bitmap = screenlets.create_empty_bitmap(w, h)
1503 self.__shape_bitmap_width = w
1504 self.__shape_bitmap_height = h
1505
1506
1507 ctx = self.__shape_bitmap.cairo_create()
1508 self.clear_cairo_context(ctx)
1509
1510
1511 if self.window.is_composited():
1512
1513 self.on_draw_shape(ctx)
1514 self.main_view.set_shape(self.__shape_bitmap, True)
1515 else:
1516 try:
1517 self.on_draw_shape(ctx)
1518 except:
1519 self.on_draw(ctx)
1520
1521 self.main_view.set_shape(self.__shape_bitmap, False)
1522
1524 """Update window shape (only call this when shape has changed
1525 because it is very ressource intense if ran too often)."""
1526
1527 if self.disable_updates:
1528 return
1529
1530
1531
1532
1533
1534 w = int(self.width * self.scale)
1535 h = int(self.height * self.scale)
1536
1537 if w==0: w = 100
1538 if h==0: h = 100
1539
1540 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1541 data = ''.zfill(w*h)
1542 self.__shape_bitmap = gtk.gdk.bitmap_create_from_data(None, data,
1543 w, h)
1544 self.__shape_bitmap_width = w
1545 self.__shape_bitmap_height = h
1546
1547 ctx = self.__shape_bitmap.cairo_create()
1548 self.clear_cairo_context(ctx)
1549 if self.has_focus and self.draw_buttons and self.show_buttons:
1550 ctx.save()
1551
1552
1553
1554
1555
1556
1557
1558
1559 ctx.translate((self.width*self.scale)-16,0)
1560 ctx.set_source_pixbuf(self.closeb, 0, 0)
1561 ctx.paint()
1562 ctx.restore()
1563 ctx.save()
1564 ctx.translate((self.width*self.scale)-32,0)
1565 ctx.set_source_pixbuf(self.prop, 0, 0)
1566 ctx.paint()
1567 ctx.restore()
1568
1569
1570 if self.window.is_composited():
1571
1572 self.on_draw_shape(ctx)
1573
1574 self.window.input_shape_combine_mask(self.__shape_bitmap, 0, 0)
1575 else:
1576 try: self.on_draw(ctx)
1577 except: self.on_draw_shape(ctx)
1578
1579 self.window.shape_combine_mask(self.__shape_bitmap,0,0)
1580 self.on_update_shape()
1581
1583 """TEST: This function is intended to shape the window whenever no
1584 composited environment can be found. (NOT WORKING YET!!!!)"""
1585
1586
1587 w = int(self.width * self.scale)
1588 h = int(self.height * self.scale)
1589
1590 if w==0: w = 100
1591 if h==0: h = 100
1592
1593 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1594 data = ''.zfill(w*h)
1595 self.__shape_bitmap = gtk.gdk.pixbuf_new_from_data(data,
1596 gtk.gdk.COLORSPACE_RGB, True, 1, w, h, w)
1597 self.__shape_bitmap_width = w
1598 self.__shape_bitmap_height = h
1599
1600
1601 if self.__shape_bitmap:
1602
1603 (pixmap,mask) = self.__shape_bitmap.render_pixmap_and_mask(255)
1604
1605 self.window.shape_combine_mask(mask)
1606
1610
1611
1612
1613
1614
1616 """Called when the Screenlet gets deleted. Return True to cancel.
1617 TODO: sometimes not properly called"""
1618 return not show_question(self, _("To quit all %s's, use 'Quit' instead. ") % self.__class__.__name__ +\
1619 _('Really delete this %s and its settings?') % self.get_short_name())
1620 """return not show_question(self, 'Deleting this instance of the '+\
1621 self.__name__ + ' will also delete all your personal '+\
1622 'changes you made to it!! If you just want to close the '+\
1623 'application, use "Quit" instead. Are you sure you want to '+\
1624 'delete this instance?')
1625 return False"""
1626
1627
1628
1629
1631 """Called after setting screenlet atributes"""
1632 pass
1633
1635 """Called before setting screenlet atributes"""
1636 pass
1637
1638
1640 """Called when the screenlet's drag-icon is created. You can supply
1641 your own icon and mask by returning them as a 2-tuple."""
1642 return (None, None)
1643
1645 """Called when screenlet was mapped"""
1646 pass
1647
1649 """Called when screenlet was unmapped"""
1650 pass
1651
1653 """Called when composite state has changed"""
1654 pass
1655
1656
1658 """Called when the Screenlet gets dragged."""
1659 pass
1660
1662 """Called when something gets dragged into the Screenlets area."""
1663 pass
1664
1666 """Called when something gets dragged out of the Screenlets area."""
1667 pass
1668
1670 """Callback for drawing the Screenlet's window - override
1671 in subclasses to implement your own drawing."""
1672 pass
1673
1675 """Callback for drawing the Screenlet's shape - override
1676 in subclasses to draw the window's input-shape-mask."""
1677 pass
1678
1679 - def on_drop (self, x, y, sel_data, timestamp):
1680 """Called when a selection is dropped on this Screenlet."""
1681 return False
1682
1684 """Called when the Screenlet's window receives focus."""
1685 pass
1686
1688 """Called when the Screenlet gets hidden."""
1689 pass
1690
1692 """Called when the Screenlet's options have been applied and the
1693 screenlet finished its initialization. If you want to have your
1694 Screenlet do things on startup you should use this handler."""
1695 pass
1696
1697 - def on_key_down (self, keycode, keyvalue, event=None):
1698 """Called when a key is pressed within the screenlet's window."""
1699 pass
1700
1702 """Called when the theme is reloaded (after loading, before redraw)."""
1703 pass
1704
1706 """Called when a menuitem is selected."""
1707 pass
1708
1710 """Called when a buttonpress-event occured in Screenlet's window.
1711 Returning True causes the event to be not further propagated."""
1712 return False
1713
1715 """Called when the mouse enters the Screenlet's window."""
1716 pass
1717
1719 """Called when the mouse leaves the Screenlet's window."""
1720 pass
1721
1723 """Called when the mouse moves in the Screenlet's window."""
1724 pass
1725
1727 """Called when a buttonrelease-event occured in Screenlet's window.
1728 Returning True causes the event to be not further propagated."""
1729 return False
1730
1732 """Callback for handling destroy-event. Perform your cleanup here!"""
1733 return True
1734
1736 """"Callback for handling the realize-event."""
1737
1739 """Called when Screenlet.scale is changed."""
1740 pass
1741
1745
1749
1751 """Called when the Screenlet gets shown after being hidden."""
1752 pass
1753
1757
1759 """Called when the Screenlet's window loses focus."""
1760 pass
1761
1763 """Called when the Screenlet's window is updating shape"""
1764 pass
1765
1766
1767
1768
1770 """set colormap for window"""
1771 if screen==None:
1772 screen = window.get_screen()
1773 map = screen.get_rgba_colormap()
1774 if map:
1775 pass
1776 else:
1777 map = screen.get_rgb_colormap()
1778 window.set_colormap(map)
1779
1818
1827
1854
1855
1873
1875
1876 print "delete_event"
1877 if self.on_delete() == True:
1878 print "Cancel delete_event"
1879 return True
1880 else:
1881 self.close()
1882 return False
1883
1884 - def destroy (self, widget, data=None):
1896
1901
1902
1904 return self.on_drop(x, y, sel_data, timestamp)
1905
1906 - def drag_end (self, widget, drag_context):
1907 print "End drag"
1908 self.is_dragged = False
1909 return False
1910
1911 - def drag_motion (self, widget, drag_context, x, y, timestamp):
1917
1918 - def drag_leave (self, widget, drag_context, timestamp):
1922
1924
1925 self.__dict__['mouse_is_over'] = True
1926 self.on_mouse_enter(event)
1927
1928
1929
1930 - def expose (self, widget, event):
1948
1959
1960
1961
1962
1969
1970
1971
1973 """Handle keypress events, needed for in-place editing."""
1974 self.on_key_down(event.keyval, event.string, event)
1975
1977
1978
1979 self.__dict__['mouse_is_over'] = False
1980 self.on_mouse_leave(event)
1981
1982
1983
2056
2059
2062
2064 self.__dict__['mousex'] = event.x / self.scale
2065 self.__dict__['mousey'] = event.y / self.scale
2066
2067 self.on_mouse_move(event)
2068
2075
2084
2085
2092
2094 """hide notification window"""
2095 if self.notify != None:
2096 self.notify.hide()
2097 self.notify = None
2098
2112
2113
2119
2120
2202
2315
2317 """A window that displays a text and serves as Notification (very basic yet)."""
2318
2319
2320 __timeout = None
2321
2322
2323 text = ''
2324 font_name = 'FreeSans 9'
2325 width = 200
2326 height = 100
2327 x = 0
2328 y = 0
2329 gradient = cairo.LinearGradient(0, 100,0, 0)
2330
2352
2354 self.__dict__[name] = value
2355 if name in ('text'):
2356 if name == 'text':
2357 self.p_layout.set_markup(value)
2358 ink_rect, logical_rect = self.p_layout.get_pixel_extents()
2359 self.window.queue_draw()
2360
2367
2372
2377
2384
2387
2389 if screen == None:
2390 screen = window.get_screen()
2391 map = screen.get_rgba_colormap()
2392 if not map:
2393 map = screen.get_rgb_colormap()
2394 window.set_colormap(map)
2395
2396 - def expose (self, widget, event):
2397 ctx = self.window.window.cairo_create()
2398 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL)
2399
2400 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2401 ctx.clip()
2402
2403 ctx.set_source_rgba(1, 1, 1, 0)
2404 ctx.set_operator (cairo.OPERATOR_SOURCE)
2405 ctx.paint()
2406
2407 self.gradient.add_color_stop_rgba(1,0.3, 0.3, 0.3, 0.9)
2408 self.gradient.add_color_stop_rgba(0.3, 0, 0, 0, 0.9)
2409 ctx.set_source(self.gradient)
2410 ctx.rectangle(0, 0, self.width, self.height)
2411 ctx.fill()
2412
2413 ctx.save()
2414 ctx.translate(3, 3)
2415 ctx.set_source_rgba(1, 1, 1, 1)
2416 ctx.show_layout(self.p_layout)
2417 ctx.fill()
2418 ctx.restore()
2419 ctx.rectangle(0, 0, self.width, self.height)
2420 ctx.set_source_rgba(0, 0, 0, 0.7)
2421 ctx.stroke()
2422
2423
2424 """class TestWidget(ShapedWidget):
2425
2426 def __init__(self, width, height):
2427 #ShapedWidget.__init__(self, width, height)
2428 super(TestWidget, self).__init__(width, height)
2429
2430 def draw(self, ctx):
2431 if self.mouse_inside:
2432 ctx.set_source_rgba(1, 0, 0, 0.8)
2433 else:
2434 ctx.set_source_rgba(1, 1, 0, 0.8)
2435 ctx.rectangle(0, 0, 32, 32)
2436 ctx.fill()
2437 """
2438
2439
2440
2441
2442
2443
2444
2446 """Launch a screenlet, either through its service or by launching a new
2447 process of the given screenlet. Name has to be the name of the Screenlet's
2448 class without trailing 'Screenlet'.
2449 NOTE: we could only launch the file here"""
2450
2451 if services.service_is_running(name):
2452
2453 srvc = services.get_service_by_name(name)
2454 if srvc:
2455 try:
2456 srvc.add('')
2457 return True
2458 except Exception, ex:
2459 print "Error while adding instance by service: %s" % ex
2460
2461 path = utils.find_first_screenlet_path(name)
2462 if path:
2463
2464 slfile = path + '/' + name + 'Screenlet.py'
2465
2466 print "Launching Screenlet from: %s" % slfile
2467 if debug:
2468 print "Logging output goes to: $HOME/.config/Screenlets/%sScreenlet.log" % name
2469 out = '$HOME/.config/Screenlets/%sScreenlet.log' % name
2470 else:
2471 out = '/dev/null'
2472 os.system('python -u %s > %s &' % (slfile, out))
2473 return True
2474 else:
2475 print "Screenlet '%s' could not be launched." % name
2476 return False
2477
2479 """Show a message for the given Screenlet (may contain Pango-Markup).
2480 If screenlet is None, this function can be used by other objects as well."""
2481 if screenlet == None:
2482 md = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,
2483 buttons=gtk.BUTTONS_OK)
2484 md.set_title(title)
2485 else:
2486 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_INFO,
2487 buttons=gtk.BUTTONS_OK)
2488 md.set_title(screenlet.__name__)
2489 md.set_markup(message)
2490 md.run()
2491 md.destroy()
2492
2494 """Show a question for the given Screenlet (may contain Pango-Markup)."""
2495 if screenlet == None:
2496 md = gtk.MessageDialog(None, type=gtk.MESSAGE_QUESTION,
2497 buttons=gtk.BUTTONS_YES_NO)
2498 md.set_title(title)
2499 else:
2500 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_QUESTION,
2501 buttons=gtk.BUTTONS_YES_NO)
2502 md.set_title(screenlet.__name__)
2503 md.set_markup(message)
2504 response = md.run()
2505 md.destroy()
2506 if response == gtk.RESPONSE_YES:
2507 return True
2508 return False
2509
2510 -def show_error (screenlet, message, title='Error'):
2511 """Show an error for the given Screenlet (may contain Pango-Markup)."""
2512 if screenlet == None:
2513 md = gtk.MessageDialog(None, type=gtk.MESSAGE_ERROR,
2514 buttons=gtk.BUTTONS_OK)
2515 md.set_title(title)
2516 else:
2517 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_ERROR,
2518 buttons=gtk.BUTTONS_OK)
2519 md.set_title(screenlet.__name__)
2520 md.set_markup(message)
2521 md.run()
2522 md.destroy()
2523
2525 """Raise a fatal error to stdout and stderr and exit with an errorcode."""
2526 import sys
2527 msg = 'FATAL ERROR: %s\n' % message
2528 sys.stdout.write(msg)
2529 sys.stderr.write(msg)
2530 sys.exit(1)
2531
2532
2533
2535 fatal_error("This screenlet seems to be written for an older version of the framework. Please download a newer version of the %s." % name)
2536