From:	CSBVAX::MRGATE!info-gnu-emacs-request@prep.ai.mit.edu@SMTP  1-JUL-1988 14:02
To:	ARISIA::EVERHART
Subj:	X11 cut buffer


Received: from TUT.CIS.OHIO-STATE.EDU by prep.ai.mit.edu; Tue, 28 Jun 88 22:41:56 EST
Received: by tut.cis.ohio-state.edu (5.54/2.0)
	id AA05555; Tue, 28 Jun 88 23:04:49 EDT
Received: from USENET by tut.cis.ohio-state.edu with netnews
	for info-gnu-emacs@prep.ai.mit.edu (info-gnu-emacs@prep.ai.mit.edu)
	(contact usenet@tut.cis.ohio-state.edu if you have questions)
Date: 29 Jun 88 00:04:55 GMT
From: spar!hastings@decwrl.dec.com  (Reed Hastings)
Organization: SPAR - Schlumberger Palo Alto Research
Subject: X11 cut buffer
Message-Id: <1512@spar.SPAR.SLB.COM>
Sender: info-gnu-emacs-request@prep.ai.mit.edu
To: info-gnu-emacs@prep.ai.mit.edu


For those running gnumacs on X11, here is some code that helps
to simplify the problem of X and gnu each having their own 
cut buffers.  Ideally the X cut buffer would always be equal 
to the top of the emacs kill ring.  This code implements that.
Thus, you can put things on the X cut
buffer with C-k, and get them with C-y.  The mouse becomes
just a different interface to the C-k, C-y family.  If you
put something into the X cut buffer from, say, xterm, you can
also retrieve it with C-y (or with the mouse interface to C-y).
At all times, the X cut buffer and the top of the kill ring
hold the thing.

This article contains
1. a table suitable for tbl <file> | troff which documents the 
   mouse button bindings.

2. some lisp code which you should save in the gnu lisp directory
   with the name x-mouse-patch-for-cut-buffers.el.

To install it put the form (require 'x-mouse-patch-for-cut-buffers)
at the *end* of x-mouse.el.  This may work for X10, too.

Reed Hastings   hastings@spar.slb.com


========================= mouse binding table ===============
..\" X windows GNU Emacs key bindings.
..\" Print with `tbl <this-file> | troff`
..\"
..rs
..sp 1i
..ps 14pt
..vs 14pt
..TS
box;
cfI s s
c | c | c
l | l | l.
Gnumacs Mouse Bindings for X11
=
Key	Button	Function
_
Unshifted	left	Move point to the mouse cursor
\^	middle	Paste text at the mouse cursor  (like C-y)
\^	right	Copy text between point and mouse cursor
\^		  but don't erase it (like M-w)
_
Control	middle	Unpaste, Rotate kill ring, and Paste (like M-y),
\^		  use after middle click, don't move mouse.
\^	right	Cut (kill) text between point and mouse cursor
\^		  (like C-w)
_
Shift	left	Buffer menu
\^	middle	Help
\^	right	Split window
_
Control-Shift	right	Unsplit window
_
..TE

Think of the X cut buffer as the top of the emacs kill ring.
You can put things in the X cut buffer with C-k, and you can put
things into the emacs kill ring from xterm or other X applications, and
access them through C-y.  The mouse buttons in emacs just give 
another way to invoke the C-k, C-y family of commands.

======================== end of mouse binding table =================

;;;======================  x-mouse-patch-for-cut-buffers.el ==========

;;; Reed Hastings 20 Jun 88  hastings@spar.slb.com

;;; 1. Each push onto the kill ring causes a stuff into the X cut buffer.
;;; 2. Each yank from the kill ring actually yanks from the X cut buffer.
;;; 3. Each yank-pop from the kill ring yanks/rotates from the kill ring,
;;;    and updates the X cut buffer.
;;; 4. There is a mouse interface to pushing and popping the unified
;;;    cut buffer/ring.

(provide 'x-mouse-patch-for-cut-buffers)

(define-key mouse-map x-button-left 'x-mouse-set-point)
(define-key mouse-map x-button-middle 'x-yank)
(define-key mouse-map x-button-right 'x-cut-text)

(define-key mouse-map x-button-c-middle 'x-yank-pop)
(define-key mouse-map x-button-c-right 'x-cut-and-wipe-text)

(define-key mouse-map x-button-s-left 'x-buffer-menu)
(define-key mouse-map x-button-s-middle 'x-help)
(define-key mouse-map x-button-s-right 'x-mouse-select-and-split)

(define-key mouse-map x-button-c-s-right 'x-mouse-keep-one-window)


;;; the way yank and yank-pop in simple.el communicate is by 
;;; setting the var last-command.
;;; Because of the way the mouse is hacked into Gnu, last-command is
;;; x-mouse-flush-queue, and we have to use a 
;;; different procedure.  We record the mouse position.  If the mouse
;;; moves the yank/yank-pop/yank-pop... chain is broken.  This is gross.
;;; If anyone knows how, please fix last command so we can use it.

(defvar mouse-position-on-last-yank nil
  "hack holder for yank/yank-top communication.")

(defun x-yank (arg)
  "Yank from X cut buffer (which is the same as the top of the
emacs kill ring) after moving the poing to the mouse cursor"
    (x-mouse-set-point arg)
    (yank nil)
    (setq mouse-position-on-last-yank arg)) ;; hack for yank-pop's benefit

(defun x-yank-pop (arg)
  (if (equal arg mouse-position-on-last-yank)
      (progn (let ((last-command 'yank)) 
	       (yank-pop 1)))
    (setq mouse-position-on-last-yank nil)
    (error "Mouse cursor has moved since last yank. Hold it still to cycle the kill ring")))

;;; from simple.el
(defun copy-region-as-kill (beg end)
  "Save the region as if killed, but don't kill it."
  (interactive "r")
  (if (eq last-command 'kill-region)
      (kill-append (buffer-substring beg end) (< end beg))
    (let ((this-string (buffer-substring beg end)))
      (copy-to-window-system-cut-buffer this-string)
      (setq kill-ring (cons this-string kill-ring)))
    (if (> (length kill-ring) kill-ring-max)
	(setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
  (setq this-command 'kill-region)
  (setq kill-ring-yank-pointer kill-ring))

;;; from simple.el
(defun kill-append (string before-p)
  (let ((new-top (if before-p
		     (concat string (car kill-ring))
		   (concat (car kill-ring) string))))
    (setcar kill-ring new-top)
    (copy-to-window-system-cut-buffer new-top)))
	  
(defun copy-to-window-system-cut-buffer  (string)
  (if window-system
      (x-store-cut-buffer string)))


;;; from simple.el
(defun yank (&optional arg)
  "Reinsert the last stretch of killed text.
More precisely, reinsert the stretch of killed text most recently
killed OR yanked.
With just C-U as argument, same but put point in front (and mark at end).
With argument n, reinsert the nth most recently killed stretch of killed
text.
See also the command \\[yank-pop]."
  (interactive "*P")
  (rotate-yank-pointer (if (listp arg) 0
			 (if (eq arg '-) -1
			   (1- arg))))
  (push-mark (point))
  (if (listp arg);;(normal case)  we are yanking from the top
      ;; of the ring, so we do have to hassle
      ;; with the X cut buffer.
      ;;see if cut buffer has changed
      (if (not (string-equal
		(x-get-cut-buffer)
		(car kill-ring-yank-pointer)))
	  ;; yes? then push the new cut buffer contents onto the kill ring
	  (setq kill-ring (setq kill-ring-yank-pointer
				(cons (x-get-cut-buffer) kill-ring)))))
  (insert (car kill-ring-yank-pointer))	      
  (if (consp arg)
      (exchange-point-and-mark)))

;;; from simple.el
(defun rotate-yank-pointer (arg)
  "Rotate the yanking point in the kill ring."
  (interactive "p")
  (if (not (= 0 arg))
      (let ((length (length kill-ring)))
	(if (zerop length)
	    (error "Kill ring is empty")
	  (setq kill-ring-yank-pointer
		(nthcdr (% (+ arg (- length (length kill-ring-yank-pointer)))
			   length)
			kill-ring))
	  (copy-to-window-system-cut-buffer (car kill-ring-yank-pointer))))))
