def __init__(self, ident, rep): self.__action_stamp = 1 # the display menu self.__DISPLAY_MENU = [ MenuItem("/__cfg", _("_Configure desklet"), callback = self.__handle_configure, icon = gtk.STOCK_PREFERENCES), MenuItem("/__move", _("_Move desklet"), callback = self.__handle_move), MenuItem("/__sep1"), MenuItem("/__src", _("_View Source"), callback = self.__handle_source, icon = gtk.STOCK_EDIT), MenuItem("/__sep2"), MenuItem("/__restart", _("Re_start desklet"), callback = self.__handle_restart, icon = gtk.STOCK_REDO), MenuItem("/__remove", _("_Remove desklet"), callback = self.__handle_remove, icon = gtk.STOCK_DELETE), MenuItem("/__remove", _("_Disable desklet"), callback = self.__handle_disable, icon = gtk.STOCK_CLOSE), MenuItem("/__sep3"), MenuItem("/__about", _("_About"), callback = self.__handle_about, icon = gtk.STOCK_ABOUT) ] # the layout object self.__layout_object = LayoutObject(None) # the stack of current mouse cursors self.__cursor_stack = [] # the controls handling the deprecated sensor stuff: id -> control self.__sensor_controls = {} # mapping of the elements to their parent arrays: child_id -> array_id self.__arrays = {} # content of this display (valid until display has been initialized) self.__content = None # scriptlets of this display (valid until display has been initialized) self.__scriptlets = [] # the root TargetGroup self.__group = None # the scripting environment self.__script = Script(ident, rep) # the path of the .display file self.__path = os.path.dirname(rep) self.__display_file = rep # the configurator object self.__configurator = DisplayConfigger(ident, self.__path) self.__configurator.set_scripting_environment(self.__script) # the about window self.__about = gtk.AboutDialog() self.__about.set_wrap_license(True) self.__about.connect("response", self.__about_response_callback) self.__about.connect("close", self.__about_close_and_delete_callback) self.__about.connect("delete_event", self.__about_close_and_delete_callback) # the readme window self.__readme = HIGDialog(buttons = (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), self_destroy = False) self.__readme.set_title("%s - README" % os.path.basename(rep)) sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) sw.set_shadow_type(gtk.SHADOW_IN) textview = gtk.TextView() textview.set_editable(False) textview.set_overwrite(False) textview.set_left_margin(8) textview.set_right_margin(8) textview.set_wrap_mode(gtk.WRAP_WORD) textview.set_cursor_visible(False) textview.set_size_request(500, 300) self.__readme_buffer = textview.get_buffer() sw.add(textview) sw.show() textview.show() self.__readme.vbox.add(sw) self.__readme.connect("response", self.__readme_response_callback) self.__readme.connect("close", self.__readme_close_and_delete_callback) self.__readme.connect("delete_event", self.__readme_close_and_delete_callback) # the unique ID of this display self.__id = ident # the last position of the mouse pointer (used for filtering out # unwanted events) self.__last_pointer_pos = (-1, -1) # mapping between sensors and targets; which target watches # which sensor? # (sensor, port) -> (target, property) self.__mapping = {} # temporary data for remembering the position of the last mouse click self.__pointer_pos = (0, 0) # whether the display reacts on events self.__is_sensitive = True gtk.HBox.__init__(self)
class Display(gtk.HBox, Observable): __slots__ = ('__sensor_controls', '__arrays', '__group', '__script', '__configurator', '__path', '__display_file', '__id', '__last_pointer_pos', '__pointer_pos', '__is_sensitive', '__cursor_stack') # observer commands OBS_CLOSE = 0 OBS_RESTART = 1 OBS_GEOMETRY = 2 OBS_SHAPE = 3 OBS_TITLE = 4 OBS_ICON = 5 OBS_FLAGS = 6 OBS_BORDERS = 7 OBS_CURSOR = 8 OBS_CLOSED = 9 OBS_DISABLE = 10 # event types EVENT_MOTION = 0 EVENT_PRESS = 1 EVENT_RELEASE = 2 EVENT_KEY_PRESS = 3 EVENT_KEY_RELEASE = 4 EVENT_LEAVE = 5 EVENT_SCROLL = 6 # regular expression to test whether a path is absolute __IS_ABSOLUTE_PATH_RE = re.compile("[a-zA-Z]+://.+") def __init__(self, ident, rep): self.__action_stamp = 1 # the display menu self.__DISPLAY_MENU = [ MenuItem("/__cfg", _("_Configure desklet"), callback = self.__handle_configure, icon = gtk.STOCK_PREFERENCES), MenuItem("/__move", _("_Move desklet"), callback = self.__handle_move), MenuItem("/__sep1"), MenuItem("/__src", _("_View Source"), callback = self.__handle_source, icon = gtk.STOCK_EDIT), MenuItem("/__sep2"), MenuItem("/__restart", _("Re_start desklet"), callback = self.__handle_restart, icon = gtk.STOCK_REDO), MenuItem("/__remove", _("_Remove desklet"), callback = self.__handle_remove, icon = gtk.STOCK_DELETE), MenuItem("/__remove", _("_Disable desklet"), callback = self.__handle_disable, icon = gtk.STOCK_CLOSE), MenuItem("/__sep3"), MenuItem("/__about", _("_About"), callback = self.__handle_about, icon = gtk.STOCK_ABOUT) ] # the layout object self.__layout_object = LayoutObject(None) # the stack of current mouse cursors self.__cursor_stack = [] # the controls handling the deprecated sensor stuff: id -> control self.__sensor_controls = {} # mapping of the elements to their parent arrays: child_id -> array_id self.__arrays = {} # content of this display (valid until display has been initialized) self.__content = None # scriptlets of this display (valid until display has been initialized) self.__scriptlets = [] # the root TargetGroup self.__group = None # the scripting environment self.__script = Script(ident, rep) # the path of the .display file self.__path = os.path.dirname(rep) self.__display_file = rep # the configurator object self.__configurator = DisplayConfigger(ident, self.__path) self.__configurator.set_scripting_environment(self.__script) # the about window self.__about = gtk.AboutDialog() self.__about.set_wrap_license(True) self.__about.connect("response", self.__about_response_callback) self.__about.connect("close", self.__about_close_and_delete_callback) self.__about.connect("delete_event", self.__about_close_and_delete_callback) # the readme window self.__readme = HIGDialog(buttons = (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), self_destroy = False) self.__readme.set_title("%s - README" % os.path.basename(rep)) sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) sw.set_shadow_type(gtk.SHADOW_IN) textview = gtk.TextView() textview.set_editable(False) textview.set_overwrite(False) textview.set_left_margin(8) textview.set_right_margin(8) textview.set_wrap_mode(gtk.WRAP_WORD) textview.set_cursor_visible(False) textview.set_size_request(500, 300) self.__readme_buffer = textview.get_buffer() sw.add(textview) sw.show() textview.show() self.__readme.vbox.add(sw) self.__readme.connect("response", self.__readme_response_callback) self.__readme.connect("close", self.__readme_close_and_delete_callback) self.__readme.connect("delete_event", self.__readme_close_and_delete_callback) # the unique ID of this display self.__id = ident # the last position of the mouse pointer (used for filtering out # unwanted events) self.__last_pointer_pos = (-1, -1) # mapping between sensors and targets; which target watches # which sensor? # (sensor, port) -> (target, property) self.__mapping = {} # temporary data for remembering the position of the last mouse click self.__pointer_pos = (0, 0) # whether the display reacts on events self.__is_sensitive = True gtk.HBox.__init__(self) # # Returns the unique ID of this display. # def get_id(self): return self.__id def get_next_child_index(self): return -1 def get_index_path(self): return [] # # Initializes the display. Call this after you have finished constructing # it. # def initialize(self): assert self.__content childtype, settings, children = self.__content # load saved positions positions = DefaultStateSaver().get_key("positions", {}) lx, ly = positions.get(self.get_id(), (UNSET_COORD, UNSET_COORD)) x = settings.get("x", lx) y = settings.get("y", ly) if (x != UNSET_COORD): settings["x"] = x if (y != UNSET_COORD): settings["y"] = y # setup the root layout object (representing the root window) self.__layout_object.set_geometry(Unit.ZERO, Unit.ZERO, Unit.Unit(gtk.gdk.screen_width(), Unit.UNIT_PX), Unit.Unit(gtk.gdk.screen_height(), Unit.UNIT_PX)) # build widget hierarchy self.new_child(childtype, settings, children) self.add(self.__group.get_widget()) # run initial scripts for s in self.__scriptlets: self.execute_script(s) # load stored configuration self.__configurator.load_config() # unlock the geometry engine gobject.idle_add(self.__group.unlock_geometry) # # Sets the content of the display. # def set_content(self, childtype, settings, children): self.__content = (childtype, settings, children) # # Sets the callbacks for the responses (about and readme dialogs). # def __about_response_callback(self, about, response_id): if (response_id < 0): self.__about.hide() self.__about.emit_stop_by_name("response") elif (response_id == 2003): self.__open_readme() elif (response_id == gtk.RESPONSE_CLOSE): self.__about.hide() def __about_close_and_delete_callback(self, about, event=None): self.__about.hide() return True def __readme_response_callback(self, readme, response_id): if (response_id == gtk.RESPONSE_CLOSE): self.__readme.hide() def __readme_close_and_delete_callback(self, readme, event=None): self.__readme.hide() return True # # Sets metadata. # def set_metadata(self, metadata): pbuf = None fbuf = None rbuf = None preview = metadata.get("preview", "") name = metadata.get("name", "") version = metadata.get("version", "") copyright = metadata.get("copyright", "") comments = metadata.get("comments", "") license = metadata.get("license", "") website = metadata.get("website", "") author = metadata.get("author", "") category = metadata.get("category", "") dependency = metadata.get("dependency", "") description = metadata.get("description", "") + "\n" # a banner without the display's name would look crappy if (name): if (preview): preview = self.get_full_path(preview) data = vfs.read_entire_file(preview) loader = gtk.gdk.PixbufLoader() loader.write(data, len(data)) loader.close() pbuf = loader.get_pixbuf() self.__configurator.set_banner(preview, "<big>%s</big> %s\n" "<small>%s</small>" % (name, version, author)) # include the LICENSE file if available for elem in ("COPYING", "LICENSE"): try: fbuf = open(self.get_full_path(elem), "r") except: pass if (fbuf): license = fbuf.read() else: log("Warning: COPYING or LICENSE not included in desklet \"%s %s\".\nPlease contact the author!" % (name, version)) # include the README file if available try: rbuf = open(self.get_full_path("README"), "r") except: log("README file not included in desklet!") if (rbuf): self.__readme_button = \ self.__about.add_button(_("_Readme"), 2003) self.__about.action_area.reorder_child(self.__readme_button, gtk.PACK_START) self.__readme_buffer.set_text(rbuf.read()) # add comments to the description if (comments): description = "%s\n%s\n" % (description, comments) # feed the About Window with the Metadata self.__about.set_name(name) self.__about.set_version(version) self.__about.set_copyright(copyright) self.__about.set_comments(description) if (license): self.__about.set_license(license) self.__about.set_website(website) self.__about.set_authors([author]) self.__about.set_logo(pbuf) # # Adds the given scriptlet. # def add_scriptlet(self, code, filename): scriptlet = Scriptlet(code, filename) self.__scriptlets.append(scriptlet) # # Executes the given script. # def execute_script(self, code): self.__script.execute(code) # # Executes the given callback script. # def execute_callback_script(self, code, this): scriptlet = Scriptlet(code, self.__display_file) self.__script.add_element(None, "self", this) self.__script.execute(scriptlet) # # Adds the given target to the scripting environment. # def add_target_to_script(self, name, target): index_path = target.get_index_path() length = len(index_path) if ("#" in name): name = name[:name.find("#")] if (length > 0): self.__script.add_element_with_path(_ROOT, name, target, index_path) else: self.__script.add_element(_ROOT, name, target) # # Builds the configurator. # def build_configurator(self, items): self.__configurator.build(items) self.__configurator.set_path(self.__path) # # Sends an event to be executed to the display. # def send_event(self, etype, *args): if (not self.__is_sensitive): return w, h = self.__group.get_widget().size_request() lx, ly = self.__pointer_pos self.__action_stamp += 1 actions = [] if (etype == self.EVENT_MOTION): x, y = args utils.request_idle_call(self.__queue_motion, x, y, w, h, False) return elif (etype == self.EVENT_LEAVE): utils.request_idle_call(self.__queue_motion, 0, 0, w, h, True) return elif (etype == self.EVENT_PRESS): button, x, y, counter = args self.__pointer_pos = (x, y) if (counter == 1): action = DisplayTarget.ACTION_PRESS else: action = DisplayTarget.ACTION_DOUBLECLICK event = Struct(button = button, _args = [button]) actions.append((action, event)) elif (etype == self.EVENT_RELEASE): button, x, y = args if (button == 1): if (abs(lx - x) < 10 and abs(ly - y) < 10): action = DisplayTarget.ACTION_CLICK event = Struct(button = button, _args = [button]) actions.append((action, event)) action = DisplayTarget.ACTION_RELEASE elif (button == 2): return elif (button == 3): action = DisplayTarget.ACTION_MENU else: return event = Struct(button = button, _args = [button]) actions.append((action, event)) elif (etype == self.EVENT_SCROLL): direction, x, y = args if (direction == gtk.gdk.SCROLL_UP): direction = 0 elif (direction == gtk.gdk.SCROLL_DOWN): direction = 1 else: direction = -1 action = DisplayTarget.ACTION_SCROLL event = Struct(direction = direction, _args = [direction]) actions.append((action, event)) elif (etype == self.EVENT_KEY_PRESS): key, x, y = args action = DisplayTarget.ACTION_KEY_PRESS event = Struct(key = key) actions.append((action, event)) elif (etype == self.EVENT_KEY_RELEASE): key, x, y = args action = DisplayTarget.ACTION_KEY_RELEASE event = Struct(key = key) actions.append((action, event)) else: # what kind of event did we get there? import traceback; traceback.print_exc() for action, event in actions: self.__group.get_layout_object().send_action( Unit.Unit(x, Unit.UNIT_PX), Unit.Unit(y, Unit.UNIT_PX), self.__action_stamp, action, event) # extend the menu or create one if there's none if (action == DisplayTarget.ACTION_MENU): utils.request_idle_call(self.open_menu, []) # # Returns the path of the .display file. # def get_path(self): return self.__path # # Returns the full path of the given path which may be relative to the # .display file. # def get_full_path(self, path): # a path is absolute iff it starts with "/" or with a protocol name # such as "http://", otherwise it's relative if (path.startswith("/") or self.__IS_ABSOLUTE_PATH_RE.match(path)): return path else: return os.path.join(self.__path, path) # # Returns the display. # def _get_display(self): return self # # Creates and returns a new layout object as a child of this element's # layout object. # def new_layout_object(self): return self.__layout_object.new_child() def new_child(self, childtype, settings, children): # we don't catch the KeyError here, but in the DisplayFactory try: self.__group = targetregistry.create(childtype, self) except KeyError, exc: log("Error: %s\n" % `exc`) self.__group.get_widget().show() cid = settings["id"] self.add_target_to_script(cid, self.__group) for t, s, c in children: self.__group.new_child(t, s, c) for key, value in settings.items(): self.__group.set_xml_prop(key, value)