XEmacs 21.2.38 (Peisino)
[chise/xemacs-chise.git.1] / lisp / mouse.el
index ced0442..0c76138 100644 (file)
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 1988, 1992-4, 1997 Free Software Foundation, Inc.
 ;; Copyright (C) 1995 Tinker Systems
-;; Copyright (C) 1995, 1996 Ben Wing.
+;; Copyright (C) 1995, 1996, 2000 Ben Wing.
 
 ;; Maintainer: XEmacs Development Team
 ;; Keywords: mouse, dumped
 
 ;; This file is dumped with XEmacs (when window system support is compiled in).
 
+;;; Authorship:
+
+;; Probably originally derived from FSF 19 pre-release.
+;; much hacked upon by Jamie Zawinski and crew, pre-1994.
+;;   (only mouse-motion stuff currently remains from that era)
+;; all mouse-track stuff completely rewritten by Ben Wing, 1995-1996.
+;; mouse-eval-sexp and *-inside-extent-p from Stig, 1995.
+;; vertical divider code c. 1998 from ?.
+
 ;;; Code:
 
 (provide 'mouse)
 (global-set-key '(control button1) 'mouse-track-insert)
 (global-set-key '(control shift button1) 'mouse-track-delete-and-insert)
 (global-set-key '(meta button1) 'mouse-track-do-rectangle)
-
-;; drops are now handled in dragdrop.el (ograf@fga.de)
-
-;; enable drag regions (ograf@fga.de)
-;; if button2 is dragged from within a region, this becomes a drop
-;;
-;; this must be changed to the new api
-(if (featurep '(or offix cde mswindows))
-    (global-set-key 'button2 'mouse-drag-or-yank)
-  (global-set-key 'button2 'mouse-yank))
+(global-set-key 'button2 'mouse-track)
 
 (defgroup mouse nil
   "Window system-independent mouse support."
@@ -68,13 +68,13 @@ text is inserted."
   :group 'mouse)
 
 (defcustom mouse-highlight-text 'context
-  "*Choose the default double-click highlighting behaviour.
+  "*Choose the default double-click highlighting behavior.
 If set to `context', double-click will highlight words when the mouse
  is at a word character, or a symbol if the mouse is at a symbol
  character.
 If set to `word', double-click will always attempt to highlight a word.
 If set to `symbol', double-click will always attempt to highlight a
- symbol (the default behaviour in previous XEmacs versions)."
+ symbol (the default behavior in previous XEmacs versions)."
   :type '(choice (const context)
                 (const word)
                 (const symbol))
@@ -84,11 +84,54 @@ If set to `symbol', double-click will always attempt to highlight a
   "Function that is called upon by `mouse-yank' to actually insert text.")
 
 (defun mouse-consolidated-yank ()
+  "Insert the current selection or, if there is none under X insert
+the X cutbuffer.  A mark is pushed, so that the inserted text lies
+between point and mark."
   (interactive)
-  (case (device-type)
-    (x (x-yank-function))
-    (tty (yank))
-    (otherwise (yank))))
+  (if (and (not (console-on-window-system-p))
+          (and (featurep 'gpm)
+               (not gpm-minor-mode)))
+      (yank)
+    (push-mark)
+    (if (region-active-p)
+       (if (consp zmacs-region-extent)
+           ;; pirated code from insert-rectangle in rect.el
+           ;; perhaps that code should be modified to handle a list of extents
+           ;; as the rectangle to be inserted?
+           (let ((lines zmacs-region-extent)
+                 (insertcolumn (current-column))
+                 (first t))
+             (push-mark)
+             (while lines
+               (or first
+                   (progn
+                     (forward-line 1)
+                     (or (bolp) (insert ?\n))
+                     (move-to-column insertcolumn t)))
+               (setq first nil)
+               (insert (extent-string (car lines)))
+               (setq lines (cdr lines))))
+         (insert (extent-string zmacs-region-extent)))
+      (insert-selection t))))
+
+(defun insert-selection (&optional check-cutbuffer-p move-point-event)
+  "Insert the current selection into buffer at point."
+  (interactive "P")
+  ;; we fallback to the clipboard if the current selection is not existent
+  (let ((text (if check-cutbuffer-p
+                 (or (get-selection-no-error)
+                     (get-cutbuffer)
+                     (get-selection-no-error 'CLIPBOARD)
+                     (error "No selection, clipboard or cut buffer available"))
+               (or (get-selection-no-error)
+                   (get-selection 'CLIPBOARD)))))
+    (cond (move-point-event
+          (mouse-set-point move-point-event)
+          (push-mark (point)))
+         ((interactive-p)
+          (push-mark (point))))
+    (insert text)
+    ))
 
 \f
 (defun mouse-select ()
@@ -142,7 +185,6 @@ location."
 (defun click-inside-extent-p (click extent)
   "Return non-nil if the button event is within the primary selection-extent.
 Return nil otherwise."
-  ;; stig@hackvan.com
   (let ((ewin (event-window click))
        (epnt (event-point click)))
     (and ewin
@@ -163,7 +205,6 @@ Return nil otherwise."
   "Return t if point is within the bounds of the primary selection extent.
 Return t is point is at the end position of the extent.
 Return nil otherwise."
-  ;; stig@hackvan.com
   (and extent
        (eq (current-buffer)
           (extent-object extent))
@@ -171,40 +212,33 @@ Return nil otherwise."
        (>= (extent-end-position extent) (point))))
 
 (defun point-inside-selection-p ()
-  ;; by Stig@hackvan.com
   (or (point-inside-extent-p primary-selection-extent)
       (point-inside-extent-p zmacs-region-extent)))
 
-(defun mouse-drag-or-yank (event)
-  "Either drag or paste the current selection.
-If the variable `mouse-yank-at-point' is non-nil,
-move the cursor to the location of the click before pasting.
-This functions has to be improved.  Currently it is just a (working) test."
-  ;; by Oliver Graf <ograf@fga.de>
-  (interactive "e")
-  (if (click-inside-extent-p event zmacs-region-extent)
-      ;; okay, this is a drag
-      (cond ((featurep 'offix)
-            (offix-start-drag-region event
-                                     (extent-start-position zmacs-region-extent)
-                                     (extent-end-position zmacs-region-extent)))
-           ((featurep 'cde)
-            ;; should also work with CDE
-            (cde-start-drag-region event
-                                   (extent-start-position zmacs-region-extent)
-                                   (extent-end-position zmacs-region-extent)))
-           (t (error "No offix or CDE support compiled in")))
-    ;; no drag, call region-funct
-    (and (not mouse-yank-at-point)
-        (mouse-set-point event))
-    (funcall mouse-yank-function))
-  )
+(defun mouse-begin-drag-n-drop (event)
+  "Begin a drag-n-drop operation.
+EVENT should be the button event that initiated the drag.
+Returns whether a drag was begun."
+  ;; #### barely implemented.
+  (when (click-inside-selection-p event)
+    (cond ((featurep 'offix)
+          (offix-start-drag-region
+           event
+           (extent-start-position zmacs-region-extent)
+           (extent-end-position zmacs-region-extent))
+          t)
+         ((featurep 'cde)
+          ;; should also work with CDE
+          (cde-start-drag-region event
+                                 (extent-start-position zmacs-region-extent)
+                                 (extent-end-position zmacs-region-extent))
+          t))))
 
 (defun mouse-eval-sexp (click force-window)
   "Evaluate the sexp under the mouse.  Usually, this is the last sexp before
 the click, but if you click on a left paren, then it is the sexp beginning
 with the paren that is evaluated.  Also, since strings evaluate to themselves,
-they're fed to re-search-forward and the matched region is highlighted until
+they're fed to `re-search-forward' and the matched region is highlighted until
 the mouse button is released.
 
 Perhaps the most useful thing about this function is that the evaluation of
@@ -213,7 +247,6 @@ click, but to the current window and the current position of point.  Thus,
 you can use `mouse-eval-sexp' to interactively test code that acts upon a
 buffer...something you cannot do with the standard `eval-last-sexp' function.
 It's also fantastic for debugging regular expressions."
-  ;; by Stig@hackvan.com
   (interactive "e\nP")
   (let (exp val result-str)
     (setq exp (save-window-excursion
@@ -310,7 +343,7 @@ Display cursor at that position for a second."
       (switch-to-buffer val))))
 
 (defun narrow-window-to-region (m n)
-  "Narrow window to region between point and last mark"
+  "Narrow window to region between point and last mark."
   (interactive "r")
   (save-excursion
     (save-restriction
@@ -459,6 +492,36 @@ A value of nil disables the timeout feature."
   :type '(choice integer (const :tag "Disabled" nil))
   :group 'mouse)
 
+(defcustom mouse-track-activate-strokes '(button1-double-click button2-click)
+  "List of mouse strokes that can cause \"activation\" of the text extent
+under the mouse.  The exact meaning of \"activation\" is dependent on the
+text clicked on and the mode of the buffer, but typically entails actions
+such as following a hyperlink or selecting an entry in a completion buffer.
+
+Possible list entries are
+
+button1-click
+button1-double-click
+button1-triple-click
+button1-down
+button2-click
+button2-double-click
+button2-triple-click
+button2-down
+
+As a general rule, you should not use the \"-down\" values, because this
+makes it impossible to have other simultaneous actions, such as selection."
+  :type '(set
+         button1-click
+         button1-double-click
+         button1-triple-click
+         button1-down
+         button2-click
+         button2-double-click
+         button2-triple-click
+         button2-down)
+  :group 'mouse)
+
 (defvar mouse-track-x-threshold '(face-width 'default)
   "Minimum number of pixels in the X direction for a drag to be initiated.
 If the mouse is moved more than either the X or Y threshold while the
@@ -495,6 +558,15 @@ produce a number.")
                         'mouse-track-scroll-undefined
                         (copy-event event)))))
 
+(defun mouse-track-do-activate (event)
+  "Execute the activate function under EVENT, if any.
+Return true if the function was activated."
+  (let ((ex (extent-at-event event 'activate-function)))
+    (when ex
+      (funcall (extent-property ex 'activate-function)
+              event ex)
+      t)))
+
 (defun mouse-track-run-hook (hook event &rest args)
   ;; ugh, can't use run-hook-with-args-until-success because we have
   ;; to get the value using symbol-value-in-buffer.  Doing a
@@ -541,9 +613,9 @@ produce a number.")
 )
 
 (defun mouse-track (event)
-  "Make a selection with the mouse.  This should be bound to a mouse button.
-The behavior of XEmacs during mouse selection is customizable using various
-hooks and variables: see `mouse-track-click-hook', `mouse-track-drag-hook',
+  "Generalized mouse-button handler.  This should be bound to a mouse button.
+The behavior of this function is customizable using various hooks and
+variables: see `mouse-track-click-hook', `mouse-track-drag-hook',
 `mouse-track-drag-up-hook', `mouse-track-down-hook', `mouse-track-up-hook',
 `mouse-track-cleanup-hook', `mouse-track-multi-click-time',
 `mouse-track-scroll-delay', `mouse-track-x-threshold', and
@@ -676,7 +748,7 @@ at the initial click position."
       (let* ((edges (window-pixel-edges window))
             (row (event-y-pixel event))
             (text-start (nth 1 edges))
-            (text-end (+ (nth 3 edges))))
+            (text-end (nth 3 edges)))
        (if (or (< row text-start)
                (> row text-end))
            nil ;; Scroll
@@ -780,7 +852,7 @@ at the initial click position."
 ;; Decide what will be the SYMBOLP argument to
 ;; default-mouse-track-{beginning,end}-of-word, according to the
 ;; syntax of the current character and value of mouse-highlight-text.
-(defsubst default-mouse-symbolp (syntax)
+(defsubst default-mouse-track-symbolp (syntax)
   (cond ((eq mouse-highlight-text 'context)
         (eq syntax ?_))
        ((eq mouse-highlight-text 'symbol)
@@ -788,22 +860,33 @@ at the initial click position."
        (t
         nil)))
 
+;; Return t if point is at an opening quote character.  This is
+;; determined by testing whether the syntax of the following character
+;; is `string', which will always be true for opening quotes and
+;; always false for closing quotes.
+(defun default-mouse-track-point-at-opening-quote-p ()
+  (save-excursion
+    (forward-char 1)
+    (eq (buffer-syntactic-context) 'string)))
+
 (defun default-mouse-track-normalize-point (type forwardp)
   (cond ((eq type 'word)
         ;; trap the beginning and end of buffer errors
         (ignore-errors
           (setq type (char-syntax (char-after (point))))
           (if forwardp
-              (if (= type ?\()
+              (if (or (= type ?\()
+                      (and (= type ?\")
+                           (default-mouse-track-point-at-opening-quote-p)))
                   (goto-char (scan-sexps (point) 1))
-                (if (= type  ?\))
-                    (forward-char 1)
-                  (default-mouse-track-end-of-word
-                    (default-mouse-symbolp type))))
-            (if (= type ?\))
+                (default-mouse-track-end-of-word
+                  (default-mouse-track-symbolp type)))
+            (if (or (= type ?\))
+                    (and (= type ?\")
+                         (not (default-mouse-track-point-at-opening-quote-p))))
                 (goto-char (scan-sexps (1+ (point)) -1))
               (default-mouse-track-beginning-of-word
-                (default-mouse-symbolp type))))))
+                (default-mouse-track-symbolp type))))))
        ((eq type 'line)
         (if forwardp (end-of-line) (beginning-of-line)))
        ((eq type 'buffer)
@@ -949,7 +1032,7 @@ at the initial click position."
             ;; always sufficient but it seems to give something
             ;; approaching a 99% success rate.  Making it higher yet
             ;; would help guarantee success with the price that the
-            ;; delay would start to become noticable.
+            ;; delay would start to become noticeable.
             ;;
             (and (eq (console-type) 'x)
                  (sit-for 0.15 t))
@@ -1055,9 +1138,26 @@ at the initial click position."
                   (disown-selection)))))
       (setq default-mouse-track-down-event nil))))
 
+;; return t if the button or motion event involved the specified button.
+(defun default-mouse-track-event-is-with-button (event n)
+  (cond ((button-event-p event)
+        (= n (event-button event)))
+       ((motion-event-p event)
+        (memq (cdr
+               (assq n '((1 . button1) (2 . button2) (3 . button3)
+                         (4 . button4) (5 . button5))))
+              (event-modifiers event)))))
+
 (defun default-mouse-track-down-hook (event click-count)
-  (setq default-mouse-track-down-event (copy-event event))
-  nil)
+  (cond ((default-mouse-track-event-is-with-button event 1)
+        (if (and (memq 'button1-down mouse-track-activate-strokes)
+                 (mouse-track-do-activate event))
+            t
+          (setq default-mouse-track-down-event (copy-event event))
+          nil))
+       ((default-mouse-track-event-is-with-button event 2)
+        (and (memq 'button2-down mouse-track-activate-strokes)
+             (mouse-track-do-activate event)))))
 
 (defun default-mouse-track-cleanup-extents-hook ()
   (remove-hook 'pre-command-hook 'default-mouse-track-cleanup-extents-hook)
@@ -1078,7 +1178,8 @@ at the initial click position."
       (if (consp extent)               ; rectangle-p
          (mapcar func extent)
        (if extent
-           (funcall func extent))))))
+           (funcall func extent)))))
+  t)
 
 (defun default-mouse-track-cleanup-extent ()
   (let ((dead-func
@@ -1098,13 +1199,16 @@ at the initial click position."
          (setq default-mouse-track-extent nil)))))
 
 (defun default-mouse-track-drag-hook (event click-count was-timeout)
-  (default-mouse-track-deal-with-down-event click-count)
-  (default-mouse-track-set-point event default-mouse-track-window)
-  (default-mouse-track-cleanup-extent)
-  (default-mouse-track-next-move default-mouse-track-min-anchor
-    default-mouse-track-max-anchor
-    default-mouse-track-extent)
-  t)
+  (cond ((default-mouse-track-event-is-with-button event 1)
+        (default-mouse-track-deal-with-down-event click-count)
+        (default-mouse-track-set-point event default-mouse-track-window)
+        (default-mouse-track-cleanup-extent)
+        (default-mouse-track-next-move default-mouse-track-min-anchor
+          default-mouse-track-max-anchor
+          default-mouse-track-extent)
+        t)
+       ((default-mouse-track-event-is-with-button event 2)
+        (mouse-begin-drag-n-drop event))))
 
 (defun default-mouse-track-return-dragged-selection (event)
   (default-mouse-track-cleanup-extent)
@@ -1155,15 +1259,45 @@ at the initial click position."
     result))
 
 (defun default-mouse-track-drag-up-hook (event click-count)
-  (let ((result (default-mouse-track-return-dragged-selection event)))
-    (if result
-       (default-mouse-track-maybe-own-selection result 'PRIMARY)))
-  t)
+  (when (default-mouse-track-event-is-with-button event 1)
+    (let ((result (default-mouse-track-return-dragged-selection event)))
+      (if result
+         (default-mouse-track-maybe-own-selection result 'PRIMARY)))
+    t))
 
 (defun default-mouse-track-click-hook (event click-count)
-  (default-mouse-track-drag-hook event click-count nil)
-  (default-mouse-track-drag-up-hook event click-count)
-  t)
+  (cond ((default-mouse-track-event-is-with-button event 1)
+        (if (and
+             (or (and (= click-count 1)
+                      (memq 'button1-click
+                            mouse-track-activate-strokes))
+                 (and (= click-count 2)
+                      (memq 'button1-double-click
+                            mouse-track-activate-strokes))
+                 (and (= click-count 3)
+                      (memq 'button1-triple-click
+                            mouse-track-activate-strokes)))
+             (mouse-track-do-activate event))
+            t
+          (default-mouse-track-drag-hook event click-count nil)
+          (default-mouse-track-drag-up-hook event click-count)
+          t))
+       ((default-mouse-track-event-is-with-button event 2)
+        (if (and
+             (or (and (= click-count 1)
+                      (memq 'button2-click
+                            mouse-track-activate-strokes))
+                 (and (= click-count 2)
+                      (memq 'button2-double-click
+                            mouse-track-activate-strokes))
+                 (and (= click-count 3)
+                      (memq 'button2-triple-click
+                            mouse-track-activate-strokes)))
+             (mouse-track-do-activate event))
+            t
+          (mouse-yank event)
+          t))))
+
 
 (add-hook 'mouse-track-down-hook 'default-mouse-track-down-hook)
 (add-hook 'mouse-track-drag-hook 'default-mouse-track-drag-hook)
@@ -1328,7 +1462,7 @@ and `mode-motion-hook'."
         ;; vars is a list of glyph variables to check for a pointer
         ;; value.
         (vars (cond
-               ;; Checking if button is non-nil is not sufficent
+               ;; Checking if button is non-nil is not sufficient
                ;; since the pointer could be over a blank portion
                ;; of the toolbar.
                ((event-over-toolbar-p event)
@@ -1374,6 +1508,7 @@ and `mode-motion-hook'."
     (cond ((extentp help)
            (or inhibit-help-echo
                (eq help last-help-echo-object) ;save some time
+              (eq (selected-window) (minibuffer-window))
                (let ((hprop (extent-property help 'help-echo)))
                  (setq last-help-echo-object help)
                  (or (stringp hprop)
@@ -1384,11 +1519,12 @@ and `mode-motion-hook'."
                 (toolbar-button-enabled-p help))
           (or (not toolbar-help-enabled)
               (eq help last-help-echo-object) ;save some time
+              (eq (selected-window) (minibuffer-window))
               (let ((hstring (toolbar-button-help-string button)))
                 (setq last-help-echo-object help)
                 (or (stringp hstring)
                     (setq hstring (funcall hstring help)))
-                (show-help-echo hstring))))
+                (and hstring (show-help-echo hstring)))))
           (last-help-echo-object
           (clear-help-echo)))
     (if mouse-grabbed-buffer (setq buffer mouse-grabbed-buffer))
@@ -1414,7 +1550,7 @@ and `mode-motion-hook'."
 ;;
 (defun drag-window-divider (event)
   "Handle resizing windows by dragging window dividers.
-This is an intenal function, normally bound to button1 event in
+This is an internal function, normally bound to button1 event in
 window-divider-map. You would not call it, but you may bind it to
 other mouse buttons."
   (interactive "e")
@@ -1468,10 +1604,10 @@ other mouse buttons."
                 (setq last-timestamp (event-timestamp event))
                 ;; Enlarge the window, calculating change in characters
                 ;; of default font. Do not let the window to become
-                ;; less than alolwed minimum (not because that's critical
+                ;; less than allowed minimum (not because that's critical
                 ;; for the code performance, just the visual effect is
                 ;; better: when cursor goes to the left of the next left
-                ;; divider, the vindow being resized shrinks to minimal
+                ;; divider, the window being resized shrinks to minimal
                 ;; size.
                 (enlarge-window (max (- window-min-width (window-width window))
                                      (/ (- (event-x-pixel event) old-right)
@@ -1481,7 +1617,7 @@ other mouse buttons."
                 ;; if the change caused more than two windows to resize
                 ;; (shifting the whole stack right is ugly), or if the
                 ;; left window side has slipped (right side cannot be
-                ;; moved any funrther to the right, so enlarge-window
+                ;; moved any further to the right, so enlarge-window
                 ;; plays bad games with the left edge.
                 (if (or (/= (count-windows) (length old-edges-all-windows))
                         (/= old-left (car (window-pixel-edges window)))