コード例 #1
0
ファイル: selection.py プロジェクト: DiGuoZhiMeng/Xpra
class ManagerSelection(gobject.GObject):
    __gsignals__ = {
        "selection-lost": no_arg_signal,

        "xpra-destroy-event": one_arg_signal,
        }

    def __str__(self):
        return "ManagerSelection(%s)" % self.atom

    def __init__(self, selection):
        gobject.GObject.__init__(self)
        self.atom = selection
        self.clipboard = GetClipboard(selection)
        self._xwindow = None

    def _owner(self):
        return X11WindowBindings().XGetSelectionOwner(self.atom)

    def owned(self):
        "Returns True if someone owns the given selection."
        return self._owner() != XNone

    # If the selection is already owned, then raise AlreadyOwned rather
    # than stealing it.
    IF_UNOWNED = "if_unowned"
    # If the selection is already owned, then steal it, and then block until
    # the previous owner has signaled that they are done cleaning up.
    FORCE = "force"
    # If the selection is already owned, then steal it and return immediately.
    # Created for the use of tests.
    FORCE_AND_RETURN = "force_and_return"
    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)

    def _owner_change(self, clipboard, event):
        log("owner_change(%s, %s)", clipboard, event)
        if str(event.selection)!=self.atom:
            #log("_owner_change(..) not our selection: %s vs %s", event.selection, self.atom)
            return
        if event.owner:
            owner = event.owner.get_xid()
            if owner==self._xwindow:
                log("_owner_change(..) we still own %s", event.selection)
                return
        if self._xwindow:
            self._xwindow = None
            self.emit("selection-lost")

    def do_xpra_destroy_event(self, event):
        remove_event_receiver(event.window, self)
        gtk_main_quit()

    def _get(self, _clipboard, outdata, _which, _userdata):
        # We are compliant with ICCCM version 2.0 (see section 4.3)
        outdata.set("INTEGER", 32, pack("@ii", 2, 0))

    def _clear(self, _clipboard, _userdata):
        self._xwindow = None
        self.emit("selection-lost")

    def window(self):
        if self._xwindow is None:
            return None
        return get_pywindow(self.clipboard, self._xwindow)
コード例 #2
0
class ClipboardInstance(object):
    def __init__(self, selection, _log):
        self.clipboard = GetClipboard(selection)
        self.selection = selection
        self._log = _log
        self.owned_label = label()
        self.get_targets = gtk.combo_box_new_text()
        self.get_targets.set_sensitive(False)
        self.get_targets.connect("changed", self.get_target_changed)
        self.set_targets = gtk.combo_box_new_text()
        self.set_targets.append_text("STRING")
        self.set_targets.append_text("UTF8_STRING")
        self.set_targets.set_active(0)
        self.set_targets.connect("changed", self.set_target_changed)
        self.value_label = label()
        self.value_entry = gtk.Entry()
        self.value_entry.set_max_length(100)
        self.value_entry.set_width_chars(32)
        self.clear_label_btn = gtk.Button("X")
        self.clear_label_btn.connect("clicked", self.clear_label)
        self.clear_entry_btn = gtk.Button("X")
        self.clear_entry_btn.connect("clicked", self.clear_entry)
        self.get_get_targets_btn = gtk.Button("Get Targets")
        self.get_get_targets_btn.connect("clicked", self.do_get_targets)
        self.get_target_btn = gtk.Button("Get Target")
        self.get_target_btn.connect("clicked", self.do_get_target)
        self.get_target_btn.set_sensitive(False)
        self.set_target_btn = gtk.Button("Set Target")
        self.set_target_btn.connect("clicked", self.do_set_target)
        self.get_string_btn = gtk.Button("Get String")
        self.get_string_btn.connect("clicked", self.do_get_string)
        self.set_string_btn = gtk.Button("Set String")
        self.set_string_btn.connect("clicked", self.do_set_string)
        self.clipboard.connect("owner-change", self.owner_changed)
        self.log("ready")

    def __repr__(self):
        return "ClipboardInstance(%s)" % self.selection

    def log(self, msg):
        self._log(self.selection, msg)

    def clear_entry(self, *_args):
        self.value_entry.set_text("")

    def clear_label(self, *_args):
        self.value_label.set_text("")

    def get_targets_callback(self, _c, targets, *_args):
        self.log("got targets: %s" % str(targets))
        if hasattr(targets, "name"):
            self.log("target is atom: %s" % targets.name())
            targets = []
        filtered = [
            x for x in (targets or []) if x not in ("MULTIPLE", "TARGETS")
        ]
        ct = self.get_targets.get_active_text()
        if not ct:
            #choose a good default target:
            for x in ("STRING", "UTF8_STRING"):
                if x in filtered:
                    ct = x
                    break
        self.get_targets.get_model().clear()
        self.get_targets.set_sensitive(True)
        i = 0
        for t in filtered:
            self.get_targets.append_text(t)
            if t == ct:
                self.get_targets.set_active(i)
            i += 1
        self.get_targets.show_all()

    def do_get_targets(self, *_args):
        self.clipboard.request_targets(self.get_targets_callback, None)

    def get_target_changed(self, _cb):
        target = self.get_targets.get_active_text()
        self.get_target_btn.set_sensitive(bool(target))

    def set_target_changed(self, cb):
        pass

    def ellipsis(self, val):
        if len(val) > 24:
            return val[:24] + ".."
        return val

    def selection_value_callback(self, _cb, selection_data, *_args):
        #print("selection_value_callback(%s, %s, %s)" % (cb, selection_data, args))
        try:
            if selection_data.data is None:
                s = ""
            else:
                s = "type=%s, format=%s, data=%s" % (
                    selection_data.type, selection_data.format,
                    self.ellipsis(re.escape(selection_data.data)))
        except TypeError:
            try:
                s = self.ellipsis("\\".join(
                    [str(x) for x in bytearray(selection_data.data)]))
            except Exception:
                s = "!ERROR! binary data?"
        self.log("Got selection data: '%s'" % s)
        self.value_label.set_text(s)

    def do_get_target(self, *_args):
        self.clear_label()
        target = self.get_targets.get_active_text()
        self.log("Requesting %s" % target)
        self.clipboard.request_contents(target, self.selection_value_callback,
                                        None)

    def selection_clear_cb(self, _clipboard, _data):
        #print("selection_clear_cb(%s, %s)", clipboard, data)
        self.log("Selection has been cleared")

    def selection_get_callback(self, _clipboard, selectiondata, _info, *_args):
        #log("selection_get_callback(%s, %s, %s, %s) targets=%s",
        #    clipboard, selectiondata, info, args, selectiondata.get_targets())
        value = self.value_entry.get_text()
        self.log("Answering selection request with value: '%s'" %
                 self.ellipsis(value))
        selectiondata.set("STRING", 8, value)

    def do_set_target(self, *_args):
        target = self.set_targets.get_active_text()
        self.log("Target set to %s" % target)
        self.clipboard.set_with_data([(target, 0, 0)],
                                     self.selection_get_callback,
                                     self.selection_clear_cb)

    def string_value_callback(self, _cb, value, *_args):
        if value is None:
            value = ""
        assert isinstance(value, str), "value is not a string!"
        self.log("Got string selection data: '%s'" % value)
        self.value_label.set_text(self.ellipsis(value))

    def do_get_string(self, *_args):
        #self.log("do_get_string%s on %s.%s" % (args, self, self.clipboard))
        self.clipboard.request_text(self.string_value_callback, None)

    def do_set_string(self, *_args):
        self.clipboard.set_text(self.ellipsis(self.value_entry.get_text()))

    def owner_changed(self, _cb, event):
        r = {}
        if not is_gtk3():
            r = {
                gtk.gdk.OWNER_CHANGE_CLOSE: "close",
                gtk.gdk.OWNER_CHANGE_DESTROY: "destroy",
                gtk.gdk.OWNER_CHANGE_NEW_OWNER: "new owner",
            }
        owner = self.clipboard.get_owner()
        #print("xid=%s, owner=%s" % (self.value_entry.get_window().xid, event.owner))
        weownit = (owner is not None)
        if weownit:
            owner_info = "(us)"
        else:
            owner_info = hex(event.owner)
        self.log("Owner changed, reason: %s, new owner=%s" %
                 (r.get(event.reason, event.reason), owner_info))
コード例 #3
0
ファイル: gtk_view_clipboard.py プロジェクト: svn2github/Xpra
class ClipboardInstance(object):
    def __init__(self, selection, _log):
        self.clipboard = GetClipboard(selection)
        self.selection = selection
        self._log = _log
        self.owned_label = label()
        self.get_targets = gtk.combo_box_new_text()
        self.get_targets.set_sensitive(False)
        self.get_targets.connect("changed", self.get_target_changed)
        self.set_targets = gtk.combo_box_new_text()
        self.set_targets.append_text("STRING")
        self.set_targets.append_text("UTF8_STRING")
        self.set_targets.set_active(0)
        self.set_targets.connect("changed", self.set_target_changed)
        self.value_label = label()
        self.value_entry = gtk.Entry()
        self.value_entry.set_max_length(100)
        self.value_entry.set_width_chars(32)
        self.clear_label_btn = gtk.Button("X")
        self.clear_label_btn.connect("clicked", self.clear_label)
        self.clear_entry_btn = gtk.Button("X")
        self.clear_entry_btn.connect("clicked", self.clear_entry)
        self.get_get_targets_btn = gtk.Button("Get Targets")
        self.get_get_targets_btn.connect("clicked", self.do_get_targets)
        self.get_target_btn = gtk.Button("Get Target")
        self.get_target_btn.connect("clicked", self.do_get_target)
        self.get_target_btn.set_sensitive(False)
        self.set_target_btn = gtk.Button("Set Target")
        self.set_target_btn.connect("clicked", self.do_set_target)
        self.get_string_btn = gtk.Button("Get String")
        self.get_string_btn.connect("clicked", self.do_get_string)
        self.set_string_btn = gtk.Button("Set String")
        self.set_string_btn.connect("clicked", self.do_set_string)
        self.clipboard.connect("owner-change", self.owner_changed)
        self.log("ready")

    def __repr__(self):
        return "ClipboardInstance(%s)" % self.selection

    def log(self, msg):
        self._log(self.selection, msg)

    def clear_entry(self, *args):
        self.value_entry.set_text("")

    def clear_label(self, *args):
        self.value_label.set_text("")

    def get_targets_callback(self, c, targets, *args):
        self.log("got targets: %s" % str(targets))
        if hasattr(targets, "name"):
            self.log("target is atom: %s" % targets.name())
            targets = []
        filtered = [x for x in (targets or []) if x not in ("MULTIPLE", "TARGETS")]
        ct = self.get_targets.get_active_text()
        if not ct:
            #choose a good default target:
            for x in ("STRING", "UTF8_STRING"):
                if x in filtered:
                    ct = x
                    break
        self.get_targets.get_model().clear()
        self.get_targets.set_sensitive(True)
        i = 0
        for t in filtered:
            self.get_targets.append_text(t)
            if t==ct:
                self.get_targets.set_active(i)
            i += 1
        self.get_targets.show_all()

    def do_get_targets(self, *args):
        self.clipboard.request_targets(self.get_targets_callback, None)

    def get_target_changed(self, cb):
        target = self.get_targets.get_active_text()
        self.get_target_btn.set_sensitive(bool(target))

    def set_target_changed(self, cb):
        pass

    def ellipsis(self, val):
        if len(val)>24:
            return val[:24]+".."
        return val

    def selection_value_callback(self, cb, selection_data, *args):
        #print("selection_value_callback(%s, %s, %s)" % (cb, selection_data, args))
        try:
            if selection_data.data is None:
                s = ""
            else:
                s = "type=%s, format=%s, data=%s" % (
                        selection_data.type,
                        selection_data.format,
                        self.ellipsis(re.escape(selection_data.data)))
        except TypeError:
            try:
                s = self.ellipsis("\\".join([str(x) for x in bytearray(selection_data.data)]))
            except:
                s = "!ERROR! binary data?"
        self.log("Got selection data: '%s'" % s)
        self.value_label.set_text(s)

    def do_get_target(self, *args):
        self.clear_label()
        target = self.get_targets.get_active_text()
        self.log("Requesting %s" % target)
        self.clipboard.request_contents(target, self.selection_value_callback, None)

    def selection_clear_cb(self, clipboard, data):
        #print("selection_clear_cb(%s, %s)", clipboard, data)
        self.log("Selection has been cleared")

    def selection_get_callback(self, clipboard, selectiondata, info, *args):
        #print("selection_get_callback(%s, %s, %s, %s) targets=%s" % (clipboard, selectiondata, info, args, selectiondata.get_targets()))
        value = self.value_entry.get_text()
        self.log("Answering selection request with value: '%s'" % self.ellipsis(value))
        selectiondata.set("STRING", 8, value)

    def do_set_target(self, *args):
        target = self.set_targets.get_active_text()
        self.log("Target set to %s" % target)
        self.clipboard.set_with_data([(target, 0, 0)], self.selection_get_callback, self.selection_clear_cb)

    def string_value_callback(self, cb, value, *args):
        if value is None:
            value = ""
        assert type(value)==str, "value is not a string!"
        self.log("Got string selection data: '%s'" % value)
        self.value_label.set_text(self.ellipsis(value))

    def do_get_string(self, *args):
        #self.log("do_get_string%s on %s.%s" % (args, self, self.clipboard))
        self.clipboard.request_text(self.string_value_callback, None)

    def do_set_string(self, *args):
        self.clipboard.set_text(self.ellipsis(self.value_entry.get_text()))

    def owner_changed(self, cb, event):
        r = {}
        if not is_gtk3():
            r = {gtk.gdk.OWNER_CHANGE_CLOSE : "close",
                 gtk.gdk.OWNER_CHANGE_DESTROY : "destroy",
                 gtk.gdk.OWNER_CHANGE_NEW_OWNER : "new owner"}
        owner = self.clipboard.get_owner()
        #print("xid=%s, owner=%s" % (self.value_entry.get_window().xid, event.owner))
        weownit = (owner is not None)
        if weownit:
            owner_info="(us)"
        else:
            owner_info = hex(event.owner)
        self.log("Owner changed, reason: %s, new owner=%s" % (
                        r.get(event.reason, event.reason), owner_info))