Move lisp/emacs-lisp/authors.el to admin/
[bpt/emacs.git] / lisp / mouse.el
CommitLineData
e1894109 1;;; mouse.el --- window system-independent mouse support -*- lexical-binding: t -*-
84176303 2
ba318903 3;; Copyright (C) 1993-1995, 1999-2014 Free Software Foundation, Inc.
eea8d4ef 4
34dc21db 5;; Maintainer: emacs-devel@gnu.org
de420e82 6;; Keywords: hardware, mouse
bd78fa1d 7;; Package: emacs
84176303 8
be010748 9;; This file is part of GNU Emacs.
72ea54a4 10
eb3fa2cf 11;; GNU Emacs is free software: you can redistribute it and/or modify
be010748 12;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) 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
eb3fa2cf 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
72ea54a4 23
edbd2f74
ER
24;;; Commentary:
25
26;; This package provides various useful commands (including help
27;; system access) through the mouse. All this code assumes that mouse
28;; interpretation has been abstracted into Emacs input events.
edbd2f74 29
aae56ea7
ER
30;;; Code:
31
cc0a8174 32;;; Utility functions.
72ea54a4 33
ad0d18af 34;; Indent track-mouse like progn.
cc0a8174 35(put 'track-mouse 'lisp-indent-function 0)
72ea54a4 36
3b558d41 37(defcustom mouse-yank-at-point nil
9201cc28 38 "If non-nil, mouse yank commands yank at point instead of at click."
3b558d41
RS
39 :type 'boolean
40 :group 'mouse)
b2dae92a 41
f9d71b42 42(defcustom mouse-drag-copy-region nil
93d68d4f
DDLHG
43 "If non-nil, copy to kill-ring upon mouse adjustments of the region.
44
45This affects `mouse-save-then-kill' (\\[mouse-save-then-kill]) in
46addition to mouse drags."
b2dae92a 47 :type 'boolean
2490cbbc 48 :version "24.1"
b2dae92a
KS
49 :group 'mouse)
50
5dbda518 51(defcustom mouse-1-click-follows-link 450
787e24c3 52 "Non-nil means that clicking Mouse-1 on a link follows the link.
65f76581 53
787e24c3
KS
54With the default setting, an ordinary Mouse-1 click on a link
55performs the same action as Mouse-2 on that link, while a longer
97b1270c 56Mouse-1 click \(hold down the Mouse-1 button for more than 450
787e24c3 57milliseconds) performs the original Mouse-1 binding \(which
65f76581
KS
58typically sets point where you click the mouse).
59
60If value is an integer, the time elapsed between pressing and
61releasing the mouse button determines whether to follow the link
787e24c3 62or perform the normal Mouse-1 action (typically set point).
22bcf204 63The absolute numeric value specifies the maximum duration of a
65f76581
KS
64\"short click\" in milliseconds. A positive value means that a
65short click follows the link, and a longer click performs the
1d68acd3 66normal action. A negative value gives the opposite behavior.
65f76581
KS
67
68If value is `double', a double click follows the link.
69
787e24c3 70Otherwise, a single Mouse-1 click unconditionally follows the link.
65f76581
KS
71
72Note that dragging the mouse never follows the link.
73
74This feature only works in modes that specifically identify
75clickable text as links, so it may not work with some external
76packages. See `mouse-on-link-p' for details."
bf247b6e 77 :version "22.1"
65f76581
KS
78 :type '(choice (const :tag "Disabled" nil)
79 (const :tag "Double click" double)
97b1270c 80 (number :tag "Single click time limit" :value 450)
65f76581
KS
81 (other :tag "Single click" t))
82 :group 'mouse)
83
185a53bb 84(defcustom mouse-1-click-in-non-selected-windows t
9201cc28 85 "If non-nil, a Mouse-1 click also follows links in non-selected windows.
185a53bb
KS
86
87If nil, a Mouse-1 click on a link in a non-selected window performs
88the normal mouse-1 binding, typically selects the window and sets
89point at the click position."
90 :type 'boolean
91 :version "22.1"
92 :group 'mouse)
93
27a98a62
SM
94(defun mouse--down-1-maybe-follows-link (&optional _prompt)
95 "Turn `mouse-1' events into `mouse-2' events if follows-link.
96Expects to be bound to `down-mouse-1' in `key-translation-map'."
97 (if (or (null mouse-1-click-follows-link)
98 (not (eq (if (eq mouse-1-click-follows-link 'double)
99 'double-down-mouse-1 'down-mouse-1)
100 (car-safe last-input-event)))
101 (not (mouse-on-link-p (event-start last-input-event)))
102 (and (not mouse-1-click-in-non-selected-windows)
103 (not (eq (selected-window)
104 (posn-window (event-start last-input-event))))))
105 nil
106 (let ((this-event last-input-event)
107 (timedout
108 (sit-for (if (numberp mouse-1-click-follows-link)
109 (/ (abs mouse-1-click-follows-link) 1000.0)
110 0))))
111 (if (if (and (numberp mouse-1-click-follows-link)
112 (>= mouse-1-click-follows-link 0))
113 timedout (not timedout))
114 nil
115
116 (let ((event (read-event)))
117 (if (eq (car-safe event) (if (eq mouse-1-click-follows-link 'double)
118 'double-mouse-1 'mouse-1))
119 ;; Turn the mouse-1 into a mouse-2 to follow links.
120 (let ((newup (if (eq mouse-1-click-follows-link 'double)
121 'double-mouse-2 'mouse-2))
122 (newdown (if (eq mouse-1-click-follows-link 'double)
123 'double-down-mouse-2 'down-mouse-2)))
124 ;; If mouse-2 has never been done by the user, it doesn't have
125 ;; the necessary property to be interpreted correctly.
126 (put newup 'event-kind (get (car event) 'event-kind))
127 (put newdown 'event-kind (get (car this-event) 'event-kind))
128 (push (cons newup (cdr event)) unread-command-events)
0e6008c5
SM
129 ;; Modify the event in place, so read-key-sequence doesn't
130 ;; generate a second fake prefix key (see fake_prefixed_keys in
131 ;; src/keyboard.c).
132 (setcar this-event newdown)
133 (vector this-event))
27a98a62
SM
134 (push event unread-command-events)
135 nil))))))
136
137(define-key key-translation-map [down-mouse-1]
138 #'mouse--down-1-maybe-follows-link)
139(define-key key-translation-map [double-down-mouse-1]
140 #'mouse--down-1-maybe-follows-link)
185a53bb 141
cc0a8174 142\f
95132d1c
RS
143;; Provide a mode-specific menu on a mouse button.
144
7e4e9c66 145(defun minor-mode-menu-from-indicator (indicator)
fb1a03c9
DN
146 "Show menu for minor mode specified by INDICATOR.
147Interactively, INDICATOR is read using completion.
148If there is no menu defined for the minor mode, then create one with
149items `Turn Off' and `Help'."
150 (interactive
5e38cdab 151 (list (completing-read
fb1a03c9
DN
152 "Minor mode indicator: "
153 (describe-minor-mode-completion-table-for-indicator))))
97b952b7
SM
154 (let* ((minor-mode (lookup-minor-mode-from-indicator indicator))
155 (mm-fun (or (get minor-mode :minor-mode-function) minor-mode)))
fb1a03c9
DN
156 (unless minor-mode (error "Cannot find minor mode for `%s'" indicator))
157 (let* ((map (cdr-safe (assq minor-mode minor-mode-map-alist)))
158 (menu (and (keymapp map) (lookup-key map [menu-bar]))))
ad0d18af
SM
159 (setq menu
160 (if menu
161 (mouse-menu-non-singleton menu)
fb1a03c9 162 `(keymap
ad0d18af 163 ,indicator
97b952b7 164 (turn-off menu-item "Turn Off minor mode" ,mm-fun)
ad0d18af 165 (help menu-item "Help for minor mode"
5e38cdab 166 (lambda () (interactive)
97b952b7 167 (describe-function ',mm-fun))))))
fb1a03c9 168 (popup-menu menu))))
7e4e9c66
GM
169
170(defun mouse-minor-mode-menu (event)
171 "Show minor-mode menu for EVENT on minor modes area of the mode line."
172 (interactive "@e")
173 (let ((indicator (car (nth 4 (car (cdr event))))))
174 (minor-mode-menu-from-indicator indicator)))
175
0b2b62ff 176(defun mouse-menu-major-mode-map ()
d5e6e0b6 177 (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
ad0d18af
SM
178 (let* (;; Keymap from which to inherit; may be null.
179 (ancestor (mouse-menu-non-singleton
b98e5762 180 (and (current-local-map)
25db2767 181 (local-key-binding [menu-bar]))))
b98e5762
DL
182 ;; Make a keymap in which our last command leads to a menu or
183 ;; default to the edit menu.
184 (newmap (if ancestor
48d33090
SM
185 (make-sparse-keymap (concat (format-mode-line mode-name)
186 " Mode"))
4d6769e1 187 menu-bar-edit-menu)))
b98e5762 188 (if ancestor
00f7c5ed 189 (set-keymap-parent newmap ancestor))
0b2b62ff 190 newmap))
95132d1c 191
ad0d18af 192(defun mouse-menu-non-singleton (menubar)
d1f14baa
CY
193 "Return menu keybar MENUBAR, or a lone submenu inside it.
194If MENUBAR defines exactly one submenu, return just that submenu.
195Otherwise, return MENUBAR."
95132d1c 196 (if menubar
ad0d18af
SM
197 (let (submap)
198 (map-keymap
199 (lambda (k v) (setq submap (if submap t (cons k v))))
00f7c5ed 200 (keymap-canonicalize menubar))
ad0d18af
SM
201 (if (eq submap t)
202 menubar
203 (lookup-key menubar (vector (car submap)))))))
de420e82 204
0b2b62ff
SM
205(defun mouse-menu-bar-map ()
206 "Return a keymap equivalent to the menu bar.
de420e82
DL
207The contents are the items that would be in the menu bar whether or
208not it is actually displayed."
d5e6e0b6 209 (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
7636d2a3
EZ
210 (let* ((local-menu (and (current-local-map)
211 (lookup-key (current-local-map) [menu-bar])))
212 (global-menu (lookup-key global-map [menu-bar]))
59836110
EZ
213 ;; If a keymap doesn't have a prompt string (a lazy
214 ;; programmer didn't bother to provide one), create it and
215 ;; insert it into the keymap; each keymap gets its own
216 ;; prompt. This is required for non-toolkit versions to
217 ;; display non-empty menu pane names.
218 (minor-mode-menus
219 (mapcar
00f7c5ed
SM
220 (lambda (menu)
221 (let* ((minor-mode (car menu))
222 (menu (cdr menu))
223 (title-or-map (cadr menu)))
224 (or (stringp title-or-map)
225 (setq menu
226 (cons 'keymap
227 (cons (concat
228 (capitalize (subst-char-in-string
229 ?- ?\s (symbol-name
230 minor-mode)))
231 " Menu")
232 (cdr menu)))))
233 menu))
59836110 234 (minor-mode-key-binding [menu-bar])))
7636d2a3
EZ
235 (local-title-or-map (and local-menu (cadr local-menu)))
236 (global-title-or-map (cadr global-menu)))
7636d2a3
EZ
237 (or (null local-menu)
238 (stringp local-title-or-map)
239 (setq local-menu (cons 'keymap
b38f5e6f 240 (cons (concat (format-mode-line mode-name)
48d33090 241 " Mode Menu")
7636d2a3
EZ
242 (cdr local-menu)))))
243 (or (stringp global-title-or-map)
244 (setq global-menu (cons 'keymap
245 (cons "Global Menu"
246 (cdr global-menu)))))
de420e82 247 ;; Supplying the list is faster than making a new map.
0b2b62ff
SM
248 ;; FIXME: We have a problem here: we have to use the global/local/minor
249 ;; so they're displayed in the expected order, but later on in the command
250 ;; loop, they're actually looked up in the opposite order.
251 (apply 'append
252 global-menu
253 local-menu
254 minor-mode-menus)))
255
256(defun mouse-major-mode-menu (event &optional prefix)
257 "Pop up a mode-specific menu of mouse commands.
258Default to the Edit menu if the major mode doesn't define a menu."
59f7af81 259 (declare (obsolete mouse-menu-major-mode-map "23.1"))
0b2b62ff
SM
260 (interactive "@e\nP")
261 (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
262 (popup-menu (mouse-menu-major-mode-map) event prefix))
0b2b62ff
SM
263
264(defun mouse-popup-menubar (event prefix)
265 "Pop up a menu equivalent to the menu bar for keyboard EVENT with PREFIX.
266The contents are the items that would be in the menu bar whether or
267not it is actually displayed."
59f7af81 268 (declare (obsolete mouse-menu-bar-map "23.1"))
0b2b62ff
SM
269 (interactive "@e \nP")
270 (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
fd6fa53f 271 (popup-menu (mouse-menu-bar-map) (unless (integerp event) event) prefix))
de420e82
DL
272
273(defun mouse-popup-menubar-stuff (event prefix)
274 "Popup a menu like either `mouse-major-mode-menu' or `mouse-popup-menubar'.
275Use the former if the menu bar is showing, otherwise the latter."
59f7af81 276 (declare (obsolete nil "23.1"))
0b2b62ff
SM
277 (interactive "@e\nP")
278 (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
279 (popup-menu
280 (if (zerop (or (frame-parameter nil 'menu-bar-lines) 0))
281 (mouse-menu-bar-map)
282 (mouse-menu-major-mode-map))
283 event prefix))
95132d1c 284\f
544e7e73
RS
285;; Commands that operate on windows.
286
d65147f6
KH
287(defun mouse-minibuffer-check (event)
288 (let ((w (posn-window (event-start event))))
289 (and (window-minibuffer-p w)
290 (not (minibuffer-window-active-p w))
71873e2b 291 (user-error "Minibuffer window is not active")))
33c448cd
RS
292 ;; Give temporary modes such as isearch a chance to turn off.
293 (run-hooks 'mouse-leave-buffer-hook))
d65147f6 294
cc0a8174 295(defun mouse-delete-window (click)
947da0c4 296 "Delete the window you click on.
6b48d742 297Do nothing if the frame has just one window.
a926a0fa 298This command must be bound to a mouse click."
ec558adc 299 (interactive "e")
6b48d742 300 (unless (one-window-p t)
a926a0fa
RS
301 (mouse-minibuffer-check click)
302 (delete-window (posn-window (event-start click)))))
cc0a8174 303
3c2dd2c0
RS
304(defun mouse-select-window (click)
305 "Select the window clicked on; don't move point."
306 (interactive "e")
d65147f6 307 (mouse-minibuffer-check click)
3c2dd2c0
RS
308 (let ((oframe (selected-frame))
309 (frame (window-frame (posn-window (event-start click)))))
310 (select-window (posn-window (event-start click)))
311 (raise-frame frame)
312 (select-frame frame)
313 (or (eq frame oframe)
e1877477 314 (set-mouse-position (selected-frame) (1- (frame-width)) 0))))
3c2dd2c0 315
b0f3a26b
JB
316(defun mouse-tear-off-window (click)
317 "Delete the window clicked on, and create a new frame displaying its buffer."
318 (interactive "e")
d65147f6 319 (mouse-minibuffer-check click)
b0f3a26b
JB
320 (let* ((window (posn-window (event-start click)))
321 (buf (window-buffer window))
01a911e3 322 (frame (make-frame)))
b0f3a26b
JB
323 (select-frame frame)
324 (switch-to-buffer buf)
325 (delete-window window)))
326
b5370f03 327(defun mouse-delete-other-windows ()
5925bb84 328 "Delete all windows except the one you click on."
b5370f03 329 (interactive "@")
cc0a8174 330 (delete-other-windows))
72ea54a4 331
cc0a8174
JB
332(defun mouse-split-window-vertically (click)
333 "Select Emacs window mouse is on, then split it vertically in half.
334The window is split at the line clicked on.
335This command must be bound to a mouse click."
947da0c4 336 (interactive "@e")
d65147f6 337 (mouse-minibuffer-check click)
b5370f03
JB
338 (let ((start (event-start click)))
339 (select-window (posn-window start))
85d6b80b 340 (let ((new-height (1+ (cdr (posn-col-row (event-end click)))))
5ba2dc3f
JB
341 (first-line window-min-height)
342 (last-line (- (window-height) window-min-height)))
343 (if (< last-line first-line)
0a50b993 344 (error "Window too short to split")
5ba2dc3f
JB
345 (split-window-vertically
346 (min (max new-height first-line) last-line))))))
cc0a8174 347
947da0c4
RS
348(defun mouse-split-window-horizontally (click)
349 "Select Emacs window mouse is on, then split it horizontally in half.
350The window is split at the column clicked on.
351This command must be bound to a mouse click."
352 (interactive "@e")
d65147f6 353 (mouse-minibuffer-check click)
5ba2dc3f
JB
354 (let ((start (event-start click)))
355 (select-window (posn-window start))
356 (let ((new-width (1+ (car (posn-col-row (event-end click)))))
357 (first-col window-min-width)
358 (last-col (- (window-width) window-min-width)))
359 (if (< last-col first-col)
0a50b993 360 (error "Window too narrow to split")
5ba2dc3f
JB
361 (split-window-horizontally
362 (min (max new-width first-col) last-col))))))
947da0c4 363
e07b9a6d
MR
364;; `mouse-drag-line' is now the common routine for handling all line
365;; dragging events combining the earlier `mouse-drag-mode-line-1' and
366;; `mouse-drag-vertical-line'. It should improve the behavior of line
367;; dragging wrt Emacs 23 as follows:
368
369;; (1) Gratuitous error messages and restrictions have been (hopefully)
370;; removed. (The help-echo that dragging the mode-line can resize a
371;; one-window-frame's window will still show through via bindings.el.)
372
373;; (2) No gratuitous selection of other windows should happen. (This
374;; has not been completely fixed for mouse-autoselected windows yet.)
375
376;; (3) Mouse clicks below a scroll-bar should pass through via unread
377;; command events.
378
379;; Note that `window-in-direction' replaces `mouse-drag-window-above'
380;; and `mouse-drag-vertical-line-rightward-window' with Emacs 24.1.
01ac65bd 381
e07b9a6d 382(defun mouse-drag-line (start-event line)
01ac65bd 383 "Drag a mode line, header line, or vertical line with the mouse.
e07b9a6d 384START-EVENT is the starting mouse-event of the drag action. LINE
01ac65bd 385must be one of the symbols `header', `mode', or `vertical'."
33c448cd
RS
386 ;; Give temporary modes such as isearch a chance to turn off.
387 (run-hooks 'mouse-leave-buffer-hook)
e07b9a6d 388 (let* ((echo-keystrokes 0)
ee0e2bdd 389 (start (event-start start-event))
e07b9a6d
MR
390 (window (posn-window start))
391 (frame (window-frame window))
392 (minibuffer-window (minibuffer-window frame))
01ac65bd
CY
393 (side (and (eq line 'vertical)
394 (or (cdr (assq 'vertical-scroll-bars
395 (frame-parameters frame)))
396 'right)))
397 (draggable t)
880e6158 398 height finished event position growth dragged)
e07b9a6d
MR
399 (cond
400 ((eq line 'header)
401 ;; Check whether header-line can be dragged at all.
53ebff1f 402 (if (window-at-side-p window 'top)
01ac65bd 403 (setq draggable nil)
880e6158 404 (setq height (/ (window-header-line-height window) 2))
53ebff1f 405 (setq window (window-in-direction 'above window t))))
e07b9a6d
MR
406 ((eq line 'mode)
407 ;; Check whether mode-line can be dragged at all.
880e6158
MR
408 (if (and (window-at-side-p window 'bottom)
409 ;; Allow resizing the minibuffer window if it's on the same
410 ;; frame as and immediately below the clicked window, and
411 ;; it's active or `resize-mini-windows' is nil.
412 (not (and (eq (window-frame minibuffer-window) frame)
413 (= (nth 1 (window-pixel-edges minibuffer-window))
414 (nth 3 (window-pixel-edges window)))
415 (or (not resize-mini-windows)
416 (eq minibuffer-window
417 (active-minibuffer-window))))))
418 (setq draggable nil)
419 (setq height (/ (window-mode-line-height window) 2))))
e07b9a6d 420 ((eq line 'vertical)
880e6158
MR
421 ;; Get the window to adjust for the vertical case. If the scroll
422 ;; bar is on the window's right or we drag a vertical divider,
423 ;; adjust the window where the start-event occurred. If the
424 ;; scroll bar is on the start-event window's left or there are no
425 ;; scrollbars, adjust the window on the left of it.
426 (unless (or (eq side 'right)
427 (not (zerop (window-right-divider-width window))))
01ac65bd 428 (setq window (window-in-direction 'left window t)))))
e07b9a6d
MR
429
430 ;; Start tracking.
544e7e73 431 (track-mouse
880e6158
MR
432 ;; Loop reading events and sampling the position of the mouse.
433 (while (not finished)
434 (setq event (read-event))
435 (setq position (mouse-pixel-position))
c8e5a42c
MR
436 ;; Do nothing if
437 ;; - there is a switch-frame event.
438 ;; - the mouse isn't in the frame that we started in
439 ;; - the mouse isn't in any Emacs frame
880e6158
MR
440 ;; Drag if
441 ;; - there is a mouse-movement event
442 ;; - there is a scroll-bar-movement event (Why? -- cyd)
443 ;; (same as mouse movement for our purposes)
444 ;; Quit if
445 ;; - there is a keyboard event or some other unknown event.
e07b9a6d 446 (cond
880e6158
MR
447 ((not (consp event))
448 (setq finished t))
c8e5a42c
MR
449 ((memq (car event) '(switch-frame select-window))
450 nil)
880e6158
MR
451 ((not (memq (car event) '(mouse-movement scroll-bar-movement)))
452 (when (consp event)
453 ;; Do not unread a drag-mouse-1 event to avoid selecting
454 ;; some other window. For vertical line dragging do not
455 ;; unread mouse-1 events either (but only if we dragged at
456 ;; least once to allow mouse-1 clicks get through).
457 (unless (and dragged
458 (if (eq line 'vertical)
459 (memq (car event) '(drag-mouse-1 mouse-1))
460 (eq (car event) 'drag-mouse-1)))
461 (push event unread-command-events)))
462 (setq finished t))
463 ((not (and (eq (car position) frame)
464 (cadr position)))
e07b9a6d
MR
465 nil)
466 ((eq line 'vertical)
880e6158
MR
467 ;; Drag vertical divider. This must be probably fixed like
468 ;; for the mode-line.
01ac65bd
CY
469 (setq growth (- (cadr position)
470 (if (eq side 'right) 0 2)
880e6158 471 (nth 2 (window-pixel-edges window))
01ac65bd 472 -1))
e07b9a6d 473 (unless (zerop growth)
880e6158 474 (setq dragged t)
a1a04df9 475 (adjust-window-trailing-edge window growth t t)))
01ac65bd
CY
476 (draggable
477 ;; Drag horizontal divider.
e07b9a6d
MR
478 (setq growth
479 (if (eq line 'mode)
880e6158
MR
480 (- (+ (cddr position) height)
481 (nth 3 (window-pixel-edges window)))
e07b9a6d 482 ;; The window's top includes the header line!
880e6158
MR
483 (- (+ (nth 3 (window-pixel-edges window)) height)
484 (cddr position))))
e07b9a6d 485 (unless (zerop growth)
880e6158
MR
486 (setq dragged t)
487 (adjust-window-trailing-edge
f49b4978 488 window (if (eq line 'mode) growth (- growth)) nil t))))))))
e07b9a6d 489
b0d22e20
GM
490(defun mouse-drag-mode-line (start-event)
491 "Change the height of a window by dragging on the mode line."
492 (interactive "e")
e07b9a6d 493 (mouse-drag-line start-event 'mode))
b0d22e20
GM
494
495(defun mouse-drag-header-line (start-event)
e07b9a6d 496 "Change the height of a window by dragging on the header line."
b0d22e20 497 (interactive "e")
e07b9a6d 498 (mouse-drag-line start-event 'header))
73c8f64c 499
08a1c178
RS
500(defun mouse-drag-vertical-line (start-event)
501 "Change the width of a window by dragging on the vertical line."
502 (interactive "e")
e07b9a6d 503 (mouse-drag-line start-event 'vertical))
08a1c178 504\f
fbd5cc6c 505(defun mouse-set-point (event &optional promote-to-region)
cc0a8174 506 "Move point to the position clicked on with the mouse.
fbd5cc6c
SM
507This should be bound to a mouse click event type.
508If PROMOTE-TO-REGION is non-nil and event is a multiple-click,
509select the corresponding element around point."
510 (interactive "e\np")
d65147f6 511 (mouse-minibuffer-check event)
fbd5cc6c
SM
512 (if (and promote-to-region (> (event-click-count event) 1))
513 (mouse-set-region event)
514 ;; Use event-end in case called from mouse-drag-region.
515 ;; If EVENT is a click, event-end and event-start give same value.
516 (posn-set-point (event-end event))))
cc0a8174 517
e6c2f5d4
RS
518(defvar mouse-last-region-beg nil)
519(defvar mouse-last-region-end nil)
520(defvar mouse-last-region-tick nil)
521
522(defun mouse-region-match ()
523 "Return non-nil if there's an active region that was set with the mouse."
524 (and (mark t) mark-active
525 (eq mouse-last-region-beg (region-beginning))
526 (eq mouse-last-region-end (region-end))
527 (eq mouse-last-region-tick (buffer-modified-tick))))
528
fbd5cc6c
SM
529(defvar mouse--drag-start-event nil)
530
652ccd35 531(defun mouse-set-region (click)
e37de120 532 "Set the region to the text dragged over, and copy to kill ring.
43f5740b
LMI
533This should be bound to a mouse drag event.
534See the `mouse-drag-copy-region' variable to control whether this
535command alters the kill ring or not."
652ccd35 536 (interactive "e")
d65147f6 537 (mouse-minibuffer-check click)
f9be2e35
CY
538 (select-window (posn-window (event-start click)))
539 (let ((beg (posn-point (event-start click)))
fbd5cc6c
SM
540 (end (posn-point (event-end click)))
541 (click-count (event-click-count click)))
542 (let ((drag-start (terminal-parameter nil 'mouse-drag-start)))
fbd5cc6c 543 (when drag-start
a366fbe2
SM
544 ;; Drag events don't come with a click count, sadly, so we hack
545 ;; our way around this problem by remembering the start-event in
546 ;; `mouse-drag-start' and fetching the click-count from there.
fbd5cc6c
SM
547 (when (and (<= click-count 1)
548 (equal beg (posn-point (event-start drag-start))))
549 (setq click-count (event-click-count drag-start)))
a366fbe2
SM
550 ;; Occasionally we get spurious drag events where the user hasn't
551 ;; dragged his mouse, but instead Emacs has dragged the text under the
552 ;; user's mouse. Try to recover those cases (bug#17562).
553 (when (and (equal (posn-x-y (event-start click))
554 (posn-x-y (event-end click)))
555 (not (eq (car drag-start) 'mouse-movement)))
556 (setq end beg))
fbd5cc6c
SM
557 (setf (terminal-parameter nil 'mouse-drag-start) nil)))
558 (when (and (integerp beg) (integerp end))
559 (let ((range (mouse-start-end beg end (1- click-count))))
560 (if (< end beg)
561 (setq end (nth 0 range) beg (nth 1 range))
562 (setq beg (nth 0 range) end (nth 1 range)))))
f9be2e35
CY
563 (and mouse-drag-copy-region (integerp beg) (integerp end)
564 ;; Don't set this-command to `kill-region', so a following
565 ;; C-w won't double the text in the kill ring. Ignore
566 ;; `last-command' so we don't append to a preceding kill.
567 (let (this-command last-command deactivate-mark)
568 (copy-region-as-kill beg end)))
569 (if (numberp beg) (goto-char beg))
570 ;; On a text terminal, bounce the cursor.
33a35434 571 (or transient-mark-mode
f9be2e35 572 (window-system)
fcfc3c63 573 (sit-for 1))
652ccd35 574 (push-mark)
1cc8a3f4 575 (set-mark (point))
f9be2e35 576 (if (numberp end) (goto-char end))
e6c2f5d4
RS
577 (mouse-set-region-1)))
578
579(defun mouse-set-region-1 ()
a5809dbd 580 ;; Set transient-mark-mode for a little while.
688468a0 581 (unless (eq (car-safe transient-mark-mode) 'only)
5d2638bd
SM
582 (setq-local transient-mark-mode
583 (cons 'only
584 (unless (eq transient-mark-mode 'lambda)
585 transient-mark-mode))))
e6c2f5d4
RS
586 (setq mouse-last-region-beg (region-beginning))
587 (setq mouse-last-region-end (region-end))
588 (setq mouse-last-region-tick (buffer-modified-tick)))
652ccd35 589
3b558d41 590(defcustom mouse-scroll-delay 0.25
9201cc28 591 "The pause between scroll steps caused by mouse drags, in seconds.
600c6e3a
JB
592If you drag the mouse beyond the edge of a window, Emacs scrolls the
593window to bring the text beyond that edge into view, with a delay of
594this many seconds between scroll steps. Scrolling stops when you move
595the mouse back into the window, or release the button.
596This variable's value may be non-integral.
3b558d41
RS
597Setting this to zero causes Emacs to scroll as fast as it can."
598 :type 'number
599 :group 'mouse)
600c6e3a 600
3b558d41 601(defcustom mouse-scroll-min-lines 1
9201cc28 602 "The minimum number of lines scrolled by dragging mouse out of window.
a3d6bb97
RS
603Moving the mouse out the top or bottom edge of the window begins
604scrolling repeatedly. The number of lines scrolled per repetition
605is normally equal to the number of lines beyond the window edge that
606the mouse has moved. However, it always scrolls at least the number
3b558d41
RS
607of lines specified by this variable."
608 :type 'integer
609 :group 'mouse)
08a1c178 610
e919a622
RS
611(defun mouse-scroll-subr (window jump &optional overlay start)
612 "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
600c6e3a
JB
613If OVERLAY is an overlay, let it stretch from START to the far edge of
614the newly visible text.
615Upon exit, point is at the far edge of the newly visible text."
08a1c178
RS
616 (cond
617 ((and (> jump 0) (< jump mouse-scroll-min-lines))
618 (setq jump mouse-scroll-min-lines))
619 ((and (< jump 0) (< (- jump) mouse-scroll-min-lines))
620 (setq jump (- mouse-scroll-min-lines))))
4e399a53
RS
621 (let ((opoint (point)))
622 (while (progn
623 (goto-char (window-start window))
624 (if (not (zerop (vertical-motion jump window)))
625 (progn
626 (set-window-start window (point))
627 (if (natnump jump)
0320e66f
RS
628 (if (window-end window)
629 (progn
630 (goto-char (window-end window))
631 ;; window-end doesn't reflect the window's new
632 ;; start position until the next redisplay.
633 (vertical-motion (1- jump) window))
634 (vertical-motion (- (window-height window) 2)))
4e399a53
RS
635 (goto-char (window-start window)))
636 (if overlay
637 (move-overlay overlay start (point)))
638 ;; Now that we have scrolled WINDOW properly,
639 ;; put point back where it was for the redisplay
640 ;; so that we don't mess up the selected window.
641 (or (eq window (selected-window))
642 (goto-char opoint))
d2287ded 643 (sit-for mouse-scroll-delay)))))
4e399a53
RS
644 (or (eq window (selected-window))
645 (goto-char opoint))))
fcfc3c63 646
dd524dbd 647(defvar mouse-selection-click-count 0)
eb6ff46f 648
c8c5bd24
RS
649(defvar mouse-selection-click-count-buffer nil)
650
600c6e3a 651(defun mouse-drag-region (start-event)
bcd5aef1 652 "Set the region to the text that the mouse is dragged over.
78210c95
RS
653Highlight the drag area as you move the mouse.
654This must be bound to a button-down mouse event.
d017deb2 655In Transient Mark mode, the highlighting remains as long as the mark
fbd5cc6c 656remains active. Otherwise, it remains until the next input event."
bcd5aef1 657 (interactive "e")
fd6fa53f
SM
658 ;; Give temporary modes such as isearch a chance to turn off.
659 (run-hooks 'mouse-leave-buffer-hook)
fbd5cc6c 660 (mouse-drag-track start-event))
6454615c 661
65f76581 662
91a2acb2 663(defun mouse-posn-property (pos property)
9ed38a84
DK
664 "Look for a property at click position.
665POS may be either a buffer position or a click position like
89bf250e 666those returned from `event-start'. If the click position is on
9ed38a84
DK
667a string, the text property PROPERTY is examined.
668If this is nil or the click is not on a string, then
669the corresponding buffer position is searched for PROPERTY.
670If PROPERTY is encountered in one of those places,
671its value is returned."
91a2acb2
DK
672 (if (consp pos)
673 (let ((w (posn-window pos)) (pt (posn-point pos))
674 (str (posn-string pos)))
675 (or (and str
676 (get-text-property (cdr str) property (car str)))
631de55b
SM
677 ;; Mouse clicks in the fringe come with a position in
678 ;; (nth 5). This is useful but is not exactly where we clicked, so
679 ;; don't look up that position's properties!
680 (and pt (not (memq (posn-area pos) '(left-fringe right-fringe
681 left-margin right-margin)))
91a2acb2
DK
682 (get-char-property pt property w))))
683 (get-char-property pos property)))
684
65f76581
KS
685(defun mouse-on-link-p (pos)
686 "Return non-nil if POS is on a link in the current buffer.
23eb76c4
TTN
687POS must be a buffer position in the current buffer or a mouse
688event location in the selected window (see `event-start').
185a53bb
KS
689However, if `mouse-1-click-in-non-selected-windows' is non-nil,
690POS may be a mouse event location in any window.
65f76581
KS
691
692A clickable link is identified by one of the following methods:
693
b41a4019 694- If the character at POS has a non-nil `follow-link' text or
e5fb57e9 695overlay property, the value of that property determines what to do.
65f76581 696
b41a4019
KS
697- If there is a local key-binding or a keybinding at position POS
698for the `follow-link' event, the binding of that event determines
699what to do.
65f76581 700
b41a4019
KS
701The resulting value determine whether POS is inside a link:
702
703- If the value is `mouse-face', POS is inside a link if there
65f76581
KS
704is a non-nil `mouse-face' property at POS. Return t in this case.
705
b41a4019 706- If the value is a function, FUNC, POS is inside a link if
65f76581 707the call \(FUNC POS) returns non-nil. Return the return value
23eb76c4 708from that call. Arg is \(posn-point POS) if POS is a mouse event.
65f76581 709
b41a4019 710- Otherwise, return the value itself.
65f76581
KS
711
712The return value is interpreted as follows:
713
714- If it is a string, the mouse-1 event is translated into the
715first character of the string, i.e. the action of the mouse-1
716click is the local or global binding of that character.
717
718- If it is a vector, the mouse-1 event is translated into the
719first element of that vector, i.e. the action of the mouse-1
720click is the local or global binding of that event.
721
722- Otherwise, the mouse-1 event is translated into a mouse-2 event
723at the same position."
91a2acb2 724 (let ((action
9a1ff164 725 (and (or (not (consp pos))
91a2acb2
DK
726 mouse-1-click-in-non-selected-windows
727 (eq (selected-window) (posn-window pos)))
728 (or (mouse-posn-property pos 'follow-link)
0e6008c5
SM
729 (let ((area (posn-area pos)))
730 (when area
731 (key-binding (vector area 'follow-link) nil t pos)))
91a2acb2
DK
732 (key-binding [follow-link] nil t pos)))))
733 (cond
734 ((eq action 'mouse-face)
735 (and (mouse-posn-property pos 'mouse-face) t))
736 ((functionp action)
9ed38a84 737 ;; FIXME: This seems questionable if the click is not in a buffer.
e9ae308c 738 ;; Should we instead decide that `action' takes a `posn'?
9ed38a84
DK
739 (if (consp pos)
740 (with-current-buffer (window-buffer (posn-window pos))
624c972d 741 (funcall action (posn-point pos)))
9ed38a84 742 (funcall action pos)))
91a2acb2 743 (t action))))
b0ca1b8a 744
5dbda518
KS
745(defun mouse-fixup-help-message (msg)
746 "Fix help message MSG for `mouse-1-click-follows-link'."
747 (let (mp pos)
748 (if (and mouse-1-click-follows-link
749 (stringp msg)
26ee77a6 750 (string-match-p "\\`mouse-2" msg)
5dbda518
KS
751 (setq mp (mouse-pixel-position))
752 (consp (setq pos (cdr mp)))
753 (car pos) (>= (car pos) 0)
754 (cdr pos) (>= (cdr pos) 0)
755 (setq pos (posn-at-x-y (car pos) (cdr pos) (car mp)))
756 (windowp (posn-window pos)))
757 (with-current-buffer (window-buffer (posn-window pos))
758 (if (mouse-on-link-p pos)
759 (setq msg (concat
760 (cond
761 ((eq mouse-1-click-follows-link 'double) "double-")
762 ((and (integerp mouse-1-click-follows-link)
763 (< mouse-1-click-follows-link 0)) "Long ")
764 (t ""))
765 "mouse-1" (substring msg 7)))))))
766 msg)
65f76581 767
fbd5cc6c 768(defun mouse-drag-track (start-event)
f1c4f757 769 "Track mouse drags by highlighting area between point and cursor.
fbd5cc6c 770The region will be defined with mark and point."
d65147f6 771 (mouse-minibuffer-check start-event)
aaf15b8b 772 (setq mouse-selection-click-count-buffer (current-buffer))
3f5c9cad 773 (deactivate-mark)
371d6a61 774 (let* ((scroll-margin 0) ; Avoid margin scrolling (Bug#9541).
aaf15b8b
SM
775 ;; We've recorded what we needed from the current buffer and
776 ;; window, now let's jump to the place of the event, where things
777 ;; are happening.
778 (_ (mouse-set-point start-event))
779 (echo-keystrokes 0)
4c9afcbe 780 (start-posn (event-start start-event))
600c6e3a
JB
781 (start-point (posn-point start-posn))
782 (start-window (posn-window start-posn))
783 (bounds (window-edges start-window))
8413d0d2 784 (make-cursor-line-fully-visible nil)
600c6e3a
JB
785 (top (nth 1 bounds))
786 (bottom (if (window-minibuffer-p start-window)
787 (nth 3 bounds)
788 ;; Don't count the mode line.
e37de120 789 (1- (nth 3 bounds))))
81133808 790 (click-count (1- (event-click-count start-event)))
a9d01547
CY
791 ;; Suppress automatic hscrolling, because that is a nuisance
792 ;; when setting point near the right fringe (but see below).
fbd5cc6c 793 (auto-hscroll-mode-saved auto-hscroll-mode))
5592c08f 794
81133808 795 (setq mouse-selection-click-count click-count)
08a1c178
RS
796 ;; In case the down click is in the middle of some intangible text,
797 ;; use the end of that text, and put it in START-POINT.
798 (if (< (point) start-point)
799 (goto-char start-point))
800 (setq start-point (point))
5592c08f 801
81133808
CY
802 ;; Activate the region, using `mouse-start-end' to determine where
803 ;; to put point and mark (e.g., double-click will select a word).
5d2638bd
SM
804 (setq-local transient-mark-mode
805 (if (eq transient-mark-mode 'lambda)
806 '(only)
807 (cons 'only transient-mark-mode)))
9852377f 808 (let ((range (mouse-start-end start-point start-point click-count)))
6d3e82d2 809 (push-mark (nth 0 range) t t)
81133808 810 (goto-char (nth 1 range)))
5592c08f 811
fbd5cc6c
SM
812 (setf (terminal-parameter nil 'mouse-drag-start) start-event)
813 (setq track-mouse t)
814 (setq auto-hscroll-mode nil)
815
816 (set-transient-map
817 (let ((map (make-sparse-keymap)))
818 (define-key map [switch-frame] #'ignore)
819 (define-key map [select-window] #'ignore)
820 (define-key map [mouse-movement]
821 (lambda (event) (interactive "e")
822 (let* ((end (event-end event))
823 (end-point (posn-point end)))
a366fbe2 824 (unless (eq end-point start-point)
fbd5cc6c 825 ;; As soon as the user moves, we can re-enable auto-hscroll.
a366fbe2
SM
826 (setq auto-hscroll-mode auto-hscroll-mode-saved)
827 ;; And remember that we have moved, so mouse-set-region can know
828 ;; its event is really a drag event.
829 (setcar start-event 'mouse-movement))
830 (if (and (eq (posn-window end) start-window)
831 (integer-or-marker-p end-point))
832 (mouse--drag-set-mark-and-point start-point
833 end-point click-count)
834 (let ((mouse-row (cdr (cdr (mouse-position)))))
835 (cond
836 ((null mouse-row))
837 ((< mouse-row top)
838 (mouse-scroll-subr start-window (- mouse-row top)
839 nil start-point))
840 ((>= mouse-row bottom)
841 (mouse-scroll-subr start-window (1+ (- mouse-row bottom))
842 nil start-point))))))))
fbd5cc6c
SM
843 map)
844 t (lambda ()
845 (setq track-mouse nil)
846 (setq auto-hscroll-mode auto-hscroll-mode-saved)
13841bfc 847 (deactivate-mark)
fbd5cc6c 848 (pop-mark)))))
5592c08f 849
6d3e82d2
CY
850(defun mouse--drag-set-mark-and-point (start click click-count)
851 (let* ((range (mouse-start-end start click click-count))
852 (beg (nth 0 range))
853 (end (nth 1 range)))
854 (cond ((eq (mark) beg)
855 (goto-char end))
856 ((eq (mark) end)
857 (goto-char beg))
858 ((< click (mark))
859 (set-mark end)
860 (goto-char beg))
861 (t
862 (set-mark beg)
863 (goto-char end)))))
864
e37de120 865;; Commands to handle xterm-style multiple clicks.
e37de120
RS
866(defun mouse-skip-word (dir)
867 "Skip over word, over whitespace, or over identical punctuation.
868If DIR is positive skip forward; if negative, skip backward."
869 (let* ((char (following-char))
870 (syntax (char-to-string (char-syntax char))))
258e3295
KH
871 (cond ((string= syntax "w")
872 ;; Here, we can't use skip-syntax-forward/backward because
873 ;; they don't pay attention to word-separating-categories,
874 ;; and thus they will skip over a true word boundary. So,
fffa137c 875 ;; we simulate the original behavior by using forward-word.
258e3295
KH
876 (if (< dir 0)
877 (if (not (looking-at "\\<"))
878 (forward-word -1))
879 (if (or (looking-at "\\<") (not (looking-at "\\>")))
880 (forward-word 1))))
881 ((string= syntax " ")
08a1c178
RS
882 (if (< dir 0)
883 (skip-syntax-backward syntax)
884 (skip-syntax-forward syntax)))
885 ((string= syntax "_")
886 (if (< dir 0)
887 (skip-syntax-backward "w_")
888 (skip-syntax-forward "w_")))
889 ((< dir 0)
890 (while (and (not (bobp)) (= (preceding-char) char))
891 (forward-char -1)))
892 (t
893 (while (and (not (eobp)) (= (following-char) char))
894 (forward-char 1))))))
e37de120 895
eb6ff46f 896(defun mouse-start-end (start end mode)
c3bb6d70 897 "Return a list of region bounds based on START and END according to MODE.
a7df580d
DL
898If MODE is 0 then set point to (min START END), mark to (max START END).
899If MODE is 1 then set point to start of word at (min START END),
900mark to end of word at (max START END).
901If MODE is 2 then do the same for lines."
e37de120
RS
902 (if (> start end)
903 (let ((temp start))
904 (setq start end
905 end temp)))
9a974c88 906 (setq mode (mod mode 3))
e37de120
RS
907 (cond ((= mode 0)
908 (list start end))
909 ((and (= mode 1)
910 (= start end)
1ec71583 911 (char-after start)
e37de120 912 (= (char-syntax (char-after start)) ?\())
6f482eec
RS
913 (list start
914 (save-excursion
915 (goto-char start)
916 (forward-sexp 1)
917 (point))))
e37de120
RS
918 ((and (= mode 1)
919 (= start end)
1ec71583 920 (char-after start)
e37de120 921 (= (char-syntax (char-after start)) ?\)))
7b611de0 922 (list (save-excursion
e37de120 923 (goto-char (1+ start))
d89a4a47
RS
924 (backward-sexp 1)
925 (point))
e37de120 926 (1+ start)))
53770877
RS
927 ((and (= mode 1)
928 (= start end)
929 (char-after start)
930 (= (char-syntax (char-after start)) ?\"))
931 (let ((open (or (eq start (point-min))
932 (save-excursion
933 (goto-char (- start 1))
934 (looking-at "\\s(\\|\\s \\|\\s>")))))
935 (if open
936 (list start
937 (save-excursion
938 (condition-case nil
7b611de0 939 (progn
53770877
RS
940 (goto-char start)
941 (forward-sexp 1)
942 (point))
943 (error end))))
f1017d55 944 (list (save-excursion
53770877
RS
945 (condition-case nil
946 (progn
947 (goto-char (1+ start))
948 (backward-sexp 1)
949 (point))
f1017d55
RS
950 (error end)))
951 (1+ start)))))
e37de120
RS
952 ((= mode 1)
953 (list (save-excursion
954 (goto-char start)
955 (mouse-skip-word -1)
956 (point))
957 (save-excursion
958 (goto-char end)
959 (mouse-skip-word 1)
960 (point))))
961 ((= mode 2)
962 (list (save-excursion
963 (goto-char start)
6d3e82d2 964 (line-beginning-position 1))
e37de120
RS
965 (save-excursion
966 (goto-char end)
967 (forward-line 1)
968 (point))))))
e66feb07 969\f
3f26b32a
RS
970;; Subroutine: set the mark where CLICK happened,
971;; but don't do anything else.
972(defun mouse-set-mark-fast (click)
d65147f6 973 (mouse-minibuffer-check click)
3f26b32a
RS
974 (let ((posn (event-start click)))
975 (select-window (posn-window posn))
976 (if (numberp (posn-point posn))
977 (push-mark (posn-point posn) t t))))
978
98aac09d
MB
979(defun mouse-undouble-last-event (events)
980 (let* ((index (1- (length events)))
981 (last (nthcdr index events))
982 (event (car last))
983 (basic (event-basic-type event))
397a88f3
RS
984 (old-modifiers (event-modifiers event))
985 (modifiers (delq 'double (delq 'triple (copy-sequence old-modifiers))))
98aac09d
MB
986 (new
987 (if (consp event)
7132500b
RS
988 ;; Use reverse, not nreverse, since event-modifiers
989 ;; does not copy the list it returns.
3bb846b8 990 (cons (event-convert-list (reverse (cons basic modifiers)))
98aac09d
MB
991 (cdr event))
992 event)))
993 (setcar last new)
397a88f3
RS
994 (if (and (not (equal modifiers old-modifiers))
995 (key-binding (apply 'vector events)))
98aac09d
MB
996 t
997 (setcar last event)
998 nil)))
999
7b611de0 1000;; Momentarily show where the mark is, if highlighting doesn't show it.
7aeb7370 1001
cc0a8174
JB
1002(defun mouse-set-mark (click)
1003 "Set mark at the position clicked on with the mouse.
1004Display cursor at that position for a second.
1005This must be bound to a mouse click."
ec558adc 1006 (interactive "e")
f598fb03
RS
1007 (mouse-minibuffer-check click)
1008 (select-window (posn-window (event-start click)))
1009 ;; We don't use save-excursion because that preserves the mark too.
72ea54a4
RS
1010 (let ((point-save (point)))
1011 (unwind-protect
cc0a8174 1012 (progn (mouse-set-point click)
897897e3
RS
1013 (push-mark nil t t)
1014 (or transient-mark-mode
1015 (sit-for 1)))
72ea54a4
RS
1016 (goto-char point-save))))
1017
cc0a8174
JB
1018(defun mouse-kill (click)
1019 "Kill the region between point and the mouse click.
1020The text is saved in the kill ring, as with \\[kill-region]."
ec558adc 1021 (interactive "e")
d65147f6 1022 (mouse-minibuffer-check click)
142c7672
KH
1023 (let* ((posn (event-start click))
1024 (click-posn (posn-point posn)))
1025 (select-window (posn-window posn))
bd307392
JB
1026 (if (numberp click-posn)
1027 (kill-region (min (point) click-posn)
1028 (max (point) click-posn)))))
72ea54a4 1029
87ef29fd
JB
1030(defun mouse-yank-at-click (click arg)
1031 "Insert the last stretch of killed text at the position clicked on.
0e57ab65 1032Also move point to one end of the text thus inserted (normally the end),
231c4d1a 1033and set mark at the beginning.
50f58001
RS
1034Prefix arguments are interpreted as with \\[yank].
1035If `mouse-yank-at-point' is non-nil, insert at point
9852377f 1036regardless of where you click."
a4cabe41 1037 (interactive "e\nP")
33c448cd
RS
1038 ;; Give temporary modes such as isearch a chance to turn off.
1039 (run-hooks 'mouse-leave-buffer-hook)
3f5c9cad
CY
1040 (when select-active-regions
1041 ;; Without this, confusing things happen upon e.g. inserting into
1042 ;; the middle of an active region.
6f3a2682 1043 (deactivate-mark))
50f58001 1044 (or mouse-yank-at-point (mouse-set-point click))
d89a4a47 1045 (setq this-command 'yank)
a814e9df 1046 (setq mouse-selection-click-count 0)
87ef29fd
JB
1047 (yank arg))
1048
63571b5a
RS
1049(defun mouse-yank-primary (click)
1050 "Insert the primary selection at the position clicked on.
e1eb5385
CY
1051Move point to the end of the inserted text, and set mark at
1052beginning. If `mouse-yank-at-point' is non-nil, insert at point
63571b5a
RS
1053regardless of where you click."
1054 (interactive "e")
1055 ;; Give temporary modes such as isearch a chance to turn off.
1056 (run-hooks 'mouse-leave-buffer-hook)
1c409d0b
CY
1057 ;; Without this, confusing things happen upon e.g. inserting into
1058 ;; the middle of an active region.
6c6a75d5 1059 (when select-active-regions
1c409d0b
CY
1060 (let (select-active-regions)
1061 (deactivate-mark)))
63571b5a 1062 (or mouse-yank-at-point (mouse-set-point click))
e7afcf30 1063 (let ((primary
5f30349b
GM
1064 (if (fboundp 'x-get-selection-value)
1065 (if (eq (framep (selected-frame)) 'w32)
1066 ;; MS-Windows emulates PRIMARY in x-get-selection, but not
1067 ;; in x-get-selection-value (the latter only accesses the
1068 ;; clipboard). So try PRIMARY first, in case they selected
1069 ;; something with the mouse in the current Emacs session.
1070 (or (x-get-selection 'PRIMARY)
1071 (x-get-selection-value))
1072 ;; Else MS-DOS or X.
1073 ;; On X, x-get-selection-value supports more formats and
1074 ;; encodings, so use it in preference to x-get-selection.
1075 (or (x-get-selection-value)
1076 (x-get-selection 'PRIMARY)))
1077 ;; FIXME: What about xterm-mouse-mode etc.?
1078 (x-get-selection 'PRIMARY))))
e1eb5385
CY
1079 (unless primary
1080 (error "No selection is available"))
1081 (push-mark (point))
1082 (insert primary)))
63571b5a 1083
87ef29fd 1084(defun mouse-kill-ring-save (click)
cc0a8174
JB
1085 "Copy the region between point and the mouse click in the kill ring.
1086This does not delete the region; it acts like \\[kill-ring-save]."
ec558adc 1087 (interactive "e")
3f26b32a 1088 (mouse-set-mark-fast click)
6452d8a6 1089 (let (this-command last-command)
5592c08f 1090 (kill-ring-save (point) (mark t))))
72ea54a4 1091
ad0d18af
SM
1092;; This function used to delete the text between point and the mouse
1093;; whenever it was equal to the front of the kill ring, but some
1094;; people found that confusing.
dbc4e1c1 1095
d2625c3d 1096;; The position of the last invocation of `mouse-save-then-kill'.
dbc4e1c1
JB
1097(defvar mouse-save-then-kill-posn nil)
1098
26d280b9 1099(defun mouse-save-then-kill-delete-region (beg end)
9a974c88
RS
1100 ;; We must make our own undo boundaries
1101 ;; because they happen automatically only for the current buffer.
1102 (undo-boundary)
dd524dbd
RS
1103 (if (or (= beg end) (eq buffer-undo-list t))
1104 ;; If we have no undo list in this buffer,
1105 ;; just delete.
1106 (delete-region beg end)
1107 ;; Delete, but make the undo-list entry share with the kill ring.
1108 ;; First, delete just one char, so in case buffer is being modified
1109 ;; for the first time, the undo list records that fact.
8faa9707 1110 (let (before-change-functions after-change-functions)
2f4b15ef
RS
1111 (delete-region beg
1112 (+ beg (if (> end beg) 1 -1))))
dd524dbd
RS
1113 (let ((buffer-undo-list buffer-undo-list))
1114 ;; Undo that deletion--but don't change the undo list!
8faa9707 1115 (let (before-change-functions after-change-functions)
2f4b15ef 1116 (primitive-undo 1 buffer-undo-list))
dd524dbd
RS
1117 ;; Now delete the rest of the specified region,
1118 ;; but don't record it.
1119 (setq buffer-undo-list t)
9a974c88
RS
1120 (if (/= (length (car kill-ring)) (- (max end beg) (min end beg)))
1121 (error "Lossage in mouse-save-then-kill-delete-region"))
dd524dbd
RS
1122 (delete-region beg end))
1123 (let ((tail buffer-undo-list))
1124 ;; Search back in buffer-undo-list for the string
1125 ;; that came from deleting one character.
1126 (while (and tail (not (stringp (car (car tail)))))
1127 (setq tail (cdr tail)))
1128 ;; Replace it with an entry for the entire deleted text.
1129 (and tail
9a974c88
RS
1130 (setcar tail (cons (car kill-ring) (min beg end))))))
1131 (undo-boundary))
eb6ff46f 1132
947da0c4 1133(defun mouse-save-then-kill (click)
d2625c3d
CY
1134 "Set the region according to CLICK; the second time, kill it.
1135CLICK should be a mouse click event.
1136
1137If the region is inactive, activate it temporarily. Set mark at
1138the original point, and move point to the position of CLICK.
1139
1140If the region is already active, adjust it. Normally, do this by
1141moving point or mark, whichever is closer, to CLICK. But if you
1142have selected whole words or lines, move point or mark to the
1143word or line boundary closest to CLICK instead.
1144
93d68d4f
DDLHG
1145If `mouse-drag-copy-region' is non-nil, this command also saves the
1146new region to the kill ring (replacing the previous kill if the
1147previous region was just saved to the kill ring).
1148
d2625c3d 1149If this command is called a second consecutive time with the same
93d68d4f
DDLHG
1150CLICK position, kill the region (or delete it
1151if `mouse-drag-copy-region' is non-nil)"
947da0c4 1152 (interactive "e")
d2625c3d
CY
1153 (mouse-minibuffer-check click)
1154 (let* ((posn (event-start click))
1155 (click-pt (posn-point posn))
1156 (window (posn-window posn))
1157 (buf (window-buffer window))
1158 ;; Don't let a subsequent kill command append to this one.
1159 (this-command this-command)
1160 ;; Check if the user has multi-clicked to select words/lines.
1161 (click-count
1162 (if (and (eq mouse-selection-click-count-buffer buf)
1163 (with-current-buffer buf (mark t)))
1164 mouse-selection-click-count
1165 0)))
1166 (cond
1167 ((not (numberp click-pt)) nil)
1168 ;; If the user clicked without moving point, kill the region.
1169 ;; This also resets `mouse-selection-click-count'.
1170 ((and (eq last-command 'mouse-save-then-kill)
1171 (eq click-pt mouse-save-then-kill-posn)
1172 (eq window (selected-window)))
93d68d4f
DDLHG
1173 (if mouse-drag-copy-region
1174 ;; Region already saved in the previous click;
1175 ;; don't make a duplicate entry, just delete.
1176 (delete-region (mark t) (point))
1177 (kill-region (mark t) (point)))
d2625c3d
CY
1178 (setq mouse-selection-click-count 0)
1179 (setq mouse-save-then-kill-posn nil))
1180
1181 ;; Otherwise, if there is a suitable region, adjust it by moving
1182 ;; one end (whichever is closer) to CLICK-PT.
1183 ((or (with-current-buffer buf (region-active-p))
1184 (and (eq window (selected-window))
1185 (mark t)
1186 (or (and (eq last-command 'mouse-save-then-kill)
1187 mouse-save-then-kill-posn)
1188 (and (memq last-command '(mouse-drag-region
1189 mouse-set-region))
1190 (or mark-even-if-inactive
1191 (not transient-mark-mode))))))
1192 (select-window window)
1193 (let* ((range (mouse-start-end click-pt click-pt click-count)))
1194 (if (< (abs (- click-pt (mark t)))
1195 (abs (- click-pt (point))))
1196 (set-mark (car range))
1197 (goto-char (nth 1 range)))
1198 (setq deactivate-mark nil)
1199 (mouse-set-region-1)
93d68d4f
DDLHG
1200 (when mouse-drag-copy-region
1201 ;; Region already copied to kill-ring once, so replace.
1202 (kill-new (filter-buffer-substring (mark t) (point)) t))
d2625c3d
CY
1203 ;; Arrange for a repeated mouse-3 to kill the region.
1204 (setq mouse-save-then-kill-posn click-pt)))
1205
1206 ;; Otherwise, set the mark where point is and move to CLICK-PT.
1207 (t
1208 (select-window window)
1209 (mouse-set-mark-fast click)
1210 (let ((before-scroll (with-current-buffer buf point-before-scroll)))
1211 (if before-scroll (goto-char before-scroll)))
1212 (exchange-point-and-mark)
1213 (mouse-set-region-1)
93d68d4f
DDLHG
1214 (when mouse-drag-copy-region
1215 (kill-new (filter-buffer-substring (mark t) (point))))
d2625c3d
CY
1216 (setq mouse-save-then-kill-posn click-pt)))))
1217
e66feb07
RS
1218\f
1219(global-set-key [M-mouse-1] 'mouse-start-secondary)
1220(global-set-key [M-drag-mouse-1] 'mouse-set-secondary)
1221(global-set-key [M-down-mouse-1] 'mouse-drag-secondary)
1222(global-set-key [M-mouse-3] 'mouse-secondary-save-then-kill)
9a974c88 1223(global-set-key [M-mouse-2] 'mouse-yank-secondary)
e66feb07 1224
aaf15b8b
SM
1225(defconst mouse-secondary-overlay
1226 (let ((ol (make-overlay (point-min) (point-min))))
1227 (delete-overlay ol)
1228 (overlay-put ol 'face 'secondary-selection)
1229 ol)
1230 "An overlay which records the current secondary selection.
1231It is deleted when there is no secondary selection.")
e66feb07 1232
a94c7fcc
RS
1233(defvar mouse-secondary-click-count 0)
1234
e66feb07
RS
1235;; A marker which records the specified first end for a secondary selection.
1236;; May be nil.
1237(defvar mouse-secondary-start nil)
1238
1239(defun mouse-start-secondary (click)
1240 "Set one end of the secondary selection to the position clicked on.
1241Use \\[mouse-secondary-save-then-kill] to set the other end
1242and complete the secondary selection."
1243 (interactive "e")
d65147f6 1244 (mouse-minibuffer-check click)
e66feb07 1245 (let ((posn (event-start click)))
aaf15b8b 1246 (with-current-buffer (window-buffer (posn-window posn))
230aaa73 1247 ;; Cancel any preexisting secondary selection.
aaf15b8b 1248 (delete-overlay mouse-secondary-overlay)
230aaa73
RS
1249 (if (numberp (posn-point posn))
1250 (progn
1251 (or mouse-secondary-start
1252 (setq mouse-secondary-start (make-marker)))
1253 (move-marker mouse-secondary-start (posn-point posn)))))))
e66feb07
RS
1254
1255(defun mouse-set-secondary (click)
1256 "Set the secondary selection to the text that the mouse is dragged over.
1257This must be bound to a mouse drag event."
1258 (interactive "e")
d65147f6 1259 (mouse-minibuffer-check click)
e66feb07
RS
1260 (let ((posn (event-start click))
1261 beg
1262 (end (event-end click)))
aaf15b8b 1263 (with-current-buffer (window-buffer (posn-window posn))
230aaa73
RS
1264 (if (numberp (posn-point posn))
1265 (setq beg (posn-point posn)))
3e4f866b
CY
1266 (move-overlay mouse-secondary-overlay beg (posn-point end))
1267 (x-set-selection
1268 'SECONDARY
1269 (buffer-substring (overlay-start mouse-secondary-overlay)
1270 (overlay-end mouse-secondary-overlay))))))
947da0c4 1271
d89a4a47 1272(defun mouse-drag-secondary (start-event)
e66feb07 1273 "Set the secondary selection to the text that the mouse is dragged over.
d89a4a47 1274Highlight the drag area as you move the mouse.
efc10c97
RS
1275This must be bound to a button-down mouse event.
1276The function returns a non-nil value if it creates a secondary selection."
e66feb07 1277 (interactive "e")
d65147f6 1278 (mouse-minibuffer-check start-event)
4c9afcbe
RS
1279 (let* ((echo-keystrokes 0)
1280 (start-posn (event-start start-event))
d89a4a47
RS
1281 (start-point (posn-point start-posn))
1282 (start-window (posn-window start-posn))
d89a4a47
RS
1283 (bounds (window-edges start-window))
1284 (top (nth 1 bounds))
1285 (bottom (if (window-minibuffer-p start-window)
1286 (nth 3 bounds)
1287 ;; Don't count the mode line.
1288 (1- (nth 3 bounds))))
1289 (click-count (1- (event-click-count start-event))))
aaf15b8b 1290 (with-current-buffer (window-buffer start-window)
a94c7fcc 1291 (setq mouse-secondary-click-count click-count)
9a974c88 1292 (if (> (mod click-count 3) 0)
26d280b9
RS
1293 ;; Double or triple press: make an initial selection
1294 ;; of one word or line.
d89a4a47
RS
1295 (let ((range (mouse-start-end start-point start-point click-count)))
1296 (set-marker mouse-secondary-start nil)
d89a4a47
RS
1297 (move-overlay mouse-secondary-overlay (car range) (nth 1 range)
1298 (window-buffer start-window)))
26d280b9 1299 ;; Single-press: cancel any preexisting secondary selection.
d89a4a47
RS
1300 (or mouse-secondary-start
1301 (setq mouse-secondary-start (make-marker)))
1302 (set-marker mouse-secondary-start start-point)
1303 (delete-overlay mouse-secondary-overlay))
1304 (let (event end end-point)
1305 (track-mouse
1306 (while (progn
1307 (setq event (read-event))
1308 (or (mouse-movement-p event)
fbd8dc8a 1309 (memq (car-safe event) '(switch-frame select-window))))
d89a4a47 1310
fbd8dc8a 1311 (if (memq (car-safe event) '(switch-frame select-window))
d89a4a47
RS
1312 nil
1313 (setq end (event-end event)
1314 end-point (posn-point end))
1315 (cond
d89a4a47
RS
1316 ;; Are we moving within the original window?
1317 ((and (eq (posn-window end) start-window)
1318 (integer-or-marker-p end-point))
d89a4a47
RS
1319 (let ((range (mouse-start-end start-point end-point
1320 click-count)))
0136e1e3
RS
1321 (if (or (/= start-point end-point)
1322 (null (marker-position mouse-secondary-start)))
1323 (progn
1324 (set-marker mouse-secondary-start nil)
1325 (move-overlay mouse-secondary-overlay
1326 (car range) (nth 1 range))))))
3b0aebe9
RS
1327 (t
1328 (let ((mouse-row (cdr (cdr (mouse-position)))))
1329 (cond
1330 ((null mouse-row))
1331 ((< mouse-row top)
e919a622
RS
1332 (mouse-scroll-subr start-window (- mouse-row top)
1333 mouse-secondary-overlay start-point))
d2287ded 1334 ((>= mouse-row bottom)
e919a622 1335 (mouse-scroll-subr start-window (1+ (- mouse-row bottom))
3b0aebe9 1336 mouse-secondary-overlay start-point)))))))))
d89a4a47 1337
4e399a53 1338 (if (consp event)
d89a4a47
RS
1339 (if (marker-position mouse-secondary-start)
1340 (save-window-excursion
1341 (delete-overlay mouse-secondary-overlay)
9a974c88 1342 (x-set-selection 'SECONDARY nil)
d89a4a47
RS
1343 (select-window start-window)
1344 (save-excursion
1345 (goto-char mouse-secondary-start)
efc10c97
RS
1346 (sit-for 1)
1347 nil))
9a974c88
RS
1348 (x-set-selection
1349 'SECONDARY
1350 (buffer-substring (overlay-start mouse-secondary-overlay)
1351 (overlay-end mouse-secondary-overlay)))))))))
e66feb07 1352
9a974c88 1353(defun mouse-yank-secondary (click)
50f58001
RS
1354 "Insert the secondary selection at the position clicked on.
1355Move point to the end of the inserted text.
1356If `mouse-yank-at-point' is non-nil, insert at point
1357regardless of where you click."
a4cabe41 1358 (interactive "e")
33c448cd
RS
1359 ;; Give temporary modes such as isearch a chance to turn off.
1360 (run-hooks 'mouse-leave-buffer-hook)
50f58001 1361 (or mouse-yank-at-point (mouse-set-point click))
b3709a53
RS
1362 (let ((secondary (x-get-selection 'SECONDARY)))
1363 (if secondary
aa2d4bd3 1364 (insert secondary)
b3709a53 1365 (error "No secondary selection"))))
9a974c88 1366
7e6404f6 1367(defun mouse-kill-secondary ()
9a974c88
RS
1368 "Kill the text in the secondary selection.
1369This is intended more as a keyboard command than as a mouse command
1370but it can work as either one.
1371
1372The current buffer (in case of keyboard use), or the buffer clicked on,
1373must be the one that the secondary selection is in. This requirement
1374is to prevent accidents."
7e6404f6
RS
1375 (interactive)
1376 (let* ((keys (this-command-keys))
1377 (click (elt keys (1- (length keys)))))
1378 (or (eq (overlay-buffer mouse-secondary-overlay)
1379 (if (listp click)
1380 (window-buffer (posn-window (event-start click)))
1381 (current-buffer)))
1382 (error "Select or click on the buffer where the secondary selection is")))
9dfab550 1383 (let (this-command)
aaf15b8b 1384 (with-current-buffer (overlay-buffer mouse-secondary-overlay)
9dfab550
RS
1385 (kill-region (overlay-start mouse-secondary-overlay)
1386 (overlay-end mouse-secondary-overlay))))
f9be2e35 1387 (delete-overlay mouse-secondary-overlay))
e66feb07
RS
1388
1389(defun mouse-secondary-save-then-kill (click)
d2625c3d
CY
1390 "Set the secondary selection and save it to the kill ring.
1391The second time, kill it. CLICK should be a mouse click event.
1392
1393If you have not called `mouse-start-secondary' in the clicked
1394buffer, activate the secondary selection and set it between point
1395and the click position CLICK.
1396
1397Otherwise, adjust the bounds of the secondary selection.
1398Normally, do this by moving its beginning or end, whichever is
1399closer, to CLICK. But if you have selected whole words or lines,
1400adjust to the word or line boundary closest to CLICK instead.
1401
1402If this command is called a second consecutive time with the same
1403CLICK position, kill the secondary selection."
e66feb07 1404 (interactive "e")
d65147f6 1405 (mouse-minibuffer-check click)
d2625c3d
CY
1406 (let* ((posn (event-start click))
1407 (click-pt (posn-point posn))
1408 (window (posn-window posn))
1409 (buf (window-buffer window))
1410 ;; Don't let a subsequent kill command append to this one.
1411 (this-command this-command)
1412 ;; Check if the user has multi-clicked to select words/lines.
1413 (click-count
1414 (if (eq (overlay-buffer mouse-secondary-overlay) buf)
1415 mouse-secondary-click-count
1416 0))
1417 (beg (overlay-start mouse-secondary-overlay))
1418 (end (overlay-end mouse-secondary-overlay)))
1419
1420 (cond
1421 ((not (numberp click-pt)) nil)
1422
1423 ;; If the secondary selection is not active in BUF, activate it.
1424 ((not (eq buf (or (overlay-buffer mouse-secondary-overlay)
1425 (if mouse-secondary-start
1426 (marker-buffer mouse-secondary-start)))))
1427 (select-window window)
1428 (setq mouse-secondary-start (make-marker))
1429 (move-marker mouse-secondary-start (point))
1430 (move-overlay mouse-secondary-overlay (point) click-pt buf)
1431 (kill-ring-save (point) click-pt))
1432
1433 ;; If the user clicked without moving point, delete the secondary
1434 ;; selection. This also resets `mouse-secondary-click-count'.
1435 ((and (eq last-command 'mouse-secondary-save-then-kill)
1436 (eq click-pt mouse-save-then-kill-posn)
1437 (eq window (selected-window)))
1438 (mouse-save-then-kill-delete-region beg end)
1439 (delete-overlay mouse-secondary-overlay)
1440 (setq mouse-secondary-click-count 0)
1441 (setq mouse-save-then-kill-posn nil))
1442
1443 ;; Otherwise, if there is a suitable secondary selection overlay,
1444 ;; adjust it by moving one end (whichever is closer) to CLICK-PT.
1445 ((and beg (eq buf (overlay-buffer mouse-secondary-overlay)))
1446 (let* ((range (mouse-start-end click-pt click-pt click-count)))
1447 (if (< (abs (- click-pt beg))
1448 (abs (- click-pt end)))
1449 (move-overlay mouse-secondary-overlay (car range) end)
1450 (move-overlay mouse-secondary-overlay beg (nth 1 range))))
1451 (setq deactivate-mark nil)
1452 (if (eq last-command 'mouse-secondary-save-then-kill)
1453 ;; If the front of the kill ring comes from an immediately
1454 ;; previous use of this command, replace the entry.
1455 (kill-new
1456 (buffer-substring (overlay-start mouse-secondary-overlay)
1457 (overlay-end mouse-secondary-overlay))
1458 t)
1459 (let (deactivate-mark)
1460 (copy-region-as-kill (overlay-start mouse-secondary-overlay)
1461 (overlay-end mouse-secondary-overlay))))
1462 (setq mouse-save-then-kill-posn click-pt))
1463
1464 ;; Otherwise, set the secondary selection overlay.
1465 (t
1466 (select-window window)
1467 (if mouse-secondary-start
1468 ;; All we have is one end of a selection, so put the other
1469 ;; end here.
1470 (let ((start (+ 0 mouse-secondary-start)))
1471 (kill-ring-save start click-pt)
1472 (move-overlay mouse-secondary-overlay start click-pt)))
1473 (setq mouse-save-then-kill-posn click-pt))))
1474
1475 ;; Finally, set the window system's secondary selection.
1476 (let (str)
1477 (and (overlay-buffer mouse-secondary-overlay)
1478 (setq str (buffer-substring (overlay-start mouse-secondary-overlay)
1479 (overlay-end mouse-secondary-overlay)))
1480 (> (length str) 0)
1481 (x-set-selection 'SECONDARY str))))
1482
e66feb07 1483\f
0d9be91c 1484(defcustom mouse-buffer-menu-maxlen 20
9201cc28 1485 "Number of buffers in one pane (submenu) of the buffer menu.
f1107960 1486If we have lots of buffers, divide them into groups of
0d9be91c 1487`mouse-buffer-menu-maxlen' and make a pane (or submenu) for each one."
3b558d41
RS
1488 :type 'integer
1489 :group 'mouse)
f1107960 1490
3ca87c7b 1491(defcustom mouse-buffer-menu-mode-mult 4
9201cc28 1492 "Group the buffers by the major mode groups on \\[mouse-buffer-menu]?
3ca87c7b
RS
1493This number which determines (in a hairy way) whether \\[mouse-buffer-menu]
1494will split the buffer menu by the major modes (see
1495`mouse-buffer-menu-mode-groups') or just by menu length.
1496Set to 1 (or even 0!) if you want to group by major mode always, and to
1497a large number if you prefer a mixed multitude. The default is 4."
1498 :type 'integer
1499 :group 'mouse
1500 :version "20.3")
1501
284a88a3 1502(defvar mouse-buffer-menu-mode-groups
e8e4d5c8 1503 (mapcar (lambda (arg) (cons (purecopy (car arg)) (purecopy (cdr arg))))
284a88a3
RS
1504 '(("Info\\|Help\\|Apropos\\|Man" . "Help")
1505 ("\\bVM\\b\\|\\bMH\\b\\|Message\\|Mail\\|Group\\|Score\\|Summary\\|Article"
1506 . "Mail/News")
1507 ("\\<C\\>" . "C")
1508 ("ObjC" . "C")
1509 ("Text" . "Text")
1510 ("Outline" . "Text")
c71a58a3 1511 ("\\(HT\\|SG\\|X\\|XHT\\)ML" . "SGML")
f399e4ad 1512 ("log\\|diff\\|vc\\|cvs\\|Annotate" . "Version Control") ; "Change Management"?
7bc61bb7
SS
1513 ("Threads\\|Memory\\|Disassembly\\|Breakpoints\\|Frames\\|Locals\\|Registers\\|Inferior I/O\\|Debugger"
1514 . "GDB")
a7610c52 1515 ("Lisp" . "Lisp")))
284a88a3
RS
1516 "How to group various major modes together in \\[mouse-buffer-menu].
1517Each element has the form (REGEXP . GROUPNAME).
1518If the major mode's name string matches REGEXP, use GROUPNAME instead.")
1519
8b34e79d 1520(defun mouse-buffer-menu (event)
2d82f7b9
RS
1521 "Pop up a menu of buffers for selection with the mouse.
1522This switches buffers in the window that you clicked on,
1523and selects that window."
ec558adc 1524 (interactive "e")
d65147f6 1525 (mouse-minibuffer-check event)
3ca87c7b 1526 (let ((buffers (buffer-list)) alist menu split-by-major-mode sum-of-squares)
284a88a3 1527 ;; Make an alist of elements that look like (MENU-ITEM . BUFFER).
cc2ee8ec
SS
1528 (dolist (buf buffers)
1529 ;; Divide all buffers into buckets for various major modes.
1530 ;; Each bucket looks like (MODE NAMESTRING BUFFERS...).
1531 (with-current-buffer buf
1532 (let* ((adjusted-major-mode major-mode) elt)
1533 (dolist (group mouse-buffer-menu-mode-groups)
1534 (when (string-match (car group) (format-mode-line mode-name))
1535 (setq adjusted-major-mode (cdr group))))
1536 (setq elt (assoc adjusted-major-mode split-by-major-mode))
1537 (unless elt
1538 (setq elt (list adjusted-major-mode
1539 (if (stringp adjusted-major-mode)
1540 adjusted-major-mode
48d33090 1541 (format-mode-line mode-name nil nil buf)))
cc2ee8ec
SS
1542 split-by-major-mode (cons elt split-by-major-mode)))
1543 (or (memq buf (cdr (cdr elt)))
1544 (setcdr (cdr elt) (cons buf (cdr (cdr elt))))))))
284a88a3
RS
1545 ;; Compute the sum of squares of sizes of the major-mode buckets.
1546 (let ((tail split-by-major-mode))
1547 (setq sum-of-squares 0)
1548 (while tail
1549 (setq sum-of-squares
1550 (+ sum-of-squares
3ca87c7b 1551 (let ((len (length (cdr (cdr (car tail)))))) (* len len))))
284a88a3 1552 (setq tail (cdr tail))))
3ca87c7b
RS
1553 (if (< (* sum-of-squares mouse-buffer-menu-mode-mult)
1554 (* (length buffers) (length buffers)))
284a88a3
RS
1555 ;; Subdividing by major modes really helps, so let's do it.
1556 (let (subdivided-menus (buffers-left (length buffers)))
1557 ;; Sort the list to put the most popular major modes first.
1558 (setq split-by-major-mode
1559 (sort split-by-major-mode
1560 (function (lambda (elt1 elt2)
1561 (> (length elt1) (length elt2))))))
1562 ;; Make a separate submenu for each major mode
1563 ;; that has more than one buffer,
1564 ;; unless all the remaining buffers are less than 1/10 of them.
1565 (while (and split-by-major-mode
1566 (and (> (length (car split-by-major-mode)) 3)
1567 (> (* buffers-left 10) (length buffers))))
4b4ea1dc
EZ
1568 (let ((this-mode-list (mouse-buffer-menu-alist
1569 (cdr (cdr (car split-by-major-mode))))))
1570 (and this-mode-list
1571 (setq subdivided-menus
1572 (cons (cons
1573 (nth 1 (car split-by-major-mode))
1574 this-mode-list)
1575 subdivided-menus))))
284a88a3
RS
1576 (setq buffers-left
1577 (- buffers-left (length (cdr (car split-by-major-mode)))))
1578 (setq split-by-major-mode (cdr split-by-major-mode)))
1579 ;; If any major modes are left over,
1580 ;; make a single submenu for them.
1581 (if split-by-major-mode
4b4ea1dc
EZ
1582 (let ((others-list
1583 (mouse-buffer-menu-alist
1584 ;; we don't need split-by-major-mode any more,
1585 ;; so we can ditch it with nconc.
1586 (apply 'nconc (mapcar 'cddr split-by-major-mode)))))
1587 (and others-list
1588 (setq subdivided-menus
1589 (cons (cons "Others" others-list)
1590 subdivided-menus)))))
3ca87c7b 1591 (setq menu (cons "Buffer Menu" (nreverse subdivided-menus))))
284a88a3
RS
1592 (progn
1593 (setq alist (mouse-buffer-menu-alist buffers))
1594 (setq menu (cons "Buffer Menu"
1595 (mouse-buffer-menu-split "Select Buffer" alist)))))
2d82f7b9
RS
1596 (let ((buf (x-popup-menu event menu))
1597 (window (posn-window (event-start event))))
3ca87c7b 1598 (when buf
f134ad18
RS
1599 (select-window
1600 (if (framep window) (frame-selected-window window)
1601 window))
3ca87c7b 1602 (switch-to-buffer buf)))))
284a88a3
RS
1603
1604(defun mouse-buffer-menu-alist (buffers)
1605 (let (tail
1606 (maxlen 0)
1607 head)
1608 (setq buffers
1609 (sort buffers
1610 (function (lambda (elt1 elt2)
1611 (string< (buffer-name elt1) (buffer-name elt2))))))
1612 (setq tail buffers)
1613 (while tail
fc2b429e 1614 (or (eq ?\s (aref (buffer-name (car tail)) 0))
284a88a3
RS
1615 (setq maxlen
1616 (max maxlen
1617 (length (buffer-name (car tail))))))
1618 (setq tail (cdr tail)))
1619 (setq tail buffers)
1620 (while tail
1621 (let ((elt (car tail)))
66564ab0 1622 (if (/= (aref (buffer-name elt) 0) ?\s)
284a88a3
RS
1623 (setq head
1624 (cons
1625 (cons
1626 (format
fc1f472b 1627 (format "%%-%ds %%s%%s %%s" maxlen)
284a88a3
RS
1628 (buffer-name elt)
1629 (if (buffer-modified-p elt) "*" " ")
7fdbcd83 1630 (with-current-buffer elt
284a88a3 1631 (if buffer-read-only "%" " "))
7b611de0 1632 (or (buffer-file-name elt)
7fdbcd83 1633 (with-current-buffer elt
284a88a3
RS
1634 (if list-buffers-directory
1635 (expand-file-name
1636 list-buffers-directory)))
1637 ""))
1638 elt)
1639 head))))
1640 (setq tail (cdr tail)))
1641 ;; Compensate for the reversal that the above loop does.
1642 (nreverse head)))
1643
1644(defun mouse-buffer-menu-split (title alist)
1645 ;; If we have lots of buffers, divide them into groups of 20
1646 ;; and make a pane (or submenu) for each one.
0d9be91c 1647 (if (> (length alist) (/ (* mouse-buffer-menu-maxlen 3) 2))
284a88a3
RS
1648 (let ((alist alist) sublists next
1649 (i 1))
1650 (while alist
0d9be91c 1651 ;; Pull off the next mouse-buffer-menu-maxlen buffers
284a88a3 1652 ;; and make them the next element of sublist.
0d9be91c 1653 (setq next (nthcdr mouse-buffer-menu-maxlen alist))
284a88a3 1654 (if next
0d9be91c 1655 (setcdr (nthcdr (1- mouse-buffer-menu-maxlen) alist)
284a88a3
RS
1656 nil))
1657 (setq sublists (cons (cons (format "Buffers %d" i) alist)
1658 sublists))
1659 (setq i (1+ i))
1660 (setq alist next))
1661 (nreverse sublists))
1662 ;; Few buffers--put them all in one pane.
1663 (list (cons title alist))))
72ea54a4 1664\f
d5e63715
SM
1665(define-obsolete-function-alias
1666 'mouse-choose-completion 'choose-completion "23.2")
f936ae06 1667
07a78410
RS
1668;; Font selection.
1669
0eb9fef3
RS
1670(defun font-menu-add-default ()
1671 (let* ((default (cdr (assq 'font (frame-parameters (selected-frame)))))
1672 (font-alist x-fixed-font-alist)
0d94f5ca 1673 (elt (or (assoc "Misc" font-alist) (nth 1 font-alist))))
0eb9fef3
RS
1674 (if (assoc "Default" elt)
1675 (delete (assoc "Default" elt) elt))
1676 (setcdr elt
6b8e486e 1677 (cons (list "Default" default)
0eb9fef3
RS
1678 (cdr elt)))))
1679
07a78410 1680(defvar x-fixed-font-alist
a7610c52
DN
1681 (list
1682 (purecopy "Font Menu")
1683 (cons
1684 (purecopy "Misc")
1685 (mapcar
1686 (lambda (arg) (cons (purecopy (car arg)) (purecopy (cdr arg))))
19d973e8 1687 ;; For these, we specify the pixel height and width.
a7610c52 1688 '(("fixed" "fixed")
19d973e8
RS
1689 ("6x10" "-misc-fixed-medium-r-normal--10-*-*-*-c-60-iso8859-1" "6x10")
1690 ("6x12"
1691 "-misc-fixed-medium-r-semicondensed--12-*-*-*-c-60-iso8859-1" "6x12")
1692 ("6x13"
1693 "-misc-fixed-medium-r-semicondensed--13-*-*-*-c-60-iso8859-1" "6x13")
1694 ("7x13" "-misc-fixed-medium-r-normal--13-*-*-*-c-70-iso8859-1" "7x13")
1695 ("7x14" "-misc-fixed-medium-r-normal--14-*-*-*-c-70-iso8859-1" "7x14")
1696 ("8x13" "-misc-fixed-medium-r-normal--13-*-*-*-c-80-iso8859-1" "8x13")
1697 ("9x15" "-misc-fixed-medium-r-normal--15-*-*-*-c-90-iso8859-1" "9x15")
1698 ("10x20" "-misc-fixed-medium-r-normal--20-*-*-*-c-100-iso8859-1" "10x20")
1699 ("11x18" "-misc-fixed-medium-r-normal--18-*-*-*-c-110-iso8859-1" "11x18")
1700 ("12x24" "-misc-fixed-medium-r-normal--24-*-*-*-c-120-iso8859-1" "12x24")
fa21fdec 1701 ("")
f29c3695
RS
1702 ("clean 5x8"
1703 "-schumacher-clean-medium-r-normal--8-*-*-*-c-50-iso8859-1")
1704 ("clean 6x8"
1705 "-schumacher-clean-medium-r-normal--8-*-*-*-c-60-iso8859-1")
19d973e8
RS
1706 ("clean 8x8"
1707 "-schumacher-clean-medium-r-normal--8-*-*-*-c-80-iso8859-1")
1708 ("clean 8x10"
1709 "-schumacher-clean-medium-r-normal--10-*-*-*-c-80-iso8859-1")
1710 ("clean 8x14"
1711 "-schumacher-clean-medium-r-normal--14-*-*-*-c-80-iso8859-1")
1712 ("clean 8x16"
1713 "-schumacher-clean-medium-r-normal--16-*-*-*-c-80-iso8859-1")
fa21fdec 1714 ("")
29a3028d 1715 ("sony 8x16" "-sony-fixed-medium-r-normal--16-*-*-*-c-80-iso8859-1")
ad0d18af
SM
1716 ;; We don't seem to have these; who knows what they are.
1717 ;; ("fg-18" "fg-18")
1718 ;; ("fg-25" "fg-25")
29a3028d
DL
1719 ("lucidasanstypewriter-12" "-b&h-lucidatypewriter-medium-r-normal-sans-*-120-*-*-*-*-iso8859-1")
1720 ("lucidasanstypewriter-bold-14" "-b&h-lucidatypewriter-bold-r-normal-sans-*-140-*-*-*-*-iso8859-1")
1721 ("lucidasanstypewriter-bold-24"
1722 "-b&h-lucidatypewriter-bold-r-normal-sans-*-240-*-*-*-*-iso8859-1")
ad0d18af
SM
1723 ;; ("lucidatypewriter-bold-r-24" "-b&h-lucidatypewriter-bold-r-normal-sans-24-240-75-75-m-140-iso8859-1")
1724 ;; ("fixed-medium-20" "-misc-fixed-medium-*-*-*-20-*-*-*-*-*-*-*")
a7610c52
DN
1725 )))
1726
1727 (cons
1728 (purecopy "Courier")
1729 (mapcar
1730 (lambda (arg) (cons (purecopy (car arg)) (purecopy (cdr arg))))
19d973e8 1731 ;; For these, we specify the point height.
a7610c52 1732 '(("8" "-adobe-courier-medium-r-normal--*-80-*-*-m-*-iso8859-1")
82c048a9
RS
1733 ("10" "-adobe-courier-medium-r-normal--*-100-*-*-m-*-iso8859-1")
1734 ("12" "-adobe-courier-medium-r-normal--*-120-*-*-m-*-iso8859-1")
1735 ("14" "-adobe-courier-medium-r-normal--*-140-*-*-m-*-iso8859-1")
1736 ("18" "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1")
1737 ("24" "-adobe-courier-medium-r-normal--*-240-*-*-m-*-iso8859-1")
1738 ("8 bold" "-adobe-courier-bold-r-normal--*-80-*-*-m-*-iso8859-1")
1739 ("10 bold" "-adobe-courier-bold-r-normal--*-100-*-*-m-*-iso8859-1")
1740 ("12 bold" "-adobe-courier-bold-r-normal--*-120-*-*-m-*-iso8859-1")
1741 ("14 bold" "-adobe-courier-bold-r-normal--*-140-*-*-m-*-iso8859-1")
1742 ("18 bold" "-adobe-courier-bold-r-normal--*-180-*-*-m-*-iso8859-1")
1743 ("24 bold" "-adobe-courier-bold-r-normal--*-240-*-*-m-*-iso8859-1")
1744 ("8 slant" "-adobe-courier-medium-o-normal--*-80-*-*-m-*-iso8859-1")
1745 ("10 slant" "-adobe-courier-medium-o-normal--*-100-*-*-m-*-iso8859-1")
1746 ("12 slant" "-adobe-courier-medium-o-normal--*-120-*-*-m-*-iso8859-1")
1747 ("14 slant" "-adobe-courier-medium-o-normal--*-140-*-*-m-*-iso8859-1")
1748 ("18 slant" "-adobe-courier-medium-o-normal--*-180-*-*-m-*-iso8859-1")
1749 ("24 slant" "-adobe-courier-medium-o-normal--*-240-*-*-m-*-iso8859-1")
1750 ("8 bold slant" "-adobe-courier-bold-o-normal--*-80-*-*-m-*-iso8859-1")
1751 ("10 bold slant" "-adobe-courier-bold-o-normal--*-100-*-*-m-*-iso8859-1")
1752 ("12 bold slant" "-adobe-courier-bold-o-normal--*-120-*-*-m-*-iso8859-1")
1753 ("14 bold slant" "-adobe-courier-bold-o-normal--*-140-*-*-m-*-iso8859-1")
1754 ("18 bold slant" "-adobe-courier-bold-o-normal--*-180-*-*-m-*-iso8859-1")
a7610c52
DN
1755 ("24 bold slant" "-adobe-courier-bold-o-normal--*-240-*-*-m-*-iso8859-1")
1756 ))))
07a78410
RS
1757 "X fonts suitable for use in Emacs.")
1758
aa360da1
GM
1759(declare-function generate-fontset-menu "fontset" ())
1760
ecb044e1
CY
1761(defun mouse-select-font ()
1762 "Prompt for a font name, using `x-popup-menu', and return it."
1763 (interactive)
1764 (unless (display-multi-font-p)
1765 (error "Cannot change fonts on this display"))
c1202d4b
CY
1766 (car
1767 (x-popup-menu
1768 (if (listp last-nonmenu-event)
1769 last-nonmenu-event
1770 (list '(0 0) (selected-window)))
1771 (append x-fixed-font-alist
1772 (list (generate-fontset-menu))))))
ecb044e1 1773
3db09e26
CY
1774(declare-function text-scale-mode "face-remap")
1775
1900a92b 1776(defun mouse-set-font (&rest fonts)
ecb044e1
CY
1777 "Set the default font for the selected frame.
1778The argument FONTS is a list of font names; the first valid font
1779in this list is used.
1780
1781When called interactively, pop up a menu and allow the user to
1782choose a font."
07a78410 1783 (interactive
8eb1dc02
RS
1784 (progn (unless (display-multi-font-p)
1785 (error "Cannot change fonts on this display"))
1786 (x-popup-menu
91c51412
LT
1787 (if (listp last-nonmenu-event)
1788 last-nonmenu-event
1789 (list '(0 0) (selected-window)))
8eb1dc02
RS
1790 ;; Append list of fontsets currently defined.
1791 (append x-fixed-font-alist (list (generate-fontset-menu))))))
df4de8c6
KH
1792 (if fonts
1793 (let (font)
1794 (while fonts
1795 (condition-case nil
1796 (progn
b7d1d101 1797 (set-frame-font (car fonts))
df4de8c6
KH
1798 (setq font (car fonts))
1799 (setq fonts nil))
3fadec1a
RS
1800 (error
1801 (setq fonts (cdr fonts)))))
df4de8c6 1802 (if (null font)
8eb1dc02 1803 (error "Font not found")))))
3db09e26
CY
1804
1805(defvar mouse-appearance-menu-map nil)
9c257005 1806(declare-function x-select-font "xfns.c" (&optional frame ignored)) ; USE_GTK
b816c5e3
GM
1807(declare-function buffer-face-mode-invoke "face-remap"
1808 (face arg &optional interactive))
f2d9c15f 1809(declare-function font-face-attributes "font.c" (font &optional frame))
3db09e26
CY
1810
1811(defun mouse-appearance-menu (event)
e8579ebc 1812 "Show a menu for changing the default face in the current buffer."
3db09e26
CY
1813 (interactive "@e")
1814 (require 'face-remap)
1815 (when (display-multi-font-p)
1816 (with-selected-window (car (event-start event))
1817 (if mouse-appearance-menu-map
1818 nil ; regenerate new fonts
1819 ;; Initialize mouse-appearance-menu-map
1820 (setq mouse-appearance-menu-map
1821 (make-sparse-keymap "Change Default Buffer Face"))
1822 (define-key mouse-appearance-menu-map [face-remap-reset-base]
1823 '(menu-item "Reset to Default" face-remap-reset-base))
1824 (define-key mouse-appearance-menu-map [text-scale-decrease]
1825 '(menu-item "Decrease Buffer Text Size" text-scale-decrease))
1826 (define-key mouse-appearance-menu-map [text-scale-increase]
1827 '(menu-item "Increase Buffer Text Size" text-scale-increase))
1828 ;; Font selector
1829 (if (functionp 'x-select-font)
1830 (define-key mouse-appearance-menu-map [x-select-font]
1831 '(menu-item "Change Buffer Font..." x-select-font))
1832 ;; If the select-font is unavailable, construct a menu.
1833 (let ((font-submenu (make-sparse-keymap "Change Text Font"))
1834 (font-alist (cdr (append x-fixed-font-alist
1835 (list (generate-fontset-menu))))))
1836 (dolist (family font-alist)
1837 (let* ((submenu-name (car family))
1838 (submenu-map (make-sparse-keymap submenu-name)))
1839 (dolist (font (cdr family))
1840 (let ((font-name (car font))
1841 font-symbol)
1842 (if (string= font-name "")
1843 (define-key submenu-map [space]
1844 '("--"))
1845 (setq font-symbol (intern (cadr font)))
1846 (define-key submenu-map (vector font-symbol)
1847 (list 'menu-item (car font) font-symbol)))))
1848 (define-key font-submenu (vector (intern submenu-name))
1849 (list 'menu-item submenu-name submenu-map))))
1850 (define-key mouse-appearance-menu-map [font-submenu]
1851 (list 'menu-item "Change Text Font" font-submenu)))))
1852 (let ((choice (x-popup-menu event mouse-appearance-menu-map)))
1853 (setq choice (nth (1- (length choice)) choice))
1854 (cond ((eq choice 'text-scale-increase)
1855 (text-scale-increase 1))
1856 ((eq choice 'text-scale-decrease)
1857 (text-scale-increase -1))
1858 ((eq choice 'face-remap-reset-base)
1859 (text-scale-mode 0)
4271b424 1860 (buffer-face-mode 0))
520713e7 1861 (choice
3db09e26
CY
1862 ;; Either choice == 'x-select-font, or choice is a
1863 ;; symbol whose name is a font.
383dcbf9
CY
1864 (let ((font (if (eq choice 'x-select-font)
1865 (x-select-font)
1866 (symbol-name choice))))
1867 (buffer-face-mode-invoke
1868 (if (fontp font 'font-spec)
1869 (list :font font)
1870 (font-face-attributes font))
1871 t (called-interactively-p 'interactive)))))))))
3db09e26 1872
cc0a8174
JB
1873\f
1874;;; Bindings for mouse commands.
1875
fbd5cc6c 1876(global-set-key [down-mouse-1] 'mouse-drag-region)
dbc4e1c1 1877(global-set-key [mouse-1] 'mouse-set-point)
dbc4e1c1 1878(global-set-key [drag-mouse-1] 'mouse-set-region)
fcfc3c63 1879
fe3f64d5
SM
1880(defun mouse--strip-first-event (_prompt)
1881 (substring (this-single-command-raw-keys) 1))
1882
1883(define-key function-key-map [left-fringe mouse-1] 'mouse--strip-first-event)
1884(define-key function-key-map [right-fringe mouse-1] 'mouse--strip-first-event)
76693d12 1885
f9d71b42 1886(global-set-key [mouse-2] 'mouse-yank-primary)
3e9323d6 1887;; Allow yanking also when the corresponding cursor is "in the fringe".
fe3f64d5
SM
1888(define-key function-key-map [right-fringe mouse-2] 'mouse--strip-first-event)
1889(define-key function-key-map [left-fringe mouse-2] 'mouse--strip-first-event)
dbc4e1c1 1890(global-set-key [mouse-3] 'mouse-save-then-kill)
fe3f64d5
SM
1891(define-key function-key-map [right-fringe mouse-3] 'mouse--strip-first-event)
1892(define-key function-key-map [left-fringe mouse-3] 'mouse--strip-first-event)
8b34e79d 1893
dbc4e1c1
JB
1894;; By binding these to down-going events, we let the user use the up-going
1895;; event to make the selection, saving a click.
08a1c178
RS
1896(global-set-key [C-down-mouse-1] 'mouse-buffer-menu)
1897(if (not (eq system-type 'ms-dos))
3db09e26 1898 (global-set-key [S-down-mouse-1] 'mouse-appearance-menu))
eef805d7 1899;; C-down-mouse-2 is bound in facemenu.el.
0b2b62ff 1900(global-set-key [C-down-mouse-3]
1e8780b1 1901 `(menu-item ,(purecopy "Menu Bar") ignore
0b2b62ff
SM
1902 :filter (lambda (_)
1903 (if (zerop (or (frame-parameter nil 'menu-bar-lines) 0))
1904 (mouse-menu-bar-map)
1905 (mouse-menu-major-mode-map)))))
95132d1c 1906
06a8c9f8
EZ
1907;; Binding mouse-1 to mouse-select-window when on mode-, header-, or
1908;; vertical-line prevents Emacs from signaling an error when the mouse
1909;; button is released after dragging these lines, on non-toolkit
1910;; versions.
3c2dd2c0 1911(global-set-key [mode-line mouse-1] 'mouse-select-window)
544e7e73
RS
1912(global-set-key [mode-line drag-mouse-1] 'mouse-select-window)
1913(global-set-key [mode-line down-mouse-1] 'mouse-drag-mode-line)
b0d22e20 1914(global-set-key [header-line down-mouse-1] 'mouse-drag-header-line)
06a8c9f8 1915(global-set-key [header-line mouse-1] 'mouse-select-window)
3c2dd2c0 1916(global-set-key [mode-line mouse-2] 'mouse-delete-other-windows)
dbc4e1c1 1917(global-set-key [mode-line mouse-3] 'mouse-delete-window)
3c2dd2c0 1918(global-set-key [mode-line C-mouse-2] 'mouse-split-window-horizontally)
9926ab64 1919(global-set-key [vertical-scroll-bar C-mouse-2] 'mouse-split-window-vertically)
b6522df6 1920(global-set-key [vertical-line C-mouse-2] 'mouse-split-window-vertically)
08a1c178 1921(global-set-key [vertical-line down-mouse-1] 'mouse-drag-vertical-line)
880e6158
MR
1922(global-set-key [right-divider down-mouse-1] 'mouse-drag-vertical-line)
1923(global-set-key [bottom-divider down-mouse-1] 'mouse-drag-mode-line)
08a1c178 1924(global-set-key [vertical-line mouse-1] 'mouse-select-window)
49116ac0
JB
1925
1926(provide 'mouse)
1927
6594deb0 1928;;; mouse.el ends here