diff -NarU10 emacs-fsar/lisp/mouse.el emacs/lisp/mouse.el --- emacs-fsar/lisp/mouse.el 2008-02-02 02:07:23.000000000 +0000 +++ emacs/lisp/mouse.el 2008-02-03 11:34:47.000000000 +0000 @@ -653,24 +653,27 @@ ;; window too thin. (if (< (- x left -1) window-min-width) (setq x (+ left window-min-width -1))) ;; compute size change needed (setq growth (- x right -1)) (condition-case nil (adjust-window-trailing-edge window growth t) (error nil)))))))))) (defun mouse-set-point (event) - "Move point to the position clicked on with the mouse. + "Move point to the position clicked on with the mouse, deactivating +region beforehand. This should be bound to a mouse click event type." (interactive "e") (mouse-minibuffer-check event) + ; select-active-regions is misleading unless this happens + (deactivate-mark) ;; Use event-end in case called from mouse-drag-region. ;; If EVENT is a click, event-end and event-start give same value. (posn-set-point (event-end event))) (defvar mouse-last-region-beg nil) (defvar mouse-last-region-end nil) (defvar mouse-last-region-tick nil) (defun mouse-region-match () "Return non-nil if there's an active region that was set with the mouse." @@ -1349,34 +1352,57 @@ The text is saved in the kill ring, as with \\[kill-region]." (interactive "e") (mouse-minibuffer-check click) (let* ((posn (event-start click)) (click-posn (posn-point posn))) (select-window (posn-window posn)) (if (numberp click-posn) (kill-region (min (point) click-posn) (max (point) click-posn))))) +(defcustom mouse-yank-at-click-action :lightins + "Whether mouse-yank-at-click should do a real `yank' +or use `interprogram-lightins-function' to try an X11-middlebutton-style +sort of insert. + +Yank: a kill-ring yank, which may in turn call `interprogram-paste-function' + +LightIns: Call `interprogram-lightins-function', do not use kill ring" + + :type '(choice (const :tag "LightIns" :lightins) + (const :tag "Yank" :yank)) + :group 'mouse) + (defun mouse-yank-at-click (click arg) - "Insert the last stretch of killed text at the position clicked on. + "Insert the last stretch of killed text as if by \\[yank] at the + position clicked on, if `mouse-yank-at-click-action' is yank. + +If `mouse-yank-at-click-action' is lightins insert text +returned by `interprogram-lightins-function' without +involving kill ring. + Also move point to one end of the text thus inserted (normally the end), and set mark at the beginning. Prefix arguments are interpreted as with \\[yank]. If `mouse-yank-at-point' is non-nil, insert at point regardless of where you click." (interactive "e\nP") ;; Give temporary modes such as isearch a chance to turn off. (run-hooks 'mouse-leave-buffer-hook) (or mouse-yank-at-point (mouse-set-point click)) - (setq this-command 'yank) (setq mouse-selection-click-count 0) - (yank arg)) + (cond ((eq mouse-yank-at-click-action :lightins) + (and interprogram-lightins-function + (insert (funcall 'interprogram-lightins-function)))) + (t + (setq this-command 'yank) + (yank arg)))) (defun mouse-yank-primary (click) "Insert the primary selection at the position clicked on. Move point to the end of the inserted text. If `mouse-yank-at-point' is non-nil, insert at point regardless of where you click." (interactive "e") ;; Give temporary modes such as isearch a chance to turn off. (run-hooks 'mouse-leave-buffer-hook) (or mouse-yank-at-point (mouse-set-point click)) @@ -1429,83 +1455,134 @@ (let ((tail buffer-undo-list)) ;; Search back in buffer-undo-list for the string ;; that came from deleting one character. (while (and tail (not (stringp (car (car tail))))) (setq tail (cdr tail))) ;; Replace it with an entry for the entire deleted text. (and tail (setcar tail (cons (car kill-ring) (min beg end)))))) (undo-boundary)) +(defcustom mouse-save-then-kill-copy-region :double + "How should mouse-save-then-kill save then kill? +Never: only adjust active region, never kill. +Single: save on single click, kill on second click +Double: adjust active region on first click, save +on second, kill on third" + +:type '(choice (const :tag "Never" nil) + (const :tag "Single" t) + (const :tag "Double" :double)) +:group 'mouse) + + + (defun mouse-save-then-kill (click) "Save text to point in kill ring; the second time, kill the text. + +Behaviour depends on `mouse-save-then-kill-copy-region'. If that +is nil, clicking merely adjusts the region. If :double, single +clicking adjusts the region, double clicking saves text to kill +ring, triple clicking kills the text. If nil, +single clicking saves text to kill ring, double clicking kills. + If the text between point and the mouse is the same as what's at the front of the kill ring, this deletes the text. Otherwise, it adds the text to the kill ring, like \\[kill-ring-save], which prepares for a second click to delete the text. If you have selected words or lines, this command extends the selection through the word or line clicked on. If you do this again in a different position, it extends the selection again. -If you do this twice in the same position, the selection is killed." +If you do this twice (or three times if :double) in the same +position, the selection is killed. +" (interactive "e") (let ((before-scroll (with-current-buffer (window-buffer (posn-window (event-start click))) point-before-scroll))) (mouse-minibuffer-check click) (let ((click-posn (posn-point (event-start click))) ;; Don't let a subsequent kill command append to this one: ;; prevent setting this-command to kill-region. (this-command this-command)) (if (and (with-current-buffer (window-buffer (posn-window (event-start click))) (and (mark t) (> (mod mouse-selection-click-count 3) 0) ;; Don't be fooled by a recent click in some other buffer. (eq mouse-selection-click-count-buffer (current-buffer))))) + ;; moving by words/lines (if (not (and (eq last-command 'mouse-save-then-kill) (equal click-posn (car (cdr-safe (cdr-safe mouse-save-then-kill-posn)))))) ;; Find both ends of the object selected by this click. (let* ((range (mouse-start-end click-posn click-posn mouse-selection-click-count))) ;; Move whichever end is closer to the click. ;; That's what xterm does, and it seems reasonable. (if (< (abs (- click-posn (mark t))) (abs (- click-posn (point)))) (set-mark (car range)) (goto-char (nth 1 range))) - ;; We have already put the old region in the kill ring. - ;; Replace it with the extended region. - ;; (It would be annoying to make a separate entry.) - (kill-new (buffer-substring (point) (mark t)) t) + + (cond ((eq mouse-save-then-kill-copy-region t) ; save on first click + ;; We have already put the old region in the kill ring. + ;; Replace it with the extended region. + ;; (It would be annoying to make a separate entry.) + (kill-new (buffer-substring (point) (mark t)) t) + ;; Arrange for a repeated mouse-3 to kill this region. + (setq mouse-save-then-kill-posn + (list (car kill-ring) (point) click-posn))) + ((eq mouse-save-then-kill-copy-region :double) ; no save on first click + ;; no save on first click, but need to know region from first + ;; nil for saved kill ring top used to indicate limbo between second and third clicks + (setq mouse-save-then-kill-posn + (list nil (point) click-posn)))) (mouse-set-region-1) - ;; Arrange for a repeated mouse-3 to kill this region. - (setq mouse-save-then-kill-posn - (list (car kill-ring) (point) click-posn)) (mouse-show-mark)) - ;; If we click this button again without moving it, - ;; that time kill. - (mouse-save-then-kill-delete-region (mark) (point)) - (setq mouse-selection-click-count 0) - (setq mouse-save-then-kill-posn nil)) - (if (and (eq last-command 'mouse-save-then-kill) + (cond ((eq mouse-save-then-kill-copy-region t) ; kill on second click + ;; If we click this button again without moving it, + ;; that time kill. + (mouse-save-then-kill-delete-region (mark) (point)) + (setq mouse-selection-click-count 0) + (setq mouse-save-then-kill-posn nil)) + ((eq mouse-save-then-kill-copy-region :double) ;save on second/kill on third + (if (car-safe mouse-save-then-kill-posn) ; kill on third + (progn + (mouse-save-then-kill-delete-region (mark) (point)) + (setq mouse-selection-click-count 0) + (setq mouse-save-then-kill-posn nil)) + (progn ; save on second + (kill-new (buffer-substring (point) (mark t)) t) + (setq mouse-save-then-kill-posn + (list (car kill-ring) (point) click-posn))))))) + ;; moving by chars + (if (and (eq last-command 'mouse-save-then-kill) mouse-save-then-kill-posn - (eq (car mouse-save-then-kill-posn) (car kill-ring)) - (equal (cdr mouse-save-then-kill-posn) (list (point) click-posn))) - ;; If this is the second time we've called - ;; mouse-save-then-kill, delete the text from the buffer. - (progn - (mouse-save-then-kill-delete-region (point) (mark)) - ;; After we kill, another click counts as "the first time". - (setq mouse-save-then-kill-posn nil)) + (equal (cdr-safe mouse-save-then-kill-posn) (list (point) click-posn))) + (cond ((eq mouse-save-then-kill-copy-region t) ; kill on second click + ;; If this is the second time we've called + ;; mouse-save-then-kill, delete the text from the buffer. + (mouse-save-then-kill-delete-region (point) (mark)) + ;; After we kill, another click counts as "the first time". + (setq mouse-save-then-kill-posn nil)) + ((eq mouse-save-then-kill-copy-region :double) ; save on second / kill on third + (if (car-safe mouse-save-then-kill-posn) ; kill on third + (progn + (mouse-save-then-kill-delete-region (point) (mark)) + (setq mouse-save-then-kill-posn nil)) + (progn ; save on second + (kill-new (buffer-substring (point) (mark t)) t) + (setq mouse-save-then-kill-posn + (list (car kill-ring) (point) click-posn)))))) ;; This is not a repetition. ;; We are adjusting an old selection or creating a new one. (if (or (and (eq last-command 'mouse-save-then-kill) mouse-save-then-kill-posn) (and mark-active transient-mark-mode) (and (memq last-command '(mouse-drag-region mouse-set-region)) (or mark-even-if-inactive (not transient-mark-mode)))) ;; We have a selection or suitable region, so adjust it. @@ -1513,31 +1590,39 @@ (new (posn-point posn))) (select-window (posn-window posn)) (if (numberp new) (progn ;; Move whichever end of the region is closer to the click. ;; That is what xterm does, and it seems reasonable. (if (<= (abs (- new (point))) (abs (- new (mark t)))) (goto-char new) (set-mark new)) (setq deactivate-mark nil))) - (kill-new (buffer-substring (point) (mark t)) t)) + (and (eq mouse-save-then-kill-copy-region t) ; save on first click + (kill-new (buffer-substring (point) (mark t)) t))) ;; Set the mark where point is, then move where clicked. (mouse-set-mark-fast click) (if before-scroll (goto-char before-scroll)) (exchange-point-and-mark) ;Why??? --Stef - (kill-new (buffer-substring (point) (mark t)))) - (mouse-show-mark) + (and (eq mouse-save-then-kill-copy-region t) ; save on first click + (kill-new (buffer-substring (point) (mark t))))) + (cond ((eq mouse-save-then-kill-copy-region t) ; save on first click + (setq mouse-save-then-kill-posn + (list (car kill-ring) (point) click-posn))) + ((eq mouse-save-then-kill-copy-region :double) ; no save on first click + ;; no save on first click, but need to know region from first + ;; nil for saved kill ring top used to indicate limbo between second and third clicks + (setq mouse-save-then-kill-posn + (list nil (point) click-posn)))) (mouse-set-region-1) - (setq mouse-save-then-kill-posn - (list (car kill-ring) (point) click-posn))))))) + (mouse-show-mark)))))) (global-set-key [M-mouse-1] 'mouse-start-secondary) (global-set-key [M-drag-mouse-1] 'mouse-set-secondary) (global-set-key [M-down-mouse-1] 'mouse-drag-secondary) (global-set-key [M-mouse-3] 'mouse-secondary-save-then-kill) (global-set-key [M-mouse-2] 'mouse-yank-secondary) (defconst mouse-secondary-overlay (let ((ol (make-overlay (point-min) (point-min)))) (delete-overlay ol) diff -NarU10 emacs-fsar/lisp/simple.el emacs/lisp/simple.el --- emacs-fsar/lisp/simple.el 2008-02-02 02:07:19.000000000 +0000 +++ emacs/lisp/simple.el 2008-02-03 04:52:54.000000000 +0000 @@ -2603,20 +2603,52 @@ 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 difficult to tell whether Emacs or some other program provided the current string, it is probably good enough to return nil if the string is equal (according to `string=') to the last text Emacs provided.") + +(defvar interprogram-lightins-function nil + "Function to call to get text made available for highlight-insertion from other programs. + +Some window systems (okay one window system, X11) provide a +facility for immediately inserting text highlighted in one program +into another, bypassing the clipboard. + +This variable holds a function that Emacs calls to obtain +text that other programs have provided for such 'lightweight +insertion'. The convention has developed on X11 +that this lightweight highlight/insertion should be entirely +independent from the clipboard proper. + +The function should be called with no arguments. If the function +returns nil, then no other program has provided such text. If the +function returns a string, then the caller of the function +\(usually `mouse-yank-at-click') will insert this string +into the buffer... without affecting the kill ring. This may +seem slightly strange, but is intended and now typical +behaviour on X11 desktops. If you DO want mouse-yank-at-click to +affect the kill ring, as it has done in the past in emacs, +adjust `mouse-yank-at-click-action' to have it use the kill +ring \(and thereby potentially `interprogram-paste-function'), which +on X11 at least \(the only relevant platform at the moment) can +in turn be adjusted to pull in PRIMARY as well as or instead of +CLIPBOARD via `x-select-enable-primary'. + +Note that the function should return a string if available +whether or not a program other than Emacs provided the string, +this is so that emacs->emacs highlight/lightins interactions +work as expected.") ;;;; The kill ring data structure. (defvar kill-ring nil "List of killed text sequences. Since the kill ring is supposed to interact nicely with cut-and-paste facilities offered by window systems, use of this variable should interact nicely with `interprogram-cut-function' and diff -NarU10 emacs-fsar/lisp/term/x-win.el emacs/lisp/term/x-win.el --- emacs-fsar/lisp/term/x-win.el 2008-02-02 02:07:32.000000000 +0000 +++ emacs/lisp/term/x-win.el 2008-02-03 05:49:25.000000000 +0000 @@ -2161,66 +2161,84 @@ functions (typically something like C-x or C-c in those programs) Highlight: Set if merely highlighting text (setting the active region) in Emacs should immediately put it in the clipboard, if `select-active-regions' is also set. This is unusual for recent X11 applications, typically highlighted text is placed in the PRIMARY X11 selection, for 'highlight/middlebutton' style X11 transfer. See `x-select-enable-primary'. It is recommended to unset `mouse-drag-copy-region' and -set `transient-mark-mode' if Highlight is set here." +set `transient-mark-mode' if Highlight is set here. + +LightIns: Set if the CLIPBOARD selection should be checked for +lightweight insert operations \( `mouse-yank-at-click' +with `mouse-yank-at-click-action' set to LightIns). This is not +customary on X11, and even if you do want the middle mouse +button (i.e. mouse-2 typically bound to mouse-yank-at-click) +to pull in the clipboard like historic emacs, it is likely you want +to set mouse-yank-at-click-action to Yank and set Paste here instead +so that the Kill Ring is side-effected by the operation. Clear as mud." :type '(choice (const :tag "None" nil) (const :tag "All" t) (set :tag "Choose" (const :tag "Cut/Copy" :cut) (const :tag "Paste" :paste) - (const :tag "Highlight" :highlight))) + (const :tag "Highlight" :highlight) + (const :tag "LightIns" :lightins))) :group 'killing) -(defcustom x-select-enable-primary '(:highlight) +(defcustom x-select-enable-primary '(:highlight :lightins) "What cut/copy/paste/highlight ops should involve PRIMARY. In X11, PRIMARY is associated with 'highlight/middlebutton-insert' style data interchange. Cut/Copy: Set if Killing (e.g. C-w/M-w) in emacs should place text in the PRIMARY X11 selection. i.e. if you want to paste killed text into other programs on your desktop with the other programs' primary insertion function (typically a middle-button-click). This is not usual for X11 applications, typically Cut/Copied text is placed in the CLIPBOARD X11 selection, for clipboard-style X11 transfer. See `x-select-enable-clipboard' Paste: Set if Yanking (e.g. C-y) in emacs should check the primary selection for text placed there with other programs' primary selection functions (typically highlighting the text in other X11 programs makes it available as the primary selection). It is not usual in X11 to do so, however it may be convenient to do so in emacs, as it reduces mousing, allowing easy keyboard insertion of the primary selection. Note that if both `x-select-enable-clipboard' and this have Paste set, the clipboard -currently takes precendence when yanking. +currently takes precendence when yanking. You might want to +set `mouse-yank-at-click-action' to Yank if you set this, rather than +setting LightIns here. Highlight: Set if merely highlighting text (an active region) in emacs should immediately put it in the primary selection, if `select-active-regions' is set. This is usual for recent X11 programs, and allows you to insert the text into the other program with their primary insertion function (typically middle-button-click). It is recommended to unset `mouse-drag-copy-region' and -set `transient-mark-mode' if Highlight is set here." +set `transient-mark-mode' if Highlight is set here. + +LightIns: Set if the PRIMARY selection should be checked for +lightweight insert operations \( `mouse-yank-at-click' +with `mouse-yank-at-click-action' set to LightIns). This is normal +on X11." :type '(choice (const :tag "None" nil) (const :tag "All" t) (set :tag "Choose" (const :tag "Cut/Copy" :cut) (const :tag "Paste" :paste) - (const :tag "Highlight" :highlight))) + (const :tag "Highlight" :highlight) + (const :tag "LightIns" :lightins))) :group 'killing) (defcustom x-select-enable-cutbuffer nil "What cut/copy/paste/highlight ops shold involve legacy Cut Buffer 0. In X, cut buffers have long been superseded by clipboard and primary selections. However, some old X programs use them. If you need to exchange data between emacs and such programs via X cut buffers, you may want to set this to a non-nil value. @@ -2229,27 +2247,32 @@ place text into X Cut Buffer 0 Paste: Set if Yanking (e.g. C-y) in Emacs should check X Cut Buffer 0 for text. Highlight: Set if merely highlighting text (an active region) in emacs should immediately put it in X Cut Buffer 0, if `select-active-regions' is also set. It is recommended to unset `mouse-drag-copy-region' and -set `transient-mark-mode' if Highlight is set here." +set `transient-mark-mode' if Highlight is set here. + +LightIns: Set if X Cut Buffer 0 should be checked for +lightweight insert operations \( `mouse-yank-at-click' +with `mouse-yank-at-click-action' set to LightIns)." :type '(choice (const :tag "None" nil) (const :tag "All" t) (set :tag "Choose" (const :tag "Cut/Copy" :cut) (const :tag "Paste" :paste) - (const :tag "Highlight" :highlight))) + (const :tag "Highlight" :highlight) + (const :tag "LightIns" :lightins))) :group 'killing) (defun x-select-text-for-op (op text &optional push) "Make TEXT, a string, the primary and/or clipboard X selection. This function matches OP against `x-select-enable-primary' and `x-select-enable-clipboard'. OP must be one of :cut or :highlight, corresponding to use as an `interprogram-cut-function' or `interprogram-highlight-function' @@ -2444,24 +2467,90 @@ ;; 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) ))) + +;; Return the value of the current X selection for a "lightweight insertion" +;; that is not intended to interact with the kill ring. No, really. +;; 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, +;; unlike x-cut-buffer-or-selection-value, it should return the same text. +;; See interprogram-lightins-function docstring... +(defun x-cut-buffer-or-selection-value-for-lightins () + ;; With multi-tty, this function may be called from a tty frame. + (when (eq (framep (selected-frame)) 'x) + (let (clip-text primary-text cut-text) + (when (or (eq x-select-enable-clipboard t) + (member :lightins x-select-enable-clipboard)) + (setq clip-text (x-selection-value 'CLIPBOARD)) + (if (string= clip-text "") (setq clip-text nil))) + + (when (or (eq x-select-enable-primary t) + (member :lightins x-select-enable-primary)) + (setq primary-text (x-selection-value 'PRIMARY))) + + (when (or (eq x-select-enable-cutbuffer t) + (member :lightins x-select-enable-cutbuffer)) + (setq cut-text (x-get-cut-buffer 0)) + ;; try to decode cut buffer. + (setq cut-text + (let ((next-coding (or next-selection-coding-system 'iso-latin-1))) + (cond ;; check cut buffer + ((or (not cut-text) (string= cut-text "")) + nil) + (t ;; ICCCM says cut buffer always contain ISO-Latin-1, but + ;; use next-selection-coding-system if not nil. + (decode-coding-string + cut-text next-coding))))) + + ;; 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) + ))) + + + + + ;; Arrange for the kill and yank functions to set and check the clipboard. (setq interprogram-cut-function 'x-select-text) (setq interprogram-paste-function 'x-cut-buffer-or-selection-value) (setq interprogram-highlight-function 'x-select-text-for-highlight) +(setq interprogram-lightins-function 'x-cut-buffer-or-selection-value-for-lightins) (defun x-clipboard-yank () "Insert the clipboard contents, or the last stretch of killed text." (interactive "*") (let ((clipboard-text (x-selection-value 'CLIPBOARD)) (x-select-enable-clipboard t)) (if (and clipboard-text (> (length clipboard-text) 0)) (kill-new clipboard-text)) (yank)))