Updated 2008-07-19 08:24:20 by dkf â–²

On comp.lang.tcl, someone asked:

''I'm using the clipboard in one application and have a problem with it. I copy a string with
    clipboard clear
    clipboard append [CNS::string_to_ior $stringname]

to the clipboard. Using xclipboard I see the string there. But, I want to copy the clipboard with <Button-2> back to an entry widget or any other widget / application. This does not work, until I highlight the string in the xclipboard.''

In most X applications, <Button-2> doesn't actually use the clipboard. Instead it uses a different ICCCM method called primary transfer.

With clipboard transfer, the source application can cut or copy data to the clipboard and then forget about it (this is a lie, see below), but primary transfer works a little bit differently. With primary transfer, the source application initially just claims ownership of the selection; it doesn't actually transfer any data until another client requests the value. That means the source application must be prepared to provide the value of the selection at any time until some other window claims ownership.

All the Tk widgets with "selectable" contents (Text, Entry, Listbox, etc.) have support for primary transfer built in. To use other application-generated text as the source of a primary transfer operation, there are two steps. First, you need to register a selection handler for the PRIMARY selection:
    selection handle -selection PRIMARY "."  my::primaryTransfer

The second step then is to claim ownership of the selection:
    selection own -selection PRIMARY -command my::lostSelection "."

Tk will call the procedure my::primaryTransfer registered in the first step whenever a client requests the value of the PRIMARY selection, and it will call my::lostSelection when another window claims ownership of the PRIMARY selection.

So for example:
	# selectText "text" --
	#       Sets the value of the PRIMARY selection to "$text".
	#       (Note: this doesn't really "set the value" of the selection.
	#       More precisely, it arranges to provide the value given
	#       when another client requests it.)
	proc my::selectText {text} {
	    variable currentSelection
	    set currentSelection $text
	    selection handle -selection PRIMARY "."  my::primaryTransfer
	    selection own -selection PRIMARY -command my::lostSelection "."

	# The following will be called whenever a client requests the value
	# of the PRIMARY selection.  See selection(n) for a description
	# of 'offset' and 'maxChars'; we probably ought to do something
	# sensible with these parameters, but it's mostly safe to
	# just ignore them.
	proc my::primaryTransfer {offset maxChars} {
	    variable currentSelection
	    return $currentSelection

	# This is called when we lose ownership of the selection:
	proc my::lostSelection {} {
	    variable currentSelection
	    set currentSelection ""
	    # Do other stuff like unhighlighting previously highlighted
	    # items here ...

Under X, it's not strictly true that an application can simply copy data to the clipboard and forget about it. Under the hood, clipboard transfer works exactly the same way as primary transfer as far as the source and target applications are concerned except that the CLIPBOARD selection is used in place of PRIMARY; in fact the implementation of the Tk clipboard command works almost exactly the same way as my::selectText above.

The xclipboard command emulates the traditional Macintosh style clipboard by claiming ownership of the CLIPBOARD selection and answering any requests for its value. When it loses the selection, it immediately asks the new owner for the value of the CLIPBOARD selection, makes a local copy, and then reasserts ownership of the CLIPBOARD. This way the clipboard contents can persist after the original application has exited.

DKF - I've never looked into this in detail, but how does it cope with non-text selection types transferred over the clipboard? I've used this technique to great effect in my own apps (allowing cut-n-paste of sophisticated graphical objects without letting a whole load of rubbish be transferred to apps that don't understand it...)

jenglish - In principle, it still works the same way as with primary transfer:

  • source application registers handlers for multiple targets ...
  • ... one of which is TARGETS, which returns a list of available target atoms (I think Tk handles this one automatically)
  • the clipboard application first asks for TARGETS, then requests the value of each target listed therein

The clipboard app must take some care, as certain targets can have side effects (e.g., DELETE).

In practice, the xclipboard client from the X11R6 distribution isn't that smart; it only asks for the TEXT target (and maybe a few others). For that reason, I usually avoid putting anything but TEXT on the CLIPBOARD, reserving other selection atoms for other data types.

Back to the original question:

But, I want to copy the clipboard with <Button-2> back to an entry widget or any other widget / application. This does not work, until I highlight the string in the xclipboard.

What's happening here is, when you highlight the text in the xclipboard window, then the xclipboard client claims ownership of the PRIMARY selection (in addition to the CLIPBOARD selection), and will act as the source for primary transfer when you press <Button-2>.

To make this work, you could set up primary transfer in the source application as outlined above, or you could reconfigure the destination applications so that <Button-2> attempts a PRIMARY transfer first and a CLIPBOARD transfer next if the first transfer fails. For 'xterm', adding the following to your .Xresources should work:
	XTerm*VT100.Translations: #override \
	    ... \
	    <Btn2Up>: insert-selection(PRIMARY,CLIPBOARD) \
	    ... \

Figuring out how to do this for all the other clients may prove tedious though...

The X selection mechanism is really kind of neat. It's very simple, yet it can support all sorts of inter-client communications policies in addition to primary transfer and clipboard transfer. There's also "quick transfer", in which the user picks the destination first and then highlights the source, which is immediately transfered to the target. Motif used to support quick transfer, but it seems to have been dropped in later releases since nobody knew about it and it never got used :-) Many Drag and Drop schemes are also built on top of X selections.

--Joe English

DKF - Note that it is impossible in Tk as it currently stands (8.4a2) to service selection requests while processing a [send] command. This could be construed as a bug...

Is this accurate? "Button 2 usually pastes in the text from CUT_BUFFER0, not using the selection protocol at all."

dchurch - No; while the ICCCM does specify CUT_BUFFER0 through CUT_BUFFER7, I've never actually seen any application use it. From what I've looked at, most applications simply call for STRING from the PRIMARY selection. For instance, Tk's default <Button-2> handler for a text widget is:
   catch {tk::TextInsert %W [::tk::GetSelection %W PRIMARY]}

For the CUT_BUFFERs to be useful, every application would have to cut data to them every time the selection were changed; this would waste space, especially with large selections, since the data must be copied to the root window. Also, it violates the nature of the cut buffer; whenever data is copied to it, buffers 0 through 6 all cycle forward by one so that a track of the 8 most recent cuts is kept. If every selection changed the cut buffer, then it would only keep track of the last eight times the user highlighted text, which is much less useful.

jenglish Many older X applications use cut buffers as a fallback if the PRIMARY selection isn't available (xterm and the Athena widget set work this way). But most newer toolkits don't use them. In particular, Tk doesn't.

Someone should write something here about INCR transfers. If they can stand to do that much deep voodoo...

DKF: Here are a few bits and pieces that I remember; accuracy not guaranteed…

X11 selection transfers (which both PRIMARY and CLIPBOARD are instances of) are done through synthesized X11 events and properties changes. Most of the details you don't need to know, but a key feature of them is that the messages used to transfer the selections have a maximum size that's actually quite low (a few kilobytes IIRC). To work around this, X11 allows transfers to be done INCRementally. The protocol is horrific, especially when dealing with UTF-8-encoded strings! But I believe Tk implements it correctly for you. (IIRC again, there were bugs in this area before 8.4, and anyway the whole notion of encoding in X11 was fairly well messed up back then anyway.)

If you want to know more, see your psychiatrist. Or tkUnixSelect.c from the Tk sources.