def acquire(self, when): old_owner = self._owner() if when is self.IF_UNOWNED and old_owner != const["XNone"]: raise AlreadyOwned 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: ts_data = self.clipboard.wait_for_contents("TIMESTAMP").data ts_num = unpack("@i", ts_data[:4])[0] # Calculate the X atom for this selection: selection_xatom = get_xatom(self.atom) # Ask X what window we used: self._xwindow = myGetSelectionOwner(self.clipboard, self.atom) root = self.clipboard.get_display().get_default_screen().get_root_window() sendClientMessage(root, root, False, const["StructureNotifyMask"], "MANAGER", ts_num, selection_xatom, self._xwindow, 0, 0) if old_owner != const["XNone"] and when is self.FORCE: # Block in a recursive mainloop until the previous owner has # cleared out. def getwin(): window = get_pywindow(self.clipboard, old_owner) window.set_events(window.get_events() | gtk.gdk.STRUCTURE_MASK) return window try: window = trap.call_synced(getwin) 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")
def do_child(disp_name, xwindow1, xwindow2, xwindow3): print("child: in do_child") d2 = gtk.gdk.Display(disp_name) w1on2 = l.get_pywindow(d2, xwindow1) w2on2 = l.get_pywindow(d2, xwindow2) w3on2 = l.get_pywindow(d2, xwindow3) mywin = self.window(d2) print("child: mywin == %s" % l.get_xwindow(mywin)) w1on2.reparent(mywin, 0, 0) w2on2.reparent(mywin, 0, 0) w3on2.reparent(mywin, 0, 0) gtk.gdk.flush() # w1 gets saved: l.XAddToSaveSet(w1on2) # w2 does not # w3 is saved, but then unsaved (to test RemoveFromSaveSet): l.XAddToSaveSet(w3on2) l.XRemoveFromSaveSet(w3on2) gtk.gdk.flush() print("child: finished")
def test_get_xwindow_pywindow(self): d2 = self.clone_display() r1 = self.root() r2 = self.root(d2) assert r1 is not r2 assert l.get_xwindow(r1) == l.get_xwindow(r2) win = self.window() assert l.get_xwindow(r1) != l.get_xwindow(win) assert l.get_pywindow(r2, l.get_xwindow(r1)) is r2 assert_raises(l.XError, l.get_pywindow, self.display, 0) # This is necessary to stop some mysterious failure (perhaps d2 being # garbage collected before r2): del r2
def test_get_children_and_get_parent_and_reparent(self): d2 = self.clone_display() w1 = self.window(self.display) w2 = self.window(d2) gtk.gdk.flush() assert not l.get_children(w1) children = l.get_children(self.root()) xchildren = map(l.get_xwindow, children) xwins = map(l.get_xwindow, [w1, w2]) # GDK creates an invisible child of the root window on each # connection, so there are some windows we don't know about: for known in xwins: assert known in xchildren assert l.get_parent(w1) == w1.get_parent() w1.reparent(l.get_pywindow(w1, l.get_xwindow(w2)), 0, 0) gtk.gdk.flush() assert map(l.get_xwindow, l.get_children(w2)) == [l.get_xwindow(w1)] assert l.get_parent(w1).xid == w2.xid
def test_configureAndNotify(self): self.conf_ev = None l.substructureRedirect(self.root()) l.add_event_receiver(self.root(), self) # Need to hold onto a handle to this, so connection doesn't get # dropped: client = self.clone_display() w1_client = self.window(client) gtk.gdk.flush() w1_wm = l.get_pywindow(self.display, l.get_xwindow(w1_client)) l.configureAndNotify(w1_client, 11, 12, 13, 14) gtk.main() assert self.conf_ev is not None assert self.conf_ev.delivered_to is self.root() assert self.conf_ev.window is w1_wm assert self.conf_ev.x == 11 assert self.conf_ev.y == 12 assert self.conf_ev.width == 13 assert self.conf_ev.height == 14 assert self.conf_ev.border_width == 0 assert self.conf_ev.value_mask == (l.const["CWX"] | l.const["CWY"] | l.const["CWWidth"] | l.const["CWHeight"] | l.const["CWBorderWidth"]) partial_mask = l.const["CWWidth"] | l.const["CWStackMode"] l.configureAndNotify(w1_client, 11, 12, 13, 14, partial_mask) gtk.main() assert self.conf_ev is not None assert self.conf_ev.delivered_to is self.root() assert self.conf_ev.window is w1_wm assert self.conf_ev.width == 13 assert self.conf_ev.border_width == 0 assert self.conf_ev.value_mask == (l.const["CWWidth"] | l.const["CWBorderWidth"])
def test_substructure_redirect(self): self.map_ev = None self.conf_ev = None root = self.root() d2 = self.clone_display() w2 = self.window(d2) gtk.gdk.flush() w1 = l.get_pywindow(self.display, l.get_xwindow(w2)) l.add_event_receiver(root, self) l.substructureRedirect(root) gtk.gdk.flush() # gdk_window_show does both a map and a configure (to raise the # window) print("showing w2") w2.show() # Can't just call gtk.main() twice, the two events may be delivered # together and processed in a single mainloop iteration. while None in (self.map_ev, self.conf_ev): gtk.main() assert self.map_ev.delivered_to is root assert self.map_ev.window is w1 assert self.conf_ev.delivered_to is root assert self.conf_ev.window is w1 for field in ("x", "y", "width", "height", "border_width", "above", "detail", "value_mask"): print(field) assert hasattr(self.conf_ev, field) self.map_ev = None self.conf_ev = None w2.move_resize(1, 2, 3, 4) gtk.main() assert self.map_ev is None assert self.conf_ev is not None assert self.conf_ev.delivered_to is root assert self.conf_ev.window is w1 assert self.conf_ev.x == 1 assert self.conf_ev.y == 2 assert self.conf_ev.width == 3 assert self.conf_ev.height == 4 assert self.conf_ev.value_mask == (l.const["CWX"] | l.const["CWY"] | l.const["CWWidth"] | l.const["CWHeight"]) self.map_ev = None self.conf_ev = None w2.move(5, 6) gtk.main() assert self.map_ev is None assert self.conf_ev.x == 5 assert self.conf_ev.y == 6 assert self.conf_ev.value_mask == (l.const["CWX"] | l.const["CWY"]) self.map_ev = None self.conf_ev = None w2.raise_() gtk.main() assert self.map_ev is None assert self.conf_ev.detail == l.const["Above"] assert self.conf_ev.value_mask == l.const["CWStackMode"]
def test_sendConfigureNotify(self): # GDK discards ConfigureNotify's sent to child windows, so we can't # use self.window(): w1 = gtk.gdk.Window(self.root(), width=10, height=10, window_type=gtk.gdk.WINDOW_TOPLEVEL, wclass=gtk.gdk.INPUT_OUTPUT, event_mask=gtk.gdk.ALL_EVENTS_MASK) self.ev = None def myfilter(ev, data=None): print("ev %s" % (ev.type,)) if ev.type == gtk.gdk.CONFIGURE: self.ev = ev gtk.main_quit() gtk.main_do_event(ev) gtk.gdk.event_handler_set(myfilter) w1.show() gtk.gdk.flush() l.sendConfigureNotify(w1) gtk.main() assert self.ev is not None assert self.ev.type == gtk.gdk.CONFIGURE assert self.ev.window == w1 assert self.ev.send_event assert self.ev.x == 0 assert self.ev.y == 0 assert self.ev.width == 10 assert self.ev.height == 10 # We have to create w2 on a separate connection, because if we just # did w1.reparent(w2, ...), then GDK would magically convert w1 from a # TOPLEVEL window into a CHILD window. # Have to hold onto a reference to d2, so it doesn't get garbage # collected and kill the connection: d2 = self.clone_display() w2 = self.window(d2) gtk.gdk.flush() w2on1 = l.get_pywindow(w1, l.get_xwindow(w2)) # Doesn't generate an event, because event mask is zeroed out. w2.move(11, 12) # Reparenting doesn't trigger a ConfigureNotify. w1.reparent(w2on1, 13, 14) # To double-check that it's still a TOPLEVEL: print(w1.get_window_type()) w1.resize(15, 16) gtk.main() # w1 in root coordinates is now at (24, 26) self.ev = None l.sendConfigureNotify(w1) gtk.main() assert self.ev is not None assert self.ev.type == gtk.gdk.CONFIGURE assert self.ev.window == w1 assert self.ev.send_event assert self.ev.x == 24 assert self.ev.y == 26 assert self.ev.width == 15 assert self.ev.height == 16
# that Xutf8TextPropertyToTextList exists. "latin1": (unicode, "STRING", 8, lambda disp, u: u.encode("latin1"), lambda disp, d: d.decode("latin1"), "\0"), "atom": (str, "ATOM", 32, lambda disp, a: struct.pack("=I", get_xatom(a)), _get_atom, ""), "u32": ((int, long), "CARDINAL", 32, lambda disp, c: struct.pack("=I", c), lambda disp, d: struct.unpack("=I", d)[0], ""), "window": (gtk.gdk.Window, "WINDOW", 32, lambda disp, c: struct.pack("=I", get_xwindow(c)), lambda disp, d: get_pywindow(disp, struct.unpack("=I", d)[0]), ""), "wm-size-hints": (WMSizeHints, "WM_SIZE_HINTS", 32, unsupported, WMSizeHints, None), "wm-hints": (WMHints, "WM_HINTS", 32, unsupported, WMHints, None), "strut": (NetWMStrut, "CARDINAL", 32, unsupported, NetWMStrut, None), "strut-partial": (NetWMStrut, "CARDINAL", 32, unsupported, NetWMStrut, None), "icon": (cairo.ImageSurface, "CARDINAL", 32, unsupported, NetWMIcons, None),
def getwin(): window = get_pywindow(self.clipboard, old_owner) window.set_events(window.get_events() | gtk.gdk.STRUCTURE_MASK) return window
# Python type, X type Atom, format, serializer, deserializer, list # terminator "utf8": (unicode, "UTF8_STRING", 8, lambda disp, u: u.encode("UTF-8"), lambda disp, d: d.decode("UTF-8"), "\0"), # In theory, there should be something clever about COMPOUND_TEXT here. I # am not sufficiently clever to deal with COMPOUNT_TEXT. Even knowing # that Xutf8TextPropertyToTextList exists. "latin1": (unicode, "STRING", 8, lambda disp, u: u.encode("latin1"), lambda disp, d: d.decode("latin1"), "\0"), "atom": (str, "ATOM", 32, lambda disp, a: struct.pack("@I", get_xatom(a)), _get_atom, ""), "u32": ((int, long), "CARDINAL", 32, lambda disp, c: struct.pack("@I", c), lambda disp, d: struct.unpack("@I", d)[0], ""), "window": (gtk.gdk.Window, "WINDOW", 32, lambda disp, c: struct.pack("@I", get_xwindow(c)), lambda disp, d: get_pywindow(disp, struct.unpack("@I", d)[0]), ""), "wm-size-hints": (WMSizeHints, "WM_SIZE_HINTS", 32, unsupported, WMSizeHints, None), "wm-hints": (WMHints, "WM_HINTS", 32, unsupported, WMHints, None), "strut": (NetWMStrut, "CARDINAL", 32, unsupported, NetWMStrut, None), "strut-partial": (NetWMStrut, "CARDINAL", 32, unsupported, NetWMStrut, None), "icon": (cairo.ImageSurface, "CARDINAL", 32, unsupported, NetWMIcons, None), "xsettings-settings": (str, "_XSETTINGS_SETTINGS", 8, lambda disp, d: d, lambda disp, d: d, None), # For uploading ad-hoc instances of the above complex structures to the # server, so we can test reading them out again: "debug-CARDINAL": (str, "CARDINAL", 32, lambda disp, c: c, lambda disp, d: d, None), # For fetching the extra information on a MULTIPLE clipboard conversion
def window(self): if self._xwindow is None: return None return get_pywindow(self.clipboard, self._xwindow)
def get_targets(): win = get_pywindow(event.requestor) atoms = prop_get(win, event.property, ["multiple-conversion"]) log("MULTIPLE clipboard atoms: %r", atoms) targets += atoms[::2]