X Selections, Cut Buffers, and Kill Rings.
© 1997, 2002 by Jamie Zawinski <jwz@jwz.org>
This document began as a description of how Emacs and XEmacs deal with copying and pasting text under X11. However, I've noticed that a lot of people are being referred here to answer more general questions of how copying and pasting work under X, or, more specifically, how they should implement copying and pasting in their own X applications. So allow me to summarize...
X11 has these things called ``selections.'' They have names. There are really only two you need to know about: the Primary selection and the Clipboard selection. An application is said to ``own'' a selection when it raises its hand and says, ``I have the Primary selection now.'' Only one application can own a selection at a time, so when one app asserts selection ownership, the previous owner loses it.
Asserting ownership of a selection doesn't actually transfer data. When you want to copy text from application A to application B, it goes like this:
- Copy text in program A: program A asserts selection ownership.
- Paste text in program B: program B notes that program A owns the selection.
- program B asks A for the text.
- program A responds, and sends the text to program B.
- program B pastes the response.
X10 had these things called ``Cut Buffers'' that were a more limited and wasteful predecessor to selections. They are obsolete; don't use them. Some applications (like xterm) still have legacy support for them, but ignore that.
Clipboard: | for when the user has explicitly copied something (e.g., the ``Edit/Copy'' menu item.) | |
Primary: | more ephemeral and implicit: it is for when the user has highlighted or selected something (e.g., dragging the mouse over some text.) | |
Cut Buffers: | Obsolete. Never, ever, ever use them. Ever. |
Contrary to what you may have come to believe, copying and pasting text under X11 works pretty much exactly the same way it does under MacOS and Windows. Really. It works like this:
- Select the text to copy;
- Pull down the ``Edit'' menu and select ``Copy.''
This causes the text to become the Clipboard Selection. - In another window, pull down the ``Edit'' menu and select ``Paste.''
This causes the current value of the Clipboard selection to be inserted.
It happens that X11 programs have a second way of copying and pasting text that is orthogonal to the Edit/Copy way described above. This causes confusion, because some people mix the two up. Here's how the other way works:
- Select the text to copy.
This causes the text to become the Primary Selection. - In another window, click the middle mouse button.
This causes the current value of the Primary selection to be inserted.
Event: | Action: |
---|---|
text highlighted with mouse |
Assert PRIMARY selection ownership. |
Edit / Copy | Make an internal copy of the highlighted text. Assert CLIPBOARD selection ownership. |
Edit / Paste | Retrieve and insert CLIPBOARD selection. |
middle button paste, if implemented |
Retrieve and insert PRIMARY selection. |
another app asks for PRIMARY |
Send currently-highlighted text, if any. |
another app asks for CLIPBOARD |
Send saved copy of last-copied text, if any. |
another app becomes PRIMARY owner |
De-highlight text. |
another app becomes CLIPBOARD owner |
Discard text copy. |
One of the really cool, yet rarely used, features of the selection mechanism is that it can negotiate what data formats to use. It's not just about text. When one application asks another for the selection, part of their communication involves the requester asking the owner for the list of types in which they are capable of delivering the selection data; then the requester picks the format they like best, and asks for it that way.
As a simple example, suppose there is a program displaying text in multiple fonts. When pasting that into a text-only program, you'd want to paste only the text. But when pasting that into a word processor, you'd want to keep the font information: if both applications spoke HTML, they could use that as the intermediate format by which they transferred the data.
More complex things are possible, too: for example, when an image is selected on a web page, the web page displayer could offer to serve that up as raw image bits; or as JPEG data; or as the original URL of the image. When trying to copy and paste an image into a text editor that can't do images, the text editor might decide that the next best thing would be to paste the filename of the image, or the URL.
The content negotiation mechansim is very powerful, and I wish more applications would take advantage of it.
You can experiment with content negotiation with other apps from an XEmacs lisp-interaction buffer. To see what types an app will convert its selection to, make a selection in that app, and then type:
-
(get-selection-internal 'PRIMARY 'TARGETS) ==> [ TARGETS TIMESTAMP TEXT STRING LENGTH FILE_NAME OWNER_OS HOST_NAME USER CLASS NAME CLIENT_WINDOW PROCESS COMPOUND_TEXT] (get-selection-internal 'PRIMARY 'FILE_NAME) ==> "https://www.jwz.org/doc/x-cut-and-paste.html"
The full technical documentation for this stuff is in the X11R6 Inter-Client Communication Conventions Manual, section 2: ``Peer-to-Peer Communication by Means of Selections.''
And now, about Emacs:
> Emacs: (car kill-ring) is always the same as the primary x selection, > therefore mouse2 and C-y pastes the same. mouse1 sets the > kill-ring as well as the primary selection.
Unless things have changed since the last time I checked, I don't believe this is true: (car kill-ring) is the same as the primary X selection only if a kill has been made in FSFmacs more recently than text has been selected in another (non-FSFmacs) X application.
> My question is: did the XEmacs people conduct a poll to determine > which behavior is preferred by the masses? (Actually, RMS asked me > this question).
No, I didn't do any surveys, but I did have a reason (in fact, the FSF behavior existed before the FSFmacs/Lucid Emacs schism occurred, and I changed it in our branch.)
The traditional X model of selection usage is that the primary selection is highly ephemeral: it is what is currently highlighted, and that tends not to stay highlighted for long (as other activity tends to dehighlight it.) For longer-lived data, the clipboard selection is used: this is what is generally associated with the Cut/Paste commands (while the primary selection is associated with click-and-drag, and in some applications, middle-click, which is not the same command as ``paste''.)
In a traditional X app, mouse-drag will own the primary selection, and the Cut/Copy commands will move the primary selection to the clipboard.
Therefore, in the emacs world, the primary selection would more logically correspond to the region between point and mark, when it is in the highlighted state (assuming one is using zmacs-regions, another of my earliest additions to the Lucid Emacs branch.) The clipboard selection would more logically correspond to the topmost element on the kill ring.
I added hooks to make it possible to do this -- when you select a region, it becomes the primary selection -- however, it turned out to not be such a good idea to do this (by default) for the kill-ring (and clipboard selection) for a couple of reasons.
The first reason was bandwidth.
Cut buffers, while officially obsolete, are still used, because there are still old programs (and more importantly, old .Xdefaults files) which cause CUT_BUFFER0 to be pasted in other apps in preference to the primary selection. So Lucid Emacs would update both. Now the problem with cut buffers is that at the time one writes a string into the cut buffer, all that data is transferred to the server immediately (selections don't work that way, with selections, the data is transferred as needed.) So this means that if you killed a lot of text (C-SPC M-> C-w, for example) you'd be sending lots and lots of bits over the wire which you likely didn't need to -- and this was a big deal when on slow connections to X servers. Hardcore emacs users kill large bodies of text all the time.
Granted, such slow server connections aren't very common nowadays, but they were then, when X terminals were still very popular (until 1994 or so, I was still doing a lot of my development on an X terminal that only had a 38.4kbps connection to the host machine.)
But that's just cut buffers, and they're ``obsolete,'' right? But then there's the XClipboard program -- basically, this is a program that sits around and makes it easier to deal with your clipboard (it keeps a history of them, among other things) but one side effect of it is that the clipboard data tends to be transferred from the selecting app to the XClipfnord app right away (with the X server as the middleman) so again, you've got the ``cut buffer'' bandwidth problem again.
The second reason was the Principle of Least Astonishment.
X's notion of clipboards (and selections in general) is binary: there is a selection or there is not; there is something on the clipboard or there is not. Whereas emacs has a kill ring, a history of past kills.
So if you decide that you want the emacs kill ring and the X clipboard selection to be unified, what does that mean? Does it mean that the top element on the ring should always be asserted as the clipboard? Ok, you can make emacs do that easily enough. But then what happens when some other app asks for ownership of the clipboard? Does that mean that that text should automatically be added to the front of emacs's kill ring as well? That would make emacs behave like XClipboard, and thus ``race'' with it for ownership (actually the two would probably get into a tug-of-war with each other.) That's not so good, and pretty tricky to make fail gracefully.
Well anyway, that's not what had been implemented in FSFmacs at the time (it did the kill-ring->selection part, but not the selection->kill-ring part) so I would have had to fix that, but also... even if it was fixed to behave consistently, it would still have the bandwidth problem.
So, I somewhat separated the kill/yank commands and the Cut/Paste commands, in that both kill and Cut write to both the kill-ring and the clipboard; but yank looks only at the kill-ring, while Paste looks only at the clipboard. This means that a naive mouse-using user, who would presumably only be using the Cut/Paste commands, would have everything do what they mean (the clipboard and kill ring would stay in sync, and since the user was mouse-oriented, they wouldn't tend to select truly huge areas semi-inadvertantly, sidestepping the bandwidth issue); but a real emacs user, driving it with the keyboard, would tend to live in the emacs ``space'' until they want to go out to the inter-X-client space by using a different gesture (either the Cut command, or selecting a region). (The region/selection interaction being less problematic since both emacs and X think there either is one or their isn't.)
So that's why.
来源:oschina
链接:https://my.oschina.net/u/4414119/blog/4780359