Package screenlets
[hide private]
[frames] | no frames]

Source Code for Package screenlets

   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   
67 -def _(s):
68 return gettext.gettext(s)
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
153 -class DefaultMenuItem(object):
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
175 -class ScreenletTheme (dict):
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
202 - def __init__ (self, path):
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
212 - def __getattr__ (self, name):
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
223 - def apply_option_overrides (self, screenlet):
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
251 - def check_entry (self, filename):
252 """Checks if a file with filename is loaded in this theme.""" 253 try: 254 if self[filename]: 255 return True 256 except: 257 #raise Exception 258 return False
259
260 - def get_text_width(self, ctx, text, font):
261 """@DEPRECATED Moved to Screenlets class: Returns the pixel width of a given text""" 262 ctx.save() 263 264 if self.p_layout == None : 265 266 self.p_layout = ctx.create_layout() 267 else: 268 269 ctx.update_layout(self.p_layout) 270 self.p_fdesc = pango.FontDescription(font) 271 self.p_layout.set_font_description(self.p_fdesc) 272 self.p_layout.set_text(text) 273 extents, lextents = self.p_layout.get_pixel_extents() 274 ctx.restore() 275 return extents[2]
276
277 - def get_text_extents(self, ctx, text, font):
278 """@DEPRECATED Moved to Screenlets class: Returns the pixel extents of a given text""" 279 ctx.save() 280 281 if self.p_layout == None : 282 283 self.p_layout = ctx.create_layout() 284 else: 285 286 ctx.update_layout(self.p_layout) 287 self.p_fdesc = pango.FontDescription(font) 288 self.p_layout.set_font_description(self.p_fdesc) 289 self.p_layout.set_text(text) 290 extents, lextents = self.p_layout.get_pixel_extents() 291 ctx.restore() 292 return extents
293
294 - def draw_text(self, ctx, text, x, y, font, size, width, allignment, weight = 0, ellipsize = pango.ELLIPSIZE_NONE):
295 """@DEPRECATED Moved to Screenlets class: Draws text""" 296 ctx.save() 297 ctx.translate(x, y) 298 if self.p_layout == None : 299 300 self.p_layout = ctx.create_layout() 301 else: 302 303 ctx.update_layout(self.p_layout) 304 self.p_fdesc = pango.FontDescription() 305 self.p_fdesc.set_family_static(font) 306 self.p_fdesc.set_size(size * pango.SCALE) 307 self.p_fdesc.set_weight(weight) 308 self.p_layout.set_font_description(self.p_fdesc) 309 self.p_layout.set_width(width * pango.SCALE) 310 self.p_layout.set_alignment(allignment) 311 self.p_layout.set_ellipsize(ellipsize) 312 self.p_layout.set_markup(text) 313 ctx.show_layout(self.p_layout) 314 ctx.restore()
315 316
317 - def draw_circle(self,ctx,x,y,width,height,fill=True):
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
337 - def draw_rectangle(self,ctx,x,y,width,height,fill=True):
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
346 - def draw_rounded_rectangle(self,ctx,x,y,rounded_angle,width,height,fill=True):
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
379 - def get_image_size(self,pix):
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
388 - def draw_image(self,ctx,x,y, pix):
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
410 - def draw_scaled_image(self,ctx,x,y, pix, w, h):
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
432 - def show_notification (self,text):
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
439 - def hide_notification (self):
440 """@DEPRECATED Moved to Screenlets class: hide notification window""" 441 if self.notify != None: 442 self.notify.hide() 443 self.notify = None
444
445 - def show_tooltip (self,text,tooltipx,tooltipy):
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
454 - def hide_tooltip (self):
455 """@DEPRECATED Moved to Screenlets class: hide tooltip window""" 456 if self.tooltip != None: 457 self.tooltip.hide() 458 self.tooltip = None
459
460 - def has_overrides (self):
461 """Check if this theme contains overrides for options.""" 462 return len(self.option_overrides) > 0
463
464 - def load_conf (self, filename):
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
487 - def load_svg (self, filename):
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
515 - def load_png (self, filename):
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
528 - def __load_all (self):
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
556 - def reload (self):
557 """Re-Load all files in the theme's path.""" 558 self.free() 559 self.__load_all()
560 561 # TODO: fix function, rsvg handles are not freed properly
562 - def free (self):
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
577 - def render (self, ctx, name):
578 """Render an image from within this theme to the given context. This 579 function can EITHER use png OR svg images, so it is possible to 580 create themes using both image-formats when a Screenlet uses this 581 function for drawing its images. The image name has to be defined 582 without the extension and the function will automatically select 583 the available one (SVG is prefered over PNG).""" 584 585 ### 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
606 - def render_png_colorized(self, ctx, name,color):
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
615 -class Screenlet (gobject.GObject, EditableOptions, Drawing):
616 """A Screenlet is a (i.e. contains a) shaped gtk-window that is 617 fully invisible by default. Subclasses of Screenlet can render 618 their owner-drawn graphics on fully transparent background.""" 619 620 # 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
895 - def __setattr__ (self, name, value):
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
975 - def check_requirements (self):
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
1023 """Appends the default menu-items to self.menu. You can add on OR'ed 1024 flag with DefaultMenuItems you want to add.""" 1025 if not self.has_started: print 'WARNING - add_default_menuitems and add_menuitems should be set in on_init ,menu values will be displayed incorrectly' 1026 1027 menu = self.menu 1028 1029 # children already exist? add separator 1030 if len(menu.get_children()) > 0: 1031 self.add_menuitem("", "-") 1032 # EXPERIMENTAL: 1033 if flags & DefaultMenuItem.XML: 1034 # create XML-menu from screenletpath/menu.xml 1035 xfile = self.get_screenlet_dir() + "/menu.xml" 1036 xmlmenu = screenlets.menu.create_menu_from_file(xfile, 1037 self.menuitem_callback) 1038 if xmlmenu: 1039 self.menu = xmlmenu 1040 # add size-selection 1041 if flags & DefaultMenuItem.SIZE: 1042 size_item = gtk.MenuItem(_("Size")) 1043 size_item.show() 1044 size_menu = gtk.Menu() 1045 menu.append(size_item) 1046 size_item.set_submenu(size_menu) 1047 #for i in xrange(10): 1048 for i in (0.2,0.3,0.4, 0.5,0.6, 0.7,0.8,0.9, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 7.5, 10): 1049 s = str(int(i * 100)) 1050 item = gtk.MenuItem(s + " %") 1051 item.connect("activate", self.menuitem_callback, 1052 "scale:"+str(i)) 1053 item.show() 1054 size_menu.append(item) 1055 # create theme-selection menu 1056 if flags & DefaultMenuItem.THEMES: 1057 themes_item = gtk.MenuItem(_("Theme")) 1058 themes_item.show() 1059 themes_menu = gtk.Menu() 1060 menu.append(themes_item) 1061 themes_item.set_submenu(themes_menu) 1062 # create theme-list from theme-directory 1063 lst = self.get_available_themes() 1064 for tname in lst: 1065 item = gtk.MenuItem(tname) 1066 item.connect("activate", self.menuitem_callback, "theme:"+tname) 1067 item.show() 1068 themes_menu.append(item) 1069 1070 # add window-options menu 1071 if flags & DefaultMenuItem.WINDOW_MENU: 1072 winmenu_item = gtk.MenuItem(_("Window")) 1073 winmenu_item.show() 1074 winmenu_menu = gtk.Menu() 1075 menu.append(winmenu_item) 1076 winmenu_item.set_submenu(winmenu_menu) 1077 # add "lock"-menuitem 1078 self.__mi_lock = item = gtk.CheckMenuItem(_("Lock")) 1079 item.set_active(self.lock_position) 1080 item.connect("activate", self.menuitem_callback, 1081 "option:lock") 1082 item.show() 1083 winmenu_menu.append(item) 1084 # add "Sticky"-menuitem 1085 self.__mi_sticky = item = gtk.CheckMenuItem(_("Sticky")) 1086 item.set_active(self.is_sticky) 1087 item.connect("activate", self.menuitem_callback, 1088 "option:sticky") 1089 item.show() 1090 winmenu_menu.append(item) 1091 # add "Widget"-menuitem 1092 self.__mi_widget = item = gtk.CheckMenuItem(_("Widget")) 1093 item.set_active(self.is_widget) 1094 item.connect("activate", self.menuitem_callback, 1095 "option:widget") 1096 item.show() 1097 winmenu_menu.append(item) 1098 # add "Keep above"-menuitem 1099 self.__mi_keep_above = item = gtk.CheckMenuItem(_("Keep above")) 1100 item.set_active(self.keep_above) 1101 item.connect("activate", self.menuitem_callback, 1102 "option:keep_above") 1103 item.show() 1104 winmenu_menu.append(item) 1105 # add "Keep Below"-menuitem 1106 self.__mi_keep_below = item = gtk.CheckMenuItem(_("Keep below")) 1107 item.set_active(self.keep_below) 1108 item.connect("activate", self.menuitem_callback, 1109 "option:keep_below") 1110 item.show() 1111 winmenu_menu.append(item) 1112 1113 # add Settings item 1114 if flags & DefaultMenuItem.PROPERTIES: 1115 add_menuitem(menu, "-", self.menuitem_callback, "") 1116 add_menuitem(menu, _("Properties..."), self.menuitem_callback, "options") 1117 # add info item 1118 if flags & DefaultMenuItem.INFO: 1119 add_menuitem(menu, _("Info..."), self.menuitem_callback, "info") 1120 # add delete item 1121 if flags & DefaultMenuItem.ADD: 1122 add_menuitem(menu, "-", self.menuitem_callback, "") 1123 add_menuitem(menu, _("Add one more %s") % self.get_short_name(), self.menuitem_callback, "add") 1124 # add delete item 1125 if flags & DefaultMenuItem.DELETE: 1126 add_menuitem(menu, _("Delete this %s") % self.get_short_name(), self.menuitem_callback, "delete") 1127 # add Quit item 1128 if flags & DefaultMenuItem.QUIT: 1129 add_menuitem(menu, "-", self.menuitem_callback, "") 1130 add_menuitem(menu, _("Quit this %s") % self.get_short_name(), self.menuitem_callback, "quit_instance") 1131 # add Quit-all item 1132 if flags & DefaultMenuItem.QUIT_ALL: 1133 add_menuitem(menu, _("Quit all %ss") % self.get_short_name(), self.menuitem_callback, "quit")
1134
1135 - def add_menuitem (self, id, label, callback=None):
1136 """Simple way to add menuitems to a right-click menu. 1137 This function wraps screenlets.menu.add_menuitem. 1138 For backwards compatibility, the order of the parameters 1139 to this function is switched.""" 1140 if not self.has_started: print 'WARNING - add_default_menuitems and add_menuitems should be set in on_init ,menu values will be displayed incorrectly' 1141 if callback is None: 1142 callback = self.menuitem_callback 1143 # call menu.add_menuitem 1144 return add_menuitem(self.menu, label, callback, id)
1145
1146 - def add_submenuitem (self, id, label, lst, callback=None):
1147 """Simple way to add submenuitems to the right-click menu through a list.""" 1148 if not self.has_started: print 'WARNING - add_default_menuitems and add_menuitems should be set in on_init ,menu values will be displayed incorrectly' 1149 1150 submenu = gtk.MenuItem(label) 1151 submenu.show() 1152 sub_menu = gtk.Menu() 1153 self.menu.append(submenu) 1154 submenu.set_submenu(sub_menu) 1155 # create theme-list from theme-directory 1156 1157 for tname in lst: 1158 item = gtk.MenuItem(tname) 1159 item.connect("activate", self.menuitem_callback, 1160 tname) 1161 item.show() 1162 sub_menu.append(item) 1163 1164 return submenu
1165 1166 1167
1168 - def load_buttons(self, event):
1169 self.closeb = self.gtk_icon_theme.load_icon ("gtk-close", 16, 0) 1170 self.prop = self.gtk_icon_theme.load_icon ("gtk-properties", 16, 0)
1171
1172 - def create_buttons(self):
1173 1174 ctx = self.window.window.cairo_create() 1175 ctx.save() 1176 #ctx.set_source_rgba(0.5,0.5,0.5,0.6) 1177 #self.theme.draw_rounded_rectangle(ctx,(self.width*self.scale)-36,0,5,36,16) 1178 #close = theme1.load_icon ("gtk-close", 16, 0) 1179 #prop = theme1.load_icon ("gtk-properties", 16, 0) 1180 #zoom1 = theme1.load_icon ("gtk-zoom-in", 16, 0) 1181 #zoom2 = theme1.load_icon ("gtk-zoom-out", 16, 0) 1182 #close = gtk.image_new_from_stock(gtk.STOCK_CLOSE, 16) 1183 ctx.translate((self.width*self.scale)-16,0) 1184 ctx.set_source_pixbuf(self.closeb, 0, 0) 1185 ctx.paint() 1186 ctx.restore() 1187 ctx.save() 1188 ctx.translate((self.width*self.scale)-32,0) 1189 ctx.set_source_pixbuf(self.prop, 0, 0) 1190 ctx.paint() 1191 ctx.restore()
1192
1193 - def clear_cairo_context (self, ctx):
1194 """Fills the given cairo.Context with fully transparent white.""" 1195 ctx.save() 1196 ctx.set_source_rgba(1, 1, 1, 0) 1197 ctx.set_operator (cairo.OPERATOR_SOURCE) 1198 ctx.paint() 1199 ctx.restore()
1200
1201 - def close (self):
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
1209 - def create_drag_icon (self):
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
1230 - def enable_saving (self, enabled=True):
1231 """Enable/Disable realtime-saving of options.""" 1232 self.saving_enabled = enabled
1233
1234 - def find_theme (self, name):
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
1244 - def get_short_name (self):
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
1250 - def get_screenlet_dir (self):
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
1261 - def get_theme_dir (self):
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
1266 - def get_available_themes (self):
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
1285 - def reshow(self):
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
1299 - def finish_loading(self):
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
1356 - def hide (self):
1357 """Hides this Screenlet's underlying gtk.Window""" 1358 self.window.hide() 1359 self.on_hide()
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
1364 - def load_theme (self, path):
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
1389 - def main (self):
1390 """If the Screenlet runs as stand-alone app, starts gtk.main()""" 1391 gtk.main()
1392
1393 - def register_service (self, service_classobj):
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
1412 - def set_is_widget (self, value):
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
1432 - def show (self):
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
1438 - def show_settings_dialog (self):
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
1462 - def redraw_canvas (self):
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
1478 - def redraw_canvas_area (self, x, y, width, height):
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
1490 - def remove_shape(self):
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
1523 - def update_shape (self):
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
1582 - def update_shape_non_composited (self):
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
1608 self.redraw_canvas() 1609 self.update_shape()
1610 1611 # ---------------------------------------------------------------------- 1612 # Screenlet's event-handler dummies 1613 # ---------------------------------------------------------------------- 1614
1615 - def on_delete (self):
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
1630 - def on_after_set_atribute(self,name, value):
1631 """Called after setting screenlet atributes""" 1632 pass
1633
1634 - def on_before_set_atribute(self,name, value):
1635 """Called before setting screenlet atributes""" 1636 pass
1637 1638
1639 - def on_create_drag_icon (self):
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
1644 - def on_map(self):
1645 """Called when screenlet was mapped""" 1646 pass
1647
1648 - def on_unmap(self):
1649 """Called when screenlet was unmapped""" 1650 pass
1651
1652 - def on_composite_changed(self):
1653 """Called when composite state has changed""" 1654 pass
1655 1656
1657 - def on_drag_begin (self, drag_context):
1658 """Called when the Screenlet gets dragged.""" 1659 pass
1660
1661 - def on_drag_enter (self, drag_context, x, y, timestamp):
1662 """Called when something gets dragged into the Screenlets area.""" 1663 pass
1664
1665 - def on_drag_leave (self, drag_context, timestamp):
1666 """Called when something gets dragged out of the Screenlets area.""" 1667 pass
1668
1669 - def on_draw (self, ctx):
1670 """Callback for drawing the Screenlet's window - override 1671 in subclasses to implement your own drawing.""" 1672 pass
1673
1674 - def on_draw_shape (self, ctx):
1675 """Callback for drawing the Screenlet's shape - override 1676 in subclasses to draw the window's input-shape-mask.""" 1677 pass
1678
1679 - def on_drop (self, x, y, sel_data, timestamp):
1680 """Called when a selection is dropped on this Screenlet.""" 1681 return False
1682
1683 - def on_focus (self, event):
1684 """Called when the Screenlet's window receives focus.""" 1685 pass
1686
1687 - def on_hide (self):
1688 """Called when the Screenlet gets hidden.""" 1689 pass
1690
1691 - def on_init (self):
1692 """Called when the Screenlet's options have been applied and the 1693 screenlet finished its initialization. If you want to have your 1694 Screenlet do things on startup you should use this handler.""" 1695 pass
1696
1697 - def on_key_down (self, keycode, keyvalue, event=None):
1698 """Called when a key is pressed within the screenlet's window.""" 1699 pass
1700
1701 - def on_load_theme (self):
1702 """Called when the theme is reloaded (after loading, before redraw).""" 1703 pass
1704
1705 - def on_menuitem_select (self, id):
1706 """Called when a menuitem is selected.""" 1707 pass
1708
1709 - def on_mouse_down (self, event):
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
1714 - def on_mouse_enter (self, event):
1715 """Called when the mouse enters the Screenlet's window.""" 1716 pass
1717
1718 - def on_mouse_leave (self, event):
1719 """Called when the mouse leaves the Screenlet's window.""" 1720 pass
1721
1722 - def on_mouse_move(self, event):
1723 """Called when the mouse moves in the Screenlet's window.""" 1724 pass
1725
1726 - def on_mouse_up (self, event):
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
1731 - def on_quit (self):
1732 """Callback for handling destroy-event. Perform your cleanup here!""" 1733 return True
1734
1735 - def on_realize (self):
1736 """"Callback for handling the realize-event."""
1737
1738 - def on_scale (self):
1739 """Called when Screenlet.scale is changed.""" 1740 pass
1741
1742 - def on_scroll_up (self):
1743 """Called when mousewheel is scrolled up (button4).""" 1744 pass
1745
1746 - def on_scroll_down (self):
1747 """Called when mousewheel is scrolled down (button5).""" 1748 pass
1749
1750 - def on_show (self):
1751 """Called when the Screenlet gets shown after being hidden.""" 1752 pass
1753
1754 - def on_switch_widget_state (self, state):
1755 """Called when the Screenlet enters/leaves "Widget"-state.""" 1756 pass
1757
1758 - def on_unfocus (self, event):
1759 """Called when the Screenlet's window loses focus.""" 1760 pass
1761
1762 - def on_update_shape(self):
1763 """Called when the Screenlet's window is updating shape""" 1764 pass
1765 # ---------------------------------------------------------------------- 1766 # Screenlet's event-handlers for GTK-events 1767 # ---------------------------------------------------------------------- 1768
1769 - def alpha_screen_changed (self, window, screen=None):
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
1780 - def button_press (self, widget, event):
1781 1782 #print "Button press" 1783 # set flags for user-handler 1784 1785 1786 # call user-handler for onmousedownbegin_move_drag 1787 if self.on_mouse_down(event) == True: 1788 return True 1789 # unhandled? continue 1790 1791 if self.mousex >= self.width - (32/self.scale) and self.mousey <= (16/self.scale) and self.draw_buttons and self.show_buttons and self.has_focus: 1792 if self.mousex >= self.width - (16/self.scale): 1793 self.menuitem_callback(widget,'quit_instance') 1794 elif self.mousex <= self.width -(16/self.scale): 1795 self.menuitem_callback(widget,'info') 1796 elif self.lock_position == False: 1797 if event.button == 1: 1798 self.is_dragged = True 1799 widget.begin_move_drag(event.button, int(event.x_root), 1800 int(event.y_root), event.time) 1801 1802 if event.button == 3: 1803 try: 1804 self.__mi_lock.set_active(self.lock_position) 1805 self.__mi_sticky.set_active(self.is_sticky) 1806 self.__mi_widget.set_active(self.is_widget) 1807 self.__mi_keep_above.set_active(self.keep_above) 1808 self.__mi_keep_below.set_active(self.keep_below) 1809 except : pass 1810 self.menu.popup(None, None, None, event.button, event.time) 1811 #elif event.button == 4: 1812 # print "MOUSEWHEEL" 1813 # self.scale -= 0.1 1814 #elif event.button == 5: 1815 # print "MOUSEWHEEL" 1816 # self.scale += 0.1 1817 return False
1818
1819 - def button_release (self, widget, event):
1820 print "Button release" 1821 if event.button==1: 1822 self.focus_in_event(self, None) 1823 self.is_dragged = False # doesn't work!!! we don't get an event when move_drag ends :( ... 1824 if self.on_mouse_up(event): 1825 return True 1826 return False
1827
1828 - def composite_changed(self,widget):
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
1856 - def configure_event (self, widget, event):
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
1874 - def delete_event (self, widget, event, data=None):
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
1884 - def destroy (self, widget, data=None):
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
1897 - def drag_begin (self, widget, drag_context):
1898 print "Start drag" 1899 self.is_dragged = True 1900 self.on_drag_begin(drag_context)
1901 #return False 1902
1903 - def drag_data_received (self, widget, dc, x, y, sel_data, info, timestamp):
1904 return self.on_drop(x, y, sel_data, timestamp)
1905
1906 - def drag_end (self, widget, drag_context):
1907 print "End drag" 1908 self.is_dragged = False 1909 return False
1910
1911 - def drag_motion (self, widget, drag_context, x, y, timestamp):
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
1918 - def drag_leave (self, widget, drag_context, timestamp):
1919 self.dragging_over = False 1920 self.on_drag_leave(drag_context, timestamp) 1921 return
1922
1923 - def enter_notify_event (self, widget, event):
1924 #self.__mouse_inside = True 1925 self.__dict__['mouse_is_over'] = True 1926 self.on_mouse_enter(event)
1927 1928 #self.redraw_canvas() 1929
1930 - def expose (self, widget, event):
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
1949 - def focus_in_event (self, widget, event):
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
1963 - def focus_out_event (self, widget, event):
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
1972 - def key_press (self, widget, event):
1973 """Handle keypress events, needed for in-place editing.""" 1974 self.on_key_down(event.keyval, event.string, event)
1975
1976 - def leave_notify_event (self, widget, event):
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
1984 - def menuitem_callback (self, widget, id):
1985 if id == "delete": 1986 if not self.on_delete(): 1987 # remove instance 1988 self.session.delete_instance (self.id) 1989 # notify about being rmeoved (does this get send???) 1990 self.service.instance_removed(self.id) 1991 elif id == "quit_instance": 1992 print 'Quitting current screenlet instance' 1993 self.session.quit_instance (self.id) 1994 self.service.instance_removed(self.id) 1995 elif id == "quit": 1996 self.close() 1997 elif id == "add": 1998 self.service.add("") 1999 elif id in ("info", "about", "settings", "options", "properties"): 2000 # show settings dialog 2001 self.show_settings_dialog() 2002 elif id.startswith('scale:'): 2003 self.scale = float(id[6:]) 2004 elif id[:5] == "size:": # DEPRECATED?? 2005 # set size and update shape (redraw is done by setting height) 2006 #self.__dict__['width'] = int(id[5:]) 2007 self.width = int(id[5:]) 2008 self.height = int(id[5:]) 2009 self.update_shape() 2010 elif id[:6]=="theme:": 2011 print "Screenlet: Set theme %s" % id[6:] 2012 # set theme 2013 self.theme_name = id[6:] 2014 elif id[:8] == "setting:": 2015 # set a boolean option to the opposite state 2016 try: 2017 if type(self.__dict__[id[8:]]) == bool: 2018 self.__dict__[id[8:]] = not self.__dict__[id[8:]] # UNSAFE!! 2019 except: 2020 print "Error: Cannot set missing or non-boolean value '"\ 2021 + id[8:] + "'" 2022 elif id[:7] == "option:": 2023 # NOTE: this part should be removed and XML-menus 2024 # should be used by default ... maybe 2025 # set option 2026 if id[7:]=="lock": 2027 if self.__mi_lock.get_active () != self.lock_position: 2028 self.lock_position = not self.lock_position 2029 elif id[7:]=="sticky": 2030 if self.__mi_sticky.get_active () != self.is_sticky: 2031 self.is_sticky = not self.is_sticky 2032 #widget.toggle() 2033 elif id[7:]=="widget": 2034 if self.__mi_widget.get_active () != self.is_widget: 2035 self.is_widget = not self.is_widget 2036 elif id[7:]=="keep_above": 2037 if self.__mi_keep_above.get_active () != self.keep_above: 2038 self.keep_above = not self.keep_above 2039 self.__mi_keep_above.set_active(self.keep_above) 2040 if self.keep_below and self.keep_above : 2041 self.keep_below = False 2042 self.__mi_keep_below.set_active(False) 2043 elif id[7:]=="keep_below": 2044 if self.__mi_keep_below.get_active () != self.keep_below: 2045 self.keep_below = not self.keep_below 2046 self.__mi_keep_below.set_active(self.keep_below) 2047 if self.keep_below and self.keep_above : 2048 self.keep_above = False 2049 self.__mi_keep_above.set_active(False) 2050 else: 2051 #print "Item: " + string 2052 pass 2053 # call user-handler 2054 self.on_menuitem_select(id) 2055 return False
2056
2057 - def map_event(self, widget, event):
2058 self.on_map()
2059
2060 - def unmap_event(self, widget, event):
2061 self.on_unmap()
2062
2063 - def motion_notify_event(self, widget, event):
2064 self.__dict__['mousex'] = event.x / self.scale 2065 self.__dict__['mousey'] = event.y / self.scale 2066 2067 self.on_mouse_move(event)
2068
2069 - def realize_event (self, widget):
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
2076 - def scroll_event (self, widget, event):
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
2086 - def show_notification (self,text):
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
2093 - def hide_notification (self):
2094 """hide notification window""" 2095 if self.notify != None: 2096 self.notify.hide() 2097 self.notify = None
2098
2099 - def show_tooltip (self,text,tooltipx,tooltipy):
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
2114 - def hide_tooltip (self):
2115 """hide tooltip window""" 2116 if self.tooltip != None: 2117 self.tooltip.hide() 2118 self.tooltip = None
2119 2120 # TEST!!!
2121 -class ShapedWidget (gtk.DrawingArea):
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
2130 - def __init__ (self, width, height):
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
2146 - def update_shape (self):
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
2161 - def button_press (self, widget, event):
2162 if event.button==1: 2163 print "left button pressed!" 2164 return False
2165
2166 - def button_release (self, widget, event):
2167 #if event.button==1: 2168 #print "left button release!" 2169 return False
2170
2171 - def enter_notify (self, widget, event):
2172 self.mouse_inside = True 2173 self.queue_draw()
2174 #print "mouse enter" 2175
2176 - def leave_notify (self, widget, event):
2177 self.mouse_inside = False 2178 self.queue_draw()
2179 #print "mouse leave" 2180
2181 - def draw (self, ctx):
2182 pass
2183
2184 - def draw_shape (self, ctx):
2185 self.draw(ctx)
2186
2187 - def expose_event (self, widget, event):
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
2203 -class Tooltip(object):
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
2217 - def __init__ (self, width, height):
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
2241 - def __setattr__ (self, name, value):
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
2257 - def show (self):
2258 """Show the Tooltip window.""" 2259 self.cancel_show() 2260 self.window.show() 2261 self.window.set_keep_above(True)
2262
2263 - def show_delayed (self, delay):
2264 """Show the Tooltip window after a given delay.""" 2265 self.cancel_show() 2266 self.__timeout = gobject.timeout_add(delay, self.__show_timeout)
2267
2268 - def hide (self):
2269 """Hide the Tooltip window.""" 2270 self.cancel_show() 2271 self.window.destroy()
2272
2273 - def cancel_show (self):
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
2280 - def __show_timeout (self):
2281 self.show()
2282
2283 - def screen_changed (self, window, screen=None):
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
2291 - def expose (self, widget, event):
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
2316 -class Notify(object):
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
2331 - def __init__ (self):
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
2353 - def __setattr__ (self, name, value):
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
2361 - def show (self):
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
2368 - def show_delayed (self, delay):
2369 """Show the Notify window after a given delay.""" 2370 self.cancel_show() 2371 self.__timeout = gobject.timeout_add(delay, self.__show_timeout)
2372
2373 - def hide (self):
2374 """Hide the Notify window.""" 2375 self.cancel_show() 2376 self.window.destroy()
2377
2378 - def cancel_show (self):
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
2385 - def __show_timeout (self):
2386 self.show()
2387
2388 - def screen_changed (self, window, screen=None):
2389 if screen == None: 2390 screen = window.get_screen() 2391 map = screen.get_rgba_colormap() 2392 if not map: 2393 map = screen.get_rgb_colormap() 2394 window.set_colormap(map)
2395
2396 - def expose (self, widget, event):
2397 ctx = self.window.window.cairo_create() 2398 ctx.set_antialias (cairo.ANTIALIAS_SUBPIXEL) # ? 2399 # 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"
2445 -def launch_screenlet (name, debug=False):
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
2478 -def show_message (screenlet, message, title=''):
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
2493 -def show_question (screenlet, message, title=''):
2494 """Show a question for the given Screenlet (may contain Pango-Markup).""" 2495 if screenlet == None: 2496 md = gtk.MessageDialog(None, type=gtk.MESSAGE_QUESTION, 2497 buttons=gtk.BUTTONS_YES_NO) 2498 md.set_title(title) 2499 else: 2500 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_QUESTION, 2501 buttons=gtk.BUTTONS_YES_NO) 2502 md.set_title(screenlet.__name__) 2503 md.set_markup(message) 2504 response = md.run() 2505 md.destroy() 2506 if response == gtk.RESPONSE_YES: 2507 return True 2508 return False
2509
2510 -def show_error (screenlet, message, title='Error'):
2511 """Show an error for the given Screenlet (may contain Pango-Markup).""" 2512 if screenlet == None: 2513 md = gtk.MessageDialog(None, type=gtk.MESSAGE_ERROR, 2514 buttons=gtk.BUTTONS_OK) 2515 md.set_title(title) 2516 else: 2517 md = gtk.MessageDialog(screenlet.window, type=gtk.MESSAGE_ERROR, 2518 buttons=gtk.BUTTONS_OK) 2519 md.set_title(screenlet.__name__) 2520 md.set_markup(message) 2521 md.run() 2522 md.destroy()
2523
2524 -def fatal_error (message):
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
2534 -def create_new_instance (name):
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