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