def _keys_changed(self, *args): self.modifier_map = grok_modifier_map(self.window) self.nuisances = set() for i in range(256): if not(i & ~self.modifier_map["nuisance"]): self.nuisances.add(i) trap.swallow(self._rebind)
def _keys_changed(self, *args): self.modifier_map = grok_modifier_map(self.window) self.nuisances = set() for i in range(256): if not (i & ~self.modifier_map["nuisance"]): self.nuisances.add(i) trap.swallow(self._rebind)
def do_selection_request_event(self, event): log.debug("do_selection_request_event(%s)", event) try: from wimpiggy.prop import prop_get from wimpiggy.error import trap except ImportError: gtk.Invisible.do_selection_request_event(self, event) return # Black magic: the superclass default handler for this signal # implements all the hards parts of selection handling, occasionally # calling back to the do_selection_get handler (below) to actually get # the data to be sent. However, it only does this for targets that # have been registered ahead of time; other targets fall through to a # default implementation that cannot be overridden. So, we swoop in # ahead of time and add whatever target was requested to the list of # targets we want to handle! # # Special cases (magic targets defined by ICCCM): # TIMESTAMP: the remote side has a different timeline than us, so # sending TIMESTAMPS across the wire doesn't make any sense. We # ignore TIMESTAMP requests, and let them fall through to GTK+'s # default handler. # TARGET: GTK+ has default handling for this, but we don't want to # use it. Fortunately, if we tell GTK+ that we can handle TARGET # requests, then it will pass them on to us rather than fall # through to the default handler. # MULTIPLE: Ugh. To handle this properly, we need to go out # ourselves and fetch the magic property off the requesting window # (with proper error trapping and all), and interpret its # contents. Probably doable (FIXME), just a pain. # # Another special case is that if an app requests the contents of a # clipboard that it currently owns, then GTK+ will short-circuit the # normal logic and request the contents directly (i.e. it calls # gtk_selection_invoke_handler) -- without giving us a chance to # assert that we can handle the requested sort of target. Fortunately, # Xpra never needs to request the clipboard when it owns it, so that's # okay. assert str(event.selection) == self._selection target = str(event.target) if target == "TIMESTAMP": pass elif target == "MULTIPLE": def get_targets(targets): atoms = prop_get(event.window, event.property, ["multiple-conversion"]) log("MULTIPLE clipboard atoms: %r", atoms) targets += atoms[::2] targets = [] trap.swallow(get_targets, targets) log("MULTIPLE clipboard targets: %r", targets) for target in targets: self.selection_add_target(self._selection, target, 0) else: self.selection_add_target(self._selection, target, 0) gtk.Invisible.do_selection_request_event(self, event)
def destroy(self): self.keymap.disconnect(self.keymap_id) self.keymap = None self.keymap_id = None trap.swallow(self.unbind_all) remove_event_receiver(self.window, self) self.window = None
def do_selection_request_event(self, event): debug("do_selection_request_event(%s)", event) # Black magic: the superclass default handler for this signal # implements all the hards parts of selection handling, occasionally # calling back to the do_selection_get handler (below) to actually get # the data to be sent. However, it only does this for targets that # have been registered ahead of time; other targets fall through to a # default implementation that cannot be overridden. So, we swoop in # ahead of time and add whatever target was requested to the list of # targets we want to handle! # # Special cases (magic targets defined by ICCCM): # TIMESTAMP: the remote side has a different timeline than us, so # sending TIMESTAMPS across the wire doesn't make any sense. We # ignore TIMESTAMP requests, and let them fall through to GTK+'s # default handler. # TARGET: GTK+ has default handling for this, but we don't want to # use it. Fortunately, if we tell GTK+ that we can handle TARGET # requests, then it will pass them on to us rather than fall # through to the default handler. # MULTIPLE: Ugh. To handle this properly, we need to go out # ourselves and fetch the magic property off the requesting window # (with proper error trapping and all), and interpret its # contents. Probably doable (FIXME), just a pain. # # Another special case is that if an app requests the contents of a # clipboard that it currently owns, then GTK+ will short-circuit the # normal logic and request the contents directly (i.e. it calls # gtk_selection_invoke_handler) -- without giving us a chance to # assert that we can handle the requested sort of target. Fortunately, # Xpra never needs to request the clipboard when it owns it, so that's # okay. assert str(event.selection) == self._selection target = str(event.target) if target == "TIMESTAMP": pass elif target == "MULTIPLE": try: from wimpiggy.prop import prop_get from wimpiggy.error import trap except ImportError: debug("MULTIPLE for property '%s' not handled due to missing wimpiggy bindings", event.property) gtk.Invisible.do_selection_request_event(self, event) return def get_targets(targets): atoms = prop_get(event.window, event.property, ["multiple-conversion"]) debug("MULTIPLE clipboard atoms: %r", atoms) targets += atoms[::2] targets = [] trap.swallow(get_targets, targets) debug("MULTIPLE clipboard targets: %r", targets) for target in targets: self.selection_add_target(self._selection, target, 0) else: debug("target for %s: %r", self._selection, target) self.selection_add_target(self._selection, target, 0) debug("do_selection_request_event(%s) target=%s, selection=%s", event, target, self._selection) gtk.Invisible.do_selection_request_event(self, event)
def destroy(self): if not self._already_composited: trap.swallow(xcomposite_unredirect_window, self._window) trap.swallow(xdamage_stop, self._window, self._damage_handle) self._damage_handle = None self._contents_handle = None self.invalidate_pixmap() remove_event_receiver(self._window, self) self._window = None
def do_get_property_contents_handle(self, name): if self._contents_handle is None: log("refreshing named pixmap", type="pixmap") assert self._listening_to is None def set_pixmap(): # The tricky part here is that the pixmap returned by # NameWindowPixmap gets invalidated every time the window's # viewable state changes. ("viewable" here is the X term that # means "mapped, and all ancestors are also mapped".) But # there is no X event that will tell you when a window's # viewability changes! Instead we have to find all ancestors, # and watch all of them for unmap and reparent events. But # what about races? I hear you cry. By doing things in the # exact order: # 1) select for StructureNotify # 2) QueryTree to get parent # 3) repeat 1 & 2 up to the root # 4) call NameWindowPixmap # we are safe. (I think.) listening = [] try: win = get_parent(self._window) while win is not None and win.get_parent() is not None: # We have to use a lowlevel function to manipulate the # event selection here, because SubstructureRedirectMask # does not roundtrip through the GDK event mask # functions. So if we used them, here, we would clobber # corral window selection masks, and those don't deserve # clobbering. They are our friends! X is driving me # slowly mad. addXSelectInput(win, const["StructureNotifyMask"]) add_event_receiver(win, self) listening.append(win) win = get_parent(win) handle = xcomposite_name_window_pixmap(self._window) except: try: self._cleanup_listening(listening) except: pass raise if handle is None: log.warn( "failed to name a window pixmap (expect an X error soon)", type="pixmap") self._cleanup_listening(listening) else: self._contents_handle = handle # Don't save the listening set until after # NameWindowPixmap has succeeded, to maintain our # invariant: self._listening_to = listening trap.swallow(set_pixmap) return self._contents_handle
def _update_window_list(self, *args): # Ignore errors because not all the windows may still exist; if so, # then it's okay to leave the lists out of date for a moment, because # in a moment we'll get a signal telling us about the window that # doesn't exist anymore, will remove it from the list, and then call # _update_window_list again. trap.swallow(prop_set, self._root, "_NET_CLIENT_LIST", ["window"], self._windows_in_order) # This is a lie, but we don't maintain a stacking order, so... trap.swallow(prop_set, self._root, "_NET_CLIENT_LIST_STACKING", ["window"], self._windows_in_order)
def destroy(self): if self._window is None: log.warn("composite window %s already destroyed!", self) return if not self._already_composited: trap.swallow(xcomposite_unredirect_window, self._window) trap.swallow(xdamage_stop, self._window, self._damage_handle) self._damage_handle = None self._contents_handle = None self.invalidate_pixmap() remove_event_receiver(self._window, self) self._window = None
def do_get_property_contents_handle(self, name): if self._contents_handle is None: log("refreshing named pixmap", type="pixmap") assert self._listening_to is None def set_pixmap(): # The tricky part here is that the pixmap returned by # NameWindowPixmap gets invalidated every time the window's # viewable state changes. ("viewable" here is the X term that # means "mapped, and all ancestors are also mapped".) But # there is no X event that will tell you when a window's # viewability changes! Instead we have to find all ancestors, # and watch all of them for unmap and reparent events. But # what about races? I hear you cry. By doing things in the # exact order: # 1) select for StructureNotify # 2) QueryTree to get parent # 3) repeat 1 & 2 up to the root # 4) call NameWindowPixmap # we are safe. (I think.) listening = [] try: win = get_parent(self._window) while win is not None and win.get_parent() is not None: # We have to use a lowlevel function to manipulate the # event selection here, because SubstructureRedirectMask # does not roundtrip through the GDK event mask # functions. So if we used them, here, we would clobber # corral window selection masks, and those don't deserve # clobbering. They are our friends! X is driving me # slowly mad. addXSelectInput(win, const["StructureNotifyMask"]) add_event_receiver(win, self) listening.append(win) win = get_parent(win) handle = xcomposite_name_window_pixmap(self._window) except: try: self._cleanup_listening(listening) except: pass raise if handle is None: log.warn("failed to name a window pixmap (expect an X error soon)", type="pixmap") self._cleanup_listening(listening) else: self._contents_handle = handle # Don't save the listening set until after # NameWindowPixmap has succeeded, to maintain our # invariant: self._listening_to = listening trap.swallow(set_pixmap) return self._contents_handle
def do_child_configure_request_event(self, event): # The point of this method is to handle configure requests on # withdrawn windows. We simply allow them to move/resize any way they # want. This is harmless because the window isn't visible anyway (and # apps can create unmapped windows with whatever coordinates they want # anyway, no harm in letting them move existing ones around), and it # means that when the window actually gets mapped, we have more # accurate info on what the app is actually requesting. if event.window in self._windows: return log("Reconfigure on withdrawn window") trap.swallow(configureAndNotify, event.window, event.x, event.y, event.width, event.height, event.value_mask)
def reset_x_focus(self): focus = self.get_focus() log("widget with focus: %s", focus, type="focus") if isinstance(focus, wimpiggy.window.WindowView): # FIXME: ugly: focus.model.give_client_focus() trap.swallow(wimpiggy.prop.prop_set, gtk.gdk.get_default_root_window(), "_NET_ACTIVE_WINDOW", "window", focus.model.get_property("client-window")) else: self._take_focus() wimpiggy.prop.prop_set(gtk.gdk.get_default_root_window(), "_NET_ACTIVE_WINDOW", "u32", const["XNone"])
def test_swallow(self): assert trap.swallow(lambda: 0) is None assert trap.swallow(lambda: 1) is None assert trap.swallow(self.cause_badwindow) is None
def acknowledge_changes(self): if self._damage_handle is not None and self._window is not None: trap.swallow(xdamage_acknowledge, self._window, self._damage_handle)