(mouse-save-then-kill-delete-region): Turn off change hooks
[bpt/emacs.git] / lisp / mouse.el
index f6b1fa3..b447bff 100644 (file)
@@ -1,6 +1,6 @@
 ;;; mouse.el --- window system-independent mouse support.
 
-;;; Copyright (C) 1993 Free Software Foundation, Inc.
+;;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: hardware
 ;;; Indent track-mouse like progn.
 (put 'track-mouse 'lisp-indent-function 0)
 
+(defvar mouse-yank-at-point nil
+  "*If non-nil, mouse yank commands yank at point instead of at click.")
 \f
+(defun mouse-minibuffer-check (event)
+  (let ((w (posn-window (event-start event))))
+    (and (window-minibuffer-p w)
+        (not (minibuffer-window-active-p w))
+        (error "Minibuffer window is not active"))))
+
 (defun mouse-delete-window (click)
   "Delete the window you click on.
 This must be bound to a mouse click."
   (interactive "e")
+  (mouse-minibuffer-check click)
   (delete-window (posn-window (event-start click))))
 
+(defun mouse-select-window (click)
+  "Select the window clicked on; don't move point."
+  (interactive "e")
+  (mouse-minibuffer-check click)
+  (let ((oframe (selected-frame))
+       (frame (window-frame (posn-window (event-start click)))))
+    (select-window (posn-window (event-start click)))
+    (raise-frame frame)
+    (select-frame frame)
+    (or (eq frame oframe)
+       (set-mouse-position (selected-frame) (1- (frame-width)) 0))
+    (unfocus-frame)))
+
 (defun mouse-tear-off-window (click)
   "Delete the window clicked on, and create a new frame displaying its buffer."
   (interactive "e")
+  (mouse-minibuffer-check click)
   (let* ((window (posn-window (event-start click)))
         (buf (window-buffer window))
-        (frame (new-frame)))
+        (frame (make-frame)))
     (select-frame frame)
     (switch-to-buffer buf)
     (delete-window window)))
@@ -63,12 +86,10 @@ This must be bound to a mouse click."
 The window is split at the line clicked on.
 This command must be bound to a mouse click."
   (interactive "@e")
+  (mouse-minibuffer-check click)
   (let ((start (event-start click)))
     (select-window (posn-window start))
-    (let ((new-height (if (eq (posn-point start) 'vertical-scroll-bar)
-                         (scroll-bar-scale (posn-col-row start)
-                                           (1- (window-height)))
-                       (1+ (cdr (posn-col-row (event-end click))))))
+    (let ((new-height (1+ (cdr (posn-col-row (event-end click)))))
          (first-line window-min-height)
          (last-line (- (window-height) window-min-height)))
       (if (< last-line first-line)
@@ -81,6 +102,7 @@ This command must be bound to a mouse click."
 The window is split at the column clicked on.
 This command must be bound to a mouse click."
   (interactive "@e")
+  (mouse-minibuffer-check click)
   (let ((start (event-start click)))
     (select-window (posn-window start))
     (let ((new-width (1+ (car (posn-col-row (event-end click)))))
@@ -95,12 +117,10 @@ This command must be bound to a mouse click."
   "Move point to the position clicked on with the mouse.
 This should be bound to a mouse click event type."
   (interactive "e")
+  (mouse-minibuffer-check event)
   ;; Use event-end in case called from mouse-drag-region.
   ;; If EVENT is a click, event-end and event-start give same value.
   (let ((posn (event-end event)))
-    (and (window-minibuffer-p (posn-window posn))
-        (not (minibuffer-window-active-p (posn-window posn)))
-        (error "Minibuffer window is not active"))
     (select-window (posn-window posn))
     (if (numberp (posn-point posn))
        (goto-char (posn-point posn)))))
@@ -109,6 +129,7 @@ This should be bound to a mouse click event type."
   "Set the region to the text dragged over, and copy to kill ring.
 This should be bound to a mouse drag event."
   (interactive "e")
+  (mouse-minibuffer-check click)
   (let ((posn (event-start click))
        (end (event-end click)))
     (select-window (posn-window posn))
@@ -162,7 +183,7 @@ Upon exit, point is at the far edge of the newly visible text."
 (defvar mouse-drag-overlay (make-overlay 1 1))
 (overlay-put mouse-drag-overlay 'face 'region)
 
-(defvar mouse-selection-click-count nil)
+(defvar mouse-selection-click-count 0)
 
 (defun mouse-drag-region (start-event)
   "Set the region to the text that the mouse is dragged over.
@@ -171,6 +192,7 @@ This must be bound to a button-down mouse event.
 In Transient Mark mode, the highlighting remains once you
 release the mouse button.  Otherwise, it does not."
   (interactive "e")
+  (mouse-minibuffer-check start-event)
   (let* ((start-posn (event-start start-event))
         (start-point (posn-point start-posn))
         (start-window (posn-window start-posn))
@@ -211,31 +233,17 @@ release the mouse button.  Otherwise, it does not."
              (let ((range (mouse-start-end start-point (point) click-count)))
                (move-overlay mouse-drag-overlay (car range) (nth 1 range))))
 
-            ;; Are we moving on a different window on the same frame?
-            ((and (windowp (posn-window end))
-                  (eq (window-frame (posn-window end)) start-frame))
-             (let ((mouse-row
-                    (+ (nth 1 (window-edges (posn-window end)))
-                       (cdr (posn-col-row end)))))
+            (t
+             (let ((mouse-row (cdr (cdr (mouse-position)))))
                (cond
+                ((null mouse-row))
                 ((< mouse-row top)
                  (mouse-scroll-subr
                   (- mouse-row top) mouse-drag-overlay start-point))
                 ((and (not (eobp))
                       (>= mouse-row bottom))
                  (mouse-scroll-subr (1+ (- mouse-row bottom))
-                                    mouse-drag-overlay start-point)))))
-
-            (t
-             (let ((mouse-y (cdr (cdr (mouse-position))))
-                   (menu-bar-lines (or (cdr (assq 'menu-bar-lines
-                                                  (frame-parameters)))
-                                       0)))
-
-               ;; Are we on the menu bar?
-               (and (integerp mouse-y) (< mouse-y menu-bar-lines)
-                    (mouse-scroll-subr (- mouse-y menu-bar-lines)
-                                       mouse-drag-overlay start-point))))))))
+                                    mouse-drag-overlay start-point)))))))))
 
       (if (and (eq (get (event-basic-type event) 'event-kind) 'mouse-click)
               (eq (posn-window (event-end event)) start-window)
@@ -281,16 +289,21 @@ If DIR is positive skip forward; if negative, skip backward."
       (let ((temp start))
         (setq start end
               end temp)))
+  (setq mode (mod mode 3))
   (cond ((= mode 0)
         (list start end))
         ((and (= mode 1)
               (= start end)
-             (not (eobp))
+             (char-after start)
               (= (char-syntax (char-after start)) ?\())
-        (list start (save-excursion (forward-sexp 1) (point))))
+        (list start
+              (save-excursion
+                (goto-char start)
+                (forward-sexp 1)
+                (point))))
         ((and (= mode 1)
               (= start end)
-             (not (eobp))
+             (char-after start)
               (= (char-syntax (char-after start)) ?\)))
         (list (save-excursion 
                 (goto-char (1+ start))
@@ -319,6 +332,7 @@ If DIR is positive skip forward; if negative, skip backward."
 ;; Subroutine: set the mark where CLICK happened,
 ;; but don't do anything else.
 (defun mouse-set-mark-fast (click)
+  (mouse-minibuffer-check click)
   (let ((posn (event-start click)))
     (select-window (posn-window posn))
     (if (numberp (posn-point posn))
@@ -348,16 +362,22 @@ This must be bound to a mouse click."
   "Kill the region between point and the mouse click.
 The text is saved in the kill ring, as with \\[kill-region]."
   (interactive "e")
-  (let ((click-posn (posn-point (event-start click))))
+  (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)))))
 
 (defun mouse-yank-at-click (click arg)
   "Insert the last stretch of killed text at the position clicked on.
-Prefix arguments are interpreted as with \\[yank]."
+Also move point to one end of the text thus inserted (normally the end).
+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")
-  (mouse-set-point click)
+  (or mouse-yank-at-point (mouse-set-point click))
   (setq this-command 'yank)
   (yank arg))
 
@@ -378,26 +398,40 @@ This does not delete the region; it acts like \\[kill-ring-save]."
 (defvar mouse-save-then-kill-posn nil)
 
 (defun mouse-save-then-kill-delete-region (beg end)
-  ;; Delete just one char, so in case buffer is being modified
-  ;; for the first time, the undo list records that fact.
-  (delete-region beg
-                (+ beg (if (> end beg) 1 -1)))
-  (let ((buffer-undo-list buffer-undo-list))
-    ;; Undo that deletion--but don't change the undo list!
-    (primitive-undo 1 buffer-undo-list)
-    ;; Now delete the rest of the specified region,
-    ;; but don't record it.
-    (setq buffer-undo-list t)
-    (delete-region beg end))
-  (if (not (eq buffer-undo-list t))
-      (let ((tail buffer-undo-list))
-       ;; Search back in buffer-undo-list for the string
-       ;; that came from the first delete-region.
-       (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)))))))
+  ;; We must make our own undo boundaries
+  ;; because they happen automatically only for the current buffer.
+  (undo-boundary)
+  (if (or (= beg end) (eq buffer-undo-list t))
+      ;; If we have no undo list in this buffer,
+      ;; just delete.
+      (delete-region beg end)
+    ;; Delete, but make the undo-list entry share with the kill ring.
+    ;; First, delete just one char, so in case buffer is being modified
+    ;; for the first time, the undo list records that fact.
+    (let (before-change-function after-change-function
+         before-change-functions after-change-functions)
+      (delete-region beg
+                    (+ beg (if (> end beg) 1 -1))))
+    (let ((buffer-undo-list buffer-undo-list))
+      ;; Undo that deletion--but don't change the undo list!
+      (let (before-change-function after-change-function
+           before-change-functions after-change-functions)
+       (primitive-undo 1 buffer-undo-list))
+      ;; Now delete the rest of the specified region,
+      ;; but don't record it.
+      (setq buffer-undo-list t)
+      (if (/= (length (car kill-ring)) (- (max end beg) (min end beg)))
+         (error "Lossage in mouse-save-then-kill-delete-region"))
+      (delete-region beg end))
+    (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))
 
 (defun mouse-save-then-kill (click)
   "Save text to point in kill ring; the second time, kill the text.
@@ -411,11 +445,12 @@ 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." 
   (interactive "e")
+  (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 (> mouse-selection-click-count 0)
+    (if (> (mod mouse-selection-click-count 3) 0)
        (if (not (and (eq last-command 'mouse-save-then-kill)
                      (equal click-posn
                             (car (cdr-safe (cdr-safe mouse-save-then-kill-posn))))))
@@ -441,15 +476,21 @@ If you do this twice in the same position, the selection is killed."
              (mouse-show-mark))
          ;; If we click this button again without moving it,
          ;; that time kill.
-         (mouse-save-then-kill-delete-region (point) (mark)))
+         (mouse-save-then-kill-delete-region (point) (mark))
+         (setq mouse-selection-click-count 0)
+         (setq mouse-save-then-kill-posn nil))
       (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.
-         (mouse-save-then-kill-delete-region (point) (mark))
-       (if (or (eq last-command 'mouse-save-then-kill)
+         (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))
+       (if (or (and (eq last-command 'mouse-save-then-kill)
+                    mouse-save-then-kill-posn)
                (and mark-active transient-mark-mode)
                (and (eq last-command 'mouse-drag-region)
                     (or mark-even-if-inactive
@@ -480,7 +521,7 @@ If you do this twice in the same position, the selection is killed."
 (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-kill-secondary)
+(global-set-key [M-mouse-2] 'mouse-yank-secondary)
 
 ;; An overlay which records the current secondary selection
 ;; or else is deleted when there is no secondary selection.
@@ -496,6 +537,7 @@ If you do this twice in the same position, the selection is killed."
 Use \\[mouse-secondary-save-then-kill] to set the other end
 and complete the secondary selection."
   (interactive "e")
+  (mouse-minibuffer-check click)
   (let ((posn (event-start click)))
     (save-excursion
       (set-buffer (window-buffer (posn-window posn)))
@@ -512,6 +554,7 @@ and complete the secondary selection."
   "Set the secondary selection to the text that the mouse is dragged over.
 This must be bound to a mouse drag event."
   (interactive "e")
+  (mouse-minibuffer-check click)
   (let ((posn (event-start click))
        beg
        (end (event-end click)))
@@ -529,6 +572,7 @@ This must be bound to a mouse drag event."
 Highlight the drag area as you move the mouse.
 This must be bound to a button-down mouse event."
   (interactive "e")
+  (mouse-minibuffer-check start-event)
   (let* ((start-posn (event-start start-event))
         (start-point (posn-point start-posn))
         (start-window (posn-window start-posn))
@@ -547,7 +591,7 @@ This must be bound to a button-down mouse event."
          (setq mouse-secondary-overlay
                (make-overlay (point) (point))))
       (overlay-put mouse-secondary-overlay 'face 'secondary-selection)
-      (if (> click-count 0)
+      (if (> (mod click-count 3) 0)
          ;; Double or triple press: make an initial selection
          ;; of one word or line.
          (let ((range (mouse-start-end start-point start-point click-count)))
@@ -586,32 +630,17 @@ This must be bound to a button-down mouse event."
                                              click-count)))
                  (move-overlay mouse-secondary-overlay
                                (car range) (nth 1 range))))
-
-              ;; Are we moving on a different window on the same frame?
-              ((and (windowp (posn-window end))
-                    (eq (window-frame (posn-window end)) start-frame))
-               (let ((mouse-row
-                      (+ (nth 1 (window-edges (posn-window end)))
-                         (cdr (posn-col-row end)))))
-                 (cond
-                  ((< mouse-row top)
-                   (mouse-scroll-subr
-                    (- mouse-row top) mouse-secondary-overlay start-point))
-                  ((and (not (eobp))
-                        (>= mouse-row bottom))
-                   (mouse-scroll-subr (1+ (- mouse-row bottom))
-                                      mouse-drag-overlay start-point)))))
-
-              (t
-               (let ((mouse-y (cdr (cdr (mouse-position))))
-                     (menu-bar-lines (or (cdr (assq 'menu-bar-lines
-                                                    (frame-parameters)))
-                                         0)))
-
-                 ;; Are we on the menu bar?
-                 (and (integerp mouse-y) (< mouse-y menu-bar-lines)
-                      (mouse-scroll-subr (- mouse-y menu-bar-lines)
-                                         mouse-secondary-overlay start-point))))))))
+               (t
+                (let ((mouse-row (cdr (cdr (mouse-position)))))
+                  (cond
+                   ((null mouse-row))
+                   ((< mouse-row top)
+                    (mouse-scroll-subr
+                     (- mouse-row top) mouse-secondary-overlay start-point))
+                   ((and (not (eobp))
+                         (>= mouse-row bottom))
+                    (mouse-scroll-subr (1+ (- mouse-row bottom))
+                                       mouse-secondary-overlay start-point)))))))))
 
        (if (and (eq (get (event-basic-type event) 'event-kind) 'mouse-click)
                 (eq (posn-window (event-end event)) start-window)
@@ -619,123 +648,169 @@ This must be bound to a button-down mouse event."
            (if (marker-position mouse-secondary-start)
                (save-window-excursion
                  (delete-overlay mouse-secondary-overlay)
+                 (x-set-selection 'SECONDARY nil)
                  (select-window start-window)
                  (save-excursion
                    (goto-char mouse-secondary-start)
                    (sit-for 1)))
-             (kill-ring-save (overlay-start mouse-secondary-overlay)
-                             (overlay-end mouse-secondary-overlay))))))))
+             (x-set-selection
+              'SECONDARY
+              (buffer-substring (overlay-start mouse-secondary-overlay)
+                                (overlay-end mouse-secondary-overlay)))))))))
+
+(defun mouse-yank-secondary (click)
+  "Insert the secondary 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")
+  (or mouse-yank-at-point (mouse-set-point click))
+  (insert (x-get-selection 'SECONDARY)))
 
 (defun mouse-kill-secondary ()
-  "Kill the text in the secondary selection."
-  (interactive "*")
-  (kill-region (overlay-start mouse-secondary-overlay)
-              (overlay-end mouse-secondary-overlay))
+  "Kill the text in the secondary selection.
+This is intended more as a keyboard command than as a mouse command
+but it can work as either one.
+
+The current buffer (in case of keyboard use), or the buffer clicked on,
+must be the one that the secondary selection is in.  This requirement
+is to prevent accidents."
+  (interactive)
+  (let* ((keys (this-command-keys))
+        (click (elt keys (1- (length keys)))))
+    (or (eq (overlay-buffer mouse-secondary-overlay)
+           (if (listp click)
+               (window-buffer (posn-window (event-start click)))
+             (current-buffer)))
+       (error "Select or click on the buffer where the secondary selection is")))
+  (save-excursion
+    (set-buffer (overlay-buffer mouse-secondary-overlay))
+    (kill-region (overlay-start mouse-secondary-overlay)
+                (overlay-end mouse-secondary-overlay)))
   (delete-overlay mouse-secondary-overlay)
+  (x-set-selection 'SECONDARY nil)
   (setq mouse-secondary-overlay nil))
 
 (defun mouse-secondary-save-then-kill (click)
   "Save text to point in kill ring; the second time, kill the text.
-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.
+You must use this in a buffer where you have recently done \\[mouse-start-secondary].
+If the text between where you did \\[mouse-start-secondary] and where
+you use this command matches the text at the front of the kill ring,
+this command 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.
+which prepares for a second click with this command 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 have already made a secondary selection in that buffer,
+this command extends or retracts the selection to where you click.
+If you do this again in a different position, it extends or retracts
+again.  If you do this twice in the same position, it kills the selection."
   (interactive "e")
+  (mouse-minibuffer-check click)
   (let ((posn (event-start click))
        (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 (> mouse-selection-click-count 0)
-       (if (not (and (eq last-command 'mouse-secondary-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 (overlay-start mouse-secondary-overlay)))
-                    (abs (- click-posn (overlay-end mouse-secondary-overlay))))
-                 (move-overlay mouse-secondary-overlay (car range)
-                               (overlay-end mouse-secondary-overlay))
+    (or (eq (window-buffer (posn-window posn))
+           (or (and mouse-secondary-overlay
+                    (overlay-buffer mouse-secondary-overlay))
+               (if mouse-secondary-start
+                   (marker-buffer mouse-secondary-start))))
+       (error "Wrong buffer"))
+    (save-excursion
+      (set-buffer (window-buffer (posn-window posn)))
+      (if (> (mod mouse-selection-click-count 3) 0)
+         (if (not (and (eq last-command 'mouse-secondary-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 (overlay-start mouse-secondary-overlay)))
+                      (abs (- click-posn (overlay-end mouse-secondary-overlay))))
+                   (move-overlay mouse-secondary-overlay (car range)
+                                 (overlay-end mouse-secondary-overlay))
                  (move-overlay mouse-secondary-overlay
                                (overlay-start mouse-secondary-overlay)
                                (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.)
-             (setcar kill-ring (buffer-substring
-                                (overlay-start mouse-secondary-overlay)
-                                (overlay-end mouse-secondary-overlay)))
-             (if interprogram-cut-function
-                 (funcall interprogram-cut-function (car kill-ring)))
-             ;; Arrange for a repeated mouse-3 to kill this region.
-             (setq mouse-save-then-kill-posn
-                   (list (car kill-ring) (point) click-posn)))
-         ;; If we click this button again without moving it,
-         ;; that time kill.
-         (progn
-           (mouse-save-then-kill-delete-region
-            (overlay-start mouse-secondary-overlay)
-            (overlay-end mouse-secondary-overlay))
-           (delete-overlay mouse-secondary-overlay)))
-      (if (and (eq last-command 'mouse-secondary-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-secondary-save-then-kill, delete the text from the buffer.
-         (progn
-           (mouse-save-then-kill-delete-region
-            (overlay-start mouse-secondary-overlay)
-            (overlay-end mouse-secondary-overlay))
-           (delete-overlay mouse-secondary-overlay))
-       (if (overlay-start mouse-secondary-overlay)
-           ;; We have a selection, so adjust it.
+               ;; 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.)
+               (setcar kill-ring (buffer-substring
+                                  (overlay-start mouse-secondary-overlay)
+                                  (overlay-end mouse-secondary-overlay)))
+               (if interprogram-cut-function
+                   (funcall interprogram-cut-function (car kill-ring)))
+               ;; Arrange for a repeated mouse-3 to kill this region.
+               (setq mouse-save-then-kill-posn
+                     (list (car kill-ring) (point) click-posn)))
+           ;; If we click this button again without moving it,
+           ;; that time kill.
            (progn
-             (select-window (posn-window posn))
-             (if (numberp click-posn)
-                 (progn
-                   ;; Move whichever end of the region is closer to the click.
-                   ;; That is what xterm does, and it seems reasonable.
-                   (if (< (abs (- click-posn (overlay-start mouse-secondary-overlay)))
-                          (abs (- click-posn (overlay-end mouse-secondary-overlay))))
-                       (move-overlay mouse-secondary-overlay click-posn
-                                     (overlay-end mouse-secondary-overlay))
+             (mouse-save-then-kill-delete-region
+              (overlay-start mouse-secondary-overlay)
+              (overlay-end mouse-secondary-overlay))
+             (setq mouse-save-then-kill-posn nil)
+             (setq mouse-selection-click-count 0)
+             (delete-overlay mouse-secondary-overlay)))
+       (if (and (eq last-command 'mouse-secondary-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-secondary-save-then-kill, delete the text from the buffer.
+           (progn
+             (mouse-save-then-kill-delete-region
+              (overlay-start mouse-secondary-overlay)
+              (overlay-end mouse-secondary-overlay))
+             (setq mouse-save-then-kill-posn nil)
+             (delete-overlay mouse-secondary-overlay))
+         (if (overlay-start mouse-secondary-overlay)
+             ;; We have a selection, so adjust it.
+             (progn
+               (if (numberp click-posn)
+                   (progn
+                     ;; Move whichever end of the region is closer to the click.
+                     ;; That is what xterm does, and it seems reasonable.
+                     (if (< (abs (- click-posn (overlay-start mouse-secondary-overlay)))
+                            (abs (- click-posn (overlay-end mouse-secondary-overlay))))
+                         (move-overlay mouse-secondary-overlay click-posn
+                                       (overlay-end mouse-secondary-overlay))
                        (move-overlay mouse-secondary-overlay
                                      (overlay-start mouse-secondary-overlay)
                                      click-posn))
-                   (setq deactivate-mark nil)))
-             (setcar kill-ring (buffer-substring
-                                (overlay-start mouse-secondary-overlay)
-                                (overlay-end mouse-secondary-overlay)))
-             (if interprogram-cut-function
-                 (funcall interprogram-cut-function (car kill-ring))))
-         (if mouse-secondary-start
-             ;; All we have is one end of a selection,
-             ;; so put the other end here.
-             (let ((start (+ 0 mouse-secondary-start)))
-               (set-buffer (window-buffer (posn-window (event-start click))))
-               (kill-ring-save start click-posn)
-               (if mouse-secondary-overlay
-                   (move-overlay mouse-secondary-overlay start click-posn)
-                 (setq mouse-secondary-overlay (make-overlay start click-posn)))
-               (overlay-put mouse-secondary-overlay 'face 'secondary-selection))))
-       (setq mouse-save-then-kill-posn
-             (list (car kill-ring) (point) click-posn))))))
+                     (setq deactivate-mark nil)))
+               (setcar kill-ring (buffer-substring
+                                  (overlay-start mouse-secondary-overlay)
+                                  (overlay-end mouse-secondary-overlay)))
+               (if interprogram-cut-function
+                   (funcall interprogram-cut-function (car kill-ring))))
+           (if mouse-secondary-start
+               ;; All we have is one end of a selection,
+               ;; so put the other end here.
+               (let ((start (+ 0 mouse-secondary-start)))
+                 (kill-ring-save start click-posn)
+                 (if mouse-secondary-overlay
+                     (move-overlay mouse-secondary-overlay start click-posn)
+                   (setq mouse-secondary-overlay (make-overlay start click-posn)))
+                 (overlay-put mouse-secondary-overlay 'face 'secondary-selection))))
+         (setq mouse-save-then-kill-posn
+               (list (car kill-ring) (point) click-posn))))
+      (x-set-selection 'SECONDARY
+                      (if (overlay-buffer mouse-secondary-overlay)
+                          (buffer-substring
+                           (overlay-start mouse-secondary-overlay)
+                           (overlay-end mouse-secondary-overlay)))))))
 \f
 (defun mouse-buffer-menu (event)
   "Pop up a menu of buffers for selection with the mouse.
 This switches buffers in the window that you clicked on,
 and selects that window."
   (interactive "e")
+  (mouse-minibuffer-check event)
   (let ((menu
         (list "Buffer Menu"
               (cons "Select Buffer"
@@ -1104,20 +1179,6 @@ and selects that window."
 \f
 ;; Choose a completion with the mouse.
 
-;; Delete the longest partial match for STRING
-;; that can be found before POINT.
-(defun mouse-delete-max-match (string)
-  (let ((len (min (length string)
-                 (- (point-max) (point-min)))))
-    (goto-char (max (point-min) (- (point) (length string))))
-    (while (and (> len 0)
-               (let ((tail (buffer-substring (point)
-                                             (+ (point) len))))
-                 (not (string= tail (substring string 0 len)))))
-      (setq len (1- len))
-      (forward-char 1))
-    (delete-char len)))
-
 (defun mouse-choose-completion (event)
   "Click on an alternative in the `*Completions*' buffer to choose it."
   (interactive "e")
@@ -1125,17 +1186,34 @@ and selects that window."
         choice)
     (save-excursion
       (set-buffer (window-buffer (posn-window (event-start event))))
+      (if completion-reference-buffer
+         (setq buffer completion-reference-buffer))
       (save-excursion
        (goto-char (posn-point (event-start event)))
-       (skip-chars-backward "^ \t\n")
-       (let ((beg (point)))
+       (let (beg end)
          (skip-chars-forward "^ \t\n")
-         (setq choice (buffer-substring beg (point))))))
-    (set-buffer buffer)
-    (mouse-delete-max-match choice)
-    (insert choice)
-    (and (equal buffer (window-buffer (minibuffer-window)))
-        (minibuffer-complete-and-exit))))
+         (while (looking-at " [^ \n\t]")
+           (forward-char 1)
+           (skip-chars-forward "^ \t\n"))
+         (setq end (point))
+         (skip-chars-backward "^ \t\n")
+         (while (and (= (preceding-char) ?\ )
+                     (not (and (> (point) (1+ (point-min)))
+                               (= (char-after (- (point) 2)) ?\ ))))
+           (backward-char 1)
+           (skip-chars-backward "^ \t\n"))
+         (setq beg (point))
+         (setq choice (buffer-substring beg end)))))
+    (let ((owindow (selected-window)))
+      (select-window (posn-window (event-start event)))
+      (if (and (one-window-p t 'selected-frame)
+              (window-dedicated-p (selected-window)))
+         ;; This is a special buffer's frame
+         (iconify-frame (selected-frame))
+       (or (window-dedicated-p (selected-window))
+           (bury-buffer)))
+      (select-window owindow))
+    (choose-completion-string choice buffer)))
 \f
 ;; Font selection.
 
@@ -1153,14 +1231,14 @@ and selects that window."
 (defvar x-fixed-font-alist
   '("Font menu"
     ("Misc"
-     ("6x10" "-misc-fixed-medium-r-semicondensed--10-110-75-75-c-60-*-1")
-     ("6x12" "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-*-1")
-     ("6x13" "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-*-1")
+     ("6x10" "-misc-fixed-medium-r-normal--10-100-75-75-c-60-*-1" "6x10")
+     ("6x12" "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-*-1" "6x12")
+     ("6x13" "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-*-1" "6x13")
      ("lucida 13"
       "-b&h-lucidatypewriter-medium-r-normal-sans-0-0-0-0-m-0-*-1")
-     ("7x13" "-misc-fixed-medium-r-normal--13-120-75-75-c-70-*-1")
-     ("7x14" "-misc-fixed-medium-r-normal--14-130-75-75-c-70-*-1")
-     ("9x15" "-misc-fixed-medium-r-normal--15-140-*-*-c-*-*-1")
+     ("7x13" "-misc-fixed-medium-r-normal--13-120-75-75-c-70-*-1" "7x13")
+     ("7x14" "-misc-fixed-medium-r-normal--14-130-75-75-c-70-*-1" "7x14")
+     ("9x15" "-misc-fixed-medium-r-normal--15-140-*-*-c-*-*-1" "9x15")
      ("")
      ("clean 8x8" "-schumacher-clean-medium-r-normal--*-80-*-*-c-*-*-1")
      ("clean 8x14" "-schumacher-clean-medium-r-normal--*-140-*-*-c-*-*-1")
@@ -1209,20 +1287,22 @@ and selects that window."
     )
   "X fonts suitable for use in Emacs.")
 
-(defun mouse-set-font (&optional font)
+(defun mouse-set-font (&rest fonts)
   "Select an emacs font from a list of known good fonts"
   (interactive
    (x-popup-menu last-nonmenu-event x-fixed-font-alist))
-  (if font
-      (progn (modify-frame-parameters (selected-frame)
-                                     (list (cons 'font font)))
-            ;; Update some standard faces too.
-            (set-face-font 'bold nil (selected-frame)) 
-            (make-face-bold 'bold (selected-frame) t)
-            (set-face-font 'italic nil (selected-frame))
-            (make-face-italic 'italic (selected-frame) t)
-            (set-face-font 'bold-italic nil (selected-frame))
-            (make-face-bold-italic 'bold-italic (selected-frame) t))))
+  (if fonts
+      (let (font)
+       (while fonts
+         (condition-case nil
+             (progn
+               (set-default-font (car fonts))
+               (setq font (car fonts))
+               (setq fonts nil))
+           (error
+            (setq fonts (cdr fonts)))))
+       (if (null font)
+           (error "Font not found")))))
 \f
 ;;; Bindings for mouse commands.
 
@@ -1245,69 +1325,10 @@ and selects that window."
 ;; Replaced with dragging mouse-1
 ;; (global-set-key [S-mouse-1] 'mouse-set-mark)
 
-(global-set-key [mode-line mouse-1] 'mouse-delete-other-windows)
+(global-set-key [mode-line mouse-1] 'mouse-select-window)
+(global-set-key [mode-line mouse-2] 'mouse-delete-other-windows)
 (global-set-key [mode-line mouse-3] 'mouse-delete-window)
-(global-set-key [mode-line S-mouse-2] 'mouse-split-window-horizontally)
-\f
-;; Define the mouse help menu tree.
-
-(defvar help-menu-map '(keymap "Help"))
-(global-set-key [C-down-mouse-2] help-menu-map)
-
-(defvar help-apropos-map (make-sparse-keymap "Is there a command that..."))
-(defvar help-keys-map (make-sparse-keymap "Key Commands <==> Functions"))
-(defvar help-manual-map (make-sparse-keymap "Manual and tutorial"))
-(defvar help-misc-map (make-sparse-keymap "Odds and ends"))
-(defvar help-modes-map (make-sparse-keymap "Modes"))
-(defvar help-admin-map (make-sparse-keymap "Administrivia"))
-
-(define-key help-menu-map [apropos]
-  (cons "@Is there a command that..." help-apropos-map))
-(define-key help-menu-map [keys]
-  (cons "@Key Commands <==> Functions" help-keys-map))
-(define-key help-menu-map [manuals]
-  (cons "@Manual and tutorial" help-manual-map))
-(define-key help-menu-map [misc]
-  (cons "@Odds and ends" help-misc-map))
-(define-key help-menu-map [modes]
-  (cons "@Modes" help-modes-map))
-(define-key help-menu-map [admin]
-  (cons "@Administrivia" help-admin-map))
-
-(define-key help-apropos-map "c" '("Command Apropos" . command-apropos))
-(define-key help-apropos-map "a" '("Apropos" . apropos))
-
-(define-key help-keys-map "b"
-  '("List all keystroke commands" . describe-bindings))
-(define-key help-keys-map "c"
-  '("Describe key briefly" . describe-key-briefly))
-(define-key help-keys-map "k"
-  '("Describe key verbose" . describe-key))
-(define-key help-keys-map "f"
-  '("Describe Lisp function" . describe-function))
-(define-key help-keys-map "w"
-  '("Where is this command" . where-is))
-
-(define-key help-manual-map "i" '("Info system" . info))
-(define-key help-manual-map "t"
-  '("Invoke Emacs tutorial" . help-with-tutorial))
-
-(define-key help-misc-map "l" '("Last 100 Keystrokes" . view-lossage))
-(define-key help-misc-map "s" '("Describe syntax table" . describe-syntax))
-
-(define-key help-modes-map "m"
-  '("Describe current major mode" . describe-mode))
-(define-key help-modes-map "b"
-  '("List all keystroke commands" . describe-bindings))
-
-(define-key help-admin-map "n"
-  '("View Emacs news" . view-emacs-news))
-(define-key help-admin-map "l"
-  '("View Emacs copying conditions" . describe-copying))
-(define-key help-admin-map "d"
-  '("Describe distribution" . describe-distribution))
-(define-key help-admin-map "w"
-  '("Describe (non)warranty" . describe-no-warranty))
+(global-set-key [mode-line C-mouse-2] 'mouse-split-window-horizontally)
 
 (provide 'mouse)