*** empty log message ***
[bpt/emacs.git] / lisp / mouse.el
CommitLineData
6594deb0 1;;; mouse.el --- window system-independent mouse support.
84176303 2
eea8d4ef
ER
3;;; Copyright (C) 1988, 1992 Free Software Foundation, Inc.
4
84176303 5;; Maintainer: FSF
84176303
ER
6;; Keywords: hardware
7
cc0a8174 8;;; This file is part of GNU Emacs.
72ea54a4 9
cc0a8174
JB
10;;; GNU Emacs is free software; you can redistribute it and/or modify
11;;; it under the terms of the GNU General Public License as published by
87ef29fd 12;;; the Free Software Foundation; either version 2, or (at your option)
cc0a8174 13;;; any later version.
72ea54a4 14
cc0a8174
JB
15;;; GNU Emacs is distributed in the hope that it will be useful,
16;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;;; GNU General Public License for more details.
72ea54a4 19
cc0a8174
JB
20;;; You should have received a copy of the GNU General Public License
21;;; along with GNU Emacs; see the file COPYING. If not, write to
22;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
72ea54a4 23
72ea54a4 24\f
cc0a8174 25;;; Utility functions.
72ea54a4 26
cc0a8174
JB
27(defun mouse-movement-p (event)
28 (and (consp event)
29 (eq (car event) 'mouse-movement)))
72ea54a4 30
cc0a8174
JB
31(defun event-window (event) (nth 1 event))
32(defun event-point (event) (nth 2 event))
33(defun mouse-coords (event) (nth 3 event))
34(defun mouse-timestamp (event) (nth 4 event))
72ea54a4 35
cc0a8174
JB
36;;; Indent track-mouse like progn.
37(put 'track-mouse 'lisp-indent-function 0)
72ea54a4 38
cc0a8174
JB
39\f
40(defun mouse-delete-window (click)
41 "Delete the window clicked on.
42This must be bound to a mouse click."
43 (interactive "K")
44 (delete-window (event-window click)))
45
46(defun mouse-delete-other-windows (click)
47 "Select Emacs window clicked on, then kill all other Emacs windows.
48This must be bound to a mouse click."
49 (interactive "K")
50 (select-window (event-window click))
51 (delete-other-windows))
72ea54a4 52
cc0a8174
JB
53(defun mouse-split-window-vertically (click)
54 "Select Emacs window mouse is on, then split it vertically in half.
55The window is split at the line clicked on.
56This command must be bound to a mouse click."
57 (interactive "K")
58 (select-window (event-window click))
59 (split-window-vertically (1+ (cdr (mouse-coords click)))))
60
61(defun mouse-set-point (click)
62 "Move point to the position clicked on with the mouse.
63This must be bound to a mouse click."
64 (interactive "K")
65 (select-window (event-window click))
bd307392
JB
66 (if (numberp (event-point click))
67 (goto-char (event-point click))))
cc0a8174
JB
68
69(defun mouse-set-mark (click)
70 "Set mark at the position clicked on with the mouse.
71Display cursor at that position for a second.
72This must be bound to a mouse click."
73 (interactive "K")
72ea54a4
RS
74 (let ((point-save (point)))
75 (unwind-protect
cc0a8174 76 (progn (mouse-set-point click)
72ea54a4 77 (push-mark nil t)
fe79ff61 78 (sit-for 1))
72ea54a4
RS
79 (goto-char point-save))))
80
cc0a8174
JB
81(defun mouse-kill (click)
82 "Kill the region between point and the mouse click.
83The text is saved in the kill ring, as with \\[kill-region]."
84 (interactive "K")
7047ec77 85 (let ((click-posn (event-point click)))
bd307392
JB
86 (if (numberp click-posn)
87 (kill-region (min (point) click-posn)
88 (max (point) click-posn)))))
72ea54a4 89
87ef29fd
JB
90(defun mouse-yank-at-click (click arg)
91 "Insert the last stretch of killed text at the position clicked on.
92Prefix arguments are interpreted as with \\[yank]."
93 (interactive "K\nP")
94 (mouse-set-point click)
95 (yank arg))
96
97(defun mouse-kill-ring-save (click)
cc0a8174
JB
98 "Copy the region between point and the mouse click in the kill ring.
99This does not delete the region; it acts like \\[kill-ring-save]."
100 (interactive "K")
101 (mouse-set-mark click)
87ef29fd 102 (call-interactively 'kill-ring-save))
72ea54a4 103
8b34e79d
RS
104(defun mouse-buffer-menu (event)
105 "Pop up a menu of buffers for selection with the mouse."
106 (interactive "K")
107 (let ((menu
108 (list "Buffer Menu"
109 (cons "Select Buffer"
110 (let ((tail (buffer-list))
111 head)
112 (while tail
113 (let ((elt (car tail)))
114 (if (not (string-match "^ "
115 (buffer-name elt)))
116 (setq head (cons
117 (cons
118 (format
119 "%14s %s"
120 (buffer-name elt)
121 (or (buffer-file-name elt) ""))
122 elt)
123 head))))
124 (setq tail (cdr tail)))
125 (reverse head))))))
126 (switch-to-buffer (or (x-popup-menu event menu) (current-buffer)))))
72ea54a4
RS
127\f
128;; Commands for the scroll bar.
129
130(defun mouse-scroll-down (nlines)
131 (interactive "@p")
132 (scroll-down nlines))
133
134(defun mouse-scroll-up (nlines)
135 (interactive "@p")
136 (scroll-up nlines))
137
138(defun mouse-scroll-down-full ()
139 (interactive "@")
140 (scroll-down nil))
141
142(defun mouse-scroll-up-full ()
143 (interactive "@")
144 (scroll-up nil))
145
146(defun mouse-scroll-move-cursor (nlines)
147 (interactive "@p")
148 (move-to-window-line nlines))
149
150(defun mouse-scroll-absolute (event)
151 (interactive "@e")
152 (let* ((pos (car event))
153 (position (car pos))
154 (length (car (cdr pos))))
155 (if (<= length 0) (setq length 1))
156 (let* ((scale-factor (max 1 (/ length (/ 8000000 (buffer-size)))))
157 (newpos (* (/ (* (/ (buffer-size) scale-factor)
158 position)
159 length)
160 scale-factor)))
161 (goto-char newpos)
162 (recenter '(4)))))
163
164(defun mouse-scroll-left (ncolumns)
165 (interactive "@p")
166 (scroll-left ncolumns))
167
168(defun mouse-scroll-right (ncolumns)
169 (interactive "@p")
170 (scroll-right ncolumns))
171
172(defun mouse-scroll-left-full ()
173 (interactive "@")
174 (scroll-left nil))
175
176(defun mouse-scroll-right-full ()
177 (interactive "@")
178 (scroll-right nil))
179
180(defun mouse-scroll-move-cursor-horizontally (ncolumns)
181 (interactive "@p")
182 (move-to-column ncolumns))
183
184(defun mouse-scroll-absolute-horizontally (event)
185 (interactive "@e")
186 (let* ((pos (car event))
187 (position (car pos))
188 (length (car (cdr pos))))
189 (set-window-hscroll (selected-window) 33)))
190
6b2154de
RS
191(global-set-key [scroll-bar mouse-1] 'mouse-scroll-up)
192(global-set-key [scroll-bar mouse-2] 'mouse-scroll-absolute)
193(global-set-key [scroll-bar mouse-3] 'mouse-scroll-down)
194
195(global-set-key [vertical-slider mouse-1] 'mouse-scroll-move-cursor)
196(global-set-key [vertical-slider mouse-2] 'mouse-scroll-move-cursor)
197(global-set-key [vertical-slider mouse-3] 'mouse-scroll-move-cursor)
198
199(global-set-key [thumbup mouse-1] 'mouse-scroll-up-full)
200(global-set-key [thumbup mouse-2] 'mouse-scroll-up-full)
201(global-set-key [thumbup mouse-3] 'mouse-scroll-up-full)
202
203(global-set-key [thumbdown mouse-1] 'mouse-scroll-down-full)
204(global-set-key [thumbdown mouse-2] 'mouse-scroll-down-full)
205(global-set-key [thumbdown mouse-3] 'mouse-scroll-down-full)
206
207(global-set-key [horizontal-scroll-bar mouse-1] 'mouse-scroll-left)
208(global-set-key [horizontal-scroll-bar mouse-2]
209 'mouse-scroll-absolute-horizontally)
210(global-set-key [horizontal-scroll-bar mouse-3] 'mouse-scroll-right)
211
212(global-set-key [horizontal-slider mouse-1]
213 'mouse-scroll-move-cursor-horizontally)
214(global-set-key [horizontal-slider mouse-2]
215 'mouse-scroll-move-cursor-horizontally)
216(global-set-key [horizontal-slider mouse-3]
217 'mouse-scroll-move-cursor-horizontally)
218
219(global-set-key [thumbleft mouse-1] 'mouse-scroll-left-full)
220(global-set-key [thumbleft mouse-2] 'mouse-scroll-left-full)
221(global-set-key [thumbleft mouse-3] 'mouse-scroll-left-full)
222
223(global-set-key [thumbright mouse-1] 'mouse-scroll-right-full)
224(global-set-key [thumbright mouse-2] 'mouse-scroll-right-full)
225(global-set-key [thumbright mouse-3] 'mouse-scroll-right-full)
226\f
84545e78
JB
227;;;;
228;;;; Here are experimental things being tested. Mouse events
229;;;; are of the form:
230;;;; ((x y) window screen-part key-sequence timestamp)
72ea54a4 231;;
84545e78
JB
232;;;;
233;;;; Dynamically track mouse coordinates
234;;;;
72ea54a4 235;;
84545e78
JB
236;;(defun track-mouse (event)
237;; "Track the coordinates, absolute and relative, of the mouse."
238;; (interactive "@e")
239;; (while mouse-grabbed
240;; (let* ((pos (read-mouse-position (selected-screen)))
241;; (abs-x (car pos))
242;; (abs-y (cdr pos))
243;; (relative-coordinate (coordinates-in-window-p
244;; (list (car pos) (cdr pos))
245;; (selected-window))))
246;; (if (consp relative-coordinate)
247;; (message "mouse: [%d %d], (%d %d)" abs-x abs-y
248;; (car relative-coordinate)
249;; (car (cdr relative-coordinate)))
250;; (message "mouse: [%d %d]" abs-x abs-y)))))
72ea54a4
RS
251
252;;
253;; Dynamically put a box around the line indicated by point
254;;
7047ec77
JB
255;;
256;;(require 'backquote)
257;;
258;;(defun mouse-select-buffer-line (event)
259;; (interactive "@e")
260;; (let ((relative-coordinate
261;; (coordinates-in-window-p (car event) (selected-window)))
262;; (abs-y (car (cdr (car event)))))
263;; (if (consp relative-coordinate)
264;; (progn
265;; (save-excursion
266;; (move-to-window-line (car (cdr relative-coordinate)))
267;; (x-draw-rectangle
268;; (selected-screen)
269;; abs-y 0
270;; (save-excursion
271;; (move-to-window-line (car (cdr relative-coordinate)))
272;; (end-of-line)
273;; (push-mark nil t)
274;; (beginning-of-line)
275;; (- (region-end) (region-beginning))) 1))
276;; (sit-for 1)
277;; (x-erase-rectangle (selected-screen))))))
278;;
279;;(defvar last-line-drawn nil)
280;;(defvar begin-delim "[^ \t]")
281;;(defvar end-delim "[^ \t]")
282;;
283;;(defun mouse-boxing (event)
284;; (interactive "@e")
285;; (save-excursion
286;; (let ((screen (selected-screen)))
287;; (while (= (x-mouse-events) 0)
288;; (let* ((pos (read-mouse-position screen))
289;; (abs-x (car pos))
290;; (abs-y (cdr pos))
291;; (relative-coordinate
292;; (coordinates-in-window-p (` ((, abs-x) (, abs-y)))
293;; (selected-window)))
294;; (begin-reg nil)
295;; (end-reg nil)
296;; (end-column nil)
297;; (begin-column nil))
298;; (if (and (consp relative-coordinate)
299;; (or (not last-line-drawn)
300;; (not (= last-line-drawn abs-y))))
301;; (progn
302;; (move-to-window-line (car (cdr relative-coordinate)))
303;; (if (= (following-char) 10)
304;; ()
305;; (progn
306;; (setq begin-reg (1- (re-search-forward end-delim)))
307;; (setq begin-column (1- (current-column)))
308;; (end-of-line)
309;; (setq end-reg (1+ (re-search-backward begin-delim)))
310;; (setq end-column (1+ (current-column)))
311;; (message "%s" (buffer-substring begin-reg end-reg))
312;; (x-draw-rectangle screen
313;; (setq last-line-drawn abs-y)
314;; begin-column
315;; (- end-column begin-column) 1))))))))))
316;;
317;;(defun mouse-erase-box ()
318;; (interactive)
319;; (if last-line-drawn
320;; (progn
321;; (x-erase-rectangle (selected-screen))
322;; (setq last-line-drawn nil))))
72ea54a4 323
cc0a8174
JB
324;;; (defun test-x-rectangle ()
325;;; (use-local-mouse-map (setq rectangle-test-map (make-sparse-keymap)))
326;;; (define-key rectangle-test-map mouse-motion-button-left 'mouse-boxing)
327;;; (define-key rectangle-test-map mouse-button-left-up 'mouse-erase-box))
72ea54a4
RS
328
329;;
330;; Here is how to do double clicking in lisp. About to change.
331;;
332
333(defvar double-start nil)
334(defconst double-click-interval 300
335 "Max ticks between clicks")
336
337(defun double-down (event)
338 (interactive "@e")
339 (if double-start
340 (let ((interval (- (nth 4 event) double-start)))
341 (if (< interval double-click-interval)
342 (progn
343 (backward-up-list 1)
344 ;; (message "Interval %d" interval)
345 (sleep-for 1)))
346 (setq double-start nil))
347 (setq double-start (nth 4 event))))
348
349(defun double-up (event)
350 (interactive "@e")
351 (and double-start
352 (> (- (nth 4 event ) double-start) double-click-interval)
353 (setq double-start nil)))
354
cc0a8174
JB
355;;; (defun x-test-doubleclick ()
356;;; (use-local-mouse-map (setq doubleclick-test-map (make-sparse-keymap)))
357;;; (define-key doubleclick-test-map mouse-button-left 'double-down)
358;;; (define-key doubleclick-test-map mouse-button-left-up 'double-up))
72ea54a4
RS
359
360;;
361;; This scrolls while button is depressed. Use preferable in scrollbar.
362;;
363
364(defvar scrolled-lines 0)
365(defconst scroll-speed 1)
366
367(defun incr-scroll-down (event)
368 (interactive "@e")
369 (setq scrolled-lines 0)
370 (incremental-scroll scroll-speed))
371
372(defun incr-scroll-up (event)
373 (interactive "@e")
374 (setq scrolled-lines 0)
375 (incremental-scroll (- scroll-speed)))
376
377(defun incremental-scroll (n)
378 (while (= (x-mouse-events) 0)
379 (setq scrolled-lines (1+ (* scroll-speed scrolled-lines)))
380 (scroll-down n)
381 (sit-for 300 t)))
382
383(defun incr-scroll-stop (event)
384 (interactive "@e")
385 (message "Scrolled %d lines" scrolled-lines)
386 (setq scrolled-lines 0)
387 (sleep-for 1))
388
cc0a8174
JB
389;;; (defun x-testing-scroll ()
390;;; (let ((scrolling-map (function mouse-vertical-scroll-bar-prefix)))
391;;; (define-key scrolling-map mouse-button-left 'incr-scroll-down)
392;;; (define-key scrolling-map mouse-button-right 'incr-scroll-up)
393;;; (define-key scrolling-map mouse-button-left-up 'incr-scroll-stop)
394;;; (define-key scrolling-map mouse-button-right-up 'incr-scroll-stop)))
72ea54a4
RS
395
396;;
397;; Some playthings suitable for picture mode? They need work.
398;;
399
400(defun mouse-kill-rectangle (event)
401 "Kill the rectangle between point and the mouse cursor."
402 (interactive "@e")
403 (let ((point-save (point)))
404 (save-excursion
405 (mouse-set-point event)
406 (push-mark nil t)
407 (if (> point-save (point))
408 (kill-rectangle (point) point-save)
409 (kill-rectangle point-save (point))))))
410
411(defun mouse-open-rectangle (event)
412 "Kill the rectangle between point and the mouse cursor."
413 (interactive "@e")
414 (let ((point-save (point)))
415 (save-excursion
416 (mouse-set-point event)
417 (push-mark nil t)
418 (if (> point-save (point))
419 (open-rectangle (point) point-save)
420 (open-rectangle point-save (point))))))
421
422;; Must be a better way to do this.
423
424(defun mouse-multiple-insert (n char)
425 (while (> n 0)
426 (insert char)
427 (setq n (1- n))))
428
429;; What this could do is not finalize until button was released.
430
431(defun mouse-move-text (event)
432 "Move text from point to cursor position, inserting spaces."
433 (interactive "@e")
434 (let* ((relative-coordinate
435 (coordinates-in-window-p (car event) (selected-window))))
436 (if (consp relative-coordinate)
437 (cond ((> (current-column) (car relative-coordinate))
438 (delete-char
439 (- (car relative-coordinate) (current-column))))
440 ((< (current-column) (car relative-coordinate))
441 (mouse-multiple-insert
442 (- (car relative-coordinate) (current-column)) " "))
443 ((= (current-column) (car relative-coordinate)) (ding))))))
cc0a8174
JB
444
445\f
446;;; Bindings for mouse commands.
447
6b2154de 448;; This won't be needed once the drag and down events
6e3ccc70
RS
449;; are properly implemented.
450(global-set-key [mouse-1] 'mouse-set-point)
451
8b34e79d
RS
452(global-set-key [down-mouse-1] 'mouse-set-point)
453(global-set-key [drag-mouse-1] 'mouse-set-mark)
87ef29fd
JB
454(global-set-key [mouse-2] 'mouse-yank-at-click)
455(global-set-key [mouse-3] 'mouse-kill-ring-save)
8b34e79d 456(global-set-key [S-mouse-3] 'mouse-kill)
87ef29fd 457
8b34e79d
RS
458(global-set-key [C-mouse-1] 'mouse-buffer-menu)
459
460;; Replaced with dragging mouse-1
461;; (global-set-key [S-mouse-1] 'mouse-set-mark)
462\f
6b2154de
RS
463;; Define the mouse help menu tree.
464
8b34e79d
RS
465(defvar help-menu-map '(keymap "Help"))
466(global-set-key [C-mouse-2] help-menu-map)
467
468(defvar help-apropos-map '(keymap "Is there a command that..."))
469(defvar help-keys-map '(keymap "Key Commands <==> Functions"))
470(defvar help-manual-map '(keymap "Manual and tutorial"))
471(defvar help-misc-map '(keymap "Odds and ends"))
472(defvar help-modes-map '(keymap "Modes"))
473(defvar help-admin-map '(keymap "Administrivia"))
474
e7691e9c 475(define-key help-menu-map [apropos]
6ec3899e 476 (cons "@Is there a command that..." help-apropos-map))
e7691e9c 477(define-key help-menu-map [keys]
6ec3899e 478 (cons "@Key Commands <==> Functions" help-keys-map))
e7691e9c 479(define-key help-menu-map [manuals]
6ec3899e 480 (cons "@Manual and tutorial" help-manual-map))
e7691e9c 481(define-key help-menu-map [misc]
6ec3899e 482 (cons "@Odds and ends" help-misc-map))
e7691e9c 483(define-key help-menu-map [modes]
6ec3899e 484 (cons "@Modes" help-modes-map))
e7691e9c 485(define-key help-menu-map [admin]
6ec3899e 486 (cons "@Administrivia" help-admin-map))
8b34e79d
RS
487
488(define-key help-apropos-map "c" '("Command Apropos" . command-apropos))
489(define-key help-apropos-map "a" '("Apropos" . apropos))
490
491(define-key help-keys-map "b"
492 '("List all keystroke commands" . describe-bindings))
493(define-key help-keys-map "c"
494 '("Describe key briefly" . describe-key-briefly))
495(define-key help-keys-map "k"
496 '("Describe key verbose" . describe-key))
497(define-key help-keys-map "f"
498 '("Describe Lisp function" . describe-function))
499(define-key help-keys-map "w"
500 '("Where is this command" . where-is))
501
502(define-key help-manual-map "i" '("Info system" . info))
503(define-key help-manual-map "t"
504 '("Invoke Emacs tutorial" . help-with-tutorial))
505
506(define-key help-misc-map "l" '("Last 100 Keystrokes" . view-lossage))
507(define-key help-misc-map "s" '("Describe syntax table" . describe-syntax))
508
509(define-key help-modes-map "m"
510 '("Describe current major mode" . describe-mode))
511(define-key help-modes-map "b"
512 '("List all keystroke commands" . describe-bindings))
513
514(define-key help-admin-map "n"
515 '("view Emacs news" . view-emacs-news))
516(define-key help-admin-map "l"
517 '("View the GNU Emacs license" . describe-copying))
518(define-key help-admin-map "d"
519 '("Describe distribution" . describe-distribution))
520(define-key help-admin-map "w"
521 '("Describe (non)warranty" . describe-no-warranty))
49116ac0
JB
522
523(provide 'mouse)
524
6594deb0 525;;; mouse.el ends here