| Home | Trees | Indices | Help |
|
|---|
|
|
1 # This application is released under the GNU General Public License
2 # v3 (or, at your option, any later version). You can find the full
3 # text of the license under http://www.gnu.org/licenses/gpl.txt.
4 # By using, editing and/or distributing this software you agree to
5 # the terms and conditions of this license.
6 # Thank you for using free software!
7
8 # Screenlets main module (c) RYX (aka Rico Pfaus) 2007 <ryx@ryxperience.com> ,
9 # Whise aka Helder Fraga <helder.fraga@hotmail.com>
10 #
11 ##@mainpage
12 #
13 ##@section intro_sec General Information
14 #
15 # INFO:
16 # - Screenlets are small owner-drawn applications that can be described as
17 # " the virtual representation of things lying/standing around on your desk".
18 # Sticknotes, clocks, rulers, ... the possibilities are endless. The goal of
19 # the Screenlets is to simplify the creation of fully themeable mini-apps that
20 # each solve basic desktop-work-related needs and generally improve the
21 # usability and eye-candy of the modern Linux-desktop.
22 #
23 # TODO: (possible improvements, not essential)
24 # - still more error-handling and maybe custom exceptions!!!
25 # - improve xml-based menu (is implemented, but I'm not happy with it)
26 # - switching themes slowly increases the memory usage (possible leak)
27 # - maybe attributes for dependancies/requirements (e.g. special
28 # python-libs or certain Screenlets)
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 # import screenlet-submodules
53 from options import *
54 import services
55 import utils
56 import sensors
57 # TEST
58 import menu
59 from menu import DefaultMenuItem, add_menuitem
60 from drawing import Drawing
61 # /TEST
62
63 # translation stuff
64 gettext.textdomain('screenlets')
65 gettext.bindtextdomain('screenlets', INSTALL_PREFIX + '/share/locale')
66
69
70 #-------------------------------------------------------------------------------
71 # CONSTANTS
72 #-------------------------------------------------------------------------------
73
74 # the application name
75 APP_NAME = "Screenlets"
76
77 # the version of the Screenlets-baseclass in use
78 VERSION = "0.1.3"
79
80 # the application copyright
81 COPYRIGHT = "(c) RYX (Rico Pfaus) <ryx@ryxperience.com>\nWhise (Helder Fraga) <helder.fraga@hotmail.com>"
82
83 # the application authors
84 AUTHORS = ["RYX (Rico Pfaus) <ryx@ryxperience.com>", "Whise (Helder Fraga)<helder.fraga@hotmail.com>","Sorcerer (Hendrik Kaju)"]
85
86 # the application comments
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 # the application website
96 WEBSITE = 'http://www.screenlets.org'
97
98 # The Screenlets download page. Notice that if you translate this, you also have to create/translate the page for your language on the Screenlets.org (it's a Wiki!)
99 THIRD_PARTY_DOWNLOAD = _("http://www.screenlets.org/index.php/Get_more_screenlets")
100
101
102 #-------------------------------------------------------------------------------
103 # PATHS
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 # note that this is the order how themes are preferred to each other
118 # don't change the order just like that
119 SCREENLETS_PATH = [DIR_USER, DIR_USER_ROOT]
120
121 SCREENLETS_PACK_PREFIX = "screenlets-pack-"
122
123 #-------------------------------------------------------------------------------
124 # DBUS
125 #-------------------------------------------------------------------------------
126
127 DAEMON_BUS = 'org.screenlets.ScreenletsDaemon'
128
129 DAEMON_PATH = '/org/screenlets/ScreenletsDaemon'
130
131 DAEMON_IFACE = 'org.screenlets.ScreenletsDaemon'
132
133 #Other stuff
134
135 DEBUG_MODE = True
136
137 DEBIAN = subprocess.call("which dpkg", shell=True)==0
138
139 #-------------------------------------------------------------------------------
140 # CLASSES
141 #-------------------------------------------------------------------------------
142
144 """A container with constants for the default menuitems"""
145
146 # default menuitem constants (is it right to increase like this?)
147 NONE = 0
148 DELETE = 1
149 THEMES = 2
150 INFO = 4
151 SIZE = 8
152 WINDOW_MENU = 16
153 PROPERTIES = 32
154 DELETE = 64
155 QUIT = 128
156 QUIT_ALL = 256
157 # EXPERIMENTAL!! If you use this, the file menu.xml in the
158 # Screenlet's data-dir is used for generating the menu ...
159 XML = 512
160 ADD = 1024
161 # the default items
162 STANDARD = 1|2|8|16|32|64|128|256|1024
163
164
166 """ScreenletThemes are simple storages that allow loading files
167 as svg-handles within a theme-directory. Each Screenlet can have
168 its own theme-directory. It is up to the Screenlet-developer if he
169 wants to let his Screenlet support themes or not. Themes are
170 turned off by default - if your Screenlet uses Themes, just set the
171 attribute 'theme_name' to the name of the theme's dir you want to use.
172 TODO: remove dict-inheritance"""
173
174 # meta-info (set through theme.conf)
175 __name__ = ''
176 __author__ = ''
177 __version__ = ''
178 __info__ = ''
179
180 # attributes
181 path = ""
182 loaded = False
183 width = 0
184 height = 0
185 option_overrides = {}
186 p_fdesc = None
187 p_layout = None
188 tooltip = None
189 notify = None
190
191
193 # set theme-path and load all files in path
194 self.path = path
195 self.svgs = {}
196 self.pngs = {}
197 self.option_overrides = {}
198 self.loaded = self.__load_all()
199 if self.loaded == False:
200 raise Exception("Error while loading ScreenletTheme in: " + path)
201
203 if name in ("width", "height"):
204 if self.loaded and len(self)>0:
205 size=self[0].get_dimension_data()
206 if name=="width":
207 return size[0]
208 else:
209 return size[1]
210 else:
211 return object.__getattr__(self, name)
212
214 """Apply this theme's overridden options to the given Screenlet."""
215 # disable the canvas-updates in the screenlet
216 screenlet.disable_updates = True
217 # theme_name needs special care (must be applied last)
218 theme_name = ''
219 # loop through overrides and appply them
220 for name in self.option_overrides:
221 print "Override: " + name
222 o = screenlet.get_option_by_name(name)
223 if o and not o.protected:
224 if name == 'theme_name':
225 # import/remember theme-name, but not apply yet
226 theme_name = o.on_import(self.option_overrides[name])
227 else:
228 # set option in screenlet
229 setattr(screenlet, name,
230 o.on_import(self.option_overrides[name]))
231 else:
232 print "WARNING: Option '%s' not found or protected." % name
233 # now apply theme
234 if theme_name != '':
235 screenlet.theme_name = theme_name
236 # re-enable updates and call redraw/reshape
237 screenlet.disable_updates = False
238 screenlet.redraw_canvas()
239 screenlet.update_shape()
240
242 """Checks if a file with filename is loaded in this theme."""
243 try:
244 if self[filename]:
245 return True
246 except:
247 #raise Exception
248 return False
249
251 """@DEPRECATED Moved to Screenlets class: Returns the pixel width of a given text"""
252 ctx.save()
253
254 if self.p_layout == None :
255
256 self.p_layout = ctx.create_layout()
257 else:
258
259 ctx.update_layout(self.p_layout)
260 self.p_fdesc = pango.FontDescription(font)
261 self.p_layout.set_font_description(self.p_fdesc)
262 self.p_layout.set_text(text)
263 extents, lextents = self.p_layout.get_pixel_extents()
264 ctx.restore()
265 return extents[2]
266
268 """@DEPRECATED Moved to Screenlets class: Returns the pixel extents of a given text"""
269 ctx.save()
270
271 if self.p_layout == None :
272
273 self.p_layout = ctx.create_layout()
274 else:
275
276 ctx.update_layout(self.p_layout)
277 self.p_fdesc = pango.FontDescription(font)
278 self.p_layout.set_font_description(self.p_fdesc)
279 self.p_layout.set_text(text)
280 extents, lextents = self.p_layout.get_pixel_extents()
281 ctx.restore()
282 return extents
283
284 - def draw_text(self, ctx, text, x, y, font, size, width, allignment, weight = 0, ellipsize = pango.ELLIPSIZE_NONE):
285 """@DEPRECATED Moved to Screenlets class: Draws text"""
286 ctx.save()
287 ctx.translate(x, y)
288 if self.p_layout == None :
289
290 self.p_layout = ctx.create_layout()
291 else:
292
293 ctx.update_layout(self.p_layout)
294 self.p_fdesc = pango.FontDescription()
295 self.p_fdesc.set_family_static(font)
296 self.p_fdesc.set_size(size * pango.SCALE)
297 self.p_fdesc.set_weight(weight)
298 self.p_layout.set_font_description(self.p_fdesc)
299 self.p_layout.set_width(width * pango.SCALE)
300 self.p_layout.set_alignment(allignment)
301 self.p_layout.set_ellipsize(ellipsize)
302 self.p_layout.set_markup(text)
303 ctx.show_layout(self.p_layout)
304 ctx.restore()
305
306
308 """@DEPRECATED Moved to Screenlets class: Draws a circule"""
309 ctx.save()
310 ctx.translate(x, y)
311 ctx.arc(width/2,height/2,min(height,width)/2,0,2*math.pi)
312 if fill:ctx.fill()
313 else: ctx.stroke()
314 ctx.restore()
315
316 - def draw_line(self,ctx,start_x,start_y,end_x,end_y,line_width = 1,close=False,preserve=False):
317 """@DEPRECATED Moved to Screenlets class: Draws a line"""
318 ctx.save()
319 ctx.move_to(start_x, start_y)
320 ctx.set_line_width(line_width)
321 ctx.rel_line_to(end_x, end_y)
322 if close : ctx.close_path()
323 if preserve: ctx.stroke_preserve()
324 else: ctx.stroke()
325 ctx.restore()
326
328 """@DEPRECATED Moved to Screenlets class: Draws a rectangle"""
329 ctx.save()
330 ctx.translate(x, y)
331 ctx.rectangle (0,0,width,height)
332 if fill:ctx.fill()
333 else: ctx.stroke()
334 ctx.restore()
335
337 """@DEPRECATED Moved to Screenlets class: Draws a rounded rectangle"""
338 ctx.save()
339 ctx.translate(x, y)
340 padding=0 # Padding from the edges of the window
341 rounded=rounded_angle # How round to make the edges 20 is ok
342 w = width
343 h = height
344
345 # Move to top corner
346 ctx.move_to(0+padding+rounded, 0+padding)
347
348 # Top right corner and round the edge
349 ctx.line_to(w-padding-rounded, 0+padding)
350 ctx.arc(w-padding-rounded, 0+padding+rounded, rounded, (math.pi/2 )+(math.pi) , 0)
351
352 # Bottom right corner and round the edge
353 ctx.line_to(w-padding, h-padding-rounded)
354 ctx.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
355
356 # Bottom left corner and round the edge.
357 ctx.line_to(0+padding+rounded, h-padding)
358 ctx.arc(0+padding+rounded, h-padding-rounded, rounded,math.pi/2, math.pi)
359
360 # Top left corner and round the edge
361 ctx.line_to(0+padding, 0+padding+rounded)
362 ctx.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi, (math.pi/2 )+(math.pi))
363
364 # Fill in the shape.
365 if fill:ctx.fill()
366 else: ctx.stroke()
367 ctx.restore()
368
370 """@DEPRECATED Moved to Screenlets class: Gets a picture width and height"""
371
372 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
373 iw = pixbuf.get_width()
374 ih = pixbuf.get_height()
375 puxbuf = None
376 return iw,ih
377
379 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path"""
380
381 ctx.save()
382 ctx.translate(x, y)
383 pixbuf = gtk.gdk.pixbuf_new_from_file(pix)
384 format = cairo.FORMAT_RGB24
385 if pixbuf.get_has_alpha():
386 format = cairo.FORMAT_ARGB32
387
388 iw = pixbuf.get_width()
389 ih = pixbuf.get_height()
390 image = cairo.ImageSurface(format, iw, ih)
391 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
392
393 ctx.paint()
394 puxbuf = None
395 image = None
396 ctx.restore()
397
398
399
401 """@DEPRECATED Moved to Screenlets class: Draws a picture from specified path with a certain width and height"""
402
403 ctx.save()
404 ctx.translate(x, y)
405 pixbuf = gtk.gdk.pixbuf_new_from_file(pix).scale_simple(w,h,gtk.gdk.INTERP_HYPER)
406 format = cairo.FORMAT_RGB24
407 if pixbuf.get_has_alpha():
408 format = cairo.FORMAT_ARGB32
409
410 iw = pixbuf.get_width()
411 ih = pixbuf.get_height()
412 image = cairo.ImageSurface(format, iw, ih)
413
414 matrix = cairo.Matrix(xx=iw/w, yy=ih/h)
415 image = ctx.set_source_pixbuf(pixbuf, 0, 0)
416 if image != None :image.set_matrix(matrix)
417 ctx.paint()
418 puxbuf = None
419 image = None
420 ctx.restore()
421
423 """@DEPRECATED Moved to Screenlets class: Show notification window at current mouse position."""
424 if self.notify == None:
425 self.notify = Notify()
426 self.notify.text = text
427 self.notify.show()
428
430 """@DEPRECATED Moved to Screenlets class: hide notification window"""
431 if self.notify != None:
432 self.notify.hide()
433 self.notify = None
434
436 """@DEPRECATED: Moved to Screenlets class: Show tooltip window at current mouse position."""
437 if self.tooltip == None:
438 self.tooltip = Tooltip(300, 400)
439 self.tooltip.text = text
440 self.tooltip.x = tooltipx
441 self.tooltip.y = tooltipy
442 self.tooltip.show()
443
445 """@DEPRECATED Moved to Screenlets class: hide tooltip window"""
446 if self.tooltip != None:
447 self.tooltip.hide()
448 self.tooltip = None
449
451 """Check if this theme contains overrides for options."""
452 return len(self.option_overrides) > 0
453
455 """Load a config-file from this theme's dir and save vars in list."""
456 ini = utils.IniReader()
457 if ini.load(filename):
458 if ini.has_section('Theme'):
459 self.__name__ = ini.get_option('name', section='Theme')
460 self.__author__ = ini.get_option('author', section='Theme')
461 self.__version__ = ini.get_option('version', section='Theme')
462 self.__info__ = ini.get_option('info', section='Theme')
463 if ini.has_section('Options'):
464 opts = ini.list_options(section='Options')
465 if opts:
466 for o in opts:
467 self.option_overrides[o[0]] = o[1]
468 print "Loaded theme config from:", filename
469 print "\tName: " + str(self.__name__)
470 print "\tAuthor: " +str(self.__author__)
471 print "\tVersion: " +str(self.__version__)
472 print "\tInfo: " +str(self.__info__)
473 else:
474 print "Failed to theme config from", filename
475
476
478 """Load an SVG-file into this theme and reference it as ref_name."""
479 if self.has_key(filename):
480 del self[filename]
481 try:
482 self[filename] = rsvg.Handle(self.path + "/" + filename)
483 self.svgs[filename[:-4]] = self[filename]
484 if self[filename] != None:
485 # set width/height
486 size=self[filename].get_dimension_data()
487 if size:
488 self.width = size[0]
489 self.height = size[1]
490 return True
491 except NameError, ex:
492 self[filename] = gtk.gdk.pixbuf_new_from_file(self.path + '/' + filename)
493 self.svgs[filename[:-4]] = self[filename]
494 if self[filename] != None:
495 # set width/height
496 self.width = self[filename].get_width()
497 self.height = self[filename].get_height()
498 print str(ex)
499 return True
500
501 else:
502 return False
503 #self[filename] = None
504
506 """Load a PNG-file into this theme and reference it as ref_name."""
507 if self.has_key(filename):
508 del self[filename]
509 self[filename] = cairo.ImageSurface.create_from_png(self.path +
510 "/" + filename)
511 self.pngs[filename[:-4]] = self[filename]
512 if self[filename] != None:
513 return True
514 else:
515 return False
516 #self[filename] = None
517
519 """Load all files in the theme's path. Currently only loads SVGs and
520 PNGs."""
521 # clear overrides
522 #self.__option_overrides = {}
523 # read dir
524 dirlst = glob.glob(self.path + '/*')
525 if len(dirlst)==0:
526 return False
527 plen = len(self.path) + 1
528 for file in dirlst:
529 fname = file[plen:]
530 if fname.endswith('.svg'):
531 # svg file
532 if self.load_svg(fname) == False:
533 return False
534 elif fname.endswith('.png'):
535 # svg file
536 if self.load_png(fname) == False:
537 return False
538 elif fname == "theme.conf":
539 print "theme.conf found! Loading option-overrides."
540 # theme.conf
541 if self.load_conf(file) == False:
542 return False
543 # print "Theme %s loaded from %s" % (self.__name__, self.path)
544 return True
545
550
551 # TODO: fix function, rsvg handles are not freed properly
553 """Deletes the Theme's contents and frees all rsvg-handles.
554 TODO: freeing rsvg-handles does NOT work for some reason"""
555 self.option_overrides.clear()
556 for filename in self:
557 try:
558 self[filename].free()
559 except AttributeError:pass
560 #self[filename].close()
561 del filename
562 self.clear()
563
564 # TEST: render-function
565 # should be used like "theme.render(context, 'notes-bg')" and then use
566 # either an svg or png image
568 """Render an image from within this theme to the given context. This
569 function can EITHER use png OR svg images, so it is possible to
570 create themes using both image-formats when a Screenlet uses this
571 function for drawing its images. The image name has to be defined
572 without the extension and the function will automatically select
573 the available one (SVG is prefered over PNG)."""
574
575 ### Render Graphics even if rsvg is not available###
576 if os.path.isfile (self.path + '/' + name + '.svg'):
577
578 try:
579 self.svgs[name].render_cairo(ctx)
580 except:
581 try:
582 ctx.set_source_pixbuf(self.svgs[name], 0, 0)
583
584 ctx.paint()
585 pixbuf = None
586 except TypeError:
587 ctx.set_source_surface(self.pngs[name], 0, 0)
588 ctx.paint()
589
590 elif os.path.isfile (self.path + '/' + name + '.png'):
591 ctx.set_source_surface(self.pngs[name], 0, 0)
592 ctx.paint()
593
594
595
597 # Scale the pixmap
598 ctx.set_source_rgba(color[0], color[1], color[2], color[3])
599 ctx.set_source_surface(self.pngs[name], 0, 0)
600 ctx.mask_surface(image, 0, 0)
601 ctx.stroke()
602
603
604
606 """A Screenlet is a (i.e. contains a) shaped gtk-window that is
607 fully invisible by default. Subclasses of Screenlet can render
608 their owner-drawn graphics on fully transparent background."""
609
610 # default meta-info for Screenlets
611 __name__ = _('No name set for this Screenlet')
612 __version__ = '0.0'
613 __author__ = _('No author defined for this Screenlet')
614 __desc__ = _('No info set for this Screenlet')
615 __requires__ = []
616 #__target_version__ = '0.0.0'
617 #__backend_version__ = '0.0.1'
618
619 # attributes (TODO: remove them here and add them to the constructor,
620 # because they only should exist per instance)
621 id = '' # id-attribute for handling instances
622 window = None # the gtk.Window behind the scenes
623 theme = None # the assigned ScreenletTheme
624 uses_theme = True # flag indicating whether Screenlet uses themes
625 draw_buttons = True
626 show_buttons = True
627 menu = None # the right-click gtk.Menu
628 is_dragged = False # TODO: make this work
629 quit_on_close = True # if True, closing this instance quits gtk
630 saving_enabled = True # if False, saving is disabled
631 dragging_over = False # true if something is dragged over
632 disable_updates = False # to temporarily avoid refresh/reshape
633 p_context = None # PangoContext
634 p_layout = None # PangoLayout
635
636 # default editable options, available for all Screenlets
637 x = 0
638 y = 0
639 mousex = 0
640 mousey = 0
641 mouse_is_over = False
642 width = 100
643 height = 100
644 scale = 1.0
645 opacity = 1.0
646 theme_name = ""
647 is_visible = True
648 is_sticky = False
649 is_widget = False
650 keep_above = True
651 keep_below = False
652 skip_pager = True
653 first_run = False
654 skip_taskbar = True
655 lock_position = False
656 allow_option_override = True # if False, overrides are ignored
657 ask_on_option_override = True # if True, overrides need confirmation
658 ignore_requirements = False # if True, DEB requirements are ignored
659 resize_on_scroll = True
660 has_started = False
661 has_focus = False
662 # internals (deprecated? we still don't get the end of a begin_move_drag)
663 gtk_icon_theme = None
664 __lastx = 0
665 __lasty = 0
666 p_fdesc = None
667 p_layout = None
668 tooltip = None
669 notify = None
670 # some menuitems (needed for checking/unchecking)
671 # DEPRECATED: remove - don't really work anyway ... (or fix the menu?)
672 __mi_keep_above = None
673 __mi_keep_below = None
674 __mi_widget = None
675 __mi_sticky = None
676 __mi_lock = None
677 # for custom signals (which aren't acutally used ... yet)
678 __gsignals__ = dict(screenlet_removed=(gobject.SIGNAL_RUN_FIRST,
679 gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)))
680
681 - def __init__ (self, id='', width=100, height=100, parent_window=None,
682 show_window=True, is_widget=False, is_sticky=False,
683 uses_theme=True, draw_buttons=True,path=os.getcwd(), drag_drop=False, session=None,
684 enable_saving=True, service_class=services.ScreenletService,
685 uses_pango=False, is_sizable=True,resize_on_scroll=True, ask_on_option_override=False):
686 """Constructor - should only be subclassed"""
687
688 # call gobject and EditableOptions superclasses
689 super(Screenlet, self).__init__()
690 EditableOptions.__init__(self)
691 # init properties
692 self.id = id
693 self.session = session
694 self.service = None
695 self.__desc__ = self.__doc__
696
697 # if we have an id and a service-class, register our service
698 if self.id and service_class:
699 self.register_service(service_class)
700 # notify service about adding this instance
701 self.service.instance_added(self.id)
702 self.width = width
703 self.height = height
704 self.is_dragged = False
705 self.__path__ = path
706 self.saving_enabled = enable_saving # used by session
707 # set some attributes without calling __setattr__
708 self.__dict__['theme_name'] = ""
709 self.__dict__['is_widget'] = is_widget
710 self.__dict__['is_sticky'] = is_sticky
711 self.__dict__['draw_buttons'] = draw_buttons
712 self.resize_on_scroll = resize_on_scroll
713 self.__dict__['x'] = 0
714 self.__dict__['y'] = 0
715 # TEST: set scale relative to theme size (NOT WORKING)
716 #self.__dict__['scale'] = width/100.0
717 # /TEST
718 # shape bitmap
719 self.__shape_bitmap = None
720 self.__shape_bitmap_width = 0
721 self.__shape_bitmap_height = 0
722 # "editable" options, first create a group
723 self.add_options_group('Screenlet',
724 _('The basic settings for this Screenlet-instance.'))
725 # if this Screenlet uses themes, add theme-specific options
726 # (NOTE: this option became hidden with 0.0.9 and doesn't use
727 # get_available_themes anymore for showing the choices)
728 self.gtk_icon_theme = gtk.icon_theme_get_default()
729 self.load_buttons(None)
730 self.gtk_icon_theme.connect("changed", self.load_buttons)
731 if draw_buttons: self.draw_buttons = True
732 else: self.draw_buttons = False
733 if uses_theme:
734 self.uses_theme = True
735 self.add_option(StringOption('Screenlet', 'theme_name',
736 'default', '', '', hidden=True))
737 # create/add options
738 self.add_option(IntOption('Screenlet', 'x',
739 0, _('X-Position'), _('The X-position of this Screenlet ...'),
740 min=0, max=gtk.gdk.screen_width()))
741 self.add_option(IntOption('Screenlet', 'y',
742 0, _('Y-Position'), _('The Y-position of this Screenlet ...'),
743 min=0, max=gtk.gdk.screen_height()))
744 self.add_option(IntOption('Screenlet', 'width',
745 width, _('Width'), _('The width of this Screenlet ...'),
746 min=16, max=1000, hidden=True))
747 self.add_option(IntOption('Screenlet', 'height',
748 height, _('Height'), _('The height of this Screenlet ...'),
749 min=16, max=1000, hidden=True))
750 self.add_option(FloatOption('Screenlet', 'scale',
751 self.scale, _('Scale'), _('The scale-factor of this Screenlet ...'),
752 min=0.1, max=10.0, digits=2, increment=0.1))
753 self.add_option(FloatOption('Screenlet', 'opacity',
754 self.opacity, _('Opacity'), _('The opacity of the Screenlet window ...'),
755 min=0.1, max=1.0, digits=2, increment=0.1))
756 self.add_option(BoolOption('Screenlet', 'is_sticky',
757 is_sticky, _('Stick to Desktop'),
758 _('Show this Screenlet on all workspaces ...')))
759 self.add_option(BoolOption('Screenlet', 'is_widget',
760 is_widget, _('Treat as Widget'),
761 _('Treat this Screenlet as a "Widget" ...')))
762 self.add_option(BoolOption('Screenlet', 'is_dragged',
763 self.is_dragged, "Is the screenlet dragged","Is the screenlet dragged", hidden=True))
764 self.add_option(BoolOption('Screenlet', 'is_sizable',
765 is_sizable, "Can the screenlet be resized","is_sizable", hidden=True))
766 self.add_option(BoolOption('Screenlet', 'is_visible',
767 self.is_visible, "Usefull to use screenlets as gnome panel applets","is_visible", hidden=True))
768 self.add_option(BoolOption('Screenlet', 'lock_position',
769 self.lock_position, _('Lock position'),
770 _('Stop the screenlet from being moved...')))
771 self.add_option(BoolOption('Screenlet', 'keep_above',
772 self.keep_above, _('Keep above'),
773 _('Keep this Screenlet above other windows ...')))
774 self.add_option(BoolOption('Screenlet', 'keep_below',
775 self.keep_below, _('Keep below'),
776 _('Keep this Screenlet below other windows ...')))
777 self.add_option(BoolOption('Screenlet', 'draw_buttons',
778 self.draw_buttons, _('Draw button controls'),
779 _('Draw buttons in top right corner')))
780 self.add_option(BoolOption('Screenlet', 'skip_pager',
781 self.skip_pager, _('Skip Pager'),
782 _('Set this Screenlet to show/hide in pagers ...')))
783 self.add_option(BoolOption('Screenlet', 'skip_taskbar',
784 self.skip_pager, _('Skip Taskbar'),
785 _('Set this Screenlet to show/hide in taskbars ...')))
786 self.add_option(BoolOption('Screenlet', 'resize_on_scroll',
787 self.resize_on_scroll, _("Resize on mouse scroll"),"resize_on_scroll"))
788 self.add_option(BoolOption('Screenlet', 'ignore_requirements',
789 self.ignore_requirements, _('Ignore requirements'),
790 _('Set this Screenlet to ignore/demand DEB requirements ...')))
791 if uses_theme:
792 self.ask_on_option_override = ask_on_option_override
793 self.add_option(BoolOption('Screenlet', 'allow_option_override',
794 self.allow_option_override, _('Allow overriding Options'),
795 _('Allow themes to override options in this screenlet ...')))
796 self.add_option(BoolOption('Screenlet', 'ask_on_option_override',
797 self.ask_on_option_override, _('Ask on Override'),
798 _('Show a confirmation-dialog when a theme wants to override ')+\
799 _('the current options of this Screenlet ...')))
800 # disable width/height
801 self.disable_option('width')
802 self.disable_option('height')
803 # create window
804 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
805 if parent_window:
806 self.window.set_parent_window(parent_window)
807 self.window.set_transient_for(parent_window)
808 self.window.set_destroy_with_parent(True)
809 self.window.resize(width, height)
810 self.window.set_decorated(False)
811 self.window.set_app_paintable(True)
812 # create pango layout, if active
813 if uses_pango:
814 self.p_context = self.window.get_pango_context()
815 if self.p_context:
816 self.p_layout = pango.Layout(self.p_context)
817 self.p_layout.set_font_description(\
818 pango.FontDescription("Sans 12"))
819 # set type hint
820
821 if str(sensors.sys_get_window_manager()).lower() == 'kwin':
822 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
823 #self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
824 elif str(sensors.sys_get_window_manager()).lower() == 'sawfish':
825 print "WARNING - You are using kwin window manager , screenlets doesnt have full compatibility with this window manager"
826 else:
827 self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_TOOLBAR)
828 self.window.set_keep_above(True)
829 self.window.set_skip_taskbar_hint(True)
830 self.window.set_skip_pager_hint(True)
831 if is_sticky:
832 self.window.stick()
833 self.alpha_screen_changed(self.window)
834 self.update_shape()
835 #self.window.set_events(gtk.gdk.BUTTON_PRESS_MASK)
836 self.window.set_events(gtk.gdk.ALL_EVENTS_MASK)
837 self.window.connect("composited-changed", self.composite_changed)
838 self.window.connect("delete_event", self.delete_event)
839 self.window.connect("destroy", self.destroy)
840 self.window.connect("expose_event", self.expose)
841 self.window.connect("button-press-event", self.button_press)
842 self.window.connect("button-release-event", self.button_release)
843 self.window.connect("configure-event", self.configure_event)
844 self.window.connect("screen-changed", self.alpha_screen_changed)
845 self.window.connect("realize", self.realize_event)
846 self.window.connect("enter-notify-event", self.enter_notify_event)
847 self.window.connect("leave-notify-event", self.leave_notify_event)
848 self.window.connect("focus-in-event", self.focus_in_event)
849 self.window.connect("focus-out-event", self.focus_out_event)
850 self.window.connect("scroll-event", self.scroll_event)
851 self.window.connect("motion-notify-event",self.motion_notify_event)
852 self.window.connect("map-event", self.map_event)
853 self.window.connect("unmap-event", self.unmap_event)
854 # add key-handlers (TODO: use keyword-attrib to activate?)
855 self.window.connect("key-press-event", self.key_press)
856 # drag/drop support (NOTE: still experimental and incomplete)
857 if drag_drop:
858 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
859 gtk.DEST_DEFAULT_DROP, #gtk.DEST_DEFAULT_ALL,
860 [("text/plain", 0, 0),
861 ("image", 0, 1),
862 ("text/uri-list", 0, 2)],
863 gtk.gdk.ACTION_COPY)
864 self.window.connect("drag_data_received", self.drag_data_received)
865 self.window.connect("drag-begin", self.drag_begin)
866 self.window.connect("drag-end", self.drag_end)
867 self.window.connect("drag-motion", self.drag_motion)
868 self.window.connect("drag-leave", self.drag_leave)
869 # create menu
870 self.menu = gtk.Menu()
871 # show window so it can realize , but hiding it so we can show it only when atributes have been set , this fixes some placement errors arround the screen egde
872
873
874 if show_window:
875 self.window.show()
876 # print os.environ['HOME'] + '/.config/Screenlets/' + self.__name__[:-9] + '/default/'+ self.id
877 if not os.path.exists(os.environ['HOME'] + '/.config/Screenlets/' + self.__name__[:-9] + '/default/'+ self.id + '.ini'):
878 self.first_run = True
879 self.window.hide()
880
881 #Make opacity available only when composite is enabled
882 if not self.window.is_composited () :
883 self.disable_option('opacity')
884
886 # set the value in GObject (ESSENTIAL!!!!)
887 self.on_before_set_atribute(name, value)
888 gobject.GObject.__setattr__(self, name, value)
889 # And do other actions
890 if name=="x" or name=="y":
891 if self.has_started:
892 self.window.move(self.x, self.y)
893 elif name == 'opacity':
894 self.window.set_opacity(value)
895 elif name == 'scale':
896 self.window.resize(int(self.width * self.scale),
897 int(self.height * self.scale))
898 # TODO: call on_resize-handler here !!!!
899 self.on_scale()
900 self.redraw_canvas()
901 self.update_shape()
902
903
904 elif name == "theme_name":
905 #self.__dict__ ['theme_name'] = value
906 #self.load_theme(self.get_theme_dir() + value)
907 # load theme
908 print "Theme set to: '%s'" % value
909 path = self.find_theme(value)
910 if path:
911 self.load_theme(path)
912 #self.load_first_theme(value)
913 self.redraw_canvas()
914 self.update_shape()
915 elif name in ("width", "height"):
916 #self.__dict__ [name] = value
917 if self.window:
918 self.window.resize(int(self.width*self.scale), int(self.height*self.scale))
919 #self.redraw_canvas()
920 self.update_shape()
921 elif name == "is_widget":
922 if self.has_started:
923 self.set_is_widget(value)
924 elif name == "is_visible":
925 if self.has_started:
926 if value == True:
927 self.reshow()
928 else:
929 self.window.hide()
930 elif name == "is_sticky":
931 if value == True:
932 self.window.stick()
933 else:
934 self.window.unstick()
935 #if self.__mi_sticky:
936 # self.__mi_sticky.set_active(value)
937 elif name == "keep_above":
938 if self.has_started == True:
939 self.window.set_keep_above(bool(value))
940 #self.__mi_keep_above.set_active(value)
941 elif name == "keep_below":
942 if self.has_started == True:
943 self.window.set_keep_below(bool(value))
944 #self.__mi_keep_below.set_active(value)
945 elif name == "skip_pager":
946 if self.window.window:
947 self.window.window.set_skip_pager_hint(bool(value))
948 elif name == "skip_taskbar":
949 if self.window.window:
950 self.window.window.set_skip_taskbar_hint(bool(value))
951 # NOTE: This is the new recommended way of storing options in real-time
952 # (we access the backend through the session here)
953 if self.saving_enabled:
954 o = self.get_option_by_name(name)
955 if o != None:
956 self.session.backend.save_option(self.id, o.name,
957 o.on_export(value))
958 self.on_after_set_atribute(name, value)
959 # /TEST
960
961 #-----------------------------------------------------------------------
962 # Screenlet's public functions
963 #-----------------------------------------------------------------------
964
966 '''Checks if required DEB packages are installed'''
967
968 req_feedback = ""
969 fail = False
970
971 # operators=['>', '=', '<']
972
973 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/"'
974 for req in self.__requires__:
975 operator = None
976 # req = req.replace(' ', '')
977 if req.find('(') != -1:
978 # package version is specified with an operator (no logical operators supported yet!)
979 pos = req.find('(')
980 package = req[:pos].strip()
981 version_str = req[pos+1:]
982 version_str = version_str[:version_str.find(')')]
983 while version_str.find(' ') != -1:
984 version_str = req.replace(' ', ' ')
985 res = version_str.split(' ')
986 version = res[1]
987 operator = res[0]
988 else:
989 # when only package name is specified
990 package = req
991 # version of the deb package if unspecified
992 version = _("?")
993
994 installed_version = os.popen(commandstr % package).readline().replace('\n', '')
995
996 if len(installed_version) < 1:
997 req_feedback += _("\n%(package)s %(version)s required, NOT INSTALLED!") % {"package":package, "version":version}
998 fail = True
999 else:
1000 req_feedback += _("\n%(package)s %(version)s installed, req %(required)s.") % {"package":package, "version":installed_version, "required":version}
1001 # will fail only if dpkg says that version is too old
1002 # otherwise it's responsibility of developer to provide
1003 # correct version id and operator (won't detect problems with these)
1004 if operator is not None:
1005 comp_command = "dpkg --compare-versions \"" + installed_version + "\" \"" + operator + "\" \"" + version + "\""
1006 # print comp_command
1007 if subprocess.call(comp_command, shell=True) != 0:
1008 fail = True
1009 if fail:
1010 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")
1011
1124
1135
1155
1156
1157
1161
1182
1184 """Fills the given cairo.Context with fully transparent white."""
1185 ctx.save()
1186 ctx.set_source_rgba(1, 1, 1, 0)
1187 ctx.set_operator (cairo.OPERATOR_SOURCE)
1188 ctx.paint()
1189 ctx.restore()
1190
1192 """Close this Screenlet
1193 TODO: send close-notify instead of destroying window?"""
1194 #self.save_settings()
1195 self.window.unmap()
1196 self.window.destroy()
1197 #self.window.event(gtk.gdk.Event(gtk.gdk.DELETE))
1198
1200 """Create drag-icon and -mask for drag-operation. Returns a 2-tuple
1201 with the icon and the mask. To supply your own icon you can use the
1202 on_create_drag_icon-handler and return the icon/mask as 2-tuple."""
1203 w = self.width
1204 h = self.height
1205 icon, mask = self.on_create_drag_icon()
1206 if icon == None:
1207 # create icon
1208 icon = gtk.gdk.Pixmap(self.window.window, w, h)
1209 ctx = icon.cairo_create()
1210 self.clear_cairo_context(ctx)
1211 self.on_draw(ctx)
1212 if mask == None:
1213 # create mask
1214 mask = gtk.gdk.Pixmap(self.window.window, w, h)
1215 ctx = mask.cairo_create()
1216 self.clear_cairo_context(ctx)
1217 self.on_draw_shape(ctx)
1218 return (icon, mask)
1219
1223
1225 """Find the best occurence of a theme and return its global path."""
1226 sn = self.get_short_name()
1227 utils.refresh_available_screenlet_paths()
1228 for p in SCREENLETS_PATH:
1229 fpath = p + '/' + sn + '/themes/' + name
1230 if os.path.isdir(fpath):
1231 return fpath
1232 return None
1233
1235 """Return the short name of this screenlet. This returns the classname
1236 of the screenlet without trailing "Screenlet". Please always use
1237 this function if you want to retrieve the short name of a Screenlet."""
1238 return self.__class__.__name__[:-9]
1239
1241 """Return the name of this screenlet's personal directory."""
1242 p = utils.find_first_screenlet_path(self.get_short_name())
1243 if p:
1244 return p
1245 else:
1246 if self.__path__ != '':
1247 return self.__path__
1248 else:
1249 return os.getcwd()
1250
1252 """Return the name of this screenlet's personal theme-dir.
1253 (Only returns the dir under the screenlet's location"""
1254 return self.get_screenlet_dir() + "/themes/"
1255
1257 """Returns a list with the names of all available themes in this
1258 Screenlet's theme-directories."""
1259 lst = []
1260 utils.refresh_available_screenlet_paths()
1261 for p in SCREENLETS_PATH:
1262 d = p + '/' + self.get_short_name() + '/themes/'
1263 if os.path.isdir(d):
1264 #dirname = self.get_theme_dir()
1265 dirlst = glob.glob(d + '*')
1266 dirlst.sort()
1267 tdlen = len(d)
1268 for fname in dirlst:
1269 if os.path.isdir(fname):
1270 dname = fname[tdlen:]
1271 if not dname in lst:
1272 lst.append(dname)
1273 return lst
1274
1276 self.window.present()
1277 self.has_started = True
1278 self.is_dragged = False
1279 self.keep_above= self.keep_above
1280 self.keep_below= self.keep_below
1281 self.skip_taskbar = self.skip_taskbar
1282 self.window.set_skip_taskbar_hint(self.skip_taskbar)
1283 self.window.set_keep_above(self.keep_above)
1284 self.window.set_keep_below(self.keep_below)
1285 if self.is_widget:
1286 self.set_is_widget(True)
1287 self.has_focus = False
1288
1290 """Called when screenlet finishes loading"""
1291
1292
1293 self.window.present()
1294
1295
1296 # the keep above and keep bellow must be reset after the window is shown this is absolutly necessary
1297 self.window.hide()
1298 self.window.move(self.x, self.y)
1299
1300 if DEBIAN and not self.ignore_requirements:
1301 self.check_requirements()
1302
1303 self.window.show()
1304 self.has_started = True
1305 self.is_dragged = False
1306 self.keep_above= self.keep_above
1307 self.keep_below= self.keep_below
1308 self.is_sticky = self.is_sticky
1309 self.skip_taskbar = self.skip_taskbar
1310 self.window.set_skip_taskbar_hint(self.skip_taskbar)
1311 self.window.set_keep_above(self.keep_above)
1312 self.window.set_keep_below(self.keep_below)
1313
1314 self.on_init()
1315 if self.is_widget:
1316 self.set_is_widget(True)
1317 self.has_focus = False
1318 ini = utils.IniReader()
1319 if ini.load (os.environ['HOME'] + '/.screenlets' + '/config.ini') and self.first_run:
1320
1321 if ini.get_option('Lock', section='Options') == 'True':
1322 self.lock_position = True
1323 elif ini.get_option('Lock', section='Options') == 'False':
1324 self.lock_position = False
1325 if ini.get_option('Sticky', section='Options') == 'True':
1326 self.is_sticky = True
1327 elif ini.get_option('Sticky', section='Options') == 'False':
1328 self.is_sticky = False
1329 if ini.get_option('Widget', section='Options') == 'True':
1330 self.is_widget = True
1331 elif ini.get_option('Widget', section='Options') == 'False':
1332 self.is_widget = False
1333 if ini.get_option('Keep_above', section='Options') == 'True':
1334 self.keep_above = True
1335 elif ini.get_option('Keep_above', section='Options') == 'False':
1336 self.keep_above = False
1337 if ini.get_option('Keep_below', section='Options') == 'True':
1338 self.keep_below = True
1339 elif ini.get_option('Keep_below', section='Options') == 'False':
1340 self.keep_below = False
1341 if ini.get_option('draw_buttons', section='Options') == 'True':
1342 self.draw_buttons = True
1343 elif ini.get_option('draw_buttons', section='Options') == 'False':
1344 self.draw_buttons = False
1345
1350
1351 # EXPERIMENTAL:
1352 # NOTE: load_theme does NOT call redraw_canvas and update_shape!!!!!
1353 # To do all in one, set attribute self.theme_name instead
1355 """Load a theme for this Screenlet from the given path. NOTE:
1356 load_theme does NOT call redraw_canvas and update_shape!!!!! To do all
1357 in one call, set the attribute self.theme_name instead."""
1358 if self.theme:
1359 self.theme.free()
1360 del self.theme
1361 self.theme = ScreenletTheme(path)
1362 # check for errors
1363 if self.theme.loaded == False:
1364 print "Error while loading theme: " + path
1365 self.theme = None
1366 else:
1367 # call user-defined handler
1368 self.on_load_theme()
1369 # if override options is allowed, apply them
1370 if self.allow_option_override:
1371 if self.theme.has_overrides():
1372 if self.ask_on_option_override==True and \
1373 show_question(self,
1374 _('This theme wants to override your settings for this Screenlet. Do you want to allow that?')) == False:
1375 return
1376 self.theme.apply_option_overrides(self)
1377 # /EXPERIMENTAL
1378
1382
1384 """Register or create the given ScreenletService-(sub)class as the new
1385 service for this Screenlet. If self is not the first instance in the
1386 current session, the service from the first instance will be used
1387 instead and no new service is created."""
1388 if self.session:
1389 if len(self.session.instances) == 0:
1390 # if it is the basic service, add name to call
1391 if service_classobj==services.ScreenletService:#BUG
1392 self.service = service_classobj(self, self.get_short_name())
1393 else:
1394 # else only pass this screenlet
1395 self.service = service_classobj(self)
1396 else:
1397 self.service = self.session.instances[0].service
1398 # TODO: throw exception??
1399 return True
1400 return False
1401
1403 """Set this window to be treated as a Widget (only supported by
1404 compiz using the widget-plugin yet)"""
1405 if value==True:
1406 # set window type to utility
1407 #self.window.window.set_type_hint(
1408 # gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
1409 # set _compiz_widget-property on window
1410 self.window.window.property_change("_COMPIZ_WIDGET",
1411 gtk.gdk.SELECTION_TYPE_WINDOW,
1412 32, gtk.gdk.PROP_MODE_REPLACE, (True,))
1413 else:
1414 # set window type to normal
1415 #self.window.window.set_type_hint(
1416 # gtk.gdk.WINDOW_TYPE_HINT_NORMAL)
1417 # set _compiz_widget-property
1418 self.window.window.property_delete("_COMPIZ_WIDGET")
1419 # notify handler
1420 self.on_switch_widget_state(value)
1421
1423 """Show this Screenlet's underlying gtk.Window"""
1424 self.window.show()
1425 self.window.move(self.x, self.y)
1426 self.on_show()
1427
1429 """Show the EditableSettingsDialog for this Screenlet."""
1430 se = OptionsDialog(490, 450)
1431 img = gtk.Image()
1432 try:
1433 d = self.get_screenlet_dir()
1434 if os.path.isfile(d + '/icon.svg'):
1435 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.svg')
1436 elif os.path.isfile(d + '/icon.png'):
1437 icn = gtk.gdk.pixbuf_new_from_file(d + '/icon.png')
1438 img.set_from_pixbuf(icn)
1439 except:
1440 img.set_from_stock(gtk.STOCK_PROPERTIES, 5)
1441 se.set_title(self.__name__)
1442 se.set_info(self.__name__, glib.markup_escape_text(self.__desc__), '(c) ' + glib.markup_escape_text(self.__author__),
1443 version='v' + self.__version__, icon=img)
1444 se.show_options_for_object(self)
1445 resp = se.run()
1446 if resp == gtk.RESPONSE_REJECT: # TODO!!!!!
1447 se.reset_to_defaults()
1448 else:
1449 self.update_shape()
1450 se.destroy()
1451
1453 """Redraw the entire Screenlet's window area.
1454 TODO: store window alloaction in class and change when size changes."""
1455 # if updates are disabled, just exit
1456 if self.disable_updates:
1457 return
1458 if self.window:
1459 x, y, w, h = self.window.get_allocation()
1460 rect = gtk.gdk.Rectangle(x, y, w, h)
1461 if self.window.window:
1462 self.window.window.invalidate_rect(rect, True)
1463 self.window.window.process_updates(True)
1464 # if self.has_focus and self.draw_buttons and self.show_buttons:
1465 # self.create_buttons()
1466
1467
1469 """Redraw the given Rectangle (x, y, width, height) within the
1470 current Screenlet's window."""
1471 # if updates are disabled, just exit
1472 if self.disable_updates:
1473 return
1474 if self.window:
1475 rect = gtk.gdk.Rectangle(x, y, width, height)
1476 if self.window.window:
1477 self.window.window.invalidate_rect(rect, True)
1478 self.window.window.process_updates(True)
1479
1481 """Removed shaped window , in case the nom composited shape has been set"""
1482 if self.window.window:
1483 self.window.window.shape_combine_mask(None,0,0)
1484
1485 w = self.window.allocation.width
1486 h = self.window.allocation.height
1487
1488 # if 0 return to avoid crashing
1489 if w==0 or h==0: return False
1490 # if size changed, recreate shape bitmap
1491 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1492 self.__shape_bitmap = screenlets.create_empty_bitmap(w, h)
1493 self.__shape_bitmap_width = w
1494 self.__shape_bitmap_height = h
1495
1496 # create context
1497 ctx = self.__shape_bitmap.cairo_create()
1498 self.clear_cairo_context(ctx)
1499
1500 # shape the window acording if the window is composited or not
1501 if self.window.is_composited():
1502 log.debug(_("Updating input shape"))
1503 self.on_draw_shape(ctx)
1504 self.main_view.set_shape(self.__shape_bitmap, True)
1505 else:
1506 try:
1507 self.on_draw_shape(ctx)
1508 except:
1509 self.on_draw(ctx)
1510 log.debug(_("Updating window shape"))
1511 self.main_view.set_shape(self.__shape_bitmap, False)
1512
1514 """Update window shape (only call this when shape has changed
1515 because it is very ressource intense if ran too often)."""
1516 # if updates are disabled, just exit
1517 if self.disable_updates:
1518 return
1519 #print "UPDATING SHAPE"
1520 # TODO:
1521 #if not self.window.is_composited():
1522 # self.update_shape_non_composited()
1523 # calculate new width/height of shape bitmap
1524 w = int(self.width * self.scale)
1525 h = int(self.height * self.scale)
1526 # if 0 set it to 100 to avoid crashes and stay interactive
1527 if w==0: w = 100
1528 if h==0: h = 100
1529 # if size changed, recreate shape bitmap
1530 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1531 data = ''.zfill(w*h)
1532 self.__shape_bitmap = gtk.gdk.bitmap_create_from_data(None, data,
1533 w, h)
1534 self.__shape_bitmap_width = w
1535 self.__shape_bitmap_height = h
1536 # create context and draw shape
1537 ctx = self.__shape_bitmap.cairo_create()
1538 self.clear_cairo_context(ctx) #TEST
1539 if self.has_focus and self.draw_buttons and self.show_buttons:
1540 ctx.save()
1541 #theme1 = gtk.icon_theme_get_default()
1542 #ctx.set_source_rgba(0.5,0.5,0.5,0.6)
1543 #self.theme.draw_rounded_rectangle(ctx,(self.width*self.scale)-36,0,5,36,16)
1544 #close = theme1.load_icon ("gtk-close", 16, 0)
1545 #prop = theme1.load_icon ("gtk-properties", 16, 0)
1546 #zoom1 = theme1.load_icon ("gtk-zoom-in", 16, 0)
1547 #zoom2 = theme1.load_icon ("gtk-zoom-out", 16, 0)
1548 #close = gtk.image_new_from_stock(gtk.STOCK_CLOSE, 16)
1549 ctx.translate((self.width*self.scale)-16,0)
1550 ctx.set_source_pixbuf(self.closeb, 0, 0)
1551 ctx.paint()
1552 ctx.restore()
1553 ctx.save()
1554 ctx.translate((self.width*self.scale)-32,0)
1555 ctx.set_source_pixbuf(self.prop, 0, 0)
1556 ctx.paint()
1557 ctx.restore()
1558 # shape the window acording if the window is composited or not
1559
1560 if self.window.is_composited():
1561
1562 self.on_draw_shape(ctx)
1563 # and cut window with mask
1564 self.window.input_shape_combine_mask(self.__shape_bitmap, 0, 0)
1565 else:
1566 try: self.on_draw(ctx) #Works better then the shape method on non composited windows
1567 except: self.on_draw_shape(ctx) # if error on on_draw use standard shape method
1568 # and cut window with mask
1569 self.window.shape_combine_mask(self.__shape_bitmap,0,0)
1570 self.on_update_shape()
1571
1573 """TEST: This function is intended to shape the window whenever no
1574 composited environment can be found. (NOT WORKING YET!!!!)"""
1575 #pixbuf = gtk.gdk.GdkPixbuf.new_from_file)
1576 # calculate new width/height of shape bitmap
1577 w = int(self.width * self.scale)
1578 h = int(self.height * self.scale)
1579 # if 0 set it to 100 to avoid crashes and stay interactive
1580 if w==0: w = 100
1581 if h==0: h = 100
1582 # if size changed, recreate shape bitmap
1583 if w != self.__shape_bitmap_width or h != self.__shape_bitmap_height:
1584 data = ''.zfill(w*h)
1585 self.__shape_bitmap = gtk.gdk.pixbuf_new_from_data(data,
1586 gtk.gdk.COLORSPACE_RGB, True, 1, w, h, w)
1587 self.__shape_bitmap_width = w
1588 self.__shape_bitmap_height = h
1589 # and render window contents to it
1590 # TOOD!!
1591 if self.__shape_bitmap:
1592 # create new mask
1593 (pixmap,mask) = self.__shape_bitmap.render_pixmap_and_mask(255)
1594 # apply new mask to window
1595 self.window.shape_combine_mask(mask)
1596
1600
1601 # ----------------------------------------------------------------------
1602 # Screenlet's event-handler dummies
1603 # ----------------------------------------------------------------------
1604
1606 """Called when the Screenlet gets deleted. Return True to cancel.
1607 TODO: sometimes not properly called"""
1608 return not show_question(self, _("To quit all %s's, use 'Quit' instead. ") % self.__class__.__name__ +\
1609 _('Really delete this %s and its settings?') % self.get_short_name())
1610 """return not show_question(self, 'Deleting this instance of the '+\
1611 self.__name__ + ' will also delete all your personal '+\
1612 'changes you made to it!! If you just want to close the '+\
1613 'application, use "Quit" instead. Are you sure you want to '+\
1614 'delete this instance?')
1615 return False"""
1616
1617 # TODO: on_drag
1618 # TODO: on_drag_end
1619
1623
1627
1628
1630 """Called when the screenlet's drag-icon is created. You can supply
1631 your own icon and mask by returning them as a 2-tuple."""
1632 return (None, None)
1633
1637
1641
1645
1646
1650
1654
1658
1660 """Callback for drawing the Screenlet's window - override
1661 in subclasses to implement your own drawing."""
1662 pass
1663
1665 """Callback for drawing the Screenlet's shape - override
1666 in subclasses to draw the window's input-shape-mask."""
1667 pass
1668
1672
1676
1680
1682 """Called when the Screenlet's options have been applied and the
1683 screenlet finished its initialization. If you want to have your
1684 Screenlet do things on startup you should use this handler."""
1685 pass
1686
1690
1694
1698
1700 """Called when a buttonpress-event occured in Screenlet's window.
1701 Returning True causes the event to be not further propagated."""
1702 return False
1703
1707
1711
1715
1717 """Called when a buttonrelease-event occured in Screenlet's window.
1718 Returning True causes the event to be not further propagated."""
1719 return False
1720
1724
1727
1731
1735
1739
1743
1747
1751
1755 # ----------------------------------------------------------------------
1756 # Screenlet's event-handlers for GTK-events
1757 # ----------------------------------------------------------------------
1758
1760 """set colormap for window"""
1761 if screen==None:
1762 screen = window.get_screen()
1763 map = screen.get_rgba_colormap()
1764 if map:
1765 pass
1766 else:
1767 map = screen.get_rgb_colormap()
1768 window.set_colormap(map)
1769
1808
1817
1819 #this handle is called when composition changed
1820 self.remove_shape() # removing previous set shape , this is absolutly necessary
1821 self.window.hide() # hiding the window and showing it again so the window can convert to the right composited state
1822 self.is_sticky = self.is_sticky #changing from non composited to composited makes the screenlets loose sticky state , this fixes that
1823 self.keep_above= self.keep_above
1824 self.keep_below= self.keep_below
1825 self.window.show()
1826 #print 'Compositing method changed to %s' % str(self.window.is_composited())
1827 self.update_shape()
1828 self.redraw_canvas()
1829
1830 if not self.window.is_composited () :
1831 self.show_buttons = False
1832 self.disable_option("opacity")
1833 # print 'Warning - Buttons will not be shown until screenlet is restarted'
1834
1835 if self.window.is_composited () :
1836 self.enable_option("opacity")
1837
1838 self.is_sticky = self.is_sticky #and again ...
1839 self.keep_above= self.keep_above
1840 self.keep_below= self.keep_below
1841 self.window.set_keep_above(self.keep_above)
1842 self.window.set_keep_below(self.keep_below)
1843 self.on_composite_changed()
1844
1845 # NOTE: this should somehow handle the end of a move_drag-operation
1847 #print "onConfigure"
1848 #print event
1849 #if self.is_dragged == True:
1850 # set new position and cause a save of this Screenlet (not use
1851 # setattr to avoid conflicts with the window.move in __setattr__)
1852 if event.x != self.x:
1853 self.__dict__['x'] = event.x
1854 if self.session:
1855 self.session.backend.save_option(self.id, 'x', str(event.x))
1856 # self.is_dragged = False
1857 if event.y != self.y:
1858 self.__dict__['y'] = event.y
1859 if self.session:
1860 self.session.backend.save_option(self.id, 'y', str(event.y))
1861 # self.is_dragged = False
1862 return False
1863
1865 # cancel event?
1866 print "delete_event"
1867 if self.on_delete() == True:
1868 print "Cancel delete_event"
1869 return True
1870 else:
1871 self.close()
1872 return False
1873
1875 # call user-defined on_quit-handler
1876 self.on_quit()
1877 #print "destroy signal occurred"
1878 self.emit("screenlet_removed", self)
1879 # close gtk?
1880 if self.quit_on_close:
1881 if self.session: # if we have a session, flush current data
1882 self.session.backend.flush()
1883 gtk.main_quit()
1884 else:
1885 del self # ??? does this really work???
1886
1891 #return False
1892
1895
1900
1902 #print "Drag motion"
1903 if self.dragging_over == False:
1904 self.dragging_over = True
1905 self.on_drag_enter(drag_context, x, y, timestamp)
1906 return False
1907
1912
1914 #self.__mouse_inside = True
1915 self.__dict__['mouse_is_over'] = True
1916 self.on_mouse_enter(event)
1917
1918 #self.redraw_canvas()
1919
1921 ctx = widget.window.cairo_create()
1922 # clear context
1923 self.clear_cairo_context(ctx)
1924 # set a clip region for the expose event
1925 ctx.rectangle(event.area.x, event.area.y,
1926 event.area.width, event.area.height)
1927 ctx.clip()
1928
1929 # scale context
1930 #ctx.scale(self.scale, self.scale)
1931 # call drawing method
1932 self.on_draw(ctx)
1933 if self.show_buttons and self.draw_buttons and self.has_focus:
1934 self.create_buttons()
1935 # and delete context (needed?)
1936 del ctx
1937 return False
1938
1940 if self.skip_taskbar==False or self.skip_pager==False or self.is_dragged==True or event is None:
1941 #Screenlet always gets focus after being dragged so this is a good method
1942 #to control the end of a move_drag operation!!!!!
1943 #This code happens on the end of a move_drag
1944 self.is_dragged=False
1945 self.has_focus = True
1946 self.on_focus(event)
1947 self.update_shape()
1948 self.redraw_canvas()
1949
1950
1951
1952
1954 if self.is_dragged==False:
1955 self.has_focus = False
1956 self.on_unfocus(event)
1957 self.update_shape()
1958 self.redraw_canvas()
1959
1960
1961
1963 """Handle keypress events, needed for in-place editing."""
1964 self.on_key_down(event.keyval, event.string, event)
1965
1967 #self.__mouse_inside = False
1968 #self.is_dragged = False
1969 self.__dict__['mouse_is_over'] = False
1970 self.on_mouse_leave(event)
1971
1972 #self.redraw_canvas()
1973
2046
2048 self.on_map()
2049
2051 self.on_unmap()
2052
2054 self.__dict__['mousex'] = event.x / self.scale
2055 self.__dict__['mousey'] = event.y / self.scale
2056
2057 self.on_mouse_move(event)
2058
2060 """called when window has been realized"""
2061 if self.window.window:
2062 self.window.window.set_back_pixmap(None, False) # needed?
2063
2064 self.on_realize()
2065
2067 if event.direction == gtk.gdk.SCROLL_UP:
2068 if self.has_focus and self.is_sizable and self.resize_on_scroll: self.scale = self.scale +0.1
2069 self.on_scroll_up()
2070 elif event.direction == gtk.gdk.SCROLL_DOWN:
2071 if self.has_focus and self.is_sizable and self.resize_on_scroll: self.scale = self.scale -0.1
2072 self.on_scroll_down()
2073 return False
2074
2075
2077 """Show notification window at current mouse position."""
2078 if self.notify == None:
2079 self.notify = Notify()
2080 self.notify.text = text
2081 self.notify.show()
2082
2084 """hide notification window"""
2085 if self.notify != None:
2086 self.notify.hide()
2087 self.notify = None
2088
2090 """Show tooltip window at current mouse position."""
2091 if self.tooltip == None:
2092 self.tooltip = Tooltip(300, 400)
2093 self.tooltip.text = text
2094 self.tooltip.x = tooltipx
2095 self.tooltip.y = tooltipy
2096 self.tooltip.show()
2097 else:
2098 #self.tooltip = Tooltip(300, 400)
2099 self.tooltip.text = text
2100 self.tooltip.x = tooltipx
2101 self.tooltip.y = tooltipy
2102 #self.tooltip.show()
2103
2109
2110 # TEST!!!
2112 """A simple base-class for creating owner-drawn gtk-widgets"""
2113
2114 __widget=None
2115
2116 mouse_inside = False
2117 width = 32
2118 height = 32
2119
2121 # call superclass
2122 super(ShapedWidget, self).__init__()
2123 # create/setup widget
2124 #self.__widget = gtk.Widget()
2125 self.set_app_paintable(True)
2126 self.set_size_request(width, height)
2127 # connect handlers
2128 self.set_events(gtk.gdk.ALL_EVENTS_MASK)
2129 self.connect("expose-event", self.expose_event)
2130 self.connect("button-press-event", self.button_press)
2131 self.connect("button-release-event", self.button_release)
2132 self.connect("enter-notify-event", self.enter_notify)
2133 self.connect("leave-notify-event", self.leave_notify)
2134
2135 # EXPERIMENTAL: TODO: cache bitmap until size changes
2137 """update widget's shape (only call this when shape has changed)"""
2138 data = ""
2139 for i in xrange(self.width*self.height):
2140 data += "0"
2141 bitmap = gtk.gdk.bitmap_create_from_data(None,
2142 data, self.width, self.height)
2143 ctx = bitmap.cairo_create()
2144 ctx.set_source_rgba(1, 1, 1, 0)
2145 ctx.set_operator (cairo.OPERATOR_SOURCE)
2146 ctx.paint()
2147 self.draw_shape(ctx)
2148 self.input_shape_combine_mask(bitmap, 0, 0)
2149 print "Updating shape."
2150
2155
2160
2164 #print "mouse enter"
2165
2169 #print "mouse leave"
2170
2173
2175 self.draw(ctx)
2176
2178 ctx = widget.window.cairo_create()
2179 # set a clip region for the expose event
2180 ctx.rectangle(event.area.x, event.area.y,
2181 event.area.width, event.area.height)
2182 ctx.clip()
2183 # clear context
2184 ctx.set_source_rgba(1, 1, 1, 0)
2185 ctx.set_operator (cairo.OPERATOR_SOURCE)
2186 ctx.paint()
2187 # call drawing method
2188 self.draw(ctx)
2189 # and delete context
2190 del ctx
2191 return False
2192
2194 """A window that displays a text and serves as Tooltip (very basic yet)."""
2195
2196 # internals
2197 __timeout = None
2198
2199 # attribs
2200 text = ''
2201 font_name = 'FreeSans 9'
2202 width = 100
2203 height = 20
2204 x = 0
2205 y = 0
2206
2208 object.__init__(self)
2209 # init
2210 self.__dict__['width'] = width
2211 self.__dict__['height'] = height
2212 self.window = gtk.Window()
2213 self.window.set_app_paintable(True)
2214 self.window.set_size_request(width, height)
2215 self.window.set_decorated(False)
2216 self.window.set_accept_focus(False)
2217 self.window.set_skip_pager_hint(True)
2218 self.window.set_skip_taskbar_hint(True)
2219 self.window.set_keep_above(True)
2220 self.screen_changed(self.window)
2221 self.window.connect("expose_event", self.expose)
2222 self.window.connect("screen-changed", self.screen_changed)
2223 #self.window.show()
2224 self.p_context = self.window.get_pango_context()
2225 self.p_layout = pango.Layout(self.p_context)
2226 self.p_layout.set_font_description(\
2227 pango.FontDescription(self.font_name))
2228 #self.p_layout.set_width(-1)
2229 self.p_layout.set_width(width * pango.SCALE - 6)
2230
2232 self.__dict__[name] = value
2233 if name in ('width', 'height', 'text'):
2234 if name== 'width':
2235 self.p_layout.set_width(width)
2236 elif name == 'text':
2237 self.p_layout.set_markup(value)
2238 ink_rect, logical_rect = self.p_layout.get_pixel_extents()
2239 self.height = min(max(logical_rect[3], 16), 400) + 6
2240 self.window.set_size_request(self.width, self.height)
2241 self.window.queue_draw()
2242 elif name == 'x':
2243 self.window.move(int(value), int(self.y))
2244 elif name == 'y':
2245 self.window.move(int(self.x), int(value))
2246
2248 """Show the Tooltip window."""
2249 self.cancel_show()
2250 self.window.show()
2251 self.window.set_keep_above(True)
2252
2254 """Show the Tooltip window after a given delay."""
2255 self.cancel_show()
2256 self.__timeout = gobject.timeout_add(delay, self.__show_timeout)
2257
2262
2264 """Cancel showing of the Tooltip."""
2265 if self.__timeout:
2266 gobject.source_remove(self.__timeout)
2267 self.p_context = None
2268 self.p_layout = None
2269
2271 self.show()
2272
2274 if screen == None:
2275 screen = window.get_screen()
2276 map = screen.get_rgba_colormap()
2277 if not map:
2278 map = screen.get_rgb_colormap()
2279 window.set_colormap(map)
2280
2282 ctx = self.window.window.cairo_create()
2283 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL) # ?
2284 # set a clip region for the expose event
2285 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2286 ctx.clip()
2287 # clear context
2288 ctx.set_source_rgba(1, 1, 1, 0)
2289 ctx.set_operator (cairo.OPERATOR_SOURCE)
2290 ctx.paint()
2291 # draw rectangle
2292 ctx.set_source_rgba(1, 1, 0.5, 1)
2293 ctx.rectangle(0, 0, self.width, self.height)
2294 ctx.fill()
2295 # draw text
2296 ctx.save()
2297 ctx.translate(3, 3)
2298 ctx.set_source_rgba(0, 0, 0, 1)
2299 ctx.show_layout(self.p_layout)
2300 ctx.fill()
2301 ctx.restore()
2302 ctx.rectangle(0, 0, self.width, self.height)
2303 ctx.set_source_rgba(0, 0, 0, 0.7)
2304 ctx.stroke()
2305
2307 """A window that displays a text and serves as Notification (very basic yet)."""
2308
2309 # internals
2310 __timeout = None
2311
2312 # attribs
2313 text = ''
2314 font_name = 'FreeSans 9'
2315 width = 200
2316 height = 100
2317 x = 0
2318 y = 0
2319 gradient = cairo.LinearGradient(0, 100,0, 0)
2320
2322 object.__init__(self)
2323 # init
2324 self.window = gtk.Window()
2325 self.window.set_app_paintable(True)
2326 self.window.set_size_request(self.width, self.height)
2327 self.window.set_decorated(False)
2328 self.window.set_accept_focus(False)
2329 self.window.set_skip_pager_hint(True)
2330 self.window.set_skip_taskbar_hint(True)
2331 self.window.set_keep_above(True)
2332 self.screen_changed(self.window)
2333 self.window.connect("expose_event", self.expose)
2334 self.window.connect("screen-changed", self.screen_changed)
2335 #self.window.show()
2336 self.p_context = self.window.get_pango_context()
2337 self.p_layout = pango.Layout(self.p_context)
2338 self.p_layout.set_font_description(\
2339 pango.FontDescription(self.font_name))
2340 #self.p_layout.set_width(-1)
2341 self.p_layout.set_width(self.width * pango.SCALE - 6)
2342
2344 self.__dict__[name] = value
2345 if name in ('text'):
2346 if name == 'text':
2347 self.p_layout.set_markup(value)
2348 ink_rect, logical_rect = self.p_layout.get_pixel_extents()
2349 self.window.queue_draw()
2350
2352 """Show the Notify window."""
2353 self.window.move(gtk.gdk.screen_width() - self.width, gtk.gdk.screen_height() - self.height)
2354 self.cancel_show()
2355 self.window.show()
2356 self.window.set_keep_above(True)
2357
2359 """Show the Notify window after a given delay."""
2360 self.cancel_show()
2361 self.__timeout = gobject.timeout_add(delay, self.__show_timeout)
2362
2367
2369 """Cancel showing of the Notify."""
2370 if self.__timeout:
2371 gobject.source_remove(self.__timeout)
2372 self.p_context = None
2373 self.p_layout = None
2374
2376 self.show()
2377
2379 if screen == None:
2380 screen = window.get_screen()
2381 map = screen.get_rgba_colormap()
2382 if not map:
2383 map = screen.get_rgb_colormap()
2384 window.set_colormap(map)
2385
2387 ctx = self.window.window.cairo_create()
2388 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL) # ?
2389 # set a clip region for the expose event
2390 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2391 ctx.clip()
2392 # clear context
2393 ctx.set_source_rgba(1, 1, 1, 0)
2394 ctx.set_operator (cairo.OPERATOR_SOURCE)
2395 ctx.paint()
2396 # draw rectangle
2397 self.gradient.add_color_stop_rgba(1,0.3, 0.3, 0.3, 0.9)
2398 self.gradient.add_color_stop_rgba(0.3, 0, 0, 0, 0.9)
2399 ctx.set_source(self.gradient)
2400 ctx.rectangle(0, 0, self.width, self.height)
2401 ctx.fill()
2402 # draw text
2403 ctx.save()
2404 ctx.translate(3, 3)
2405 ctx.set_source_rgba(1, 1, 1, 1)
2406 ctx.show_layout(self.p_layout)
2407 ctx.fill()
2408 ctx.restore()
2409 ctx.rectangle(0, 0, self.width, self.height)
2410 ctx.set_source_rgba(0, 0, 0, 0.7)
2411 ctx.stroke()
2412
2413 # TEST (as the name implies)
2414 """class TestWidget(ShapedWidget):
2415
2416 def __init__(self, width, height):
2417 #ShapedWidget.__init__(self, width, height)
2418 super(TestWidget, self).__init__(width, height)
2419
2420 def draw(self, ctx):
2421 if self.mouse_inside:
2422 ctx.set_source_rgba(1, 0, 0, 0.8)
2423 else:
2424 ctx.set_source_rgba(1, 1, 0, 0.8)
2425 ctx.rectangle(0, 0, 32, 32)
2426 ctx.fill()
2427 """
2428
2429
2430 # ------------------------------------------------------------------------------
2431 # MODULE-FUNCTIONS
2432 # ------------------------------------------------------------------------------
2433
2434 # the new recommended way of launching a screenlet from the "outside"
2436 """Launch a screenlet, either through its service or by launching a new
2437 process of the given screenlet. Name has to be the name of the Screenlet's
2438 class without trailing 'Screenlet'.
2439 NOTE: we could only launch the file here"""
2440 # check for service
2441 if services.service_is_running(name):
2442 # add screenlet through service, if running
2443 srvc = services.get_service_by_name(name)
2444 if srvc:
2445 try:
2446 srvc.add('') # empty string for auto-creating ID
2447 return True
2448 except Exception, ex:
2449 print "Error while adding instance by service: %s" % ex
2450 # service not running or error? launch screenlet's file
2451 path = utils.find_first_screenlet_path(name)
2452 if path:
2453 # get full path of screenlet's file
2454 slfile = path + '/' + name + 'Screenlet.py'
2455 # launch screenlet as separate process
2456 print "Launching Screenlet from: %s" % slfile
2457 if debug:
2458 print "Logging output goes to: $HOME/.config/Screenlets/%sScreenlet.log" % name
2459 out = '$HOME/.config/Screenlets/%sScreenlet.log' % name
2460 else:
2461 out = '/dev/null'
2462 os.system('python -u %s > %s &' % (slfile, out))
2463 return True
2464 else:
2465 print "Screenlet '%s' could not be launched." % name
2466 return False
2467
2469 """Show a message for the given Screenlet (may contain Pango-Markup).
2470 If screenlet is None, this function can be used by other objects as well."""
2471 if screenlet == None:
2472 md = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,
2473 buttons=gtk.BUTTONS_OK)
2474 md.set_title(title)
2475 else:
2476 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_INFO,
2477 buttons=gtk.BUTTONS_OK)
2478 md.set_title(screenlet.__name__)
2479 md.set_markup(message)
2480 md.run()
2481 md.destroy()
2482
2484 """Show a question for the given Screenlet (may contain Pango-Markup)."""
2485 if screenlet == None:
2486 md = gtk.MessageDialog(None, type=gtk.MESSAGE_QUESTION,
2487 buttons=gtk.BUTTONS_YES_NO)
2488 md.set_title(title)
2489 else:
2490 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_QUESTION,
2491 buttons=gtk.BUTTONS_YES_NO)
2492 md.set_title(screenlet.__name__)
2493 md.set_markup(message)
2494 response = md.run()
2495 md.destroy()
2496 if response == gtk.RESPONSE_YES:
2497 return True
2498 return False
2499
2501 """Show an error for the given Screenlet (may contain Pango-Markup)."""
2502 if screenlet == None:
2503 md = gtk.MessageDialog(None, type=gtk.MESSAGE_ERROR,
2504 buttons=gtk.BUTTONS_OK)
2505 md.set_title(title)
2506 else:
2507 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_ERROR,
2508 buttons=gtk.BUTTONS_OK)
2509 md.set_title(screenlet.__name__)
2510 md.set_markup(message)
2511 md.run()
2512 md.destroy()
2513
2515 """Raise a fatal error to stdout and stderr and exit with an errorcode."""
2516 import sys
2517 msg = 'FATAL ERROR: %s\n' % message
2518 sys.stdout.write(msg)
2519 sys.stderr.write(msg)
2520 sys.exit(1)
2521
2522 # LEGACY support: functions that are not used any longer (raise fatal error)
2523
2525 fatal_error("This screenlet seems to be written for an older version of the framework. Please download a newer version of the %s." % name)
2526
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sat Dec 4 19:47:04 2010 | http://epydoc.sourceforge.net |