def unpack(clipboard, selection_data, _user_data=None): log("unpack %s: %s", clipboard, type(selection_data)) global sanitize_gtkselectiondata if selection_data and sanitize_gtkselectiondata(selection_data): self._clipboard.set_text("", len=-1) selection_data = None if selection_data is None: cb(None, None, None) return log("unpack: %s", selection_data) data = selectiondata_get_data(selection_data) dtype = selectiondata_get_data_type(selection_data) dformat = selectiondata_get_format(selection_data) log("unpack(..) type=%s, format=%s, data=%s:%s", dtype, dformat, type(data), len(data or "")) isstring = dtype in (b"UTF8_STRING", b"STRING") and dformat==8 if isstring: if self._strip_nullbyte: #we may have to strip the nullbyte: if data and data[-1]=='\0': log("stripping end of string null byte") data = data[:-1] if data and data==self._loop_uuid: log("not sending loop uuid value '%s', returning an empty string instead", data) data= "" cb(str(dtype), dformat, data)
def unpack(clipboard, selection_data, _user_data=None): log("unpack %s: %s", clipboard, type(selection_data)) global sanitize_gtkselectiondata if selection_data and sanitize_gtkselectiondata(selection_data): self._clipboard.set_text("") if selection_data is None: cb(None, None, None) return log("unpack: %s", selection_data) data = selectiondata_get_data(selection_data) dtype = selectiondata_get_data_type(selection_data) dformat = selectiondata_get_format(selection_data) log("unpack(..) type=%s, format=%s, data=%s:%s", dtype, dformat, type(data), len(data or "")) if self._strip_nullbyte and dtype in (b"UTF8_STRING", b"STRING") and dformat == 8: #we may have to strip the nullbyte: if data and data[-1] == '\0': log("stripping end of string null byte") data = data[:-1] cb(str(dtype), dformat, data)
def acquire(self, when): old_owner = self._owner() if when is self.IF_UNOWNED and old_owner != XNone: raise AlreadyOwned if is_gtk3(): set_clipboard_data(self.clipboard, "VERSION") else: self.clipboard.set_with_data([("VERSION", 0, 0)], self._get, self._clear, None) # Having acquired the selection, we have to announce our existence # (ICCCM 2.8, still). The details here probably don't matter too # much; I've never heard of an app that cares about these messages, # and metacity actually gets the format wrong in several ways (no # MANAGER or owner_window atoms). But might as well get it as right # as possible. # To announce our existence, we need: # -- the timestamp we arrived at # -- the manager selection atom # -- the window that registered the selection # Of course, because Gtk is doing so much magic for us, we have to do # some weird tricks to get at these. # Ask ourselves when we acquired the selection: contents = wait_for_contents(self.clipboard, "TIMESTAMP") ts_data = selectiondata_get_data(contents) #data is a timestamp, X11 datatype is Time which is CARD32, #(which is 64 bits on 64-bit systems!) Lsize = calcsize("@L") if len(ts_data)==Lsize: ts_num = unpack("@L", ts_data[:Lsize])[0] else: ts_num = 0 #CurrentTime log.warn("invalid data for 'TIMESTAMP': %s", ([hex(ord(x)) for x in ts_data])) # Calculate the X atom for this selection: selection_xatom = get_xatom(self.atom) # Ask X what window we used: self._xwindow = X11WindowBindings().XGetSelectionOwner(self.atom) root = self.clipboard.get_display().get_default_screen().get_root_window() xid = get_xwindow(root) X11WindowBindings().sendClientMessage(xid, xid, False, StructureNotifyMask, "MANAGER", ts_num, selection_xatom, self._xwindow) if old_owner != XNone and when is self.FORCE: # Block in a recursive mainloop until the previous owner has # cleared out. try: with xsync: window = get_pywindow(self.clipboard, old_owner) window.set_events(window.get_events() | STRUCTURE_MASK) log("got window") except XError: log("Previous owner is already gone, not blocking") else: log("Waiting for previous owner to exit...") add_event_receiver(window, self) gtk_main() log("...they did.") window = get_pywindow(self.clipboard, self._xwindow) window.set_title("Xpra-ManagerSelection") if is_gtk3(): #we can't use set_with_data(..), #so we have to listen for owner-change: self.clipboard.connect("owner-change", self._owner_change)