| 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 = 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 # CLASSES
151 #-------------------------------------------------------------------------------
152
154 """A container with constants for the default menuitems"""
155
156 # default menuitem constants (is it right to increase like this?)
157 NONE = 0
158 DELETE = 1
159 THEMES = 2
160 INFO = 4
161 SIZE = 8
162 WINDOW_MENU = 16
163 PROPERTIES = 32
164 DELETE = 64
165 QUIT = 128
166 QUIT_ALL = 256
167 # EXPERIMENTAL!! If you use this, the file menu.xml in the
168 # Screenlet's data-dir is used for generating the menu ...
169 XML = 512
170 ADD = 1024
171 # the default items
172 STANDARD = 1|2|8|16|32|64|128|256|1024
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 # meta-info (set through theme.conf)
185 __name__ = ''
186 __author__ = ''
187 __version__ = ''
188 __info__ = ''
189
190 # attributes
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
203 # set theme-path and load all files in path
204 self.path = path
205 self.svgs = {}
206 self.pngs = {}
207 self.option_overrides = {}
208 self.loaded = self.__load_all()
209 if self.loaded == False:
210 raise Exception("Error while loading ScreenletTheme in: " + path)
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
224 """Apply this theme's overridden options to the given Screenlet."""
225 # disable the canvas-updates in the screenlet
226 screenlet.disable_updates = True
227 # theme_name needs special care (must be applied last)
228 theme_name = ''
229 # loop through overrides and appply them
230 for name in self.option_overrides:
231 print "Override: " + name
232 o = screenlet.get_option_by_name(name)
233 if o and not o.protected:
234 if name == 'theme_name':
235 # import/remember theme-name, but not apply yet
236 theme_name = o.on_import(self.option_overrides[name])
237 else:
238 # set option in screenlet
239 setattr(screenlet, name,
240 o.on_import(self.option_overrides[name]))
241 else:
242 print "WARNING: Option '%s' not found or protected." % name
243 # now apply theme
244 if theme_name != '':
245 screenlet.theme_name = theme_name
246 # re-enable updates and call redraw/reshape
247 screenlet.disable_updates = False
248 screenlet.redraw_canvas()
249 screenlet.update_shape()
250
252 """Checks if a file with filename is loaded in this theme."""
253 try:
254 if self[filename]:
255 return True
256 except:
257 #raise Exception
258 return False
259
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
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 # Padding from the edges of the window
351 rounded=rounded_angle # How round to make the edges 20 is ok
352 w = width
353 h = height
354
355 # Move to top corner
356 ctx.move_to(0+padding+rounded, 0+padding)
357
358 # Top right corner and round the edge
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 # Bottom right corner and round the edge
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 # Bottom left corner and round the edge.
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 # Top left corner and round the edge
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 # Fill in the shape.
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
433 """@DEPRECATED Moved to Screenlets class: Show notification window at current mouse position."""
434 if self.notify == None:
435 self.notify = Notify()
436 self.notify.text = text
437 self.notify.show()
438
440 """@DEPRECATED Moved to Screenlets class: hide notification window"""
441 if self.notify != None:
442 self.notify.hide()
443 self.notify = None
444
446 """@DEPRECATED: Moved to Screenlets class: Show tooltip window at current mouse position."""
447 if self.tooltip == None:
448 self.tooltip = Tooltip(300, 400)
449 self.tooltip.text = text
450 self.tooltip.x = tooltipx
451 self.tooltip.y = tooltipy
452 self.tooltip.show()
453
455 """@DEPRECATED Moved to Screenlets class: hide tooltip window"""
456 if self.tooltip != None:
457 self.tooltip.hide()
458 self.tooltip = None
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 # set width/height
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 # set width/height
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 #self[filename] = None
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 #self[filename] = None
527
529 """Load all files in the theme's path. Currently only loads SVGs and
530 PNGs."""
531 # clear overrides
532 #self.__option_overrides = {}
533 # read dir
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 # svg file
542 if self.load_svg(fname) == False:
543 return False
544 elif fname.endswith('.png'):
545 # svg file
546 if self.load_png(fname) == False:
547 return False
548 elif fname == "theme.conf":
549 print "theme.conf found! Loading option-overrides."
550 # theme.conf
551 if self.load_conf(file) == False:
552 return False
553 # print "Theme %s loaded from %s" % (self.__name__, self.path)
554 return True
555
560
561 # TODO: fix function, rsvg handles are not freed properly
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 #self[filename].close()
571 del filename
572 self.clear()
573
574 # TEST: render-function
575 # should be used like "theme.render(context, 'notes-bg')" and then use
576 # either an svg or png image
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 ### Render Graphics even if rsvg is not available###
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 # Scale the pixmap
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
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 # default meta-info for Screenlets
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 #__target_version__ = '0.0.0'
627 #__backend_version__ = '0.0.1'
628
629 # attributes (TODO: remove them here and add them to the constructor,
630 # because they only should exist per instance)
631 id = '' # id-attribute for handling instances
632 window = None # the gtk.Window behind the scenes
633 theme = None # the assigned ScreenletTheme
634 uses_theme = True # flag indicating whether Screenlet uses themes
635 draw_buttons = True
636 show_buttons = True
637 menu = None # the right-click gtk.Menu
638 is_dragged = False # TODO: make this work
639 quit_on_close = True # if True, closing this instance quits gtk
640 saving_enabled = True # if False, saving is disabled
641 dragging_over = False # true if something is dragged over
642 disable_updates = False # to temporarily avoid refresh/reshape
643 p_context = None # PangoContext
644 p_layout = None # PangoLayout
645
646 # default editable options, available for all Screenlets
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 # if False, overrides are ignored
667 ask_on_option_override = True # if True, overrides need confirmation
668 ignore_requirements = False # if True, DEB requirements are ignored
669 resize_on_scroll = True
670 has_started = False
671 has_focus = False
672 # internals (deprecated? we still don't get the end of a begin_move_drag)
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 # some menuitems (needed for checking/unchecking)
681 # DEPRECATED: remove - don't really work anyway ... (or fix the menu?)
682 __mi_keep_above = None
683 __mi_keep_below = None
684 __mi_widget = None
685 __mi_sticky = None
686 __mi_lock = None
687 # for custom signals (which aren't acutally used ... yet)
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 # call gobject and EditableOptions superclasses
699 super(Screenlet, self).__init__()
700 EditableOptions.__init__(self)
701 # init properties
702 self.id = id
703 self.session = session
704 self.service = None
705 self.__desc__ = self.__doc__
706
707 # if we have an id and a service-class, register our service
708 if self.id and service_class:
709 self.register_service(service_class)
710 # notify service about adding this instance
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 # used by session
717 # set some attributes without calling __setattr__
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 # TEST: set scale relative to theme size (NOT WORKING)
726 #self.__dict__['scale'] = width/100.0
727 # /TEST
728 # shape bitmap
729 self.__shape_bitmap = None
730 self.__shape_bitmap_width = 0
731 self.__shape_bitmap_height = 0
732 # "editable" options, first create a group
733 self.add_options_group('Screenlet',
734 _('The basic settings for this Screenlet-instance.'))
735 # if this Screenlet uses themes, add theme-specific options
736 # (NOTE: this option became hidden with 0.0.9 and doesn't use
737 # get_available_themes anymore for showing the choices)
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 # create/add options
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 # disable width/height
811 self.disable_option('width')
812 self.disable_option('height')
813 # create window
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 # create pango layout, if active
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 # set type hint
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 #self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
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 #self.window.set_events(gtk.gdk.BUTTON_PRESS_MASK)
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 # add key-handlers (TODO: use keyword-attrib to activate?)
865 self.window.connect("key-press-event", self.key_press)
866 # drag/drop support (NOTE: still experimental and incomplete)
867 if drag_drop:
868 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
869 gtk.DEST_DEFAULT_DROP, #gtk.DEST_DEFAULT_ALL,
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 # create menu
880 self.menu = gtk.Menu()
881 # 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
882
883
884 if show_window:
885 self.window.show()
886 # print os.environ['HOME'] + '/.config/Screenlets/' + self.__name__[:-9] + '/default/'+ self.id
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 #Make opacity available only when composite is enabled
892 if not self.window.is_composited () :
893 self.disable_option('opacity')
894
896 # set the value in GObject (ESSENTIAL!!!!)
897 self.on_before_set_atribute(name, value)
898 gobject.GObject.__setattr__(self, name, value)
899 # And do other actions
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 # TODO: call on_resize-handler here !!!!
909 self.on_scale()
910 self.redraw_canvas()
911 self.update_shape()
912
913
914 elif name == "theme_name":
915 #self.__dict__ ['theme_name'] = value
916 #self.load_theme(self.get_theme_dir() + value)
917 # load theme
918 print "Theme set to: '%s'" % value
919 path = self.find_theme(value)
920 if path:
921 self.load_theme(path)
922 #self.load_first_theme(value)
923 self.redraw_canvas()
924 self.update_shape()
925 elif name in ("width", "height"):
926 #self.__dict__ [name] = value
927 if self.window:
928 self.window.resize(int(self.width*self.scale), int(self.height*self.scale))
929 #self.redraw_canvas()
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 #if self.__mi_sticky:
946 # self.__mi_sticky.set_active(value)
947 elif name == "keep_above":
948 if self.has_started == True:
949 self.window.set_keep_above(bool(value))
950 #self.__mi_keep_above.set_active(value)
951 elif name == "keep_below":
952 if self.has_started == True:
953 self.window.set_keep_below(bool(value))
954 #self.__mi_keep_below.set_active(value)
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 # NOTE: This is the new recommended way of storing options in real-time
962 # (we access the backend through the session here)
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 # /TEST
970
971 #-----------------------------------------------------------------------
972 # Screenlet's public functions
973 #-----------------------------------------------------------------------
974
976 '''Checks if required DEB packages are installed'''
977
978 req_feedback = ""
979 fail = False
980
981 # operators=['>', '=', '<']
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 # req = req.replace(' ', '')
987 if req.find('(') != -1:
988 # package version is specified with an operator (no logical operators supported yet!)
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 # when only package name is specified
1000 package = req
1001 # version of the deb package if unspecified
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 # will fail only if dpkg says that version is too old
1012 # otherwise it's responsibility of developer to provide
1013 # correct version id and operator (won't detect problems with these)
1014 if operator is not None:
1015 comp_command = "dpkg --compare-versions \"" + installed_version + "\" \"" + operator + "\" \"" + version + "\""
1016 # print comp_command
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
1134
1145
1165
1166
1167
1171
1192
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 #self.save_settings()
1205 self.window.unmap()
1206 self.window.destroy()
1207 #self.window.event(gtk.gdk.Event(gtk.gdk.DELETE))
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 # create icon
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 # create mask
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
1233
1235 """Find the best occurence of a theme and return its global path."""
1236 sn = self.get_short_name()
1237 utils.refresh_available_screenlet_paths()
1238 for p in SCREENLETS_PATH:
1239 fpath = p + '/' + sn + '/themes/' + name
1240 if os.path.isdir(fpath):
1241 return fpath
1242 return None
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 #dirname = self.get_theme_dir()
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
1286 self.window.present()
1287 self.has_started = True
1288 self.is_dragged = False
1289 self.keep_above= self.keep_above
1290 self.keep_below= self.keep_below
1291 self.skip_taskbar = self.skip_taskbar
1292 self.window.set_skip_taskbar_hint(self.skip_taskbar)
1293 self.window.set_keep_above(self.keep_above)
1294 self.window.set_keep_below(self.keep_below)
1295 if self.is_widget:
1296 self.set_is_widget(True)
1297 self.has_focus = False
1298
1300 """Called when screenlet finishes loading"""
1301
1302
1303 self.window.present()
1304
1305
1306 # the keep above and keep bellow must be reset after the window is shown this is absolutly necessary
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
1360
1361 # EXPERIMENTAL:
1362 # NOTE: load_theme does NOT call redraw_canvas and update_shape!!!!!
1363 # To do all in one, set attribute self.theme_name instead
1365 """Load a theme for this Screenlet from the given path. NOTE:
1366 load_theme does NOT call redraw_canvas and update_shape!!!!! To do all
1367 in one call, set the attribute self.theme_name instead."""
1368 if self.theme:
1369 self.theme.free()
1370 del self.theme
1371 self.theme = ScreenletTheme(path)
1372 # check for errors
1373 if self.theme.loaded == False:
1374 print "Error while loading theme: " + path
1375 self.theme = None
1376 else:
1377 # call user-defined handler
1378 self.on_load_theme()
1379 # if override options is allowed, apply them
1380 if self.allow_option_override:
1381 if self.theme.has_overrides():
1382 if self.ask_on_option_override==True and \
1383 show_question(self,
1384 _('This theme wants to override your settings for this Screenlet. Do you want to allow that?')) == False:
1385 return
1386 self.theme.apply_option_overrides(self)
1387 # /EXPERIMENTAL
1388
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 # if it is the basic service, add name to call
1401 if service_classobj==services.ScreenletService:#BUG
1402 self.service = service_classobj(self, self.get_short_name())
1403 else:
1404 # else only pass this screenlet
1405 self.service = service_classobj(self)
1406 else:
1407 self.service = self.session.instances[0].service
1408 # TODO: throw exception??
1409 return True
1410 return False
1411
1413 """Set this window to be treated as a Widget (only supported by
1414 compiz using the widget-plugin yet)"""
1415 if value==True:
1416 # set window type to utility
1417 #self.window.window.set_type_hint(
1418 # gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
1419 # set _compiz_widget-property on window
1420 self.window.window.property_change("_COMPIZ_WIDGET",
1421 gtk.gdk.SELECTION_TYPE_WINDOW,
1422 32, gtk.gdk.PROP_MODE_REPLACE, (True,))
1423 else:
1424 # set window type to normal
1425 #self.window.window.set_type_hint(
1426 # gtk.gdk.WINDOW_TYPE_HINT_NORMAL)
1427 # set _compiz_widget-property
1428 self.window.window.property_delete("_COMPIZ_WIDGET")
1429 # notify handler
1430 self.on_switch_widget_state(value)
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: # TODO!!!!!
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 # if updates are disabled, just exit
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 # if self.has_focus and self.draw_buttons and self.show_buttons:
1475 # self.create_buttons()
1476
1477
1479 """Redraw the given Rectangle (x, y, width, height) within the
1480 current Screenlet's window."""
1481 # if updates are disabled, just exit
1482 if self.disable_updates:
1483 return
1484 if self.window:
1485 rect = gtk.gdk.Rectangle(x, y, width, height)
1486 if self.window.window:
1487 self.window.window.invalidate_rect(rect, True)
1488 self.window.window.process_updates(True)
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 # if 0 return to avoid crashing
1499 if w==0 or h==0: return False
1500 # if size changed, recreate shape bitmap
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 # create context
1507 ctx = self.__shape_bitmap.cairo_create()
1508 self.clear_cairo_context(ctx)
1509
1510 # shape the window acording if the window is composited or not
1511 if self.window.is_composited():
1512 # log.debug(_("Updating input shape"))
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 # log.debug(_("Updating window shape"))
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 # if updates are disabled, just exit
1527 if self.disable_updates:
1528 return
1529 #print "UPDATING SHAPE"
1530 # TODO:
1531 #if not self.window.is_composited():
1532 # self.update_shape_non_composited()
1533 # calculate new width/height of shape bitmap
1534 w = int(self.width * self.scale)
1535 h = int(self.height * self.scale)
1536 # if 0 set it to 100 to avoid crashes and stay interactive
1537 if w==0: w = 100
1538 if h==0: h = 100
1539 # if size changed, recreate shape bitmap
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 # create context and draw shape
1547 ctx = self.__shape_bitmap.cairo_create()
1548 self.clear_cairo_context(ctx) #TEST
1549 if self.has_focus and self.draw_buttons and self.show_buttons:
1550 ctx.save()
1551 #theme1 = gtk.icon_theme_get_default()
1552 #ctx.set_source_rgba(0.5,0.5,0.5,0.6)
1553 #self.theme.draw_rounded_rectangle(ctx,(self.width*self.scale)-36,0,5,36,16)
1554 #close = theme1.load_icon ("gtk-close", 16, 0)
1555 #prop = theme1.load_icon ("gtk-properties", 16, 0)
1556 #zoom1 = theme1.load_icon ("gtk-zoom-in", 16, 0)
1557 #zoom2 = theme1.load_icon ("gtk-zoom-out", 16, 0)
1558 #close = gtk.image_new_from_stock(gtk.STOCK_CLOSE, 16)
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 # shape the window acording if the window is composited or not
1569
1570 if self.window.is_composited():
1571
1572 self.on_draw_shape(ctx)
1573 # and cut window with mask
1574 self.window.input_shape_combine_mask(self.__shape_bitmap, 0, 0)
1575 else:
1576 try: self.on_draw(ctx) #Works better then the shape method on non composited windows
1577 except: self.on_draw_shape(ctx) # if error on on_draw use standard shape method
1578 # and cut window with mask
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 #pixbuf = gtk.gdk.GdkPixbuf.new_from_file)
1586 # calculate new width/height of shape bitmap
1587 w = int(self.width * self.scale)
1588 h = int(self.height * self.scale)
1589 # if 0 set it to 100 to avoid crashes and stay interactive
1590 if w==0: w = 100
1591 if h==0: h = 100
1592 # if size changed, recreate shape bitmap
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 # and render window contents to it
1600 # TOOD!!
1601 if self.__shape_bitmap:
1602 # create new mask
1603 (pixmap,mask) = self.__shape_bitmap.render_pixmap_and_mask(255)
1604 # apply new mask to window
1605 self.window.shape_combine_mask(mask)
1606
1610
1611 # ----------------------------------------------------------------------
1612 # Screenlet's event-handler dummies
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 # TODO: on_drag
1628 # TODO: on_drag_end
1629
1633
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
1647
1651
1655
1656
1660
1664
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
1682
1686
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
1700
1704
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
1717
1721
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
1734
1737
1741
1745
1749
1753
1757
1761
1765 # ----------------------------------------------------------------------
1766 # Screenlet's event-handlers for GTK-events
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
1829 #this handle is called when composition changed
1830 self.remove_shape() # removing previous set shape , this is absolutly necessary
1831 self.window.hide() # hiding the window and showing it again so the window can convert to the right composited state
1832 self.is_sticky = self.is_sticky #changing from non composited to composited makes the screenlets loose sticky state , this fixes that
1833 self.keep_above= self.keep_above
1834 self.keep_below= self.keep_below
1835 self.window.show()
1836 #print 'Compositing method changed to %s' % str(self.window.is_composited())
1837 self.update_shape()
1838 self.redraw_canvas()
1839
1840 if not self.window.is_composited () :
1841 self.show_buttons = False
1842 self.disable_option("opacity")
1843 # print 'Warning - Buttons will not be shown until screenlet is restarted'
1844
1845 if self.window.is_composited () :
1846 self.enable_option("opacity")
1847
1848 self.is_sticky = self.is_sticky #and again ...
1849 self.keep_above= self.keep_above
1850 self.keep_below= self.keep_below
1851 self.window.set_keep_above(self.keep_above)
1852 self.window.set_keep_below(self.keep_below)
1853 self.on_composite_changed()
1854
1855 # NOTE: this should somehow handle the end of a move_drag-operation
1857 #print "onConfigure"
1858 #print event
1859 #if self.is_dragged == True:
1860 # set new position and cause a save of this Screenlet (not use
1861 # setattr to avoid conflicts with the window.move in __setattr__)
1862 if event.x != self.x:
1863 self.__dict__['x'] = event.x
1864 if self.session:
1865 self.session.backend.save_option(self.id, 'x', str(event.x))
1866 # self.is_dragged = False
1867 if event.y != self.y:
1868 self.__dict__['y'] = event.y
1869 if self.session:
1870 self.session.backend.save_option(self.id, 'y', str(event.y))
1871 # self.is_dragged = False
1872 return False
1873
1875 # cancel event?
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
1885 # call user-defined on_quit-handler
1886 self.on_quit()
1887 #print "destroy signal occurred"
1888 self.emit("screenlet_removed", self)
1889 # close gtk?
1890 if self.quit_on_close:
1891 if self.session: # if we have a session, flush current data
1892 self.session.backend.flush()
1893 gtk.main_quit()
1894 else:
1895 del self # ??? does this really work???
1896
1901 #return False
1902
1905
1910
1912 #print "Drag motion"
1913 if self.dragging_over == False:
1914 self.dragging_over = True
1915 self.on_drag_enter(drag_context, x, y, timestamp)
1916 return False
1917
1922
1924 #self.__mouse_inside = True
1925 self.__dict__['mouse_is_over'] = True
1926 self.on_mouse_enter(event)
1927
1928 #self.redraw_canvas()
1929
1931 ctx = widget.window.cairo_create()
1932 # clear context
1933 self.clear_cairo_context(ctx)
1934 # set a clip region for the expose event
1935 ctx.rectangle(event.area.x, event.area.y,
1936 event.area.width, event.area.height)
1937 ctx.clip()
1938
1939 # scale context
1940 #ctx.scale(self.scale, self.scale)
1941 # call drawing method
1942 self.on_draw(ctx)
1943 if self.show_buttons and self.draw_buttons and self.has_focus:
1944 self.create_buttons()
1945 # and delete context (needed?)
1946 del ctx
1947 return False
1948
1950 if self.skip_taskbar==False or self.skip_pager==False or self.is_dragged==True or event is None:
1951 #Screenlet always gets focus after being dragged so this is a good method
1952 #to control the end of a move_drag operation!!!!!
1953 #This code happens on the end of a move_drag
1954 self.is_dragged=False
1955 self.has_focus = True
1956 self.on_focus(event)
1957 self.update_shape()
1958 self.redraw_canvas()
1959
1960
1961
1962
1964 if self.is_dragged==False:
1965 self.has_focus = False
1966 self.on_unfocus(event)
1967 self.update_shape()
1968 self.redraw_canvas()
1969
1970
1971
1973 """Handle keypress events, needed for in-place editing."""
1974 self.on_key_down(event.keyval, event.string, event)
1975
1977 #self.__mouse_inside = False
1978 #self.is_dragged = False
1979 self.__dict__['mouse_is_over'] = False
1980 self.on_mouse_leave(event)
1981
1982 #self.redraw_canvas()
1983
2056
2058 self.on_map()
2059
2061 self.on_unmap()
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
2070 """called when window has been realized"""
2071 if self.window.window:
2072 self.window.window.set_back_pixmap(None, False) # needed?
2073
2074 self.on_realize()
2075
2077 if event.direction == gtk.gdk.SCROLL_UP:
2078 if self.has_focus and self.is_sizable and self.resize_on_scroll: self.scale = self.scale +0.1
2079 self.on_scroll_up()
2080 elif event.direction == gtk.gdk.SCROLL_DOWN:
2081 if self.has_focus and self.is_sizable and self.resize_on_scroll: self.scale = self.scale -0.1
2082 self.on_scroll_down()
2083 return False
2084
2085
2087 """Show notification window at current mouse position."""
2088 if self.notify == None:
2089 self.notify = Notify()
2090 self.notify.text = text
2091 self.notify.show()
2092
2094 """hide notification window"""
2095 if self.notify != None:
2096 self.notify.hide()
2097 self.notify = None
2098
2100 """Show tooltip window at current mouse position."""
2101 if self.tooltip == None:
2102 self.tooltip = Tooltip(300, 400)
2103 self.tooltip.text = text
2104 self.tooltip.x = tooltipx
2105 self.tooltip.y = tooltipy
2106 self.tooltip.show()
2107 else:
2108 #self.tooltip = Tooltip(300, 400)
2109 self.tooltip.text = text
2110 self.tooltip.x = tooltipx
2111 self.tooltip.y = tooltipy
2112 #self.tooltip.show()
2113
2119
2120 # TEST!!!
2122 """A simple base-class for creating owner-drawn gtk-widgets"""
2123
2124 __widget=None
2125
2126 mouse_inside = False
2127 width = 32
2128 height = 32
2129
2131 # call superclass
2132 super(ShapedWidget, self).__init__()
2133 # create/setup widget
2134 #self.__widget = gtk.Widget()
2135 self.set_app_paintable(True)
2136 self.set_size_request(width, height)
2137 # connect handlers
2138 self.set_events(gtk.gdk.ALL_EVENTS_MASK)
2139 self.connect("expose-event", self.expose_event)
2140 self.connect("button-press-event", self.button_press)
2141 self.connect("button-release-event", self.button_release)
2142 self.connect("enter-notify-event", self.enter_notify)
2143 self.connect("leave-notify-event", self.leave_notify)
2144
2145 # EXPERIMENTAL: TODO: cache bitmap until size changes
2147 """update widget's shape (only call this when shape has changed)"""
2148 data = ""
2149 for i in xrange(self.width*self.height):
2150 data += "0"
2151 bitmap = gtk.gdk.bitmap_create_from_data(None,
2152 data, self.width, self.height)
2153 ctx = bitmap.cairo_create()
2154 ctx.set_source_rgba(1, 1, 1, 0)
2155 ctx.set_operator (cairo.OPERATOR_SOURCE)
2156 ctx.paint()
2157 self.draw_shape(ctx)
2158 self.input_shape_combine_mask(bitmap, 0, 0)
2159 print "Updating shape."
2160
2165
2170
2174 #print "mouse enter"
2175
2179 #print "mouse leave"
2180
2183
2185 self.draw(ctx)
2186
2188 ctx = widget.window.cairo_create()
2189 # set a clip region for the expose event
2190 ctx.rectangle(event.area.x, event.area.y,
2191 event.area.width, event.area.height)
2192 ctx.clip()
2193 # clear context
2194 ctx.set_source_rgba(1, 1, 1, 0)
2195 ctx.set_operator (cairo.OPERATOR_SOURCE)
2196 ctx.paint()
2197 # call drawing method
2198 self.draw(ctx)
2199 # and delete context
2200 del ctx
2201 return False
2202
2204 """A window that displays a text and serves as Tooltip (very basic yet)."""
2205
2206 # internals
2207 __timeout = None
2208
2209 # attribs
2210 text = ''
2211 font_name = 'FreeSans 9'
2212 width = 100
2213 height = 20
2214 x = 0
2215 y = 0
2216
2218 object.__init__(self)
2219 # init
2220 self.__dict__['width'] = width
2221 self.__dict__['height'] = height
2222 self.window = gtk.Window()
2223 self.window.set_app_paintable(True)
2224 self.window.set_size_request(width, height)
2225 self.window.set_decorated(False)
2226 self.window.set_accept_focus(False)
2227 self.window.set_skip_pager_hint(True)
2228 self.window.set_skip_taskbar_hint(True)
2229 self.window.set_keep_above(True)
2230 self.screen_changed(self.window)
2231 self.window.connect("expose_event", self.expose)
2232 self.window.connect("screen-changed", self.screen_changed)
2233 #self.window.show()
2234 self.p_context = self.window.get_pango_context()
2235 self.p_layout = pango.Layout(self.p_context)
2236 self.p_layout.set_font_description(\
2237 pango.FontDescription(self.font_name))
2238 #self.p_layout.set_width(-1)
2239 self.p_layout.set_width(width * pango.SCALE - 6)
2240
2242 self.__dict__[name] = value
2243 if name in ('width', 'height', 'text'):
2244 if name== 'width':
2245 self.p_layout.set_width(width)
2246 elif name == 'text':
2247 self.p_layout.set_markup(value)
2248 ink_rect, logical_rect = self.p_layout.get_pixel_extents()
2249 self.height = min(max(logical_rect[3], 16), 400) + 6
2250 self.window.set_size_request(self.width, self.height)
2251 self.window.queue_draw()
2252 elif name == 'x':
2253 self.window.move(int(value), int(self.y))
2254 elif name == 'y':
2255 self.window.move(int(self.x), int(value))
2256
2258 """Show the Tooltip window."""
2259 self.cancel_show()
2260 self.window.show()
2261 self.window.set_keep_above(True)
2262
2264 """Show the Tooltip window after a given delay."""
2265 self.cancel_show()
2266 self.__timeout = gobject.timeout_add(delay, self.__show_timeout)
2267
2272
2274 """Cancel showing of the Tooltip."""
2275 if self.__timeout:
2276 gobject.source_remove(self.__timeout)
2277 self.p_context = None
2278 self.p_layout = None
2279
2281 self.show()
2282
2284 if screen == None:
2285 screen = window.get_screen()
2286 map = screen.get_rgba_colormap()
2287 if not map:
2288 map = screen.get_rgb_colormap()
2289 window.set_colormap(map)
2290
2292 ctx = self.window.window.cairo_create()
2293 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL) # ?
2294 # set a clip region for the expose event
2295 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2296 ctx.clip()
2297 # clear context
2298 ctx.set_source_rgba(1, 1, 1, 0)
2299 ctx.set_operator (cairo.OPERATOR_SOURCE)
2300 ctx.paint()
2301 # draw rectangle
2302 ctx.set_source_rgba(1, 1, 0.5, 1)
2303 ctx.rectangle(0, 0, self.width, self.height)
2304 ctx.fill()
2305 # draw text
2306 ctx.save()
2307 ctx.translate(3, 3)
2308 ctx.set_source_rgba(0, 0, 0, 1)
2309 ctx.show_layout(self.p_layout)
2310 ctx.fill()
2311 ctx.restore()
2312 ctx.rectangle(0, 0, self.width, self.height)
2313 ctx.set_source_rgba(0, 0, 0, 0.7)
2314 ctx.stroke()
2315
2317 """A window that displays a text and serves as Notification (very basic yet)."""
2318
2319 # internals
2320 __timeout = None
2321
2322 # attribs
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
2332 object.__init__(self)
2333 # init
2334 self.window = gtk.Window()
2335 self.window.set_app_paintable(True)
2336 self.window.set_size_request(self.width, self.height)
2337 self.window.set_decorated(False)
2338 self.window.set_accept_focus(False)
2339 self.window.set_skip_pager_hint(True)
2340 self.window.set_skip_taskbar_hint(True)
2341 self.window.set_keep_above(True)
2342 self.screen_changed(self.window)
2343 self.window.connect("expose_event", self.expose)
2344 self.window.connect("screen-changed", self.screen_changed)
2345 #self.window.show()
2346 self.p_context = self.window.get_pango_context()
2347 self.p_layout = pango.Layout(self.p_context)
2348 self.p_layout.set_font_description(\
2349 pango.FontDescription(self.font_name))
2350 #self.p_layout.set_width(-1)
2351 self.p_layout.set_width(self.width * pango.SCALE - 6)
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
2362 """Show the Notify window."""
2363 self.window.move(gtk.gdk.screen_width() - self.width, gtk.gdk.screen_height() - self.height)
2364 self.cancel_show()
2365 self.window.show()
2366 self.window.set_keep_above(True)
2367
2369 """Show the Notify window after a given delay."""
2370 self.cancel_show()
2371 self.__timeout = gobject.timeout_add(delay, self.__show_timeout)
2372
2377
2379 """Cancel showing of the Notify."""
2380 if self.__timeout:
2381 gobject.source_remove(self.__timeout)
2382 self.p_context = None
2383 self.p_layout = None
2384
2386 self.show()
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
2397 ctx = self.window.window.cairo_create()
2398 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL) # ?
2399 # set a clip region for the expose event
2400 ctx.rectangle(event.area.x, event.area.y,event.area.width, event.area.height)
2401 ctx.clip()
2402 # clear context
2403 ctx.set_source_rgba(1, 1, 1, 0)
2404 ctx.set_operator (cairo.OPERATOR_SOURCE)
2405 ctx.paint()
2406 # draw rectangle
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 # draw text
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 # TEST (as the name implies)
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 # MODULE-FUNCTIONS
2442 # ------------------------------------------------------------------------------
2443
2444 # the new recommended way of launching a screenlet from the "outside"
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 # check for service
2451 if services.service_is_running(name):
2452 # add screenlet through service, if running
2453 srvc = services.get_service_by_name(name)
2454 if srvc:
2455 try:
2456 srvc.add('') # empty string for auto-creating ID
2457 return True
2458 except Exception, ex:
2459 print "Error while adding instance by service: %s" % ex
2460 # service not running or error? launch screenlet's file
2461 path = utils.find_first_screenlet_path(name)
2462 if path:
2463 # get full path of screenlet's file
2464 slfile = path + '/' + name + 'Screenlet.py'
2465 # launch screenlet as separate process
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
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 # LEGACY support: functions that are not used any longer (raise fatal error)
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
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Feb 28 23:21:26 2011 | http://epydoc.sourceforge.net |