One of the many tasks when writing an editor for Linux – which I am with my “edlib” project – is to support sending and received content from other applications for copy/paste operations. The X11 protocol provides support this is with “Selections” and a “clipboard” which are documented in the ICCCM – the Inter-Client Communication Conventions Manual. Unfortunately the big-picture of how this should work is poor described, and consequently different applications can behave quite differently and many, in my opinion, get it wrong.
While the selection mechanism can seem confusing and needlessly complex, it actually makes lot of sense and is easy to work with, providing you look at the right way. The important observation is that the “PRIMARY” selection and the “CLIPBOARD” should NOT provide different content. They are really just different interfaces to essentially the same content. Let me explain ….
The X11 protocol has low-level support for sending arbitrary data between applications. Any data to be transferred has an address (called a “Selection Atom” in the ICCCM) and a number of views (called “TARGETS”). Given an address and a view, an application can ask for and receive content, which is a stream of 1, 2, or 4 byte values and a “type” which is defined by convention.
Any client can request ownership for a given address, and will be granted ownership until some other client requests ownership. The client will then be forwarded any requests for content. There are some well-known views on the content that can always be requested including “TARGETS” which provides a list of views that are supported, and “TIMESTAMP” which provides the time content was updated. Other views can be agreed by convention, of which “STRING” and “STRING_UTF8” are most interesting for now.
The ICCCM defines three address, PRIMARY, SECONDARY, and CLIPBOARD. We will ignore “SECONDARY” because it doesn’t seem useful and very few applications do anything useful with it. We’ll just pretend it doesn’t exist.
“PRIMARY” is a “Selection”. It is used “for all commands that take only a single argument”. That implies that it is something that be acted upon in various ways. If you imaging using a mouse or the keyboard to select a range of text in a document, you might then want to delete that text, or copy it for later use, or even both, which we call “cut”. You might want to check the spelling or do a word-count or make all alphabetic characters upper case, or treat the text as a mathematical expression and evaluate it. There are boundless thing you might want to do with a selection, and while copying it is a common option, it is far from the only one.
“CLIPBOARD” is not a selection (despite being one of the “Selection Atoms” that I am calling “Addresses”). The ICCCM says that the CLIPBOARD “is used to hold data that is being transferred between clients”. So this is not the argument to a command, it is a datum to be communicated. Obviously it might be the result of performing some operation on a selection, though not necessarily. The ICCCM goes on to explain in some detail how the CLIPBOARD is used. How an application which creates a clipping should claim ownership of “CLIPBOARD” and how an application which wants to “paste” the current clipping can communicate with the owner to get it. This is all quite straight forward and applications tend to have no trouble implementing it correctly. It is the handling of “PRIMARY” – the selection – which is troublesome.
The ICCCM doesn’t provide detail on how “PRIMARY” should by used, only what it is (as mentioned above – a command argument). So some applications treat it like a parallel clipboard. GNU-emacs in particular takes exactly this approach. If you select text with the mouse, it is made available via PRIMARY. If you copy text via the keyboard, it is made available via CLIPBOARD. If you paste with the mouse, you get PRIMARY. If you paste (yank in emacs-speak) with the keyboard, you get CLIPBOARD. Other applications have other handlings in various ways. This variety is often confusing, and sometimes it is hard to really achieve what you want (or at least, what “I” want!).
Now, at last, I can tell you what the better way is. How do you handle PRIMARY? PRIMARY, remember, is just a selection. I hasn’t been (or may not have been) copied YET. Until some application requests a copy, PRIMARY is just a selection – anything could happen to it. As soon as any application requests the content of PRIMARY, that it the moment when the content of the selection becomes a clipping. It becomes THE clipping. From that point until some other selection or clipping is created, both PRIMARY and CLIPBOARD should belong to the same application, and they should appear to have the same content. Because they are now the same thing. If the content of PRIMARY is never requested, then it never becomes a clipping. Maybe nothing ever happens to it, or maybe some operation entirely local to the owning application happens to it. There may be a sequence of many PRIMARY selections covering different content in different applications. And the PRIMARY selection might even be discarded so that there is no selection for a time. All the while the content of the CLIPBOARD could remain unchanged as nothing new has been clipped.
How is this implemented? I have two descriptions. An “ideal” which is easier to understand but wouldn’t work well with current applications, and a “practical” which is how new applications should work, and how edlib works (assuming no bugs). In each case, CLIPBOARD is handled how ICCCM says it should be, so that will not be dwelt on.
Ideal Implementation.
- When an application creates a selection, it claims ownership of PRIMARY, with the current time. When that selection ceases to exist for any reason, the application renounces ownership of PRIMARY.
- When an application wants to access the current clipping, and does not own PRIMARY, it makes a request to the owner of PRIMARY to copy the content to the CLIPBOARD. This would be easy to fit in the the X11 protocol, but no applications support it, so it is not practical. After making this request, which might fail if no-one owns PRIMARY, the application then collects CLIPBOARD in the normal way. It would presumable have been claimed by whichever application owned PRIMARY.
- When an application wants to access the current clipping and it DOES own PRIMARY, then it has finer control. Obviously it can do whatever it likes, but a sensible thing to consider is whether the content is being requested to paste it into the selection. If it is, then it doesn’t make sense to copy PRIMARY to the CLIPBOARD first. If it will be pasted elsewhere, or used in some other way, it would make sense to copy the content of the selection to the CLIPBOARD first, then use it.
- When an application that owns PRIMARY is asked to copy it to the CLIPBOARD, it requests ownership of CLIPBOARD with the same timestamp that PRIMARY was acquired with. If the CLIPBOARD was already newer than PRIMARY, this will fail and the content of CLIPBOARD will be used. If PRIMARY is newer than CLIPBOARD it will succeed and the content of PRIMARY will become available from the CLIPBOARD.
- When an application takes ownership of the CLIPBOARD for any reason, whether from the PRIMARY selection or not, it should take and then discard ownership of PRIMARY so there is no PRIMARY selection. This is not strictly needed given that an old PRIMARY will not over-write a newer CLIPBOARD, but it allows better visual feedback so that a selection which still exists but is not PRIMARY can be a different colour and so it can be seen that it will not be the source of a copy request.
As noted, this ideal approach won’t work as current applications don’t ask PRIMARY to copy content to the CLIPBOARD, and instead request content directly from PRIMARY. It is fairly easy to find a practical approach which allows for this.
The Practical Implementation
- As with the Ideal approach, an application still claims ownership of PRIMARY when a selection is created, and renounces ownership when that selection disappears.
- When an application wants to access the clipping, it requests the TIMESTAMP for PRIMARY and then for CLIPBOARD, though as describe above it may choose to ignore PRIMARY if it owns it. Whichever (non-ignored) selection has the newer timestamp is chosen and the content is collected.
- When PRIMARY is requested from an application, even when only the TIMESTAMP is requested, it takes a copy of the content and requests ownership of CLIPBOARD, so the content will subsequently be available from either.
- When an application takes ownership of CLIPBOARD, it also takes ownership of PRIMARY and ensure they both report the same content.
An application written to implement this specification will always be able to access the most recent content, whether it was placed in the PRIMARY selection or in the CLIPBOARD. It will be able to provide its content to any requester, whether they ask for PRIMARY or CLIPBOARD content. It also allows the CLIPBOARD to maintain content for a period of time while selections are made but not copied. I find that this behaviour is easy to understand and easy to work with.
If you happen to be writing code to make use for X11 PRIMARY and CLIPBOARD selections, please consider following this approach. It is will make everyone happy.