From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: [PATCH] Improve X Selection? Date: Wed, 17 Oct 2007 10:01:42 -0400 Message-ID: References: <4715AFBF.7040205@swipnet.se> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1192629725 17185 80.91.229.12 (17 Oct 2007 14:02:05 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 17 Oct 2007 14:02:05 +0000 (UTC) Cc: rms@gnu.org, emacs-devel@gnu.org To: Jan =?iso-8859-1?Q?Dj=3Frv?= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Oct 17 16:02:04 2007 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1Ii9TG-0007yl-Vq for ged-emacs-devel@m.gmane.org; Wed, 17 Oct 2007 16:02:03 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Ii9T9-0000PQ-RE for ged-emacs-devel@m.gmane.org; Wed, 17 Oct 2007 10:01:55 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Ii9T5-0000Ot-Sr for emacs-devel@gnu.org; Wed, 17 Oct 2007 10:01:51 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Ii9T3-0000Nx-TX for emacs-devel@gnu.org; Wed, 17 Oct 2007 10:01:51 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Ii9T3-0000Nu-QD for emacs-devel@gnu.org; Wed, 17 Oct 2007 10:01:49 -0400 Original-Received: from tomts13.bellnexxia.net ([209.226.175.34] helo=tomts13-srv.bellnexxia.net) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Ii9Sy-00038r-Oq; Wed, 17 Oct 2007 10:01:45 -0400 Original-Received: from pastel.home ([74.12.207.168]) by tomts13-srv.bellnexxia.net (InterMail vM.5.01.06.13 201-253-122-130-113-20050324) with ESMTP id <20071017140143.TBIL13659.tomts13-srv.bellnexxia.net@pastel.home>; Wed, 17 Oct 2007 10:01:43 -0400 Original-Received: by pastel.home (Postfix, from userid 20848) id E7E1C88BA; Wed, 17 Oct 2007 10:01:42 -0400 (EDT) In-Reply-To: <4715AFBF.7040205@swipnet.se> ("Jan =?iso-8859-1?Q?Dj=3Frv=22?= =?iso-8859-1?Q?'s?= message of "Wed\, 17 Oct 2007 08\:46\:23 +0200") User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/23.0.50 (gnu/linux) X-detected-kernel: by monty-python.gnu.org: Solaris 8 (1) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:81062 Archived-At: >> Does anyone see a reason not to install this? > Yes, it is annoying by default. Default should be the old behaviour. And it > drags in unwanted selections, or the same text multiple times. Also, say you > select text in an application and then copy it to the clipboard (a very common > thing to do). When you paste in Emacs with the tool bar, you get the > CLIPBOARD. Then you do M-y. You now get exactly the same thing, but from > PRIMARY. This is annoying > If people want to drag in the same text many times or get all selections that > is fine, but it should not be the default. Agreed. It needs to be refined and the default should (at least for now) preserve the current behavior. The easiest way is to introduce a boolean config var which either selects this new behavior or the current one. Then it's OK to install this new behavior "as is" and improve it later on. Stefan >> Date: Mon, 15 Oct 2007 20:15:29 -0400 >> From: Tom Horsley >> To: bug-gnu-emacs@gnu.org >> Mime-Version: 1.0 >> Content-Type: text/plain; charset=ISO-8859-1 >> Subject: [PATCH] Improve X Selection? >> >> To liven up the "Improve X Selection" thread, here is a patch against >> emacs-22.1 that implements (to the best of my ability) the original scheme I >> suggested at the start of the thread (my email address has changed, since I >> am doing this work at home, not at ccur.com). The (current-kill) function >> (apparently the only caller of interprogram-paste-function) has been >> modified to accept either a simple string or a list of strings. To go with >> that, the (x-cut-buffer-or-selection-value) function has been modified to >> return a list of selection strings if multiple selections have changed since >> the last call, the order of the selections and which selections it uses are >> determined by the new variable x-paste-selection-names. >> >> I freely admit that some of the hackery I've done here was somewhat blind, >> so it is entirely possible that I have screwed up some subtle details >> somewhere (particularly all the coding system stuff going on in the cut >> buffer code I extracted into a helper function from the old code), but it >> seems to work for me in my testing so far. >> >> Anyway this is something more concrete to play with and see how folks like >> it. I note that it doesn't preclude implementing different paste functions >> in different contexts as has been suggested in the original thread (menu, >> keyboard, mouse, etc), you can always do a 'let' to modify the >> x-paste-selection-names temporarily then call the common code, but I have to >> say I prefer not having to think about which selection I'm going to get - >> just lump 'em all in the kill-ring, and if I see the wrong text, I can just >> do a yank-pop to get the other string. >> >> >> *** emacs-22.1/lisp/ChangeLog Sat Jun 2 00:30:23 2007 >> --- emacs-22.1lisp/ChangeLog Mon Oct 15 19:50:53 2007 >> *************** >> *** 1,3 **** >> --- 1,15 ---- >> + 2007-10-15 Tom Horsley >> + >> + * simple.el (current-kill): Accept list of strings as well >> + as single string from `interprogram-paste-function'. >> + >> + * term/x-win.el (x-cut-buffer-or-selection-value): Modify >> + to return list of all changed selections ordered by the >> + selection named mentioned in the new variable >> + `x-paste-selection-names'. >> + (x-cut-buffer-selection): New function used to make >> + X cut buffer act somewhat like a selection. >> + >> 2007-06-02 Chong Yidong >> >> * Version 22.1 released. >> *** emacs-22.1/lisp/simple.el Sun May 27 10:35:51 2007 >> --- emacs-22.1lisp/simple.el Mon Oct 15 17:53:29 2007 >> *************** >> *** 2409,2414 **** >> --- 2409,2419 ---- >> string, then the caller of the function \(usually `current-kill') >> should put this string in the kill ring as the latest kill. >> >> + This function may also return a list of strings if the window >> + system supports multiple selections. The first string will be >> + used as the pasted text, but the other will be placed in the >> + kill ring for easy access via `yank-pop'. >> + >> Note that the function should return a string only if a program other >> than Emacs has provided a string for pasting; if Emacs provided the >> most recent string, the function should return nil. If it is >> *************** >> *** 2490,2500 **** >> >> (defun current-kill (n &optional do-not-move) >> "Rotate the yanking point by N places, and then return that kill. >> ! If N is zero, `interprogram-paste-function' is set, and calling it >> ! returns a string, then that string is added to the front of the >> ! kill ring and returned as the latest kill. >> ! If optional arg DO-NOT-MOVE is non-nil, then don't actually move the >> ! yanking point; just return the Nth kill forward." >> (let ((interprogram-paste (and (= n 0) >> interprogram-paste-function >> (funcall interprogram-paste-function)))) >> --- 2495,2505 ---- >> >> (defun current-kill (n &optional do-not-move) >> "Rotate the yanking point by N places, and then return that kill. >> ! If N is zero, `interprogram-paste-function' is set, and calling it returns a >> ! string or list of strings, then that string (or list) is added to the front >> ! of the kill ring and the string (or first string in the list) is returned as >> ! the latest kill. If optional arg DO-NOT-MOVE is non-nil, then don't >> ! actually move the yanking point; just return the Nth kill forward." >> (let ((interprogram-paste (and (= n 0) >> interprogram-paste-function >> (funcall interprogram-paste-function)))) >> *************** >> *** 2504,2511 **** >> ;; text to the kill ring, so Emacs doesn't try to own the >> ;; selection, with identical text. >> (let ((interprogram-cut-function nil)) >> ! (kill-new interprogram-paste)) >> ! interprogram-paste) >> (or kill-ring (error "Kill ring is empty")) >> (let ((ARGth-kill-element >> (nthcdr (mod (- n (length kill-ring-yank-pointer)) >> --- 2509,2518 ---- >> ;; text to the kill ring, so Emacs doesn't try to own the >> ;; selection, with identical text. >> (let ((interprogram-cut-function nil)) >> ! (if (listp interprogram-paste) >> ! (mapc 'kill-new (nreverse interprogram-paste)) >> ! (kill-new interprogram-paste))) >> ! (car kill-ring)) >> (or kill-ring (error "Kill ring is empty")) >> (let ((ARGth-kill-element >> (nthcdr (mod (- n (length kill-ring-yank-pointer)) >> *** emacs-22.1/lisp/term/x-win.el Tue Mar 6 00:50:48 2007 >> --- emacs-22.1lisp/term/x-win.el Mon Oct 15 19:46:30 2007 >> *************** >> *** 2126,2137 **** >> ;; seperately in case another X application only sets one of them >> ;; (say the cut buffer) we aren't fooled by the PRIMARY or >> ;; CLIPBOARD selection staying the same. >> - (defvar x-last-selected-text-clipboard nil >> - "The value of the CLIPBOARD X selection last time we selected or >> - pasted text.") >> - (defvar x-last-selected-text-primary nil >> - "The value of the PRIMARY X selection last time we selected or >> - pasted text.") >> (defvar x-last-selected-text-cut nil >> "The value of the X cut buffer last time we selected or pasted text. >> The actual text stored in the X cut buffer is what encoded from this value.") >> --- 2126,2131 ---- >> *************** >> *** 2151,2156 **** >> --- 2145,2161 ---- >> :type 'boolean >> :group 'killing) >> >> + ;; In addition to representing the prefered order of selections >> + ;; for paste operations, the symbols in the x-paste-selection-names >> + ;; list also use the 'lastval symbol property to remember the >> + ;; previous selection value so that only selections which have >> + ;; changed since the last paste operation will be returned. >> + (defvar x-paste-selection-names >> + '( CLIPBOARD PRIMARY SECONDARY x-cut-buffer-selection ) >> + "The list of selection names in priority order. If the name is >> + bound to a function, that function is called to obtain the selection >> + string, otherwise the named X selection is fetched.") >> + >> (defun x-select-text (text &optional push) >> "Make TEXT, a string, the primary X selection. >> Also, set the value of X cut buffer 0, for backward compatibility >> *************** >> *** 2289,2340 **** >> (remove-text-properties 0 (length text) '(foreign-selection nil) text)) >> text)) >> >> ! ;; Return the value of the current X selection. >> ! ;; Consult the selection, and the cut buffer. Treat empty strings >> ! ;; as if they were unset. >> ! ;; If this function is called twice and finds the same text, >> ! ;; it returns nil the second time. This is so that a single >> ! ;; selection won't be added to the kill ring over and over. >> ! (defun x-cut-buffer-or-selection-value () >> ! (let (clip-text primary-text cut-text) >> ! (when x-select-enable-clipboard >> ! (setq clip-text (x-selection-value 'CLIPBOARD)) >> ! (if (string= clip-text "") (setq clip-text nil)) >> ! >> ! ;; Check the CLIPBOARD selection for 'newness', is it different >> ! ;; from what we remebered them to be last time we did a >> ! ;; cut/paste operation. >> ! (setq clip-text >> ! (cond;; check clipboard >> ! ((or (not clip-text) (string= clip-text "")) >> ! (setq x-last-selected-text-clipboard nil)) >> ! ((eq clip-text x-last-selected-text-clipboard) nil) >> ! ((string= clip-text x-last-selected-text-clipboard) >> ! ;; Record the newer string, >> ! ;; so subsequent calls can use the `eq' test. >> ! (setq x-last-selected-text-clipboard clip-text) >> ! nil) >> ! (t >> ! (setq x-last-selected-text-clipboard clip-text)))) >> ! ) >> ! >> ! (setq primary-text (x-selection-value 'PRIMARY)) >> ! ;; Check the PRIMARY selection for 'newness', is it different >> ! ;; from what we remebered them to be last time we did a >> ! ;; cut/paste operation. >> ! (setq primary-text >> ! (cond;; check primary selection >> ! ((or (not primary-text) (string= primary-text "")) >> ! (setq x-last-selected-text-primary nil)) >> ! ((eq primary-text x-last-selected-text-primary) nil) >> ! ((string= primary-text x-last-selected-text-primary) >> ! ;; Record the newer string, >> ! ;; so subsequent calls can use the `eq' test. >> ! (setq x-last-selected-text-primary primary-text) >> ! nil) >> ! (t >> ! (setq x-last-selected-text-primary primary-text)))) >> ! >> (setq cut-text (x-get-cut-buffer 0)) >> >> ;; Check the x cut buffer for 'newness', is it different >> --- 2294,2303 ---- >> (remove-text-properties 0 (length text) '(foreign-selection nil) text)) >> text)) >> >> ! (defun x-cut-buffer-selection () >> ! "Helper function used to make fetching the X cut >> ! buffer act much like fetching an X selection." >> ! (let (cut-text) >> (setq cut-text (x-get-cut-buffer 0)) >> >> ;; Check the x cut buffer for 'newness', is it different >> *************** >> *** 2366,2394 **** >> >> ;; As we have done one selection, clear this now. >> (setq next-selection-coding-system nil) >> >> ! ;; At this point we have recorded the current values for the >> ! ;; selection from clipboard (if we are supposed to) primary, >> ! ;; and cut buffer. So return the first one that has changed >> ! ;; (which is the first non-null one). >> ! ;; >> ! ;; NOTE: There will be cases where more than one of these has >> ! ;; changed and the new values differ. This indicates that >> ! ;; something like the following has happened since the last time >> ! ;; we looked at the selections: Application X set all the >> ! ;; selections, then Application Y set only one or two of them (say >> ! ;; just the cut-buffer). In this case since we don't have >> ! ;; timestamps there is no way to know what the 'correct' value to >> ! ;; return is. The nice thing to do would be to tell the user we >> ! ;; saw multiple possible selections and ask the user which was the >> ! ;; one they wanted. >> ! ;; This code is still a big improvement because now the user can >> ! ;; futz with the current selection and get emacs to pay attention >> ! ;; to the cut buffer again (previously as soon as clipboard or >> ! ;; primary had been set the cut buffer would essentially never be >> ! ;; checked again). >> ! (or clip-text primary-text cut-text) >> ! )) >> >> >> ;; Do the actual X Windows setup here; the above code just defines >> --- 2329,2383 ---- >> >> ;; As we have done one selection, clear this now. >> (setq next-selection-coding-system nil) >> + cut-text >> + )) >> >> ! ;; Return only the changed values of all the X selections in the list >> ! ;; x-paste-selection-names. The changed selection strings will be ordered >> ! ;; in the returned list according to the x-paste-selection-names order. >> ! (defun x-cut-buffer-or-selection-value () >> ! (let ((selection-names x-paste-selection-names) >> ! sel-name >> ! sel-string >> ! changed-list) >> ! (while selection-names >> ! (setq sel-name (car selection-names)) >> ! (setq selection-names (cdr selection-names)) >> ! (if (fboundp sel-name) >> ! (setq sel-string (funcall sel-name)) >> ! (setq sel-string (x-selection-value sel-name)) >> ! ) >> ! (if (string= sel-string "") (setq sel-string nil)) >> ! (setq sel-string >> ! (cond >> ! ((not sel-string) >> ! (put sel-name 'lastval nil)) >> ! ((eq sel-string (get sel-name 'lastval)) nil) >> ! ((string= sel-string (get sel-name 'lastval)) >> ! ;; Record the newer string, >> ! ;; so subsequent calls can use the `eq' test. >> ! (put sel-name 'lastval sel-string) >> ! nil) >> ! (t >> ! (put sel-name 'lastval sel-string)))) >> ! ;; emacs is one app that often sets multiple selections to the >> ! ;; same string. Other apps may also do this, so don't add the >> ! ;; selection to the list if the same string is already in the >> ! ;; list via a previous selection. >> ! (if (and sel-string (not (member sel-string changed-list))) >> ! (setq changed-list (cons sel-string changed-list))) >> ! ) >> ! ;; At this point, the changed-list holds the strings from all the >> ! ;; different selections which have changed. Typically, the caller of >> ! ;; this routine will push them all on the kill-ring, so if you get the >> ! ;; incorrect text pasted, you can do something like yank-pop to fetch >> ! ;; the one you really want. If we only have one selection, just >> ! ;; return that string, not the list. If we have multiple selections, >> ! ;; reverse the list to get them in the proper priority order. >> ! (if (= (length changed-list) 1) >> ! (car changed-list) >> ! (nreverse changed-list) >> ! ))) >> >> >> ;; Do the actual X Windows setup here; the above code just defines >> >> >> >> >> >> _______________________________________________ >> Emacs-devel mailing list >> Emacs-devel@gnu.org >> http://lists.gnu.org/mailman/listinfo/emacs-devel > _______________________________________________ > Emacs-devel mailing list > Emacs-devel@gnu.org > http://lists.gnu.org/mailman/listinfo/emacs-devel