(mode-line-mode-menu): Move before (new) first use.
[bpt/emacs.git] / lisp / mouse.el
CommitLineData
be010748 1;;; mouse.el --- window system-independent mouse support
84176303 2
0d30b337 3;; Copyright (C) 1993, 1994, 1995, 1999, 2000, 2001, 2002, 2003,
48d33090 4;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
eea8d4ef 5
84176303 6;; Maintainer: FSF
de420e82 7;; Keywords: hardware, mouse
84176303 8
be010748 9;; This file is part of GNU Emacs.
72ea54a4 10
be010748
RS
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
b4aa6026 13;; the Free Software Foundation; either version 3, or (at your option)
be010748 14;; any later version.
72ea54a4 15
be010748
RS
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
72ea54a4 20
be010748 21;; You should have received a copy of the GNU General Public License
4c9afcbe 22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
72ea54a4 25
edbd2f74
ER
26;;; Commentary:
27
28;; This package provides various useful commands (including help
29;; system access) through the mouse. All this code assumes that mouse
30;; interpretation has been abstracted into Emacs input events.
31;;
32;; The code is rather X-dependent.
33
aae56ea7
ER
34;;; Code:
35
cc0a8174 36;;; Utility functions.
72ea54a4 37
cc0a8174
JB
38;;; Indent track-mouse like progn.
39(put 'track-mouse 'lisp-indent-function 0)
72ea54a4 40
3b558d41
RS
41(defcustom mouse-yank-at-point nil
42 "*If non-nil, mouse yank commands yank at point instead of at click."
43 :type 'boolean
44 :group 'mouse)
b2dae92a
KS
45
46(defcustom mouse-drag-copy-region t
47 "*If non-nil, mouse drag copies region to kill-ring."
48 :type 'boolean
bf247b6e 49 :version "22.1"
b2dae92a
KS
50 :group 'mouse)
51
5dbda518 52(defcustom mouse-1-click-follows-link 450
787e24c3 53 "Non-nil means that clicking Mouse-1 on a link follows the link.
65f76581 54
787e24c3
KS
55With the default setting, an ordinary Mouse-1 click on a link
56performs the same action as Mouse-2 on that link, while a longer
97b1270c 57Mouse-1 click \(hold down the Mouse-1 button for more than 450
787e24c3 58milliseconds) performs the original Mouse-1 binding \(which
65f76581
KS
59typically sets point where you click the mouse).
60
61If value is an integer, the time elapsed between pressing and
62releasing the mouse button determines whether to follow the link
787e24c3 63or perform the normal Mouse-1 action (typically set point).
65f76581
KS
64The absolute numeric value specifices the maximum duration of a
65\"short click\" in milliseconds. A positive value means that a
66short click follows the link, and a longer click performs the
1d68acd3 67normal action. A negative value gives the opposite behavior.
65f76581
KS
68
69If value is `double', a double click follows the link.
70
787e24c3 71Otherwise, a single Mouse-1 click unconditionally follows the link.
65f76581
KS
72
73Note that dragging the mouse never follows the link.
74
75This feature only works in modes that specifically identify
76clickable text as links, so it may not work with some external
77packages. See `mouse-on-link-p' for details."
bf247b6e 78 :version "22.1"
65f76581
KS
79 :type '(choice (const :tag "Disabled" nil)
80 (const :tag "Double click" double)
97b1270c 81 (number :tag "Single click time limit" :value 450)
65f76581
KS
82 (other :tag "Single click" t))
83 :group 'mouse)
84
185a53bb
KS
85(defcustom mouse-1-click-in-non-selected-windows t
86 "*If non-nil, a Mouse-1 click also follows links in non-selected windows.
87
88If nil, a Mouse-1 click on a link in a non-selected window performs
89the normal mouse-1 binding, typically selects the window and sets
90point at the click position."
91 :type 'boolean
92 :version "22.1"
93 :group 'mouse)
94
95
cc0a8174 96\f
95132d1c
RS
97;; Provide a mode-specific menu on a mouse button.
98
21ad0f7b
SM
99(defun popup-menu (menu &optional position prefix)
100 "Popup the given menu and call the selected option.
de420e82
DL
101MENU can be a keymap, an easymenu-style menu or a list of keymaps as for
102`x-popup-menu'.
21ad0f7b
SM
103POSITION can be a click event or ((XOFFSET YOFFSET) WINDOW) and defaults to
104 the current mouse position.
105PREFIX is the prefix argument (if any) to pass to the command."
de420e82
DL
106 (let* ((map (cond
107 ((keymapp menu) menu)
108 ((and (listp menu) (keymapp (car menu))) menu)
109 (t (let* ((map (easy-menu-create-menu (car menu) (cdr menu)))
72596e2f
SM
110 (filter (when (symbolp map)
111 (plist-get (get map 'menu-prop) :filter))))
112 (if filter (funcall filter (symbol-function map)) map)))))
0dd672a6 113 event cmd)
b52a30d8 114 (unless position
d32af6dd 115 (let ((mp (mouse-pixel-position)))
b52a30d8 116 (setq position (list (list (cadr mp) (cddr mp)) (car mp)))))
21ad0f7b 117 ;; The looping behavior was taken from lmenu's popup-menu-popup
7636d2a3
EZ
118 (while (and map (setq event
119 ;; map could be a prefix key, in which case
120 ;; we need to get its function cell
121 ;; definition.
d32af6dd 122 (x-popup-menu position (indirect-function map))))
21ad0f7b
SM
123 ;; Strangely x-popup-menu returns a list.
124 ;; mouse-major-mode-menu was using a weird:
125 ;; (key-binding (apply 'vector (append '(menu-bar) menu-prefix events)))
0dd672a6
SM
126 (setq cmd
127 (if (and (not (keymapp map)) (listp map))
128 ;; We were given a list of keymaps. Search them all
129 ;; in sequence until a first binding is found.
130 (let ((mouse-click (apply 'vector event))
131 binding)
132 (while (and map (null binding))
133 (setq binding (lookup-key (car map) mouse-click))
134 (if (numberp binding) ; `too long'
135 (setq binding nil))
136 (setq map (cdr map)))
137 binding)
138 ;; We were given a single keymap.
139 (lookup-key map (apply 'vector event))))
140 ;; Clear out echoing, which perhaps shows a prefix arg.
141 (message "")
142 ;; Maybe try again but with the submap.
143 (setq map (if (keymapp cmd) cmd)))
324cd972
RS
144 ;; If the user did not cancel by refusing to select,
145 ;; and if the result is a command, run it.
146 (when (and (null map) (commandp cmd))
0dd672a6
SM
147 (setq prefix-arg prefix)
148 ;; `setup-specified-language-environment', for instance,
149 ;; expects this to be set from a menu keymap.
150 (setq last-command-event (car (last event)))
151 ;; mouse-major-mode-menu was using `command-execute' instead.
65b61266 152 (call-interactively cmd))))
bcd010a0 153
7e4e9c66 154(defun minor-mode-menu-from-indicator (indicator)
fb1a03c9
DN
155 "Show menu for minor mode specified by INDICATOR.
156Interactively, INDICATOR is read using completion.
157If there is no menu defined for the minor mode, then create one with
158items `Turn Off' and `Help'."
159 (interactive
160 (list (completing-read
161 "Minor mode indicator: "
162 (describe-minor-mode-completion-table-for-indicator))))
7e4e9c66 163 (let ((minor-mode (lookup-minor-mode-from-indicator indicator)))
fb1a03c9
DN
164 (unless minor-mode (error "Cannot find minor mode for `%s'" indicator))
165 (let* ((map (cdr-safe (assq minor-mode minor-mode-map-alist)))
166 (menu (and (keymapp map) (lookup-key map [menu-bar]))))
167 (unless menu
168 (setq menu
169 `(keymap
170 (,(intern indicator) ,indicator
171 keymap
172 (turn-off menu-item "Turn Off minor mode"
173 (lambda ()
174 (interactive)
175 (,minor-mode -1)
176 (message ,(format "`%S' turned OFF" minor-mode))))
177 (help menu-item "Help for minor mode"
178 (lambda () (interactive)
179 (describe-function
180 ',minor-mode)))))))
181 (popup-menu menu))))
7e4e9c66
GM
182
183(defun mouse-minor-mode-menu (event)
184 "Show minor-mode menu for EVENT on minor modes area of the mode line."
185 (interactive "@e")
186 (let ((indicator (car (nth 4 (car (cdr event))))))
187 (minor-mode-menu-from-indicator indicator)))
188
bcd010a0
DL
189(defvar mouse-major-mode-menu-prefix) ; dynamically bound
190
40cfe0d8 191(defun mouse-major-mode-menu (event &optional prefix)
b98e5762
DL
192 "Pop up a mode-specific menu of mouse commands.
193Default to the Edit menu if the major mode doesn't define a menu."
95132d1c
RS
194 ;; Switch to the window clicked on, because otherwise
195 ;; the mode's commands may not make sense.
6a16c4cb 196 (interactive "@e\nP")
25f9b4bf 197 ;; Let the mode update its menus first.
179fc9ef 198 (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
b98e5762
DL
199 (let* (;; This is where mouse-major-mode-menu-prefix
200 ;; returns the prefix we should use (after menu-bar).
201 ;; It is either nil or (SOME-SYMBOL).
202 (mouse-major-mode-menu-prefix nil)
203 ;; Keymap from which to inherit; may be null.
204 (ancestor (mouse-major-mode-menu-1
205 (and (current-local-map)
25db2767 206 (local-key-binding [menu-bar]))))
b98e5762
DL
207 ;; Make a keymap in which our last command leads to a menu or
208 ;; default to the edit menu.
209 (newmap (if ancestor
48d33090
SM
210 (make-sparse-keymap (concat (format-mode-line mode-name)
211 " Mode"))
0595c9f9
GM
212 menu-bar-edit-menu))
213 uniq)
b98e5762
DL
214 (if ancestor
215 ;; Make our menu inherit from the desired keymap which we want
216 ;; to display as the menu now.
0595c9f9
GM
217 ;; Sometimes keymaps contain duplicate menu code, leading to
218 ;; duplicates in the popped-up menu. Avoid this by simply
219 ;; taking the first of any identically-named menus.
220 ;; http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg00469.html
221 (set-keymap-parent newmap
222 (progn
223 (dolist (e ancestor)
224 (unless (and (listp e)
225 (assoc (car e) uniq))
226 (setq uniq (append uniq (list e)))))
227 uniq)))
21ad0f7b
SM
228 (popup-menu newmap event prefix)))
229
95132d1c
RS
230
231;; Compute and cache the equivalent keys in MENU and all its submenus.
d5c847bb
KH
232;;;(defun mouse-major-mode-menu-compute-equiv-keys (menu)
233;;; (and (eq (car menu) 'keymap)
234;;; (x-popup-menu nil menu))
235;;; (while menu
236;;; (and (consp (car menu))
237;;; (consp (cdr (car menu)))
238;;; (let ((tail (cdr (car menu))))
239;;; (while (and (consp tail)
240;;; (not (eq (car tail) 'keymap)))
241;;; (setq tail (cdr tail)))
242;;; (if (consp tail)
243;;; (mouse-major-mode-menu-compute-equiv-keys tail))))
244;;; (setq menu (cdr menu))))
95132d1c
RS
245
246;; Given a mode's menu bar keymap,
247;; if it defines exactly one menu bar menu,
248;; return just that menu.
249;; Otherwise return a menu for all of them.
250(defun mouse-major-mode-menu-1 (menubar)
251 (if menubar
252 (let ((tail menubar)
253 submap)
254 (while tail
255 (if (consp (car tail))
256 (if submap
257 (setq submap t)
d5c847bb 258 (setq submap (car tail))))
95132d1c 259 (setq tail (cdr tail)))
d5c847bb 260 (if (eq submap t)
d3e458b0 261 menubar
d5c847bb 262 (setq mouse-major-mode-menu-prefix (list (car submap)))
a45423d8 263 (lookup-key menubar (vector (car submap)))))))
de420e82
DL
264
265(defun mouse-popup-menubar (event prefix)
a7df580d 266 "Pop up a menu equivalent to the menu bar for keyboard EVENT with PREFIX.
de420e82
DL
267The contents are the items that would be in the menu bar whether or
268not it is actually displayed."
269 (interactive "@e \nP")
179fc9ef 270 (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
7636d2a3
EZ
271 (let* ((local-menu (and (current-local-map)
272 (lookup-key (current-local-map) [menu-bar])))
273 (global-menu (lookup-key global-map [menu-bar]))
59836110
EZ
274 ;; If a keymap doesn't have a prompt string (a lazy
275 ;; programmer didn't bother to provide one), create it and
276 ;; insert it into the keymap; each keymap gets its own
277 ;; prompt. This is required for non-toolkit versions to
278 ;; display non-empty menu pane names.
279 (minor-mode-menus
280 (mapcar
281 (function
282 (lambda (menu)
283 (let* ((minor-mode (car menu))
284 (menu (cdr menu))
285 (title-or-map (cadr menu)))
286 (or (stringp title-or-map)
287 (setq menu
288 (cons 'keymap
289 (cons (concat
290 (capitalize (subst-char-in-string
66564ab0 291 ?- ?\s (symbol-name
59836110
EZ
292 minor-mode)))
293 " Menu")
294 (cdr menu)))))
295 menu)))
296 (minor-mode-key-binding [menu-bar])))
7636d2a3
EZ
297 (local-title-or-map (and local-menu (cadr local-menu)))
298 (global-title-or-map (cadr global-menu)))
7636d2a3
EZ
299 (or (null local-menu)
300 (stringp local-title-or-map)
301 (setq local-menu (cons 'keymap
b38f5e6f 302 (cons (concat (format-mode-line mode-name)
48d33090 303 " Mode Menu")
7636d2a3
EZ
304 (cdr local-menu)))))
305 (or (stringp global-title-or-map)
306 (setq global-menu (cons 'keymap
307 (cons "Global Menu"
308 (cdr global-menu)))))
de420e82 309 ;; Supplying the list is faster than making a new map.
25db2767
DL
310 (popup-menu (append (list global-menu)
311 (if local-menu
312 (list local-menu))
313 minor-mode-menus)
7636d2a3 314 event prefix)))
de420e82
DL
315
316(defun mouse-popup-menubar-stuff (event prefix)
317 "Popup a menu like either `mouse-major-mode-menu' or `mouse-popup-menubar'.
318Use the former if the menu bar is showing, otherwise the latter."
319 (interactive "@e \nP")
320 (if (zerop (assoc-default 'menu-bar-lines (frame-parameters) 'eq 0))
321 (mouse-popup-menubar event prefix)
322 (mouse-major-mode-menu event prefix)))
95132d1c 323\f
544e7e73
RS
324;; Commands that operate on windows.
325
d65147f6
KH
326(defun mouse-minibuffer-check (event)
327 (let ((w (posn-window (event-start event))))
328 (and (window-minibuffer-p w)
329 (not (minibuffer-window-active-p w))
33c448cd
RS
330 (error "Minibuffer window is not active")))
331 ;; Give temporary modes such as isearch a chance to turn off.
332 (run-hooks 'mouse-leave-buffer-hook))
d65147f6 333
cc0a8174 334(defun mouse-delete-window (click)
947da0c4 335 "Delete the window you click on.
6b48d742 336Do nothing if the frame has just one window.
a926a0fa 337This command must be bound to a mouse click."
ec558adc 338 (interactive "e")
6b48d742 339 (unless (one-window-p t)
a926a0fa
RS
340 (mouse-minibuffer-check click)
341 (delete-window (posn-window (event-start click)))))
cc0a8174 342
3c2dd2c0
RS
343(defun mouse-select-window (click)
344 "Select the window clicked on; don't move point."
345 (interactive "e")
d65147f6 346 (mouse-minibuffer-check click)
3c2dd2c0
RS
347 (let ((oframe (selected-frame))
348 (frame (window-frame (posn-window (event-start click)))))
349 (select-window (posn-window (event-start click)))
350 (raise-frame frame)
351 (select-frame frame)
352 (or (eq frame oframe)
e1877477 353 (set-mouse-position (selected-frame) (1- (frame-width)) 0))))
3c2dd2c0 354
b0f3a26b
JB
355(defun mouse-tear-off-window (click)
356 "Delete the window clicked on, and create a new frame displaying its buffer."
357 (interactive "e")
d65147f6 358 (mouse-minibuffer-check click)
b0f3a26b
JB
359 (let* ((window (posn-window (event-start click)))
360 (buf (window-buffer window))
01a911e3 361 (frame (make-frame)))
b0f3a26b
JB
362 (select-frame frame)
363 (switch-to-buffer buf)
364 (delete-window window)))
365
b5370f03 366(defun mouse-delete-other-windows ()
5925bb84 367 "Delete all windows except the one you click on."
b5370f03 368 (interactive "@")
cc0a8174 369 (delete-other-windows))
72ea54a4 370
cc0a8174
JB
371(defun mouse-split-window-vertically (click)
372 "Select Emacs window mouse is on, then split it vertically in half.
373The window is split at the line clicked on.
374This command must be bound to a mouse click."
947da0c4 375 (interactive "@e")
d65147f6 376 (mouse-minibuffer-check click)
b5370f03
JB
377 (let ((start (event-start click)))
378 (select-window (posn-window start))
85d6b80b 379 (let ((new-height (1+ (cdr (posn-col-row (event-end click)))))
5ba2dc3f
JB
380 (first-line window-min-height)
381 (last-line (- (window-height) window-min-height)))
382 (if (< last-line first-line)
0a50b993 383 (error "Window too short to split")
5ba2dc3f
JB
384 (split-window-vertically
385 (min (max new-height first-line) last-line))))))
cc0a8174 386
947da0c4
RS
387(defun mouse-split-window-horizontally (click)
388 "Select Emacs window mouse is on, then split it horizontally in half.
389The window is split at the column clicked on.
390This command must be bound to a mouse click."
391 (interactive "@e")
d65147f6 392 (mouse-minibuffer-check click)
5ba2dc3f
JB
393 (let ((start (event-start click)))
394 (select-window (posn-window start))
395 (let ((new-width (1+ (car (posn-col-row (event-end click)))))
396 (first-col window-min-width)
397 (last-col (- (window-width) window-min-width)))
398 (if (< last-col first-col)
0a50b993 399 (error "Window too narrow to split")
5ba2dc3f
JB
400 (split-window-horizontally
401 (min (max new-width first-col) last-col))))))
947da0c4 402
4a4fa24d
RS
403(defun mouse-drag-window-above (window)
404 "Return the (or a) window directly above WINDOW.
405That means one whose bottom edge is at the same height as WINDOW's top edge."
5915523a
EZ
406 (let ((start-top (nth 1 (window-edges window)))
407 (start-left (nth 0 (window-edges window)))
408 (start-right (nth 2 (window-edges window)))
4a4fa24d
RS
409 (start-window window)
410 above-window)
411 (setq window (previous-window window 0))
412 (while (and (not above-window) (not (eq window start-window)))
5915523a
EZ
413 (let ((left (nth 0 (window-edges window)))
414 (right (nth 2 (window-edges window))))
415 (when (and (= (+ (window-height window) (nth 1 (window-edges window)))
416 start-top)
417 (or (and (<= left start-left) (<= start-right right))
418 (and (<= start-left left) (<= left start-right))
419 (and (<= start-left right) (<= right start-right))))
420 (setq above-window window)))
4a4fa24d
RS
421 (setq window (previous-window window)))
422 above-window))
423
424(defun mouse-drag-move-window-bottom (window growth)
425 "Move the bottom of WINDOW up or down by GROWTH lines.
426Move it down if GROWTH is positive, or up if GROWTH is negative.
427If this would make WINDOW too short,
428shrink the window or windows above it to make room."
91d99be6
RS
429 (condition-case nil
430 (adjust-window-trailing-edge window growth nil)
431 (error nil)))
4a4fa24d 432
7a892a8b
DP
433(defsubst mouse-drag-move-window-top (window growth)
434 "Move the top of WINDOW up or down by GROWTH lines.
435Move it down if GROWTH is positive, or up if GROWTH is negative.
436If this would make WINDOW too short, shrink the window or windows
437above it to make room."
438 ;; Moving the top of WINDOW is actually moving the bottom of the
439 ;; window above.
440 (let ((window-above (mouse-drag-window-above window)))
441 (and window-above
442 (mouse-drag-move-window-bottom window-above (- growth)))))
443
b0d22e20
GM
444(defun mouse-drag-mode-line-1 (start-event mode-line-p)
445 "Change the height of a window by dragging on the mode or header line.
446START-EVENT is the starting mouse-event of the drag action.
4a4fa24d 447MODE-LINE-P non-nil means dragging a mode line; nil means a header line."
33c448cd
RS
448 ;; Give temporary modes such as isearch a chance to turn off.
449 (run-hooks 'mouse-leave-buffer-hook)
ee0e2bdd
GM
450 (let* ((done nil)
451 (echo-keystrokes 0)
452 (start (event-start start-event))
453 (start-event-window (posn-window start))
454 (start-event-frame (window-frame start-event-window))
455 (start-nwindows (count-windows t))
ee0e2bdd
GM
456 (minibuffer (frame-parameter nil 'minibuffer))
457 should-enlarge-minibuffer event mouse y top bot edges wconfig growth)
544e7e73
RS
458 (track-mouse
459 (progn
544e7e73
RS
460 ;; if this is the bottommost ordinary window, then to
461 ;; move its modeline the minibuffer must be enlarged.
462 (setq should-enlarge-minibuffer
463 (and minibuffer
b0d22e20 464 mode-line-p
544e7e73
RS
465 (not (one-window-p t))
466 (= (nth 1 (window-edges minibuffer))
35da1e48 467 (nth 3 (window-edges start-event-window)))))
7b611de0 468
544e7e73
RS
469 ;; loop reading events and sampling the position of
470 ;; the mouse.
471 (while (not done)
472 (setq event (read-event)
473 mouse (mouse-position))
7b611de0 474
544e7e73
RS
475 ;; do nothing if
476 ;; - there is a switch-frame event.
477 ;; - the mouse isn't in the frame that we started in
478 ;; - the mouse isn't in any Emacs frame
479 ;; drag if
480 ;; - there is a mouse-movement event
481 ;; - there is a scroll-bar-movement event
482 ;; (same as mouse movement for our purposes)
483 ;; quit if
c291e344
MR
484 ;; - there is a keyboard event or some other unknown event.
485 (cond ((not (consp event))
544e7e73 486 (setq done t))
7b611de0 487
fbd8dc8a 488 ((memq (car event) '(switch-frame select-window))
544e7e73 489 nil)
7b611de0 490
ee0e2bdd
GM
491 ((not (memq (car event) '(mouse-movement scroll-bar-movement)))
492 (when (consp event)
c291e344
MR
493 ;; Do not unread a drag-mouse-1 event since it will cause the
494 ;; selection of the window above when dragging the modeline
495 ;; above the selected window.
496 (unless (eq (car event) 'drag-mouse-1)
497 (push event unread-command-events)))
544e7e73 498 (setq done t))
7b611de0 499
544e7e73
RS
500 ((not (eq (car mouse) start-event-frame))
501 nil)
7b611de0 502
544e7e73
RS
503 ((null (car (cdr mouse)))
504 nil)
7b611de0 505
544e7e73
RS
506 (t
507 (setq y (cdr (cdr mouse))
35da1e48 508 edges (window-edges start-event-window)
544e7e73
RS
509 top (nth 1 edges)
510 bot (nth 3 edges))
7b611de0 511
544e7e73 512 ;; compute size change needed
b0d22e20 513 (cond (mode-line-p
b0d22e20 514 (setq growth (- y bot -1)))
739e92a7
EZ
515 (t ; header line
516 (when (< (- bot y) window-min-height)
517 (setq y (- bot window-min-height)))
518 ;; The window's top includes the header line!
519 (setq growth (- top y))))
b0d22e20 520 (setq wconfig (current-window-configuration))
7b611de0 521
951e0427 522 ;; Check for an error case.
ee0e2bdd
GM
523 (when (and (/= growth 0)
524 (not minibuffer)
525 (one-window-p t))
526 (error "Attempt to resize sole window"))
7b611de0 527
544e7e73
RS
528 ;; grow/shrink minibuffer?
529 (if should-enlarge-minibuffer
ad64cd77
RS
530 (unless resize-mini-windows
531 (mouse-drag-move-window-bottom start-event-window growth))
544e7e73 532 ;; no. grow/shrink the selected window
ee0e2bdd 533 ;(message "growth = %d" growth)
7a892a8b
DP
534 (if mode-line-p
535 (mouse-drag-move-window-bottom start-event-window growth)
536 (mouse-drag-move-window-top start-event-window growth)))
7b611de0 537
544e7e73
RS
538 ;; if this window's growth caused another
539 ;; window to be deleted because it was too
540 ;; short, rescind the change.
541 ;;
542 ;; if size change caused space to be stolen
543 ;; from a window above this one, rescind the
a45423d8 544 ;; change, but only if we didn't grow/shrink
544e7e73
RS
545 ;; the minibuffer. minibuffer size changes
546 ;; can cause all windows to shrink... no way
547 ;; around it.
ee0e2bdd
GM
548 (when (or (/= start-nwindows (count-windows t))
549 (and (not should-enlarge-minibuffer)
4a4fa24d 550 (> growth 0)
ee0e2bdd 551 mode-line-p
c291e344
MR
552 (/= top
553 (nth 1 (window-edges
554 ;; Choose right window.
555 start-event-window)))))
ee0e2bdd 556 (set-window-configuration wconfig)))))))))
b0d22e20
GM
557
558(defun mouse-drag-mode-line (start-event)
559 "Change the height of a window by dragging on the mode line."
560 (interactive "e")
561 (mouse-drag-mode-line-1 start-event t))
562
563(defun mouse-drag-header-line (start-event)
ee0e2bdd
GM
564 "Change the height of a window by dragging on the header line.
565Windows whose header-lines are at the top of the frame cannot be
566resized by dragging their header-line."
b0d22e20 567 (interactive "e")
ee0e2bdd
GM
568 ;; Changing the window's size by dragging its header-line when the
569 ;; header-line is at the top of the frame is somewhat strange,
570 ;; because the header-line doesn't move, so don't do it.
571 (let* ((start (event-start start-event))
572 (window (posn-window start))
573 (frame (window-frame window))
574 (first-window (frame-first-window frame)))
efe4e5af
CY
575 (unless (or (eq window first-window)
576 (= (nth 1 (window-edges window))
577 (nth 1 (window-edges first-window))))
578 (mouse-drag-mode-line-1 start-event nil))))
b0d22e20 579
544e7e73 580\f
73c8f64c
RS
581(defun mouse-drag-vertical-line-rightward-window (window)
582 "Return a window that is immediately to the right of WINDOW, or nil."
583 (let ((bottom (nth 3 (window-inside-edges window)))
584 (left (nth 0 (window-inside-edges window)))
585 best best-right
586 (try (previous-window window)))
587 (while (not (eq try window))
588 (let ((try-top (nth 1 (window-inside-edges try)))
589 (try-bottom (nth 3 (window-inside-edges try)))
590 (try-right (nth 2 (window-inside-edges try))))
591 (if (and (< try-top bottom)
592 (>= try-bottom bottom)
593 (< try-right left)
594 (or (null best-right) (> try-right best-right)))
595 (setq best-right try-right best try)))
596 (setq try (previous-window try)))
597 best))
598
08a1c178
RS
599(defun mouse-drag-vertical-line (start-event)
600 "Change the width of a window by dragging on the vertical line."
601 (interactive "e")
602 ;; Give temporary modes such as isearch a chance to turn off.
603 (run-hooks 'mouse-leave-buffer-hook)
5d6a85e0
RS
604 (let* ((done nil)
605 (echo-keystrokes 0)
606 (start-event-frame (window-frame (car (car (cdr start-event)))))
607 (start-event-window (car (car (cdr start-event))))
e9ae308c 608 event mouse x left right edges growth
5d6a85e0
RS
609 (which-side
610 (or (cdr (assq 'vertical-scroll-bars (frame-parameters start-event-frame)))
611 'right)))
89a94f1e
CY
612 (cond
613 ((one-window-p t)
614 (error "Attempt to resize sole ordinary window"))
615 ((and (eq which-side 'right)
616 (>= (nth 2 (window-inside-edges start-event-window))
617 (frame-width start-event-frame)))
618 (error "Attempt to drag rightmost scrollbar"))
619 ((and (eq which-side 'left)
620 (= (nth 0 (window-inside-edges start-event-window)) 0))
621 (error "Attempt to drag leftmost scrollbar")))
08a1c178
RS
622 (track-mouse
623 (progn
08a1c178
RS
624 ;; loop reading events and sampling the position of
625 ;; the mouse.
626 (while (not done)
627 (setq event (read-event)
628 mouse (mouse-position))
629 ;; do nothing if
630 ;; - there is a switch-frame event.
631 ;; - the mouse isn't in the frame that we started in
632 ;; - the mouse isn't in any Emacs frame
633 ;; drag if
634 ;; - there is a mouse-movement event
635 ;; - there is a scroll-bar-movement event
636 ;; (same as mouse movement for our purposes)
637 ;; quit if
638 ;; - there is a keyboard event or some other unknown event
639 ;; unknown event.
640 (cond ((integerp event)
641 (setq done t))
fbd8dc8a 642 ((memq (car event) '(switch-frame select-window))
08a1c178
RS
643 nil)
644 ((not (memq (car event)
645 '(mouse-movement scroll-bar-movement)))
646 (if (consp event)
647 (setq unread-command-events
648 (cons event unread-command-events)))
649 (setq done t))
650 ((not (eq (car mouse) start-event-frame))
651 nil)
652 ((null (car (cdr mouse)))
653 nil)
654 (t
4199d5be
RS
655 (let ((window
656 ;; If the scroll bar is on the window's left,
657 ;; adjust the window on the left.
658 (if (eq which-side 'right)
35da1e48 659 start-event-window
73c8f64c 660 (mouse-drag-vertical-line-rightward-window
35da1e48 661 start-event-window))))
b0ea497f 662 (setq x (- (car (cdr mouse))
4e363e7e 663 (if (eq which-side 'right) 0 2))
4199d5be 664 edges (window-edges window)
b0ea497f
KH
665 left (nth 0 edges)
666 right (nth 2 edges))
667 ;; scale back a move that would make the
668 ;; window too thin.
669 (if (< (- x left -1) window-min-width)
670 (setq x (+ left window-min-width -1)))
671 ;; compute size change needed
4199d5be
RS
672 (setq growth (- x right -1))
673 (condition-case nil
674 (adjust-window-trailing-edge window growth t)
675 (error nil))))))))))
08a1c178 676\f
2a5fa27b 677(defun mouse-set-point (event)
cc0a8174 678 "Move point to the position clicked on with the mouse.
2a5fa27b 679This should be bound to a mouse click event type."
ec558adc 680 (interactive "e")
d65147f6 681 (mouse-minibuffer-check event)
2a5fa27b
RS
682 ;; Use event-end in case called from mouse-drag-region.
683 ;; If EVENT is a click, event-end and event-start give same value.
541a44d2 684 (posn-set-point (event-end event)))
cc0a8174 685
e6c2f5d4
RS
686(defvar mouse-last-region-beg nil)
687(defvar mouse-last-region-end nil)
688(defvar mouse-last-region-tick nil)
689
690(defun mouse-region-match ()
691 "Return non-nil if there's an active region that was set with the mouse."
692 (and (mark t) mark-active
693 (eq mouse-last-region-beg (region-beginning))
694 (eq mouse-last-region-end (region-end))
695 (eq mouse-last-region-tick (buffer-modified-tick))))
696
652ccd35 697(defun mouse-set-region (click)
e37de120 698 "Set the region to the text dragged over, and copy to kill ring.
2a5fa27b 699This should be bound to a mouse drag event."
652ccd35 700 (interactive "e")
d65147f6 701 (mouse-minibuffer-check click)
652ccd35
RS
702 (let ((posn (event-start click))
703 (end (event-end click)))
704 (select-window (posn-window posn))
705 (if (numberp (posn-point posn))
706 (goto-char (posn-point posn)))
fcfc3c63 707 ;; If mark is highlighted, no need to bounce the cursor.
33a35434
KH
708 ;; On X, we highlight while dragging, thus once again no need to bounce.
709 (or transient-mark-mode
14059374 710 (memq (framep (selected-frame)) '(x pc w32 mac))
fcfc3c63 711 (sit-for 1))
652ccd35 712 (push-mark)
1cc8a3f4 713 (set-mark (point))
652ccd35 714 (if (numberp (posn-point end))
e37de120
RS
715 (goto-char (posn-point end)))
716 ;; Don't set this-command to kill-region, so that a following
717 ;; C-w will not double the text in the kill ring.
91a6bc10 718 ;; Ignore last-command so we don't append to a preceding kill.
b2dae92a
KS
719 (when mouse-drag-copy-region
720 (let (this-command last-command deactivate-mark)
721 (copy-region-as-kill (mark) (point))))
e6c2f5d4
RS
722 (mouse-set-region-1)))
723
724(defun mouse-set-region-1 ()
a5809dbd 725 ;; Set transient-mark-mode for a little while.
cc47c660
RS
726 (if (memq transient-mark-mode '(nil identity))
727 (setq transient-mark-mode 'only))
e6c2f5d4
RS
728 (setq mouse-last-region-beg (region-beginning))
729 (setq mouse-last-region-end (region-end))
730 (setq mouse-last-region-tick (buffer-modified-tick)))
652ccd35 731
3b558d41 732(defcustom mouse-scroll-delay 0.25
600c6e3a
JB
733 "*The pause between scroll steps caused by mouse drags, in seconds.
734If you drag the mouse beyond the edge of a window, Emacs scrolls the
735window to bring the text beyond that edge into view, with a delay of
736this many seconds between scroll steps. Scrolling stops when you move
737the mouse back into the window, or release the button.
738This variable's value may be non-integral.
3b558d41
RS
739Setting this to zero causes Emacs to scroll as fast as it can."
740 :type 'number
741 :group 'mouse)
600c6e3a 742
3b558d41 743(defcustom mouse-scroll-min-lines 1
a3d6bb97
RS
744 "*The minimum number of lines scrolled by dragging mouse out of window.
745Moving the mouse out the top or bottom edge of the window begins
746scrolling repeatedly. The number of lines scrolled per repetition
747is normally equal to the number of lines beyond the window edge that
748the mouse has moved. However, it always scrolls at least the number
3b558d41
RS
749of lines specified by this variable."
750 :type 'integer
751 :group 'mouse)
08a1c178 752
e919a622
RS
753(defun mouse-scroll-subr (window jump &optional overlay start)
754 "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
600c6e3a
JB
755If OVERLAY is an overlay, let it stretch from START to the far edge of
756the newly visible text.
757Upon exit, point is at the far edge of the newly visible text."
08a1c178
RS
758 (cond
759 ((and (> jump 0) (< jump mouse-scroll-min-lines))
760 (setq jump mouse-scroll-min-lines))
761 ((and (< jump 0) (< (- jump) mouse-scroll-min-lines))
762 (setq jump (- mouse-scroll-min-lines))))
4e399a53
RS
763 (let ((opoint (point)))
764 (while (progn
765 (goto-char (window-start window))
766 (if (not (zerop (vertical-motion jump window)))
767 (progn
768 (set-window-start window (point))
769 (if (natnump jump)
0320e66f
RS
770 (if (window-end window)
771 (progn
772 (goto-char (window-end window))
773 ;; window-end doesn't reflect the window's new
774 ;; start position until the next redisplay.
775 (vertical-motion (1- jump) window))
776 (vertical-motion (- (window-height window) 2)))
4e399a53
RS
777 (goto-char (window-start window)))
778 (if overlay
779 (move-overlay overlay start (point)))
780 ;; Now that we have scrolled WINDOW properly,
781 ;; put point back where it was for the redisplay
782 ;; so that we don't mess up the selected window.
783 (or (eq window (selected-window))
784 (goto-char opoint))
d2287ded 785 (sit-for mouse-scroll-delay)))))
4e399a53
RS
786 (or (eq window (selected-window))
787 (goto-char opoint))))
fcfc3c63 788
dc269e81 789;; Create an overlay and immediately delete it, to get "overlay in no buffer".
aaf15b8b
SM
790(defconst mouse-drag-overlay
791 (let ((ol (make-overlay (point-min) (point-min))))
792 (delete-overlay ol)
793 (overlay-put ol 'face 'region)
794 ol))
600c6e3a 795
dd524dbd 796(defvar mouse-selection-click-count 0)
eb6ff46f 797
c8c5bd24
RS
798(defvar mouse-selection-click-count-buffer nil)
799
600c6e3a 800(defun mouse-drag-region (start-event)
bcd5aef1 801 "Set the region to the text that the mouse is dragged over.
78210c95
RS
802Highlight the drag area as you move the mouse.
803This must be bound to a button-down mouse event.
d017deb2 804In Transient Mark mode, the highlighting remains as long as the mark
6454615c
RS
805remains active. Otherwise, it remains until the next input event.
806
807If the click is in the echo area, display the `*Messages*' buffer."
bcd5aef1 808 (interactive "e")
fbd8dc8a
SM
809 (let ((w (posn-window (event-start start-event))))
810 (if (and (window-minibuffer-p w)
811 (not (minibuffer-window-active-p w)))
6454615c 812 (save-excursion
2e36c3b0 813 ;; Swallow the up-event.
6454615c 814 (read-event)
4bdce438 815 (set-buffer (get-buffer-create "*Messages*"))
6454615c
RS
816 (goto-char (point-max))
817 (display-buffer (current-buffer)))
818 ;; Give temporary modes such as isearch a chance to turn off.
819 (run-hooks 'mouse-leave-buffer-hook)
f1c4f757 820 (mouse-drag-track start-event t))))
6454615c 821
65f76581 822
91a2acb2 823(defun mouse-posn-property (pos property)
9ed38a84
DK
824 "Look for a property at click position.
825POS may be either a buffer position or a click position like
89bf250e 826those returned from `event-start'. If the click position is on
9ed38a84
DK
827a string, the text property PROPERTY is examined.
828If this is nil or the click is not on a string, then
829the corresponding buffer position is searched for PROPERTY.
830If PROPERTY is encountered in one of those places,
831its value is returned."
91a2acb2
DK
832 (if (consp pos)
833 (let ((w (posn-window pos)) (pt (posn-point pos))
834 (str (posn-string pos)))
835 (or (and str
836 (get-text-property (cdr str) property (car str)))
837 (and pt
838 (get-char-property pt property w))))
839 (get-char-property pos property)))
840
65f76581
KS
841(defun mouse-on-link-p (pos)
842 "Return non-nil if POS is on a link in the current buffer.
23eb76c4
TTN
843POS must be a buffer position in the current buffer or a mouse
844event location in the selected window (see `event-start').
185a53bb
KS
845However, if `mouse-1-click-in-non-selected-windows' is non-nil,
846POS may be a mouse event location in any window.
65f76581
KS
847
848A clickable link is identified by one of the following methods:
849
b41a4019 850- If the character at POS has a non-nil `follow-link' text or
e5fb57e9 851overlay property, the value of that property determines what to do.
65f76581 852
b41a4019
KS
853- If there is a local key-binding or a keybinding at position POS
854for the `follow-link' event, the binding of that event determines
855what to do.
65f76581 856
b41a4019
KS
857The resulting value determine whether POS is inside a link:
858
859- If the value is `mouse-face', POS is inside a link if there
65f76581
KS
860is a non-nil `mouse-face' property at POS. Return t in this case.
861
b41a4019 862- If the value is a function, FUNC, POS is inside a link if
65f76581 863the call \(FUNC POS) returns non-nil. Return the return value
23eb76c4 864from that call. Arg is \(posn-point POS) if POS is a mouse event.
65f76581 865
b41a4019 866- Otherwise, return the value itself.
65f76581
KS
867
868The return value is interpreted as follows:
869
870- If it is a string, the mouse-1 event is translated into the
871first character of the string, i.e. the action of the mouse-1
872click is the local or global binding of that character.
873
874- If it is a vector, the mouse-1 event is translated into the
875first element of that vector, i.e. the action of the mouse-1
876click is the local or global binding of that event.
877
878- Otherwise, the mouse-1 event is translated into a mouse-2 event
879at the same position."
91a2acb2
DK
880 (let ((action
881 (and (or (not (consp pos))
882 mouse-1-click-in-non-selected-windows
883 (eq (selected-window) (posn-window pos)))
884 (or (mouse-posn-property pos 'follow-link)
885 (key-binding [follow-link] nil t pos)))))
886 (cond
887 ((eq action 'mouse-face)
888 (and (mouse-posn-property pos 'mouse-face) t))
889 ((functionp action)
9ed38a84 890 ;; FIXME: This seems questionable if the click is not in a buffer.
e9ae308c 891 ;; Should we instead decide that `action' takes a `posn'?
9ed38a84
DK
892 (if (consp pos)
893 (with-current-buffer (window-buffer (posn-window pos))
624c972d 894 (funcall action (posn-point pos)))
9ed38a84 895 (funcall action pos)))
91a2acb2 896 (t action))))
b0ca1b8a 897
5dbda518
KS
898(defun mouse-fixup-help-message (msg)
899 "Fix help message MSG for `mouse-1-click-follows-link'."
900 (let (mp pos)
901 (if (and mouse-1-click-follows-link
902 (stringp msg)
903 (save-match-data
904 (string-match "^mouse-2" msg))
905 (setq mp (mouse-pixel-position))
906 (consp (setq pos (cdr mp)))
907 (car pos) (>= (car pos) 0)
908 (cdr pos) (>= (cdr pos) 0)
909 (setq pos (posn-at-x-y (car pos) (cdr pos) (car mp)))
910 (windowp (posn-window pos)))
911 (with-current-buffer (window-buffer (posn-window pos))
912 (if (mouse-on-link-p pos)
913 (setq msg (concat
914 (cond
915 ((eq mouse-1-click-follows-link 'double) "double-")
916 ((and (integerp mouse-1-click-follows-link)
917 (< mouse-1-click-follows-link 0)) "Long ")
918 (t ""))
919 "mouse-1" (substring msg 7)))))))
920 msg)
65f76581 921
aaf15b8b
SM
922(defun mouse-move-drag-overlay (ol start end mode)
923 (unless (= start end)
924 ;; Go to START first, so that when we move to END, if it's in the middle
925 ;; of intangible text, point jumps in the direction away from START.
926 ;; Don't do it if START=END otherwise a single click risks selecting
927 ;; a region if it's on intangible text. This exception was originally
928 ;; only applied on entry to mouse-drag-region, which had the problem
929 ;; that a tiny move during a single-click would cause the intangible
930 ;; text to be selected.
931 (goto-char start)
39739f21
SM
932 (goto-char end)
933 (setq end (point)))
934 (let ((range (mouse-start-end start end mode)))
aaf15b8b
SM
935 (move-overlay ol (car range) (nth 1 range))))
936
624c972d 937(defun mouse-drag-track (start-event &optional
f1c4f757
S
938 do-mouse-drag-region-post-process)
939 "Track mouse drags by highlighting area between point and cursor.
940The region will be defined with mark and point, and the overlay
941will be deleted after return. DO-MOUSE-DRAG-REGION-POST-PROCESS
942should only be used by mouse-drag-region."
d65147f6 943 (mouse-minibuffer-check start-event)
aaf15b8b
SM
944 (setq mouse-selection-click-count-buffer (current-buffer))
945 (let* ((original-window (selected-window))
946 ;; We've recorded what we needed from the current buffer and
947 ;; window, now let's jump to the place of the event, where things
948 ;; are happening.
949 (_ (mouse-set-point start-event))
950 (echo-keystrokes 0)
4c9afcbe 951 (start-posn (event-start start-event))
600c6e3a
JB
952 (start-point (posn-point start-posn))
953 (start-window (posn-window start-posn))
02beb936 954 (start-window-start (window-start start-window))
1853aa6b 955 (start-hscroll (window-hscroll start-window))
600c6e3a 956 (bounds (window-edges start-window))
8413d0d2 957 (make-cursor-line-fully-visible nil)
600c6e3a
JB
958 (top (nth 1 bounds))
959 (bottom (if (window-minibuffer-p start-window)
960 (nth 3 bounds)
961 ;; Don't count the mode line.
e37de120 962 (1- (nth 3 bounds))))
b0ca1b8a 963 (on-link (and mouse-1-click-follows-link
185a53bb 964 (or mouse-1-click-in-non-selected-windows
aaf15b8b
SM
965 (eq start-window original-window))
966 ;; Use start-point before the intangibility
967 ;; treatment, in case we click on a link inside an
968 ;; intangible text.
91a2acb2 969 (mouse-on-link-p start-posn)))
aaf15b8b
SM
970 (click-count (1- (event-click-count start-event)))
971 (remap-double-click (and on-link
972 (eq mouse-1-click-follows-link 'double)
a9d01547
CY
973 (= click-count 1)))
974 ;; Suppress automatic hscrolling, because that is a nuisance
975 ;; when setting point near the right fringe (but see below).
976 (automatic-hscrolling-saved automatic-hscrolling)
977 (automatic-hscrolling nil))
eb6ff46f 978 (setq mouse-selection-click-count click-count)
08a1c178
RS
979 ;; In case the down click is in the middle of some intangible text,
980 ;; use the end of that text, and put it in START-POINT.
981 (if (< (point) start-point)
982 (goto-char start-point))
983 (setq start-point (point))
aaf15b8b 984 (if remap-double-click ;; Don't expand mouse overlay in links
65f76581 985 (setq click-count 0))
aaf15b8b
SM
986 (mouse-move-drag-overlay mouse-drag-overlay start-point start-point
987 click-count)
988 (overlay-put mouse-drag-overlay 'window start-window)
f767385c 989 (deactivate-mark)
f002506f 990 (let (event end end-point last-end-point)
bcd5aef1 991 (track-mouse
600c6e3a 992 (while (progn
b846d039 993 (setq event (read-event))
aaf15b8b
SM
994 (or (mouse-movement-p event)
995 (memq (car-safe event) '(switch-frame select-window))))
996 (if (memq (car-safe event) '(switch-frame select-window))
b846d039 997 nil
a9d01547
CY
998 ;; Automatic hscrolling did not occur during the call to
999 ;; `read-event'; but if the user subsequently drags the
1000 ;; mouse, go ahead and hscroll.
1001 (let ((automatic-hscrolling automatic-hscrolling-saved))
1002 (redisplay))
b846d039
JB
1003 (setq end (event-end event)
1004 end-point (posn-point end))
3617aa76 1005 (if (numberp end-point)
d5c847bb 1006 (setq last-end-point end-point))
b846d039
JB
1007
1008 (cond
b846d039
JB
1009 ;; Are we moving within the original window?
1010 ((and (eq (posn-window end) start-window)
1011 (integer-or-marker-p end-point))
aaf15b8b 1012 (mouse-move-drag-overlay mouse-drag-overlay start-point end-point click-count))
b846d039 1013
50e527bc
KH
1014 (t
1015 (let ((mouse-row (cdr (cdr (mouse-position)))))
aaf15b8b
SM
1016 (cond
1017 ((null mouse-row))
1018 ((< mouse-row top)
1019 (mouse-scroll-subr start-window (- mouse-row top)
1020 mouse-drag-overlay start-point))
1021 ((>= mouse-row bottom)
1022 (mouse-scroll-subr start-window (1+ (- mouse-row bottom))
1023 mouse-drag-overlay start-point)))))))))
b2013aad 1024
2e3329a5
RS
1025 ;; In case we did not get a mouse-motion event
1026 ;; for the final move of the mouse before a drag event
1027 ;; pretend that we did get one.
1028 (when (and (memq 'drag (event-modifiers (car-safe event)))
aaf15b8b 1029 (setq end (event-end event)
2e3329a5
RS
1030 end-point (posn-point end))
1031 (eq (posn-window end) start-window)
1032 (integer-or-marker-p end-point))
aaf15b8b 1033 (mouse-move-drag-overlay mouse-drag-overlay start-point end-point click-count))
2e3329a5 1034
f1c4f757 1035 ;; Handle the terminating event
4e399a53 1036 (if (consp event)
f28e9cbd
CY
1037 (let* ((fun (key-binding (vector (car event))))
1038 (do-multi-click (and (> (event-click-count event) 0)
1039 (functionp fun)
624c972d
JB
1040 (not (memq fun
1041 '(mouse-set-point
f1c4f757
S
1042 mouse-set-region))))))
1043 ;; Run the binding of the terminating up-event, if possible.
f28e9cbd
CY
1044 (if (and (not (= (overlay-start mouse-drag-overlay)
1045 (overlay-end mouse-drag-overlay)))
1046 (not do-multi-click))
bb3aa835
RS
1047 (let* ((stop-point
1048 (if (numberp (posn-point (event-end event)))
1049 (posn-point (event-end event))
1050 last-end-point))
1051 ;; The end that comes from where we ended the drag.
1052 ;; Point goes here.
1053 (region-termination
f1c4f757
S
1054 (if (and stop-point (< stop-point start-point))
1055 (overlay-start mouse-drag-overlay)
1056 (overlay-end mouse-drag-overlay)))
1057 ;; The end that comes from where we started the drag.
1058 ;; Mark goes there.
1059 (region-commencement
1060 (- (+ (overlay-end mouse-drag-overlay)
1061 (overlay-start mouse-drag-overlay))
1062 region-termination))
1063 last-command this-command)
177ffe92
MR
1064 (when (eq transient-mark-mode 'identity)
1065 ;; Reset `transient-mark-mode' to avoid expanding the region
1066 ;; while scrolling (compare thread on "Erroneous selection
1067 ;; extension ..." on bug-gnu-emacs from 2007-06-10).
1068 (setq transient-mark-mode nil))
f1c4f757
S
1069 (push-mark region-commencement t t)
1070 (goto-char region-termination)
1071 (if (not do-mouse-drag-region-post-process)
1072 ;; Skip all post-event handling, return immediately.
1073 (delete-overlay mouse-drag-overlay)
1074 ;; Don't let copy-region-as-kill set deactivate-mark.
1075 (when mouse-drag-copy-region
1076 (let (deactivate-mark)
1077 (copy-region-as-kill (point) (mark t))))
1078 (let ((buffer (current-buffer)))
1079 (mouse-show-mark)
1080 ;; mouse-show-mark can call read-event,
1081 ;; and that means the Emacs server could switch buffers
1082 ;; under us. If that happened,
1083 ;; avoid trying to use the region.
1084 (and (mark t) mark-active
1085 (eq buffer (current-buffer))
1086 (mouse-set-region-1)))))
aaf15b8b 1087 ;; Run the binding of the terminating up-event.
f28e9cbd
CY
1088 ;; If a multiple click is not bound to mouse-set-point,
1089 ;; cancel the effects of mouse-move-drag-overlay to
1090 ;; avoid producing wrong results.
1091 (if do-multi-click (goto-char start-point))
1092 (delete-overlay mouse-drag-overlay)
aaf15b8b 1093 (when (and (functionp fun)
05b531f6
EZ
1094 (= start-hscroll (window-hscroll start-window))
1095 ;; Don't run the up-event handler if the
1096 ;; window start changed in a redisplay after
1097 ;; the mouse-set-point for the down-mouse
1098 ;; event at the beginning of this function.
1099 ;; When the window start has changed, the
1100 ;; up-mouse event will contain a different
1101 ;; position due to the new window contents,
1102 ;; and point is set again.
1103 (or end-point
1104 (= (window-start start-window)
1105 start-window-start)))
1106 (when (and on-link
18e980c2
RS
1107 (or (not end-point) (= end-point start-point))
1108 (consp event)
1109 (or remap-double-click
1110 (and
1111 (not (eq mouse-1-click-follows-link 'double))
1112 (= click-count 0)
1113 (= (event-click-count event) 1)
18e980c2
RS
1114 (or (not (integerp mouse-1-click-follows-link))
1115 (let ((t0 (posn-timestamp (event-start start-event)))
1116 (t1 (posn-timestamp (event-end event))))
1117 (and (integerp t0) (integerp t1)
1118 (if (> mouse-1-click-follows-link 0)
1119 (<= (- t1 t0) mouse-1-click-follows-link)
1120 (< (- t0 t1) mouse-1-click-follows-link))))))))
745cfc57 1121 ;; If we rebind to mouse-2, reselect previous selected window,
18e980c2
RS
1122 ;; so that the mouse-2 event runs in the same
1123 ;; situation as if user had clicked it directly.
1124 ;; Fixes the bug reported by juri@jurta.org on 2005-12-27.
18e980c2
RS
1125 (if (or (vectorp on-link) (stringp on-link))
1126 (setq event (aref on-link 0))
745cfc57 1127 (select-window original-window)
cbf090c4
RS
1128 (setcar event 'mouse-2)
1129 ;; If this mouse click has never been done by
1130 ;; the user, it doesn't have the necessary
1131 ;; property to be interpreted correctly.
1132 (put 'mouse-2 'event-kind 'mouse-click)))
aaf15b8b
SM
1133 (push event unread-command-events))))
1134
1135 ;; Case where the end-event is not a cons cell (it's just a boring
1136 ;; char-key-press).
e6c2f5d4 1137 (delete-overlay mouse-drag-overlay)))))
e37de120
RS
1138\f
1139;; Commands to handle xterm-style multiple clicks.
e37de120
RS
1140(defun mouse-skip-word (dir)
1141 "Skip over word, over whitespace, or over identical punctuation.
1142If DIR is positive skip forward; if negative, skip backward."
1143 (let* ((char (following-char))
1144 (syntax (char-to-string (char-syntax char))))
258e3295
KH
1145 (cond ((string= syntax "w")
1146 ;; Here, we can't use skip-syntax-forward/backward because
1147 ;; they don't pay attention to word-separating-categories,
1148 ;; and thus they will skip over a true word boundary. So,
1149 ;; we simularte the original behaviour by using
1150 ;; forward-word.
1151 (if (< dir 0)
1152 (if (not (looking-at "\\<"))
1153 (forward-word -1))
1154 (if (or (looking-at "\\<") (not (looking-at "\\>")))
1155 (forward-word 1))))
1156 ((string= syntax " ")
08a1c178
RS
1157 (if (< dir 0)
1158 (skip-syntax-backward syntax)
1159 (skip-syntax-forward syntax)))
1160 ((string= syntax "_")
1161 (if (< dir 0)
1162 (skip-syntax-backward "w_")
1163 (skip-syntax-forward "w_")))
1164 ((< dir 0)
1165 (while (and (not (bobp)) (= (preceding-char) char))
1166 (forward-char -1)))
1167 (t
1168 (while (and (not (eobp)) (= (following-char) char))
1169 (forward-char 1))))))
e37de120 1170
eb6ff46f 1171(defun mouse-start-end (start end mode)
c3bb6d70 1172 "Return a list of region bounds based on START and END according to MODE.
a7df580d
DL
1173If MODE is 0 then set point to (min START END), mark to (max START END).
1174If MODE is 1 then set point to start of word at (min START END),
1175mark to end of word at (max START END).
1176If MODE is 2 then do the same for lines."
e37de120
RS
1177 (if (> start end)
1178 (let ((temp start))
1179 (setq start end
1180 end temp)))
9a974c88 1181 (setq mode (mod mode 3))
e37de120
RS
1182 (cond ((= mode 0)
1183 (list start end))
1184 ((and (= mode 1)
1185 (= start end)
1ec71583 1186 (char-after start)
e37de120 1187 (= (char-syntax (char-after start)) ?\())
6f482eec
RS
1188 (list start
1189 (save-excursion
1190 (goto-char start)
1191 (forward-sexp 1)
1192 (point))))
e37de120
RS
1193 ((and (= mode 1)
1194 (= start end)
1ec71583 1195 (char-after start)
e37de120 1196 (= (char-syntax (char-after start)) ?\)))
7b611de0 1197 (list (save-excursion
e37de120 1198 (goto-char (1+ start))
d89a4a47
RS
1199 (backward-sexp 1)
1200 (point))
e37de120 1201 (1+ start)))
53770877
RS
1202 ((and (= mode 1)
1203 (= start end)
1204 (char-after start)
1205 (= (char-syntax (char-after start)) ?\"))
1206 (let ((open (or (eq start (point-min))
1207 (save-excursion
1208 (goto-char (- start 1))
1209 (looking-at "\\s(\\|\\s \\|\\s>")))))
1210 (if open
1211 (list start
1212 (save-excursion
1213 (condition-case nil
7b611de0 1214 (progn
53770877
RS
1215 (goto-char start)
1216 (forward-sexp 1)
1217 (point))
1218 (error end))))
f1017d55 1219 (list (save-excursion
53770877
RS
1220 (condition-case nil
1221 (progn
1222 (goto-char (1+ start))
1223 (backward-sexp 1)
1224 (point))
f1017d55
RS
1225 (error end)))
1226 (1+ start)))))
e37de120
RS
1227 ((= mode 1)
1228 (list (save-excursion
1229 (goto-char start)
1230 (mouse-skip-word -1)
1231 (point))
1232 (save-excursion
1233 (goto-char end)
1234 (mouse-skip-word 1)
1235 (point))))
1236 ((= mode 2)
1237 (list (save-excursion
1238 (goto-char start)
1239 (beginning-of-line 1)
1240 (point))
1241 (save-excursion
1242 (goto-char end)
1243 (forward-line 1)
1244 (point))))))
e66feb07 1245\f
3f26b32a
RS
1246;; Subroutine: set the mark where CLICK happened,
1247;; but don't do anything else.
1248(defun mouse-set-mark-fast (click)
d65147f6 1249 (mouse-minibuffer-check click)
3f26b32a
RS
1250 (let ((posn (event-start click)))
1251 (select-window (posn-window posn))
1252 (if (numberp (posn-point posn))
1253 (push-mark (posn-point posn) t t))))
1254
98aac09d
MB
1255(defun mouse-undouble-last-event (events)
1256 (let* ((index (1- (length events)))
1257 (last (nthcdr index events))
1258 (event (car last))
1259 (basic (event-basic-type event))
397a88f3
RS
1260 (old-modifiers (event-modifiers event))
1261 (modifiers (delq 'double (delq 'triple (copy-sequence old-modifiers))))
98aac09d
MB
1262 (new
1263 (if (consp event)
7132500b
RS
1264 ;; Use reverse, not nreverse, since event-modifiers
1265 ;; does not copy the list it returns.
3bb846b8 1266 (cons (event-convert-list (reverse (cons basic modifiers)))
98aac09d
MB
1267 (cdr event))
1268 event)))
1269 (setcar last new)
397a88f3
RS
1270 (if (and (not (equal modifiers old-modifiers))
1271 (key-binding (apply 'vector events)))
98aac09d
MB
1272 t
1273 (setcar last event)
1274 nil)))
1275
7b611de0 1276;; Momentarily show where the mark is, if highlighting doesn't show it.
7aeb7370 1277
c3bb6d70
RS
1278(defcustom mouse-region-delete-keys '([delete] [deletechar] [backspace])
1279 "List of keys that should cause the mouse region to be deleted."
1280 :group 'mouse
1281 :type '(repeat key-sequence))
7aeb7370 1282
3f26b32a 1283(defun mouse-show-mark ()
d3d3d650
RS
1284 (let ((inhibit-quit t)
1285 (echo-keystrokes 0)
1286 event events key ignore
b10c429f 1287 (x-lost-selection-functions
ab60bd74
SS
1288 (when (boundp 'x-lost-selection-functions)
1289 (copy-sequence x-lost-selection-functions))))
1290 (add-hook 'x-lost-selection-functions
d3d3d650 1291 (lambda (seltype)
ab60bd74
SS
1292 (when (eq seltype 'PRIMARY)
1293 (setq ignore t)
1294 (throw 'mouse-show-mark t))))
d3d3d650
RS
1295 (if transient-mark-mode
1296 (delete-overlay mouse-drag-overlay)
1297 (move-overlay mouse-drag-overlay (point) (mark t)))
1298 (catch 'mouse-show-mark
1299 ;; In this loop, execute scroll bar and switch-frame events.
fbd8dc8a 1300 ;; Should we similarly handle `select-window' events? --Stef
d3d3d650
RS
1301 ;; Also ignore down-events that are undefined.
1302 (while (progn (setq event (read-event))
1303 (setq events (append events (list event)))
1304 (setq key (apply 'vector events))
1305 (or (and (consp event)
1306 (eq (car event) 'switch-frame))
1307 (and (consp event)
1308 (eq (posn-point (event-end event))
1309 'vertical-scroll-bar))
1310 (and (memq 'down (event-modifiers event))
1311 (not (key-binding key))
1312 (not (mouse-undouble-last-event events))
1313 (not (member key mouse-region-delete-keys)))))
1314 (and (consp event)
1315 (or (eq (car event) 'switch-frame)
1316 (eq (posn-point (event-end event))
1317 'vertical-scroll-bar))
1318 (let ((keys (vector 'vertical-scroll-bar event)))
1319 (and (key-binding keys)
1320 (progn
1321 (call-interactively (key-binding keys)
1322 nil keys)
1323 (setq events nil)))))))
1324 ;; If we lost the selection, just turn off the highlighting.
ab60bd74 1325 (unless ignore
d3d3d650
RS
1326 ;; For certain special keys, delete the region.
1327 (if (member key mouse-region-delete-keys)
760a2050
KS
1328 (progn
1329 ;; Since notionally this is a separate command,
1330 ;; run all the hooks that would be run if it were
1331 ;; executed separately.
1332 (run-hooks 'post-command-hook)
1333 (setq last-command this-command)
1334 (setq this-original-command 'delete-region)
1335 (setq this-command (or (command-remapping this-original-command)
1336 this-original-command))
1337 (run-hooks 'pre-command-hook)
1338 (call-interactively this-command))
d3d3d650
RS
1339 ;; Otherwise, unread the key so it gets executed normally.
1340 (setq unread-command-events
1341 (nconc events unread-command-events))))
1342 (setq quit-flag nil)
1343 (unless transient-mark-mode
f4b60fe6 1344 (delete-overlay mouse-drag-overlay))))
3f26b32a 1345
cc0a8174
JB
1346(defun mouse-set-mark (click)
1347 "Set mark at the position clicked on with the mouse.
1348Display cursor at that position for a second.
1349This must be bound to a mouse click."
ec558adc 1350 (interactive "e")
f598fb03
RS
1351 (mouse-minibuffer-check click)
1352 (select-window (posn-window (event-start click)))
1353 ;; We don't use save-excursion because that preserves the mark too.
72ea54a4
RS
1354 (let ((point-save (point)))
1355 (unwind-protect
cc0a8174 1356 (progn (mouse-set-point click)
897897e3
RS
1357 (push-mark nil t t)
1358 (or transient-mark-mode
1359 (sit-for 1)))
72ea54a4
RS
1360 (goto-char point-save))))
1361
cc0a8174
JB
1362(defun mouse-kill (click)
1363 "Kill the region between point and the mouse click.
1364The text is saved in the kill ring, as with \\[kill-region]."
ec558adc 1365 (interactive "e")
d65147f6 1366 (mouse-minibuffer-check click)
142c7672
KH
1367 (let* ((posn (event-start click))
1368 (click-posn (posn-point posn)))
1369 (select-window (posn-window posn))
bd307392
JB
1370 (if (numberp click-posn)
1371 (kill-region (min (point) click-posn)
1372 (max (point) click-posn)))))
72ea54a4 1373
87ef29fd
JB
1374(defun mouse-yank-at-click (click arg)
1375 "Insert the last stretch of killed text at the position clicked on.
0e57ab65 1376Also move point to one end of the text thus inserted (normally the end),
231c4d1a 1377and set mark at the beginning.
50f58001
RS
1378Prefix arguments are interpreted as with \\[yank].
1379If `mouse-yank-at-point' is non-nil, insert at point
1380regardless of where you click."
a4cabe41 1381 (interactive "e\nP")
33c448cd
RS
1382 ;; Give temporary modes such as isearch a chance to turn off.
1383 (run-hooks 'mouse-leave-buffer-hook)
50f58001 1384 (or mouse-yank-at-point (mouse-set-point click))
d89a4a47 1385 (setq this-command 'yank)
a814e9df 1386 (setq mouse-selection-click-count 0)
87ef29fd
JB
1387 (yank arg))
1388
63571b5a
RS
1389(defun mouse-yank-primary (click)
1390 "Insert the primary selection at the position clicked on.
1391Move point to the end of the inserted text.
1392If `mouse-yank-at-point' is non-nil, insert at point
1393regardless of where you click."
1394 (interactive "e")
1395 ;; Give temporary modes such as isearch a chance to turn off.
1396 (run-hooks 'mouse-leave-buffer-hook)
1397 (or mouse-yank-at-point (mouse-set-point click))
1398 (let ((primary (x-get-selection 'PRIMARY)))
1399 (if primary
1400 (insert (x-get-selection 'PRIMARY))
1401 (error "No primary selection"))))
1402
87ef29fd 1403(defun mouse-kill-ring-save (click)
cc0a8174
JB
1404 "Copy the region between point and the mouse click in the kill ring.
1405This does not delete the region; it acts like \\[kill-ring-save]."
ec558adc 1406 (interactive "e")
3f26b32a 1407 (mouse-set-mark-fast click)
6452d8a6
RS
1408 (let (this-command last-command)
1409 (kill-ring-save (point) (mark t)))
3f26b32a 1410 (mouse-show-mark))
72ea54a4 1411
dbc4e1c1
JB
1412;;; This function used to delete the text between point and the mouse
1413;;; whenever it was equal to the front of the kill ring, but some
1414;;; people found that confusing.
1415
1416;;; A list (TEXT START END), describing the text and position of the last
1417;;; invocation of mouse-save-then-kill.
1418(defvar mouse-save-then-kill-posn nil)
1419
26d280b9 1420(defun mouse-save-then-kill-delete-region (beg end)
9a974c88
RS
1421 ;; We must make our own undo boundaries
1422 ;; because they happen automatically only for the current buffer.
1423 (undo-boundary)
dd524dbd
RS
1424 (if (or (= beg end) (eq buffer-undo-list t))
1425 ;; If we have no undo list in this buffer,
1426 ;; just delete.
1427 (delete-region beg end)
1428 ;; Delete, but make the undo-list entry share with the kill ring.
1429 ;; First, delete just one char, so in case buffer is being modified
1430 ;; for the first time, the undo list records that fact.
8faa9707 1431 (let (before-change-functions after-change-functions)
2f4b15ef
RS
1432 (delete-region beg
1433 (+ beg (if (> end beg) 1 -1))))
dd524dbd
RS
1434 (let ((buffer-undo-list buffer-undo-list))
1435 ;; Undo that deletion--but don't change the undo list!
8faa9707 1436 (let (before-change-functions after-change-functions)
2f4b15ef 1437 (primitive-undo 1 buffer-undo-list))
dd524dbd
RS
1438 ;; Now delete the rest of the specified region,
1439 ;; but don't record it.
1440 (setq buffer-undo-list t)
9a974c88
RS
1441 (if (/= (length (car kill-ring)) (- (max end beg) (min end beg)))
1442 (error "Lossage in mouse-save-then-kill-delete-region"))
dd524dbd
RS
1443 (delete-region beg end))
1444 (let ((tail buffer-undo-list))
1445 ;; Search back in buffer-undo-list for the string
1446 ;; that came from deleting one character.
1447 (while (and tail (not (stringp (car (car tail)))))
1448 (setq tail (cdr tail)))
1449 ;; Replace it with an entry for the entire deleted text.
1450 (and tail
9a974c88
RS
1451 (setcar tail (cons (car kill-ring) (min beg end))))))
1452 (undo-boundary))
eb6ff46f 1453
947da0c4 1454(defun mouse-save-then-kill (click)
40a45a9f
RS
1455 "Save text to point in kill ring; the second time, kill the text.
1456If the text between point and the mouse is the same as what's
1457at the front of the kill ring, this deletes the text.
1458Otherwise, it adds the text to the kill ring, like \\[kill-ring-save],
eb6ff46f
RS
1459which prepares for a second click to delete the text.
1460
1461If you have selected words or lines, this command extends the
1462selection through the word or line clicked on. If you do this
1463again in a different position, it extends the selection again.
7b611de0 1464If you do this twice in the same position, the selection is killed."
947da0c4 1465 (interactive "e")
53016bea
RS
1466 (let ((before-scroll
1467 (with-current-buffer (window-buffer (posn-window (event-start click)))
1468 point-before-scroll)))
b64548c7
RS
1469 (mouse-minibuffer-check click)
1470 (let ((click-posn (posn-point (event-start click)))
1471 ;; Don't let a subsequent kill command append to this one:
1472 ;; prevent setting this-command to kill-region.
1473 (this-command this-command))
aaf15b8b
SM
1474 (if (and (with-current-buffer
1475 (window-buffer (posn-window (event-start click)))
c8c5bd24
RS
1476 (and (mark t) (> (mod mouse-selection-click-count 3) 0)
1477 ;; Don't be fooled by a recent click in some other buffer.
7b611de0 1478 (eq mouse-selection-click-count-buffer
c8c5bd24 1479 (current-buffer)))))
b64548c7
RS
1480 (if (not (and (eq last-command 'mouse-save-then-kill)
1481 (equal click-posn
1482 (car (cdr-safe (cdr-safe mouse-save-then-kill-posn))))))
1483 ;; Find both ends of the object selected by this click.
1484 (let* ((range
1485 (mouse-start-end click-posn click-posn
1486 mouse-selection-click-count)))
1487 ;; Move whichever end is closer to the click.
1488 ;; That's what xterm does, and it seems reasonable.
1489 (if (< (abs (- click-posn (mark t)))
1490 (abs (- click-posn (point))))
1491 (set-mark (car range))
1492 (goto-char (nth 1 range)))
1493 ;; We have already put the old region in the kill ring.
1494 ;; Replace it with the extended region.
1495 ;; (It would be annoying to make a separate entry.)
1496 (kill-new (buffer-substring (point) (mark t)) t)
e6c2f5d4 1497 (mouse-set-region-1)
b64548c7
RS
1498 ;; Arrange for a repeated mouse-3 to kill this region.
1499 (setq mouse-save-then-kill-posn
1500 (list (car kill-ring) (point) click-posn))
1501 (mouse-show-mark))
1502 ;; If we click this button again without moving it,
1503 ;; that time kill.
bcde3748 1504 (mouse-save-then-kill-delete-region (mark) (point))
b64548c7 1505 (setq mouse-selection-click-count 0)
dd524dbd 1506 (setq mouse-save-then-kill-posn nil))
b64548c7
RS
1507 (if (and (eq last-command 'mouse-save-then-kill)
1508 mouse-save-then-kill-posn
1509 (eq (car mouse-save-then-kill-posn) (car kill-ring))
1510 (equal (cdr mouse-save-then-kill-posn) (list (point) click-posn)))
1511 ;; If this is the second time we've called
1512 ;; mouse-save-then-kill, delete the text from the buffer.
1513 (progn
1514 (mouse-save-then-kill-delete-region (point) (mark))
1515 ;; After we kill, another click counts as "the first time".
1516 (setq mouse-save-then-kill-posn nil))
c8f264ae
RS
1517 ;; This is not a repetition.
1518 ;; We are adjusting an old selection or creating a new one.
b64548c7
RS
1519 (if (or (and (eq last-command 'mouse-save-then-kill)
1520 mouse-save-then-kill-posn)
1521 (and mark-active transient-mark-mode)
1522 (and (memq last-command
1523 '(mouse-drag-region mouse-set-region))
1524 (or mark-even-if-inactive
1525 (not transient-mark-mode))))
1526 ;; We have a selection or suitable region, so adjust it.
1527 (let* ((posn (event-start click))
1528 (new (posn-point posn)))
1529 (select-window (posn-window posn))
1530 (if (numberp new)
1531 (progn
1532 ;; Move whichever end of the region is closer to the click.
1533 ;; That is what xterm does, and it seems reasonable.
ed784c53 1534 (if (<= (abs (- new (point))) (abs (- new (mark t))))
b64548c7
RS
1535 (goto-char new)
1536 (set-mark new))
1537 (setq deactivate-mark nil)))
aaf15b8b 1538 (kill-new (buffer-substring (point) (mark t)) t))
b64548c7
RS
1539 ;; Set the mark where point is, then move where clicked.
1540 (mouse-set-mark-fast click)
1541 (if before-scroll
1542 (goto-char before-scroll))
aaf15b8b
SM
1543 (exchange-point-and-mark) ;Why??? --Stef
1544 (kill-new (buffer-substring (point) (mark t))))
1545 (mouse-show-mark)
e6c2f5d4 1546 (mouse-set-region-1)
b64548c7
RS
1547 (setq mouse-save-then-kill-posn
1548 (list (car kill-ring) (point) click-posn)))))))
e66feb07
RS
1549\f
1550(global-set-key [M-mouse-1] 'mouse-start-secondary)
1551(global-set-key [M-drag-mouse-1] 'mouse-set-secondary)
1552(global-set-key [M-down-mouse-1] 'mouse-drag-secondary)
1553(global-set-key [M-mouse-3] 'mouse-secondary-save-then-kill)
9a974c88 1554(global-set-key [M-mouse-2] 'mouse-yank-secondary)
e66feb07 1555
aaf15b8b
SM
1556(defconst mouse-secondary-overlay
1557 (let ((ol (make-overlay (point-min) (point-min))))
1558 (delete-overlay ol)
1559 (overlay-put ol 'face 'secondary-selection)
1560 ol)
1561 "An overlay which records the current secondary selection.
1562It is deleted when there is no secondary selection.")
e66feb07 1563
a94c7fcc
RS
1564(defvar mouse-secondary-click-count 0)
1565
e66feb07
RS
1566;; A marker which records the specified first end for a secondary selection.
1567;; May be nil.
1568(defvar mouse-secondary-start nil)
1569
1570(defun mouse-start-secondary (click)
1571 "Set one end of the secondary selection to the position clicked on.
1572Use \\[mouse-secondary-save-then-kill] to set the other end
1573and complete the secondary selection."
1574 (interactive "e")
d65147f6 1575 (mouse-minibuffer-check click)
e66feb07 1576 (let ((posn (event-start click)))
aaf15b8b 1577 (with-current-buffer (window-buffer (posn-window posn))
230aaa73 1578 ;; Cancel any preexisting secondary selection.
aaf15b8b 1579 (delete-overlay mouse-secondary-overlay)
230aaa73
RS
1580 (if (numberp (posn-point posn))
1581 (progn
1582 (or mouse-secondary-start
1583 (setq mouse-secondary-start (make-marker)))
1584 (move-marker mouse-secondary-start (posn-point posn)))))))
e66feb07
RS
1585
1586(defun mouse-set-secondary (click)
1587 "Set the secondary selection to the text that the mouse is dragged over.
1588This must be bound to a mouse drag event."
1589 (interactive "e")
d65147f6 1590 (mouse-minibuffer-check click)
e66feb07
RS
1591 (let ((posn (event-start click))
1592 beg
1593 (end (event-end click)))
aaf15b8b 1594 (with-current-buffer (window-buffer (posn-window posn))
230aaa73
RS
1595 (if (numberp (posn-point posn))
1596 (setq beg (posn-point posn)))
3e4f866b
CY
1597 (move-overlay mouse-secondary-overlay beg (posn-point end))
1598 (x-set-selection
1599 'SECONDARY
1600 (buffer-substring (overlay-start mouse-secondary-overlay)
1601 (overlay-end mouse-secondary-overlay))))))
947da0c4 1602
d89a4a47 1603(defun mouse-drag-secondary (start-event)
e66feb07 1604 "Set the secondary selection to the text that the mouse is dragged over.
d89a4a47 1605Highlight the drag area as you move the mouse.
efc10c97
RS
1606This must be bound to a button-down mouse event.
1607The function returns a non-nil value if it creates a secondary selection."
e66feb07 1608 (interactive "e")
d65147f6 1609 (mouse-minibuffer-check start-event)
4c9afcbe
RS
1610 (let* ((echo-keystrokes 0)
1611 (start-posn (event-start start-event))
d89a4a47
RS
1612 (start-point (posn-point start-posn))
1613 (start-window (posn-window start-posn))
d89a4a47
RS
1614 (bounds (window-edges start-window))
1615 (top (nth 1 bounds))
1616 (bottom (if (window-minibuffer-p start-window)
1617 (nth 3 bounds)
1618 ;; Don't count the mode line.
1619 (1- (nth 3 bounds))))
1620 (click-count (1- (event-click-count start-event))))
aaf15b8b 1621 (with-current-buffer (window-buffer start-window)
a94c7fcc 1622 (setq mouse-secondary-click-count click-count)
9a974c88 1623 (if (> (mod click-count 3) 0)
26d280b9
RS
1624 ;; Double or triple press: make an initial selection
1625 ;; of one word or line.
d89a4a47
RS
1626 (let ((range (mouse-start-end start-point start-point click-count)))
1627 (set-marker mouse-secondary-start nil)
aaf15b8b
SM
1628 ;; Why the double move? --Stef
1629 ;; (move-overlay mouse-secondary-overlay 1 1
1630 ;; (window-buffer start-window))
d89a4a47
RS
1631 (move-overlay mouse-secondary-overlay (car range) (nth 1 range)
1632 (window-buffer start-window)))
26d280b9 1633 ;; Single-press: cancel any preexisting secondary selection.
d89a4a47
RS
1634 (or mouse-secondary-start
1635 (setq mouse-secondary-start (make-marker)))
1636 (set-marker mouse-secondary-start start-point)
1637 (delete-overlay mouse-secondary-overlay))
1638 (let (event end end-point)
1639 (track-mouse
1640 (while (progn
1641 (setq event (read-event))
1642 (or (mouse-movement-p event)
fbd8dc8a 1643 (memq (car-safe event) '(switch-frame select-window))))
d89a4a47 1644
fbd8dc8a 1645 (if (memq (car-safe event) '(switch-frame select-window))
d89a4a47
RS
1646 nil
1647 (setq end (event-end event)
1648 end-point (posn-point end))
1649 (cond
d89a4a47
RS
1650 ;; Are we moving within the original window?
1651 ((and (eq (posn-window end) start-window)
1652 (integer-or-marker-p end-point))
d89a4a47
RS
1653 (let ((range (mouse-start-end start-point end-point
1654 click-count)))
0136e1e3
RS
1655 (if (or (/= start-point end-point)
1656 (null (marker-position mouse-secondary-start)))
1657 (progn
1658 (set-marker mouse-secondary-start nil)
1659 (move-overlay mouse-secondary-overlay
1660 (car range) (nth 1 range))))))
3b0aebe9
RS
1661 (t
1662 (let ((mouse-row (cdr (cdr (mouse-position)))))
1663 (cond
1664 ((null mouse-row))
1665 ((< mouse-row top)
e919a622
RS
1666 (mouse-scroll-subr start-window (- mouse-row top)
1667 mouse-secondary-overlay start-point))
d2287ded 1668 ((>= mouse-row bottom)
e919a622 1669 (mouse-scroll-subr start-window (1+ (- mouse-row bottom))
3b0aebe9 1670 mouse-secondary-overlay start-point)))))))))
d89a4a47 1671
4e399a53 1672 (if (consp event)
d89a4a47
RS
1673 (if (marker-position mouse-secondary-start)
1674 (save-window-excursion
1675 (delete-overlay mouse-secondary-overlay)
9a974c88 1676 (x-set-selection 'SECONDARY nil)
d89a4a47
RS
1677 (select-window start-window)
1678 (save-excursion
1679 (goto-char mouse-secondary-start)
efc10c97
RS
1680 (sit-for 1)
1681 nil))
9a974c88
RS
1682 (x-set-selection
1683 'SECONDARY
1684 (buffer-substring (overlay-start mouse-secondary-overlay)
1685 (overlay-end mouse-secondary-overlay)))))))))
e66feb07 1686
9a974c88 1687(defun mouse-yank-secondary (click)
50f58001
RS
1688 "Insert the secondary selection at the position clicked on.
1689Move point to the end of the inserted text.
1690If `mouse-yank-at-point' is non-nil, insert at point
1691regardless of where you click."
a4cabe41 1692 (interactive "e")
33c448cd
RS
1693 ;; Give temporary modes such as isearch a chance to turn off.
1694 (run-hooks 'mouse-leave-buffer-hook)
50f58001 1695 (or mouse-yank-at-point (mouse-set-point click))
b3709a53
RS
1696 (let ((secondary (x-get-selection 'SECONDARY)))
1697 (if secondary
1698 (insert (x-get-selection 'SECONDARY))
1699 (error "No secondary selection"))))
9a974c88 1700
7e6404f6 1701(defun mouse-kill-secondary ()
9a974c88
RS
1702 "Kill the text in the secondary selection.
1703This is intended more as a keyboard command than as a mouse command
1704but it can work as either one.
1705
1706The current buffer (in case of keyboard use), or the buffer clicked on,
1707must be the one that the secondary selection is in. This requirement
1708is to prevent accidents."
7e6404f6
RS
1709 (interactive)
1710 (let* ((keys (this-command-keys))
1711 (click (elt keys (1- (length keys)))))
1712 (or (eq (overlay-buffer mouse-secondary-overlay)
1713 (if (listp click)
1714 (window-buffer (posn-window (event-start click)))
1715 (current-buffer)))
1716 (error "Select or click on the buffer where the secondary selection is")))
9dfab550 1717 (let (this-command)
aaf15b8b 1718 (with-current-buffer (overlay-buffer mouse-secondary-overlay)
9dfab550
RS
1719 (kill-region (overlay-start mouse-secondary-overlay)
1720 (overlay-end mouse-secondary-overlay))))
e66feb07 1721 (delete-overlay mouse-secondary-overlay)
9dfab550 1722;;; (x-set-selection 'SECONDARY nil)
aaf15b8b 1723 )
e66feb07
RS
1724
1725(defun mouse-secondary-save-then-kill (click)
d89a4a47 1726 "Save text to point in kill ring; the second time, kill the text.
7bbe2cc7
RS
1727You must use this in a buffer where you have recently done \\[mouse-start-secondary].
1728If the text between where you did \\[mouse-start-secondary] and where
1729you use this command matches the text at the front of the kill ring,
1730this command deletes the text.
e66feb07 1731Otherwise, it adds the text to the kill ring, like \\[kill-ring-save],
7bbe2cc7 1732which prepares for a second click with this command to delete the text.
d89a4a47 1733
7bbe2cc7
RS
1734If you have already made a secondary selection in that buffer,
1735this command extends or retracts the selection to where you click.
1736If you do this again in a different position, it extends or retracts
1737again. If you do this twice in the same position, it kills the selection."
e66feb07 1738 (interactive "e")
d65147f6 1739 (mouse-minibuffer-check click)
d89a4a47
RS
1740 (let ((posn (event-start click))
1741 (click-posn (posn-point (event-start click)))
e66feb07
RS
1742 ;; Don't let a subsequent kill command append to this one:
1743 ;; prevent setting this-command to kill-region.
1744 (this-command this-command))
9a974c88 1745 (or (eq (window-buffer (posn-window posn))
aaf15b8b 1746 (or (overlay-buffer mouse-secondary-overlay)
9a974c88
RS
1747 (if mouse-secondary-start
1748 (marker-buffer mouse-secondary-start))))
1749 (error "Wrong buffer"))
aaf15b8b 1750 (with-current-buffer (window-buffer (posn-window posn))
a94c7fcc 1751 (if (> (mod mouse-secondary-click-count 3) 0)
9a974c88
RS
1752 (if (not (and (eq last-command 'mouse-secondary-save-then-kill)
1753 (equal click-posn
1754 (car (cdr-safe (cdr-safe mouse-save-then-kill-posn))))))
1755 ;; Find both ends of the object selected by this click.
1756 (let* ((range
1757 (mouse-start-end click-posn click-posn
a94c7fcc 1758 mouse-secondary-click-count)))
9a974c88
RS
1759 ;; Move whichever end is closer to the click.
1760 ;; That's what xterm does, and it seems reasonable.
1761 (if (< (abs (- click-posn (overlay-start mouse-secondary-overlay)))
1762 (abs (- click-posn (overlay-end mouse-secondary-overlay))))
1763 (move-overlay mouse-secondary-overlay (car range)
1764 (overlay-end mouse-secondary-overlay))
d89a4a47
RS
1765 (move-overlay mouse-secondary-overlay
1766 (overlay-start mouse-secondary-overlay)
1767 (nth 1 range)))
9a974c88
RS
1768 ;; We have already put the old region in the kill ring.
1769 ;; Replace it with the extended region.
1770 ;; (It would be annoying to make a separate entry.)
f69140fd
KH
1771 (kill-new (buffer-substring
1772 (overlay-start mouse-secondary-overlay)
1773 (overlay-end mouse-secondary-overlay)) t)
9a974c88
RS
1774 ;; Arrange for a repeated mouse-3 to kill this region.
1775 (setq mouse-save-then-kill-posn
1776 (list (car kill-ring) (point) click-posn)))
1777 ;; If we click this button again without moving it,
1778 ;; that time kill.
d89a4a47 1779 (progn
9a974c88
RS
1780 (mouse-save-then-kill-delete-region
1781 (overlay-start mouse-secondary-overlay)
1782 (overlay-end mouse-secondary-overlay))
1783 (setq mouse-save-then-kill-posn nil)
a94c7fcc 1784 (setq mouse-secondary-click-count 0)
9a974c88
RS
1785 (delete-overlay mouse-secondary-overlay)))
1786 (if (and (eq last-command 'mouse-secondary-save-then-kill)
1787 mouse-save-then-kill-posn
1788 (eq (car mouse-save-then-kill-posn) (car kill-ring))
1789 (equal (cdr mouse-save-then-kill-posn) (list (point) click-posn)))
1790 ;; If this is the second time we've called
1791 ;; mouse-secondary-save-then-kill, delete the text from the buffer.
1792 (progn
1793 (mouse-save-then-kill-delete-region
1794 (overlay-start mouse-secondary-overlay)
1795 (overlay-end mouse-secondary-overlay))
1796 (setq mouse-save-then-kill-posn nil)
1797 (delete-overlay mouse-secondary-overlay))
1798 (if (overlay-start mouse-secondary-overlay)
1799 ;; We have a selection, so adjust it.
1800 (progn
1801 (if (numberp click-posn)
1802 (progn
1803 ;; Move whichever end of the region is closer to the click.
1804 ;; That is what xterm does, and it seems reasonable.
1805 (if (< (abs (- click-posn (overlay-start mouse-secondary-overlay)))
1806 (abs (- click-posn (overlay-end mouse-secondary-overlay))))
1807 (move-overlay mouse-secondary-overlay click-posn
1808 (overlay-end mouse-secondary-overlay))
d89a4a47
RS
1809 (move-overlay mouse-secondary-overlay
1810 (overlay-start mouse-secondary-overlay)
1811 click-posn))
9a974c88 1812 (setq deactivate-mark nil)))
0136e1e3 1813 (if (eq last-command 'mouse-secondary-save-then-kill)
7b611de0 1814 ;; If the front of the kill ring comes from
f69140fd
KH
1815 ;; an immediately previous use of this command,
1816 ;; replace it with the extended region.
1817 ;; (It would be annoying to make a separate entry.)
1818 (kill-new (buffer-substring
0136e1e3 1819 (overlay-start mouse-secondary-overlay)
f69140fd 1820 (overlay-end mouse-secondary-overlay)) t)
1fa01bcd
RS
1821 (let (deactivate-mark)
1822 (copy-region-as-kill (overlay-start mouse-secondary-overlay)
1823 (overlay-end mouse-secondary-overlay)))))
9a974c88
RS
1824 (if mouse-secondary-start
1825 ;; All we have is one end of a selection,
1826 ;; so put the other end here.
1827 (let ((start (+ 0 mouse-secondary-start)))
1828 (kill-ring-save start click-posn)
aaf15b8b 1829 (move-overlay mouse-secondary-overlay start click-posn))))
9a974c88
RS
1830 (setq mouse-save-then-kill-posn
1831 (list (car kill-ring) (point) click-posn))))
fb28fd5b
RS
1832 (if (overlay-buffer mouse-secondary-overlay)
1833 (x-set-selection 'SECONDARY
9a974c88
RS
1834 (buffer-substring
1835 (overlay-start mouse-secondary-overlay)
1836 (overlay-end mouse-secondary-overlay)))))))
e66feb07 1837\f
0d9be91c 1838(defcustom mouse-buffer-menu-maxlen 20
f1107960
RS
1839 "*Number of buffers in one pane (submenu) of the buffer menu.
1840If we have lots of buffers, divide them into groups of
0d9be91c 1841`mouse-buffer-menu-maxlen' and make a pane (or submenu) for each one."
3b558d41
RS
1842 :type 'integer
1843 :group 'mouse)
f1107960 1844
3ca87c7b
RS
1845(defcustom mouse-buffer-menu-mode-mult 4
1846 "*Group the buffers by the major mode groups on \\[mouse-buffer-menu]?
1847This number which determines (in a hairy way) whether \\[mouse-buffer-menu]
1848will split the buffer menu by the major modes (see
1849`mouse-buffer-menu-mode-groups') or just by menu length.
1850Set to 1 (or even 0!) if you want to group by major mode always, and to
1851a large number if you prefer a mixed multitude. The default is 4."
1852 :type 'integer
1853 :group 'mouse
1854 :version "20.3")
1855
284a88a3
RS
1856(defvar mouse-buffer-menu-mode-groups
1857 '(("Info\\|Help\\|Apropos\\|Man" . "Help")
1858 ("\\bVM\\b\\|\\bMH\\b\\|Message\\|Mail\\|Group\\|Score\\|Summary\\|Article"
1859 . "Mail/News")
1860 ("\\<C\\>" . "C")
1861 ("ObjC" . "C")
1862 ("Text" . "Text")
1863 ("Outline" . "Text")
c71a58a3
SS
1864 ("\\(HT\\|SG\\|X\\|XHT\\)ML" . "SGML")
1865 ("log\\|diff\\|vc\\|cvs" . "Version Control") ; "Change Management"?
284a88a3
RS
1866 ("Lisp" . "Lisp"))
1867 "How to group various major modes together in \\[mouse-buffer-menu].
1868Each element has the form (REGEXP . GROUPNAME).
1869If the major mode's name string matches REGEXP, use GROUPNAME instead.")
1870
8b34e79d 1871(defun mouse-buffer-menu (event)
2d82f7b9
RS
1872 "Pop up a menu of buffers for selection with the mouse.
1873This switches buffers in the window that you clicked on,
1874and selects that window."
ec558adc 1875 (interactive "e")
d65147f6 1876 (mouse-minibuffer-check event)
3ca87c7b 1877 (let ((buffers (buffer-list)) alist menu split-by-major-mode sum-of-squares)
284a88a3 1878 ;; Make an alist of elements that look like (MENU-ITEM . BUFFER).
cc2ee8ec
SS
1879 (dolist (buf buffers)
1880 ;; Divide all buffers into buckets for various major modes.
1881 ;; Each bucket looks like (MODE NAMESTRING BUFFERS...).
1882 (with-current-buffer buf
1883 (let* ((adjusted-major-mode major-mode) elt)
1884 (dolist (group mouse-buffer-menu-mode-groups)
1885 (when (string-match (car group) (format-mode-line mode-name))
1886 (setq adjusted-major-mode (cdr group))))
1887 (setq elt (assoc adjusted-major-mode split-by-major-mode))
1888 (unless elt
1889 (setq elt (list adjusted-major-mode
1890 (if (stringp adjusted-major-mode)
1891 adjusted-major-mode
48d33090 1892 (format-mode-line mode-name nil nil buf)))
cc2ee8ec
SS
1893 split-by-major-mode (cons elt split-by-major-mode)))
1894 (or (memq buf (cdr (cdr elt)))
1895 (setcdr (cdr elt) (cons buf (cdr (cdr elt))))))))
284a88a3
RS
1896 ;; Compute the sum of squares of sizes of the major-mode buckets.
1897 (let ((tail split-by-major-mode))
1898 (setq sum-of-squares 0)
1899 (while tail
1900 (setq sum-of-squares
1901 (+ sum-of-squares
3ca87c7b 1902 (let ((len (length (cdr (cdr (car tail)))))) (* len len))))
284a88a3 1903 (setq tail (cdr tail))))
3ca87c7b
RS
1904 (if (< (* sum-of-squares mouse-buffer-menu-mode-mult)
1905 (* (length buffers) (length buffers)))
284a88a3
RS
1906 ;; Subdividing by major modes really helps, so let's do it.
1907 (let (subdivided-menus (buffers-left (length buffers)))
1908 ;; Sort the list to put the most popular major modes first.
1909 (setq split-by-major-mode
1910 (sort split-by-major-mode
1911 (function (lambda (elt1 elt2)
1912 (> (length elt1) (length elt2))))))
1913 ;; Make a separate submenu for each major mode
1914 ;; that has more than one buffer,
1915 ;; unless all the remaining buffers are less than 1/10 of them.
1916 (while (and split-by-major-mode
1917 (and (> (length (car split-by-major-mode)) 3)
1918 (> (* buffers-left 10) (length buffers))))
4b4ea1dc
EZ
1919 (let ((this-mode-list (mouse-buffer-menu-alist
1920 (cdr (cdr (car split-by-major-mode))))))
1921 (and this-mode-list
1922 (setq subdivided-menus
1923 (cons (cons
1924 (nth 1 (car split-by-major-mode))
1925 this-mode-list)
1926 subdivided-menus))))
284a88a3
RS
1927 (setq buffers-left
1928 (- buffers-left (length (cdr (car split-by-major-mode)))))
1929 (setq split-by-major-mode (cdr split-by-major-mode)))
1930 ;; If any major modes are left over,
1931 ;; make a single submenu for them.
1932 (if split-by-major-mode
4b4ea1dc
EZ
1933 (let ((others-list
1934 (mouse-buffer-menu-alist
1935 ;; we don't need split-by-major-mode any more,
1936 ;; so we can ditch it with nconc.
1937 (apply 'nconc (mapcar 'cddr split-by-major-mode)))))
1938 (and others-list
1939 (setq subdivided-menus
1940 (cons (cons "Others" others-list)
1941 subdivided-menus)))))
3ca87c7b 1942 (setq menu (cons "Buffer Menu" (nreverse subdivided-menus))))
284a88a3
RS
1943 (progn
1944 (setq alist (mouse-buffer-menu-alist buffers))
1945 (setq menu (cons "Buffer Menu"
1946 (mouse-buffer-menu-split "Select Buffer" alist)))))
2d82f7b9
RS
1947 (let ((buf (x-popup-menu event menu))
1948 (window (posn-window (event-start event))))
3ca87c7b 1949 (when buf
f134ad18
RS
1950 (select-window
1951 (if (framep window) (frame-selected-window window)
1952 window))
3ca87c7b 1953 (switch-to-buffer buf)))))
284a88a3
RS
1954
1955(defun mouse-buffer-menu-alist (buffers)
1956 (let (tail
1957 (maxlen 0)
1958 head)
1959 (setq buffers
1960 (sort buffers
1961 (function (lambda (elt1 elt2)
1962 (string< (buffer-name elt1) (buffer-name elt2))))))
1963 (setq tail buffers)
1964 (while tail
fc2b429e 1965 (or (eq ?\s (aref (buffer-name (car tail)) 0))
284a88a3
RS
1966 (setq maxlen
1967 (max maxlen
1968 (length (buffer-name (car tail))))))
1969 (setq tail (cdr tail)))
1970 (setq tail buffers)
1971 (while tail
1972 (let ((elt (car tail)))
66564ab0 1973 (if (/= (aref (buffer-name elt) 0) ?\s)
284a88a3
RS
1974 (setq head
1975 (cons
1976 (cons
1977 (format
fc1f472b 1978 (format "%%-%ds %%s%%s %%s" maxlen)
284a88a3
RS
1979 (buffer-name elt)
1980 (if (buffer-modified-p elt) "*" " ")
1981 (save-excursion
1982 (set-buffer elt)
1983 (if buffer-read-only "%" " "))
7b611de0 1984 (or (buffer-file-name elt)
284a88a3
RS
1985 (save-excursion
1986 (set-buffer elt)
1987 (if list-buffers-directory
1988 (expand-file-name
1989 list-buffers-directory)))
1990 ""))
1991 elt)
1992 head))))
1993 (setq tail (cdr tail)))
1994 ;; Compensate for the reversal that the above loop does.
1995 (nreverse head)))
1996
1997(defun mouse-buffer-menu-split (title alist)
1998 ;; If we have lots of buffers, divide them into groups of 20
1999 ;; and make a pane (or submenu) for each one.
0d9be91c 2000 (if (> (length alist) (/ (* mouse-buffer-menu-maxlen 3) 2))
284a88a3
RS
2001 (let ((alist alist) sublists next
2002 (i 1))
2003 (while alist
0d9be91c 2004 ;; Pull off the next mouse-buffer-menu-maxlen buffers
284a88a3 2005 ;; and make them the next element of sublist.
0d9be91c 2006 (setq next (nthcdr mouse-buffer-menu-maxlen alist))
284a88a3 2007 (if next
0d9be91c 2008 (setcdr (nthcdr (1- mouse-buffer-menu-maxlen) alist)
284a88a3
RS
2009 nil))
2010 (setq sublists (cons (cons (format "Buffers %d" i) alist)
2011 sublists))
2012 (setq i (1+ i))
2013 (setq alist next))
2014 (nreverse sublists))
2015 ;; Few buffers--put them all in one pane.
2016 (list (cons title alist))))
72ea54a4 2017\f
5ba2dc3f 2018;;; These need to be rewritten for the new scroll bar implementation.
dbc4e1c1
JB
2019
2020;;;!! ;; Commands for the scroll bar.
7b611de0 2021;;;!!
dbc4e1c1
JB
2022;;;!! (defun mouse-scroll-down (click)
2023;;;!! (interactive "@e")
2024;;;!! (scroll-down (1+ (cdr (mouse-coords click)))))
7b611de0 2025;;;!!
dbc4e1c1
JB
2026;;;!! (defun mouse-scroll-up (click)
2027;;;!! (interactive "@e")
2028;;;!! (scroll-up (1+ (cdr (mouse-coords click)))))
7b611de0 2029;;;!!
dbc4e1c1
JB
2030;;;!! (defun mouse-scroll-down-full ()
2031;;;!! (interactive "@")
2032;;;!! (scroll-down nil))
7b611de0 2033;;;!!
dbc4e1c1
JB
2034;;;!! (defun mouse-scroll-up-full ()
2035;;;!! (interactive "@")
2036;;;!! (scroll-up nil))
7b611de0 2037;;;!!
dbc4e1c1
JB
2038;;;!! (defun mouse-scroll-move-cursor (click)
2039;;;!! (interactive "@e")
2040;;;!! (move-to-window-line (1+ (cdr (mouse-coords click)))))
7b611de0 2041;;;!!
dbc4e1c1
JB
2042;;;!! (defun mouse-scroll-absolute (event)
2043;;;!! (interactive "@e")
2044;;;!! (let* ((pos (car event))
2045;;;!! (position (car pos))
2046;;;!! (length (car (cdr pos))))
2047;;;!! (if (<= length 0) (setq length 1))
2048;;;!! (let* ((scale-factor (max 1 (/ length (/ 8000000 (buffer-size)))))
2049;;;!! (newpos (* (/ (* (/ (buffer-size) scale-factor)
2050;;;!! position)
2051;;;!! length)
2052;;;!! scale-factor)))
2053;;;!! (goto-char newpos)
2054;;;!! (recenter '(4)))))
7b611de0 2055;;;!!
dbc4e1c1
JB
2056;;;!! (defun mouse-scroll-left (click)
2057;;;!! (interactive "@e")
2058;;;!! (scroll-left (1+ (car (mouse-coords click)))))
7b611de0 2059;;;!!
dbc4e1c1
JB
2060;;;!! (defun mouse-scroll-right (click)
2061;;;!! (interactive "@e")
2062;;;!! (scroll-right (1+ (car (mouse-coords click)))))
7b611de0 2063;;;!!
dbc4e1c1
JB
2064;;;!! (defun mouse-scroll-left-full ()
2065;;;!! (interactive "@")
2066;;;!! (scroll-left nil))
7b611de0 2067;;;!!
dbc4e1c1
JB
2068;;;!! (defun mouse-scroll-right-full ()
2069;;;!! (interactive "@")
2070;;;!! (scroll-right nil))
7b611de0 2071;;;!!
dbc4e1c1
JB
2072;;;!! (defun mouse-scroll-move-cursor-horizontally (click)
2073;;;!! (interactive "@e")
2074;;;!! (move-to-column (1+ (car (mouse-coords click)))))
7b611de0 2075;;;!!
dbc4e1c1
JB
2076;;;!! (defun mouse-scroll-absolute-horizontally (event)
2077;;;!! (interactive "@e")
2078;;;!! (let* ((pos (car event))
2079;;;!! (position (car pos))
2080;;;!! (length (car (cdr pos))))
2081;;;!! (set-window-hscroll (selected-window) 33)))
7b611de0 2082;;;!!
dbc4e1c1
JB
2083;;;!! (global-set-key [scroll-bar mouse-1] 'mouse-scroll-up)
2084;;;!! (global-set-key [scroll-bar mouse-2] 'mouse-scroll-absolute)
2085;;;!! (global-set-key [scroll-bar mouse-3] 'mouse-scroll-down)
7b611de0 2086;;;!!
dbc4e1c1
JB
2087;;;!! (global-set-key [vertical-slider mouse-1] 'mouse-scroll-move-cursor)
2088;;;!! (global-set-key [vertical-slider mouse-2] 'mouse-scroll-move-cursor)
2089;;;!! (global-set-key [vertical-slider mouse-3] 'mouse-scroll-move-cursor)
7b611de0 2090;;;!!
dbc4e1c1
JB
2091;;;!! (global-set-key [thumbup mouse-1] 'mouse-scroll-up-full)
2092;;;!! (global-set-key [thumbup mouse-2] 'mouse-scroll-up-full)
2093;;;!! (global-set-key [thumbup mouse-3] 'mouse-scroll-up-full)
7b611de0 2094;;;!!
dbc4e1c1
JB
2095;;;!! (global-set-key [thumbdown mouse-1] 'mouse-scroll-down-full)
2096;;;!! (global-set-key [thumbdown mouse-2] 'mouse-scroll-down-full)
2097;;;!! (global-set-key [thumbdown mouse-3] 'mouse-scroll-down-full)
7b611de0 2098;;;!!
dbc4e1c1
JB
2099;;;!! (global-set-key [horizontal-scroll-bar mouse-1] 'mouse-scroll-left)
2100;;;!! (global-set-key [horizontal-scroll-bar mouse-2]
2101;;;!! 'mouse-scroll-absolute-horizontally)
2102;;;!! (global-set-key [horizontal-scroll-bar mouse-3] 'mouse-scroll-right)
7b611de0 2103;;;!!
dbc4e1c1
JB
2104;;;!! (global-set-key [horizontal-slider mouse-1]
2105;;;!! 'mouse-scroll-move-cursor-horizontally)
2106;;;!! (global-set-key [horizontal-slider mouse-2]
2107;;;!! 'mouse-scroll-move-cursor-horizontally)
2108;;;!! (global-set-key [horizontal-slider mouse-3]
2109;;;!! 'mouse-scroll-move-cursor-horizontally)
7b611de0 2110;;;!!
dbc4e1c1
JB
2111;;;!! (global-set-key [thumbleft mouse-1] 'mouse-scroll-left-full)
2112;;;!! (global-set-key [thumbleft mouse-2] 'mouse-scroll-left-full)
2113;;;!! (global-set-key [thumbleft mouse-3] 'mouse-scroll-left-full)
7b611de0 2114;;;!!
dbc4e1c1
JB
2115;;;!! (global-set-key [thumbright mouse-1] 'mouse-scroll-right-full)
2116;;;!! (global-set-key [thumbright mouse-2] 'mouse-scroll-right-full)
2117;;;!! (global-set-key [thumbright mouse-3] 'mouse-scroll-right-full)
7b611de0 2118;;;!!
dbc4e1c1
JB
2119;;;!! (global-set-key [horizontal-scroll-bar S-mouse-2]
2120;;;!! 'mouse-split-window-horizontally)
2121;;;!! (global-set-key [mode-line S-mouse-2]
2122;;;!! 'mouse-split-window-horizontally)
2123;;;!! (global-set-key [vertical-scroll-bar S-mouse-2]
2124;;;!! 'mouse-split-window)
6b2154de 2125\f
dbc4e1c1
JB
2126;;;!! ;;;;
2127;;;!! ;;;; Here are experimental things being tested. Mouse events
2128;;;!! ;;;; are of the form:
2129;;;!! ;;;; ((x y) window screen-part key-sequence timestamp)
2130;;;!! ;;
2131;;;!! ;;;;
2132;;;!! ;;;; Dynamically track mouse coordinates
2133;;;!! ;;;;
2134;;;!! ;;
2135;;;!! ;;(defun track-mouse (event)
2136;;;!! ;; "Track the coordinates, absolute and relative, of the mouse."
2137;;;!! ;; (interactive "@e")
2138;;;!! ;; (while mouse-grabbed
2139;;;!! ;; (let* ((pos (read-mouse-position (selected-screen)))
2140;;;!! ;; (abs-x (car pos))
2141;;;!! ;; (abs-y (cdr pos))
2142;;;!! ;; (relative-coordinate (coordinates-in-window-p
2143;;;!! ;; (list (car pos) (cdr pos))
2144;;;!! ;; (selected-window))))
2145;;;!! ;; (if (consp relative-coordinate)
2146;;;!! ;; (message "mouse: [%d %d], (%d %d)" abs-x abs-y
2147;;;!! ;; (car relative-coordinate)
2148;;;!! ;; (car (cdr relative-coordinate)))
2149;;;!! ;; (message "mouse: [%d %d]" abs-x abs-y)))))
7b611de0 2150;;;!!
dbc4e1c1
JB
2151;;;!! ;;
2152;;;!! ;; Dynamically put a box around the line indicated by point
2153;;;!! ;;
2154;;;!! ;;
2155;;;!! ;;(require 'backquote)
2156;;;!! ;;
2157;;;!! ;;(defun mouse-select-buffer-line (event)
2158;;;!! ;; (interactive "@e")
2159;;;!! ;; (let ((relative-coordinate
2160;;;!! ;; (coordinates-in-window-p (car event) (selected-window)))
2161;;;!! ;; (abs-y (car (cdr (car event)))))
2162;;;!! ;; (if (consp relative-coordinate)
2163;;;!! ;; (progn
2164;;;!! ;; (save-excursion
2165;;;!! ;; (move-to-window-line (car (cdr relative-coordinate)))
2166;;;!! ;; (x-draw-rectangle
2167;;;!! ;; (selected-screen)
2168;;;!! ;; abs-y 0
2169;;;!! ;; (save-excursion
2170;;;!! ;; (move-to-window-line (car (cdr relative-coordinate)))
2171;;;!! ;; (end-of-line)
2172;;;!! ;; (push-mark nil t)
2173;;;!! ;; (beginning-of-line)
2174;;;!! ;; (- (region-end) (region-beginning))) 1))
2175;;;!! ;; (sit-for 1)
2176;;;!! ;; (x-erase-rectangle (selected-screen))))))
2177;;;!! ;;
2178;;;!! ;;(defvar last-line-drawn nil)
2179;;;!! ;;(defvar begin-delim "[^ \t]")
2180;;;!! ;;(defvar end-delim "[^ \t]")
2181;;;!! ;;
2182;;;!! ;;(defun mouse-boxing (event)
2183;;;!! ;; (interactive "@e")
2184;;;!! ;; (save-excursion
2185;;;!! ;; (let ((screen (selected-screen)))
2186;;;!! ;; (while (= (x-mouse-events) 0)
2187;;;!! ;; (let* ((pos (read-mouse-position screen))
2188;;;!! ;; (abs-x (car pos))
2189;;;!! ;; (abs-y (cdr pos))
2190;;;!! ;; (relative-coordinate
b2013aad 2191;;;!! ;; (coordinates-in-window-p `(,abs-x ,abs-y)
dbc4e1c1
JB
2192;;;!! ;; (selected-window)))
2193;;;!! ;; (begin-reg nil)
2194;;;!! ;; (end-reg nil)
2195;;;!! ;; (end-column nil)
2196;;;!! ;; (begin-column nil))
2197;;;!! ;; (if (and (consp relative-coordinate)
2198;;;!! ;; (or (not last-line-drawn)
2199;;;!! ;; (not (= last-line-drawn abs-y))))
2200;;;!! ;; (progn
2201;;;!! ;; (move-to-window-line (car (cdr relative-coordinate)))
2202;;;!! ;; (if (= (following-char) 10)
2203;;;!! ;; ()
2204;;;!! ;; (progn
2205;;;!! ;; (setq begin-reg (1- (re-search-forward end-delim)))
2206;;;!! ;; (setq begin-column (1- (current-column)))
2207;;;!! ;; (end-of-line)
2208;;;!! ;; (setq end-reg (1+ (re-search-backward begin-delim)))
2209;;;!! ;; (setq end-column (1+ (current-column)))
2210;;;!! ;; (message "%s" (buffer-substring begin-reg end-reg))
2211;;;!! ;; (x-draw-rectangle screen
2212;;;!! ;; (setq last-line-drawn abs-y)
2213;;;!! ;; begin-column
2214;;;!! ;; (- end-column begin-column) 1))))))))))
2215;;;!! ;;
2216;;;!! ;;(defun mouse-erase-box ()
2217;;;!! ;; (interactive)
2218;;;!! ;; (if last-line-drawn
2219;;;!! ;; (progn
2220;;;!! ;; (x-erase-rectangle (selected-screen))
2221;;;!! ;; (setq last-line-drawn nil))))
7b611de0 2222;;;!!
dbc4e1c1
JB
2223;;;!! ;;; (defun test-x-rectangle ()
2224;;;!! ;;; (use-local-mouse-map (setq rectangle-test-map (make-sparse-keymap)))
2225;;;!! ;;; (define-key rectangle-test-map mouse-motion-button-left 'mouse-boxing)
2226;;;!! ;;; (define-key rectangle-test-map mouse-button-left-up 'mouse-erase-box))
7b611de0 2227;;;!!
dbc4e1c1
JB
2228;;;!! ;;
2229;;;!! ;; Here is how to do double clicking in lisp. About to change.
2230;;;!! ;;
7b611de0 2231;;;!!
dbc4e1c1
JB
2232;;;!! (defvar double-start nil)
2233;;;!! (defconst double-click-interval 300
2234;;;!! "Max ticks between clicks")
7b611de0 2235;;;!!
dbc4e1c1
JB
2236;;;!! (defun double-down (event)
2237;;;!! (interactive "@e")
2238;;;!! (if double-start
2239;;;!! (let ((interval (- (nth 4 event) double-start)))
2240;;;!! (if (< interval double-click-interval)
2241;;;!! (progn
2242;;;!! (backward-up-list 1)
2243;;;!! ;; (message "Interval %d" interval)
2244;;;!! (sleep-for 1)))
2245;;;!! (setq double-start nil))
2246;;;!! (setq double-start (nth 4 event))))
7b611de0 2247;;;!!
dbc4e1c1
JB
2248;;;!! (defun double-up (event)
2249;;;!! (interactive "@e")
2250;;;!! (and double-start
2251;;;!! (> (- (nth 4 event ) double-start) double-click-interval)
2252;;;!! (setq double-start nil)))
7b611de0 2253;;;!!
dbc4e1c1
JB
2254;;;!! ;;; (defun x-test-doubleclick ()
2255;;;!! ;;; (use-local-mouse-map (setq doubleclick-test-map (make-sparse-keymap)))
2256;;;!! ;;; (define-key doubleclick-test-map mouse-button-left 'double-down)
2257;;;!! ;;; (define-key doubleclick-test-map mouse-button-left-up 'double-up))
7b611de0 2258;;;!!
dbc4e1c1 2259;;;!! ;;
5ba2dc3f 2260;;;!! ;; This scrolls while button is depressed. Use preferable in scroll bar.
dbc4e1c1 2261;;;!! ;;
7b611de0 2262;;;!!
dbc4e1c1
JB
2263;;;!! (defvar scrolled-lines 0)
2264;;;!! (defconst scroll-speed 1)
7b611de0 2265;;;!!
dbc4e1c1
JB
2266;;;!! (defun incr-scroll-down (event)
2267;;;!! (interactive "@e")
2268;;;!! (setq scrolled-lines 0)
2269;;;!! (incremental-scroll scroll-speed))
7b611de0 2270;;;!!
dbc4e1c1
JB
2271;;;!! (defun incr-scroll-up (event)
2272;;;!! (interactive "@e")
2273;;;!! (setq scrolled-lines 0)
2274;;;!! (incremental-scroll (- scroll-speed)))
7b611de0 2275;;;!!
dbc4e1c1
JB
2276;;;!! (defun incremental-scroll (n)
2277;;;!! (while (= (x-mouse-events) 0)
2278;;;!! (setq scrolled-lines (1+ (* scroll-speed scrolled-lines)))
2279;;;!! (scroll-down n)
2280;;;!! (sit-for 300 t)))
7b611de0 2281;;;!!
dbc4e1c1
JB
2282;;;!! (defun incr-scroll-stop (event)
2283;;;!! (interactive "@e")
2284;;;!! (message "Scrolled %d lines" scrolled-lines)
2285;;;!! (setq scrolled-lines 0)
2286;;;!! (sleep-for 1))
7b611de0 2287;;;!!
dbc4e1c1
JB
2288;;;!! ;;; (defun x-testing-scroll ()
2289;;;!! ;;; (let ((scrolling-map (function mouse-vertical-scroll-bar-prefix)))
2290;;;!! ;;; (define-key scrolling-map mouse-button-left 'incr-scroll-down)
2291;;;!! ;;; (define-key scrolling-map mouse-button-right 'incr-scroll-up)
2292;;;!! ;;; (define-key scrolling-map mouse-button-left-up 'incr-scroll-stop)
2293;;;!! ;;; (define-key scrolling-map mouse-button-right-up 'incr-scroll-stop)))
7b611de0 2294;;;!!
dbc4e1c1
JB
2295;;;!! ;;
2296;;;!! ;; Some playthings suitable for picture mode? They need work.
2297;;;!! ;;
7b611de0 2298;;;!!
dbc4e1c1
JB
2299;;;!! (defun mouse-kill-rectangle (event)
2300;;;!! "Kill the rectangle between point and the mouse cursor."
2301;;;!! (interactive "@e")
2302;;;!! (let ((point-save (point)))
2303;;;!! (save-excursion
2304;;;!! (mouse-set-point event)
2305;;;!! (push-mark nil t)
2306;;;!! (if (> point-save (point))
2307;;;!! (kill-rectangle (point) point-save)
2308;;;!! (kill-rectangle point-save (point))))))
7b611de0 2309;;;!!
dbc4e1c1
JB
2310;;;!! (defun mouse-open-rectangle (event)
2311;;;!! "Kill the rectangle between point and the mouse cursor."
2312;;;!! (interactive "@e")
2313;;;!! (let ((point-save (point)))
2314;;;!! (save-excursion
2315;;;!! (mouse-set-point event)
2316;;;!! (push-mark nil t)
2317;;;!! (if (> point-save (point))
2318;;;!! (open-rectangle (point) point-save)
2319;;;!! (open-rectangle point-save (point))))))
7b611de0 2320;;;!!
dbc4e1c1 2321;;;!! ;; Must be a better way to do this.
7b611de0 2322;;;!!
dbc4e1c1
JB
2323;;;!! (defun mouse-multiple-insert (n char)
2324;;;!! (while (> n 0)
2325;;;!! (insert char)
2326;;;!! (setq n (1- n))))
7b611de0 2327;;;!!
dbc4e1c1 2328;;;!! ;; What this could do is not finalize until button was released.
7b611de0 2329;;;!!
dbc4e1c1
JB
2330;;;!! (defun mouse-move-text (event)
2331;;;!! "Move text from point to cursor position, inserting spaces."
2332;;;!! (interactive "@e")
2333;;;!! (let* ((relative-coordinate
2334;;;!! (coordinates-in-window-p (car event) (selected-window))))
2335;;;!! (if (consp relative-coordinate)
2336;;;!! (cond ((> (current-column) (car relative-coordinate))
2337;;;!! (delete-char
2338;;;!! (- (car relative-coordinate) (current-column))))
2339;;;!! ((< (current-column) (car relative-coordinate))
2340;;;!! (mouse-multiple-insert
2341;;;!! (- (car relative-coordinate) (current-column)) " "))
2342;;;!! ((= (current-column) (car relative-coordinate)) (ding))))))
07a78410 2343\f
f936ae06
RS
2344;; Choose a completion with the mouse.
2345
2346(defun mouse-choose-completion (event)
49e61c42 2347 "Click on an alternative in the `*Completions*' buffer to choose it."
f936ae06 2348 (interactive "e")
33c448cd
RS
2349 ;; Give temporary modes such as isearch a chance to turn off.
2350 (run-hooks 'mouse-leave-buffer-hook)
d89a4a47 2351 (let ((buffer (window-buffer))
02680e9b
RS
2352 choice
2353 base-size)
f936ae06
RS
2354 (save-excursion
2355 (set-buffer (window-buffer (posn-window (event-start event))))
f36f4e9e
RS
2356 (if completion-reference-buffer
2357 (setq buffer completion-reference-buffer))
02680e9b 2358 (setq base-size completion-base-size)
f936ae06
RS
2359 (save-excursion
2360 (goto-char (posn-point (event-start event)))
b6be5d95 2361 (let (beg end)
9a43a594
RS
2362 (if (and (not (eobp)) (get-text-property (point) 'mouse-face))
2363 (setq end (point) beg (1+ (point))))
2364 (if (null beg)
2365 (error "No completion here"))
2366 (setq beg (previous-single-property-change beg 'mouse-face))
2f5ed2e8
RS
2367 (setq end (or (next-single-property-change end 'mouse-face)
2368 (point-max)))
8a30a619 2369 (setq choice (buffer-substring-no-properties beg end)))))
73e2025f
RS
2370 (let ((owindow (selected-window)))
2371 (select-window (posn-window (event-start event)))
874a2cbd
RS
2372 (if (and (one-window-p t 'selected-frame)
2373 (window-dedicated-p (selected-window)))
2374 ;; This is a special buffer's frame
2375 (iconify-frame (selected-frame))
2376 (or (window-dedicated-p (selected-window))
2377 (bury-buffer)))
73e2025f 2378 (select-window owindow))
02680e9b 2379 (choose-completion-string choice buffer base-size)))
f936ae06 2380\f
07a78410
RS
2381;; Font selection.
2382
0eb9fef3
RS
2383(defun font-menu-add-default ()
2384 (let* ((default (cdr (assq 'font (frame-parameters (selected-frame)))))
2385 (font-alist x-fixed-font-alist)
0d94f5ca 2386 (elt (or (assoc "Misc" font-alist) (nth 1 font-alist))))
0eb9fef3
RS
2387 (if (assoc "Default" elt)
2388 (delete (assoc "Default" elt) elt))
2389 (setcdr elt
6b8e486e 2390 (cons (list "Default" default)
0eb9fef3
RS
2391 (cdr elt)))))
2392
07a78410 2393(defvar x-fixed-font-alist
d2b532fe 2394 '("Font Menu"
07a78410 2395 ("Misc"
19d973e8
RS
2396 ;; For these, we specify the pixel height and width.
2397 ("fixed" "fixed")
2398 ("6x10" "-misc-fixed-medium-r-normal--10-*-*-*-c-60-iso8859-1" "6x10")
2399 ("6x12"
2400 "-misc-fixed-medium-r-semicondensed--12-*-*-*-c-60-iso8859-1" "6x12")
2401 ("6x13"
2402 "-misc-fixed-medium-r-semicondensed--13-*-*-*-c-60-iso8859-1" "6x13")
2403 ("7x13" "-misc-fixed-medium-r-normal--13-*-*-*-c-70-iso8859-1" "7x13")
2404 ("7x14" "-misc-fixed-medium-r-normal--14-*-*-*-c-70-iso8859-1" "7x14")
2405 ("8x13" "-misc-fixed-medium-r-normal--13-*-*-*-c-80-iso8859-1" "8x13")
2406 ("9x15" "-misc-fixed-medium-r-normal--15-*-*-*-c-90-iso8859-1" "9x15")
2407 ("10x20" "-misc-fixed-medium-r-normal--20-*-*-*-c-100-iso8859-1" "10x20")
2408 ("11x18" "-misc-fixed-medium-r-normal--18-*-*-*-c-110-iso8859-1" "11x18")
2409 ("12x24" "-misc-fixed-medium-r-normal--24-*-*-*-c-120-iso8859-1" "12x24")
fa21fdec 2410 ("")
f29c3695
RS
2411 ("clean 5x8"
2412 "-schumacher-clean-medium-r-normal--8-*-*-*-c-50-iso8859-1")
2413 ("clean 6x8"
2414 "-schumacher-clean-medium-r-normal--8-*-*-*-c-60-iso8859-1")
19d973e8
RS
2415 ("clean 8x8"
2416 "-schumacher-clean-medium-r-normal--8-*-*-*-c-80-iso8859-1")
2417 ("clean 8x10"
2418 "-schumacher-clean-medium-r-normal--10-*-*-*-c-80-iso8859-1")
2419 ("clean 8x14"
2420 "-schumacher-clean-medium-r-normal--14-*-*-*-c-80-iso8859-1")
2421 ("clean 8x16"
2422 "-schumacher-clean-medium-r-normal--16-*-*-*-c-80-iso8859-1")
fa21fdec 2423 ("")
29a3028d 2424 ("sony 8x16" "-sony-fixed-medium-r-normal--16-*-*-*-c-80-iso8859-1")
07a78410
RS
2425;;; We don't seem to have these; who knows what they are.
2426;;; ("fg-18" "fg-18")
2427;;; ("fg-25" "fg-25")
29a3028d
DL
2428 ("lucidasanstypewriter-12" "-b&h-lucidatypewriter-medium-r-normal-sans-*-120-*-*-*-*-iso8859-1")
2429 ("lucidasanstypewriter-bold-14" "-b&h-lucidatypewriter-bold-r-normal-sans-*-140-*-*-*-*-iso8859-1")
2430 ("lucidasanstypewriter-bold-24"
2431 "-b&h-lucidatypewriter-bold-r-normal-sans-*-240-*-*-*-*-iso8859-1")
07a78410
RS
2432;;; ("lucidatypewriter-bold-r-24" "-b&h-lucidatypewriter-bold-r-normal-sans-24-240-75-75-m-140-iso8859-1")
2433;;; ("fixed-medium-20" "-misc-fixed-medium-*-*-*-20-*-*-*-*-*-*-*")
29a3028d 2434 )
07a78410 2435 ("Courier"
19d973e8 2436 ;; For these, we specify the point height.
82c048a9
RS
2437 ("8" "-adobe-courier-medium-r-normal--*-80-*-*-m-*-iso8859-1")
2438 ("10" "-adobe-courier-medium-r-normal--*-100-*-*-m-*-iso8859-1")
2439 ("12" "-adobe-courier-medium-r-normal--*-120-*-*-m-*-iso8859-1")
2440 ("14" "-adobe-courier-medium-r-normal--*-140-*-*-m-*-iso8859-1")
2441 ("18" "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1")
2442 ("24" "-adobe-courier-medium-r-normal--*-240-*-*-m-*-iso8859-1")
2443 ("8 bold" "-adobe-courier-bold-r-normal--*-80-*-*-m-*-iso8859-1")
2444 ("10 bold" "-adobe-courier-bold-r-normal--*-100-*-*-m-*-iso8859-1")
2445 ("12 bold" "-adobe-courier-bold-r-normal--*-120-*-*-m-*-iso8859-1")
2446 ("14 bold" "-adobe-courier-bold-r-normal--*-140-*-*-m-*-iso8859-1")
2447 ("18 bold" "-adobe-courier-bold-r-normal--*-180-*-*-m-*-iso8859-1")
2448 ("24 bold" "-adobe-courier-bold-r-normal--*-240-*-*-m-*-iso8859-1")
2449 ("8 slant" "-adobe-courier-medium-o-normal--*-80-*-*-m-*-iso8859-1")
2450 ("10 slant" "-adobe-courier-medium-o-normal--*-100-*-*-m-*-iso8859-1")
2451 ("12 slant" "-adobe-courier-medium-o-normal--*-120-*-*-m-*-iso8859-1")
2452 ("14 slant" "-adobe-courier-medium-o-normal--*-140-*-*-m-*-iso8859-1")
2453 ("18 slant" "-adobe-courier-medium-o-normal--*-180-*-*-m-*-iso8859-1")
2454 ("24 slant" "-adobe-courier-medium-o-normal--*-240-*-*-m-*-iso8859-1")
2455 ("8 bold slant" "-adobe-courier-bold-o-normal--*-80-*-*-m-*-iso8859-1")
2456 ("10 bold slant" "-adobe-courier-bold-o-normal--*-100-*-*-m-*-iso8859-1")
2457 ("12 bold slant" "-adobe-courier-bold-o-normal--*-120-*-*-m-*-iso8859-1")
2458 ("14 bold slant" "-adobe-courier-bold-o-normal--*-140-*-*-m-*-iso8859-1")
2459 ("18 bold slant" "-adobe-courier-bold-o-normal--*-180-*-*-m-*-iso8859-1")
2460 ("24 bold slant" "-adobe-courier-bold-o-normal--*-240-*-*-m-*-iso8859-1"))
07a78410
RS
2461 )
2462 "X fonts suitable for use in Emacs.")
2463
1900a92b 2464(defun mouse-set-font (&rest fonts)
624c972d 2465 "Select an Emacs font from a list of known good fonts and fontsets."
07a78410 2466 (interactive
8eb1dc02
RS
2467 (progn (unless (display-multi-font-p)
2468 (error "Cannot change fonts on this display"))
2469 (x-popup-menu
91c51412
LT
2470 (if (listp last-nonmenu-event)
2471 last-nonmenu-event
2472 (list '(0 0) (selected-window)))
8eb1dc02
RS
2473 ;; Append list of fontsets currently defined.
2474 (append x-fixed-font-alist (list (generate-fontset-menu))))))
df4de8c6
KH
2475 (if fonts
2476 (let (font)
2477 (while fonts
2478 (condition-case nil
2479 (progn
3fadec1a 2480 (set-default-font (car fonts))
df4de8c6
KH
2481 (setq font (car fonts))
2482 (setq fonts nil))
3fadec1a
RS
2483 (error
2484 (setq fonts (cdr fonts)))))
df4de8c6 2485 (if (null font)
8eb1dc02 2486 (error "Font not found")))))
cc0a8174
JB
2487\f
2488;;; Bindings for mouse commands.
2489
fcfc3c63 2490(define-key global-map [down-mouse-1] 'mouse-drag-region)
dbc4e1c1 2491(global-set-key [mouse-1] 'mouse-set-point)
dbc4e1c1 2492(global-set-key [drag-mouse-1] 'mouse-set-region)
fcfc3c63 2493
e37de120
RS
2494;; These are tested for in mouse-drag-region.
2495(global-set-key [double-mouse-1] 'mouse-set-point)
2496(global-set-key [triple-mouse-1] 'mouse-set-point)
2497
76693d12
KS
2498;; Clicking on the fringes causes hscrolling:
2499(global-set-key [left-fringe mouse-1] 'mouse-set-point)
2500(global-set-key [right-fringe mouse-1] 'mouse-set-point)
2501
dbc4e1c1 2502(global-set-key [mouse-2] 'mouse-yank-at-click)
3e9323d6 2503;; Allow yanking also when the corresponding cursor is "in the fringe".
d97c13b2 2504(global-set-key [right-fringe mouse-2] 'mouse-yank-at-click)
84e42e60 2505(global-set-key [left-fringe mouse-2] 'mouse-yank-at-click)
dbc4e1c1 2506(global-set-key [mouse-3] 'mouse-save-then-kill)
84e42e60
EZ
2507(global-set-key [right-fringe mouse-3] 'mouse-save-then-kill)
2508(global-set-key [left-fringe mouse-3] 'mouse-save-then-kill)
8b34e79d 2509
dbc4e1c1
JB
2510;; By binding these to down-going events, we let the user use the up-going
2511;; event to make the selection, saving a click.
08a1c178
RS
2512(global-set-key [C-down-mouse-1] 'mouse-buffer-menu)
2513(if (not (eq system-type 'ms-dos))
2514 (global-set-key [S-down-mouse-1] 'mouse-set-font))
eef805d7 2515;; C-down-mouse-2 is bound in facemenu.el.
de420e82 2516(global-set-key [C-down-mouse-3] 'mouse-popup-menubar-stuff)
95132d1c 2517
07a78410 2518
8b34e79d
RS
2519;; Replaced with dragging mouse-1
2520;; (global-set-key [S-mouse-1] 'mouse-set-mark)
947da0c4 2521
06a8c9f8
EZ
2522;; Binding mouse-1 to mouse-select-window when on mode-, header-, or
2523;; vertical-line prevents Emacs from signaling an error when the mouse
2524;; button is released after dragging these lines, on non-toolkit
2525;; versions.
3c2dd2c0 2526(global-set-key [mode-line mouse-1] 'mouse-select-window)
544e7e73
RS
2527(global-set-key [mode-line drag-mouse-1] 'mouse-select-window)
2528(global-set-key [mode-line down-mouse-1] 'mouse-drag-mode-line)
b0d22e20 2529(global-set-key [header-line down-mouse-1] 'mouse-drag-header-line)
06a8c9f8 2530(global-set-key [header-line mouse-1] 'mouse-select-window)
3c2dd2c0 2531(global-set-key [mode-line mouse-2] 'mouse-delete-other-windows)
dbc4e1c1 2532(global-set-key [mode-line mouse-3] 'mouse-delete-window)
3c2dd2c0 2533(global-set-key [mode-line C-mouse-2] 'mouse-split-window-horizontally)
9926ab64 2534(global-set-key [vertical-scroll-bar C-mouse-2] 'mouse-split-window-vertically)
b6522df6 2535(global-set-key [vertical-line C-mouse-2] 'mouse-split-window-vertically)
08a1c178
RS
2536(global-set-key [vertical-line down-mouse-1] 'mouse-drag-vertical-line)
2537(global-set-key [vertical-line mouse-1] 'mouse-select-window)
49116ac0
JB
2538
2539(provide 'mouse)
2540
2fe85227
DL
2541;; This file contains the functionality of the old mldrag.el.
2542(defalias 'mldrag-drag-mode-line 'mouse-drag-mode-line)
2543(defalias 'mldrag-drag-vertical-line 'mouse-drag-vertical-line)
342a1e7b
SM
2544(make-obsolete 'mldrag-drag-mode-line 'mouse-drag-mode-line "21.1")
2545(make-obsolete 'mldrag-drag-vertical-line 'mouse-drag-vertical-line "21.1")
2fe85227
DL
2546(provide 'mldrag)
2547
f002506f 2548;; arch-tag: 9a710ce1-914a-4923-9b81-697f7bf82ab3
6594deb0 2549;;; mouse.el ends here