comparison lisp/mouse-sel.el @ 11490:01f5b6e9c234

Downcase function parameters. Doc fixes. Rewrite to support secondary selection. (mouse-sel-maintainer-address): New constant. (mouse-sel-submit-bug-report): New function. Rename mouse-sel-selection-type to mouse-sel-primary-thing. (mouse-sel-secondary-thing): New variable. (mouse-sel-selection-alist): New constant. (mouse-sel-set-selection-function): Semantics changed. Value should now be a function taking two arguments. (mouse-sel-get-selection-function): Semantics changed. Value should now be a function taking one argument. (mouse-sel-selection-owner-p-function): New variable. Removed variable mouse-sel-check-selection-function. Rename mouse-sel-determine-selection-type to mouse-sel-determine-selection-thing. (mouse-sel-set-selection): New function. (mouse-sel-get-selection): New function. (mouse-sel-selection-owner-p): New function. (mouse-sel-selection-overlay): New function. (mouse-sel-selection-thing): New function. (mouse-sel-region-to-primary): New function. (mouse-sel-primary-to-region): New function. (mouse-sel-eval-at-event-end): New macro. (mouse-sel-determine-selection-thing): Quad-click selects paragraphs. Removed variable mouse-sel-retain-highlight; use inverse of transient-mark-mode instead. (mouse-select-internal): New function. (mouse-select): Re-written using mouse-select-internal and mouse-sel-primary-to-region. (mouse-select-secondary): New function. (mouse-extend-internal): New function. (mouse-extend): Re-written using mouse-extend-internal, mouse-sel-region-to-primary and mouse-sel-primary-to-region. (mouse-extend-secondary): New function. (mouse-insert-selection-internal): New function. (mouse-insert-selection): Re-written using mouse-insert-selection-internal. (mouse-insert-secondary): New function. (mouse-sel-validate-selection): Check all selections in mouse-sel-selection-alist.
author Richard M. Stallman <rms@gnu.org>
date Wed, 19 Apr 1995 04:35:22 +0000
parents 3181c9270f40
children efb59db39da7
comparison
equal deleted inserted replaced
11489:cfb899623032 11490:01f5b6e9c234
1 ;;; mouse-sel.el --- Multi-click selection support for Emacs 19 1 ;;; mouse-sel.el --- Multi-click selection support for Emacs 19
2 2
3 ;; Copyright (C) 1993, 1994 Free Software Foundation, Inc. 3 ;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
4 4
5 ;; Author: Mike Williams <mikew@gopher.dosli.govt.nz> 5 ;; Author: Mike Williams <mikew@gopher.dosli.govt.nz>
6 ;; Keywords: mouse 6 ;; Keywords: mouse
7 ;; Version: 2.1
8 7
9 ;; This file is part of GNU Emacs. 8 ;; This file is part of GNU Emacs.
10 9
11 ;; GNU Emacs is free software; you can redistribute it and/or modify 10 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by 11 ;; it under the terms of the GNU General Public License as published by
32 ;; * Double-clicking on word constituents selects words. 31 ;; * Double-clicking on word constituents selects words.
33 ;; Double-clicking on symbol constituents selects symbols. 32 ;; Double-clicking on symbol constituents selects symbols.
34 ;; Double-clicking on quotes or parentheses selects sexps. 33 ;; Double-clicking on quotes or parentheses selects sexps.
35 ;; Double-clicking on whitespace selects whitespace. 34 ;; Double-clicking on whitespace selects whitespace.
36 ;; Triple-clicking selects lines. 35 ;; Triple-clicking selects lines.
36 ;; Quad-clicking selects paragraphs.
37 ;; 37 ;;
38 ;; * Selecting sets the region & X primary selection, but does NOT affect 38 ;; * Selecting sets the region & X primary selection, but does NOT affect
39 ;; the kill-ring. Because the mouse handlers set the primary selection 39 ;; the kill-ring. Because the mouse handlers set the primary selection
40 ;; directly, mouse-sel sets the variables interprogram-cut-function 40 ;; directly, mouse-sel sets the variables interprogram-cut-function
41 ;; and interprogram-paste-function to nil. 41 ;; and interprogram-paste-function to nil.
42 ;; 42 ;;
43 ;; * Clicking mouse-2 pastes contents of primary selection at the mouse 43 ;; * Clicking mouse-2 inserts the contents of the primary selection at
44 ;; position. 44 ;; the mouse position (or point, if mouse-yank-at-point is non-nil).
45 ;; 45 ;;
46 ;; * Pressing mouse-2 while selecting or extending copies selection 46 ;; * Pressing mouse-2 while selecting or extending copies selection
47 ;; to the kill ring. Pressing mouse-1 or mouse-3 kills it. 47 ;; to the kill ring. Pressing mouse-1 or mouse-3 kills it.
48 ;; 48 ;;
49 ;; * Double-clicking mouse-3 also kills selection. 49 ;; * Double-clicking mouse-3 also kills selection.
50 ;;
51 ;; * M-mouse-1, M-mouse-2 & M-mouse-3 work similarly to mouse-1, mouse-2
52 ;; & mouse-3, but operate on the X secondary selection rather than the
53 ;; primary selection and region.
50 ;; 54 ;;
51 ;; This module requires my thingatpt.el module, which it uses to find the 55 ;; This module requires my thingatpt.el module, which it uses to find the
52 ;; bounds of words, lines, sexps, etc. 56 ;; bounds of words, lines, sexps, etc.
53 ;; 57 ;;
54 ;; Thanks to KevinB@bartley.demon.co.uk for his useful input. 58 ;; Thanks to KevinB@bartley.demon.co.uk for his useful input.
69 ;; * You can control the way mouse-sel binds its keys by setting the value 73 ;; * You can control the way mouse-sel binds its keys by setting the value
70 ;; of mouse-sel-default-bindings before loading mouse-sel. 74 ;; of mouse-sel-default-bindings before loading mouse-sel.
71 ;; 75 ;;
72 ;; (a) If mouse-sel-default-bindings = t (the default) 76 ;; (a) If mouse-sel-default-bindings = t (the default)
73 ;; 77 ;;
74 ;; Mouse sets and pastes selection 78 ;; Mouse sets and insert selection
75 ;; mouse-1 mouse-select 79 ;; mouse-1 mouse-select
76 ;; mouse-2 mouse-insert-selection 80 ;; mouse-2 mouse-insert-selection
77 ;; mouse-3 mouse-extend 81 ;; mouse-3 mouse-extend
78 ;; 82 ;;
79 ;; Selection/kill-ring interaction is disabled 83 ;; Selection/kill-ring interaction is disabled
80 ;; interprogram-cut-function = nil 84 ;; interprogram-cut-function = nil
81 ;; interprogram-paste-function = nil 85 ;; interprogram-paste-function = nil
82 ;; 86 ;;
83 ;; (b) If mouse-sel-default-bindings = 'interprogram-cut-paste 87 ;; (b) If mouse-sel-default-bindings = 'interprogram-cut-paste
84 ;; 88 ;;
85 ;; Mouse sets selection, and pastes from kill-ring 89 ;; Mouse sets selection, and pastes from kill-ring
86 ;; mouse-1 mouse-select 90 ;; mouse-1 mouse-select
87 ;; mouse-2 mouse-yank-at-click 91 ;; mouse-2 mouse-yank-at-click
88 ;; mouse-3 mouse-extend 92 ;; mouse-3 mouse-extend
89 ;; 93 ;;
90 ;; Selection/kill-ring interaction is retained 94 ;; Selection/kill-ring interaction is retained
91 ;; interprogram-cut-function = x-select-text 95 ;; interprogram-cut-function = x-select-text
92 ;; interprogram-paste-function = x-cut-buffer-or-selection-value 96 ;; interprogram-paste-function = x-cut-buffer-or-selection-value
93 ;; 97 ;;
106 ;; cursor makes it look like one extra character is selected). You can 110 ;; cursor makes it look like one extra character is selected). You can
107 ;; disable this behaviour with: 111 ;; disable this behaviour with:
108 ;; 112 ;;
109 ;; (setq mouse-sel-leave-point-near-mouse nil) 113 ;; (setq mouse-sel-leave-point-near-mouse nil)
110 ;; 114 ;;
111 ;; * Normally, the selection highlight will be removed when the mouse is 115 ;; * By default, mouse-select cycles the click count after 4 clicks. That
112 ;; lifted. You can tell mouse-sel to retain the selection highlight 116 ;; is, clicking mouse-1 five times has the same effect as clicking it
113 ;; (useful if you don't use transient-mark-mode) with: 117 ;; once, clicking six times has the same effect as clicking twice, etc.
114 ;;
115 ;; (setq mouse-sel-retain-highlight t)
116 ;;
117 ;; * By default, mouse-select cycles the click count after 3 clicks. That
118 ;; is, clicking mouse-1 four times has the same effect as clicking it
119 ;; once, clicking five times has the same effect as clicking twice, etc.
120 ;; Disable this behaviour with: 118 ;; Disable this behaviour with:
121 ;; 119 ;;
122 ;; (setq mouse-sel-cycle-clicks nil) 120 ;; (setq mouse-sel-cycle-clicks nil)
123 ;; 121 ;;
124 ;; * The variables mouse-sel-{set,get,check}-selection-function control how 122 ;; * The variables mouse-sel-{set,get}-selection-function control how the
125 ;; the selection is handled. Under X Windows, these variables default so 123 ;; selection is handled. Under X Windows, these variables default so
126 ;; that the X primary selection is used. Under other windowing systems, 124 ;; that the X primary selection is used. Under other windowing systems,
127 ;; alternate functions are used, which simply store the selection value 125 ;; alternate functions are used, which simply store the selection value
128 ;; in a variable. 126 ;; in a variable.
129 ;; 127 ;;
130 ;;--- Hints ---------------------------------------------------------------
131 ;;
132 ;; * You can change the selection highlight face by altering the properties 128 ;; * You can change the selection highlight face by altering the properties
133 ;; of mouse-drag-overlay, eg. 129 ;; of mouse-drag-overlay, eg.
134 ;; 130 ;;
135 ;; (overlay-put mouse-drag-overlay 'face 'bold) 131 ;; (overlay-put mouse-drag-overlay 'face 'bold)
136 ;;
137 ;; * Pasting from the primary selection under emacs 19.19 is SLOW (there's
138 ;; a two second delay). The following code will cause mouse-sel to use
139 ;; the cut buffer rather than the primary selection. However, be aware
140 ;; that cut buffers are OBSOLETE, and some X applications may not support
141 ;; them.
142 ;;
143 ;; (setq mouse-sel-set-selection-function 'x-select-text
144 ;; mouse-sel-get-selection-function 'x-get-cut-buffer)
145 ;;
146 ;;--- Warnings ------------------------------------------------------------
147 ;;
148 ;; * When selecting sexps, the selection extends by sexps at the same
149 ;; nesting level. This also means the selection cannot be extended out
150 ;; of the enclosing nesting level. This is INTENTIONAL.
151 132
152 ;;; Code: ================================================================= 133 ;;; Code: =================================================================
153 134
154 (provide 'mouse-sel) 135 (provide 'mouse-sel)
155 136
156 (require 'mouse) 137 (require 'mouse)
157 (require 'thingatpt) 138 (require 'thingatpt)
158 139 (require 'backquote)
159 ;;=== Version =============================================================
160
161 (defconst mouse-sel-version "2.1"
162 "The version number of mouse-sel (as string).")
163 140
164 ;;=== User Variables ====================================================== 141 ;;=== User Variables ======================================================
165 142
166 (defvar mouse-sel-leave-point-near-mouse t 143 (defvar mouse-sel-leave-point-near-mouse t
167 "*Leave point near last mouse position. 144 "*Leave point near last mouse position.
168 If non-nil, \\[mouse-select] and \\[mouse-extend] leave point at the end 145 If non-nil, \\[mouse-select] and \\[mouse-extend] will leave point at the end
169 of the region nearest to where the mouse last was. 146 of the region nearest to where the mouse last was.
170 If nil, point is always placed at the beginning of the region.") 147 If nil, point will always be placed at the beginning of the region.")
171
172 (defvar mouse-sel-retain-highlight nil
173 "*Retain highlight after dragging is finished.
174 If non-nil, regions selected using \\[mouse-select] and \\[mouse-extend] will
175 remain highlighted.
176 If nil, highlighting turns off when you release the mouse button.")
177 148
178 (defvar mouse-sel-cycle-clicks t 149 (defvar mouse-sel-cycle-clicks t
179 "*If non-nil, \\[mouse-select] cycles the click-counts after 3 clicks. 150 "*If non-nil, \\[mouse-select] cycles the click-counts after 4 clicks.")
180 Ie. 4 clicks = 1 click, 5 clicks = 2 clicks, etc.")
181 151
182 (defvar mouse-sel-default-bindings t 152 (defvar mouse-sel-default-bindings t
183 "Set to nil before loading `mouse-sel' to prevent default mouse bindings.") 153 "Set to nil before loading `mouse-sel' to prevent default mouse bindings.")
184 154
185 ;;=== Selection =========================================================== 155 ;;=== Internal Variables/Constants ========================================
186 156
187 (defvar mouse-sel-selection-type nil "Type of current selection") 157 (defvar mouse-sel-primary-thing nil
188 (make-variable-buffer-local 'mouse-sel-selection-type) 158 "Type of PRIMARY selection in current buffer.")
189 159 (make-variable-buffer-local 'mouse-sel-primary-thing)
190 (defvar mouse-sel-selection "" 160
191 "Store the selection value when using a window systems other than X.") 161 (defvar mouse-sel-secondary-thing nil
192 162 "Type of SECONDARY selection in current buffer.")
163 (make-variable-buffer-local 'mouse-sel-secondary-thing)
164
165 ;; Ensure that secondary overlay is defined
166 (if (overlayp mouse-secondary-overlay) nil
167 (setq mouse-secondary-overlay (make-overlay 1 1))
168 (overlay-put mouse-secondary-overlay 'face 'secondary-selection))
169
170 (defconst mouse-sel-selection-alist
171 '((PRIMARY mouse-drag-overlay mouse-sel-primary-thing)
172 (SECONDARY mouse-secondary-overlay mouse-sel-secondary-thing))
173 "Alist associating selections with variables. Each element is of
174 the form:
175
176 (SELECTION-NAME OVERLAY-SYMBOL SELECTION-THING-SYMBOL)
177
178 where SELECTION-NAME = name of selection
179 OVERLAY-SYMBOL = name of variable containing overlay to use
180 SELECTION-THING-SYMBOL = name of variable where the current selection
181 type for this selection should be stored.")
182
193 (defvar mouse-sel-set-selection-function 183 (defvar mouse-sel-set-selection-function
194 (if (fboundp 'x-set-selection) 184 (if (fboundp 'x-set-selection)
195 (function (lambda (s) (x-set-selection 'PRIMARY s))) 185 'x-set-selection)
196 (function (lambda (s) (setq mouse-sel-selection s))))
197 "Function to call to set selection. 186 "Function to call to set selection.
198 Called with one argument, the text to select.") 187 Called with two arguments:
188
189 SELECTION, the name of the selection concerned, and
190 VALUE, the text to store.")
199 191
200 (defvar mouse-sel-get-selection-function 192 (defvar mouse-sel-get-selection-function
201 (if (fboundp 'x-get-selection) 193 (if (fboundp 'x-get-selection)
202 'x-get-selection 194 'x-get-selection)
203 (function (lambda () mouse-sel-selection)))
204 "Function to call to get the selection. 195 "Function to call to get the selection.
205 Called with no argument.") 196 Called with one argument:
206 197
207 (defvar mouse-sel-check-selection-function 198 SELECTION: the name of the selection concerned.")
199
200 (defvar mouse-sel-selection-owner-p-function
208 (if (fboundp 'x-selection-owner-p) 201 (if (fboundp 'x-selection-owner-p)
209 'x-selection-owner-p 202 'x-selection-owner-p)
210 nil)
211 "Function to check whether Emacs still owns the selection. 203 "Function to check whether Emacs still owns the selection.
212 Called with no arguments.") 204 Called with one argument:
213 205
214 (defun mouse-sel-determine-selection-type (NCLICKS) 206 SELECTION: the name of the selection concerned.")
215 "Determine what \"thing\" `mouse-sel' should operate on. 207
216 The first argument, NCLICKS, is the number of consecutive 208 ;;=== Support/access functions ============================================
217 mouse clicks at the same position." 209
218 (let* ((next-char (char-after (point))) 210 (defun mouse-sel-determine-selection-thing (nclicks)
219 (char-syntax (if next-char (char-syntax next-char))) 211 "Determine what `thing' `mouse-sel' should operate on.
220 (nclicks (if mouse-sel-cycle-clicks (1+ (% (1- NCLICKS) 3)) NCLICKS))) 212 The first argument is NCLICKS, is the number of consecutive
221 (cond 213 mouse clicks at the same position.
222 ((= nclicks 1) nil)
223 ((>= nclicks 3) 'line)
224 ((memq char-syntax '(?\( ?\) ?\" ?')) 'sexp)
225 ((memq next-char '(? ?\t ?\n)) 'whitespace)
226 ((eq char-syntax ?_) 'symbol)
227 ((eq char-syntax ?w) 'word))))
228
229 (defun mouse-select (EVENT)
230 "Set region/selection using the mouse.
231
232 Clicking sets point to click position, and deactivates the mark
233 if you are in Transient Mark mode.
234 Dragging extends region/selection.
235 214
236 Double-clicking on word constituents selects words. 215 Double-clicking on word constituents selects words.
237 Double-clicking on symbol constituents selects symbols. 216 Double-clicking on symbol constituents selects symbols.
238 Double-clicking on quotes or parentheses selects sexps. 217 Double-clicking on quotes or parentheses selects sexps.
239 Double-clicking on whitespace selects whitespace. 218 Double-clicking on whitespace selects whitespace.
240 Triple-clicking selects lines. 219 Triple-clicking selects lines.
241 220 Quad-clicking selects paragraphs.
242 Clicking mouse-2 while selecting copies the region to the kill-ring. 221
243 Clicking mouse-1 or mouse-3 kills the region. 222 Feel free to re-define this function to support your own desired
223 multi-click semantics."
224 (let* ((next-char (char-after (point)))
225 (char-syntax (if next-char (char-syntax next-char))))
226 (if mouse-sel-cycle-clicks
227 (setq nclicks (1+ (% (1- nclicks) 4))))
228 (cond
229 ((= nclicks 1) nil)
230 ((= nclicks 3) 'line)
231 ((>= nclicks 4) 'paragraph)
232 ((memq char-syntax '(?\( ?\) ?\" ?')) 'sexp)
233 ((memq next-char '(? ?\t ?\n)) 'whitespace)
234 ((eq char-syntax ?_) 'symbol)
235 ((eq char-syntax ?w) 'word))))
236
237 (defun mouse-sel-set-selection (selection value)
238 "Set the specified SELECTION to VALUE."
239 (if mouse-sel-set-selection-function
240 (funcall mouse-sel-set-selection-function selection value)
241 (put 'mouse-sel-internal-selection selection value)))
242
243 (defun mouse-sel-get-selection (selection)
244 "Get the value of the specified SELECTION."
245 (if mouse-sel-get-selection-function
246 (funcall mouse-sel-get-selection-function selection)
247 (get 'mouse-sel-internal-selection selection)))
248
249 (defun mouse-sel-selection-owner-p (selection)
250 "Determine whether Emacs owns the specified SELECTION."
251 (if mouse-sel-selection-owner-p-function
252 (funcall mouse-sel-selection-owner-p-function selection)
253 t))
254
255 (defun mouse-sel-selection-overlay (selection)
256 "Return overlay corresponding to SELECTION."
257 (let ((symbol (nth 1 (assoc selection mouse-sel-selection-alist))))
258 (or symbol (error "No overlay corresponding to %s selection" selection))
259 (symbol-value symbol)))
260
261 (defun mouse-sel-selection-thing (selection)
262 "Return overlay corresponding to SELECTION."
263 (let ((symbol (nth 2 (assoc selection mouse-sel-selection-alist))))
264 (or symbol (error "No symbol corresponding to %s selection" selection))
265 symbol))
266
267 (defun mouse-sel-region-to-primary (orig-window)
268 "Convert region to PRIMARY overlay and deactivate region.
269 Argument ORIG-WINDOW specifies the window the cursor was in when the
270 originating command was issued, and is used to determine whether the
271 region was visible or not."
272 (if transient-mark-mode
273 (let ((overlay (mouse-sel-selection-overlay 'PRIMARY)))
274 (cond
275 ((and mark-active
276 (or highlight-nonselected-windows
277 (eq orig-window (selected-window))))
278 ;; Region was visible, so convert region to overlay
279 (move-overlay overlay (region-beginning) (region-end)
280 (current-buffer)))
281 ((eq orig-window (selected-window))
282 ;; Point was visible, so set overlay at point
283 (move-overlay overlay (point) (point) (current-buffer)))
284 (t
285 ;; Nothing was visible, so remove overlay
286 (delete-overlay overlay)))
287 (setq mark-active nil))))
288
289 (defun mouse-sel-primary-to-region (&optional direction)
290 "Convert PRIMARY overlay to region.
291 Optional argument DIRECTION specifies the mouse drag direction: a value of
292 1 indicates that the mouse was dragged left-to-right, otherwise it was
293 dragged right-to-left."
294 (let* ((overlay (mouse-sel-selection-overlay 'PRIMARY))
295 (start (overlay-start overlay))
296 (end (overlay-end overlay)))
297 (if (eq start end)
298 (progn
299 (if start (goto-char start))
300 (deactivate-mark))
301 (if (and mouse-sel-leave-point-near-mouse (eq direction 1))
302 (progn
303 (goto-char end)
304 (push-mark start 'nomsg 'active))
305 (goto-char start)
306 (push-mark end 'nomsg 'active)))
307 (if transient-mark-mode (delete-overlay overlay))))
308
309 (defmacro mouse-sel-eval-at-event-end (event &rest forms)
310 "Evaluate forms at mouse position.
311 Move to the end position of EVENT, execute FORMS, and restore original
312 point and window."
313 (`
314 (let ((posn (event-end (, event))))
315 (if posn (mouse-minibuffer-check (, event)))
316 (if (and posn (not (windowp (posn-window posn))))
317 (error "Cursor not in text area of window"))
318 (let (orig-window orig-point-marker)
319 (setq orig-window (selected-window))
320 (if posn (select-window (posn-window posn)))
321 (setq orig-point-marker (point-marker))
322 (if (and posn (numberp (posn-point posn)))
323 (goto-char (posn-point posn)))
324 (unwind-protect
325 (progn
326 (,@ forms))
327 (goto-char (marker-position orig-point-marker))
328 (move-marker orig-point-marker nil)
329 (select-window orig-window)
330 )))))
331
332 (put 'mouse-sel-eval-at-event-end 'lisp-indent-hook 1)
333
334 ;;=== Select ==============================================================
335
336 (defun mouse-select (event)
337 "Set region/selection using the mouse.
338
339 Click sets point & mark to click position.
340 Dragging extends region/selection.
341
342 Multi-clicking selects word/lines/paragraphs, as determined by
343 'mouse-sel-determine-selection-thing.
344
345 Clicking mouse-2 while selecting copies selected text to the kill-ring.
346 Clicking mouse-1 or mouse-3 kills the selected text.
244 347
245 This should be bound to a down-mouse event." 348 This should be bound to a down-mouse event."
349 (interactive "@e")
350 (let (direction)
351 (unwind-protect
352 (setq direction (mouse-select-internal 'PRIMARY event))
353 (mouse-sel-primary-to-region direction))))
354
355 (defun mouse-select-secondary (event)
356 "Set secondary selection using the mouse.
357
358 Click sets the start of the secondary selection to click position.
359 Dragging extends the secondary selection.
360
361 Multi-clicking selects word/lines/paragraphs, as determined by
362 'mouse-sel-determine-selection-thing.
363
364 Clicking mouse-2 while selecting copies selected text to the kill-ring.
365 Clicking mouse-1 or mouse-3 kills the selected text.
366
367 This should be bound to a down-mouse event."
368 (interactive "e")
369 (mouse-select-internal 'SECONDARY event))
370
371 (defun mouse-select-internal (selection event)
372 "Set SELECTION using the mouse."
373 (mouse-sel-eval-at-event-end event
374 (let ((thing-symbol (mouse-sel-selection-thing selection))
375 (overlay (mouse-sel-selection-overlay selection)))
376 (set thing-symbol
377 (mouse-sel-determine-selection-thing (event-click-count event)))
378 (let ((object-bounds (bounds-of-thing-at-point
379 (symbol-value thing-symbol))))
380 (if object-bounds
381 (progn
382 (move-overlay overlay
383 (car object-bounds) (cdr object-bounds)
384 (current-buffer)))
385 (move-overlay overlay (point) (point) (current-buffer)))))
386 (mouse-extend-internal selection)))
387
388 ;;=== Extend ==============================================================
389
390 (defun mouse-extend (event)
391 "Extend region/selection using the mouse."
246 (interactive "e") 392 (interactive "e")
247 (mouse-set-point EVENT) 393 (let ((orig-window (selected-window))
248 (setq mouse-sel-selection-type 394 direction)
249 (mouse-sel-determine-selection-type (event-click-count EVENT))) 395 (select-window (posn-window (event-end event)))
250 (let ((object-bounds (bounds-of-thing-at-point mouse-sel-selection-type))) 396 (unwind-protect
251 (if object-bounds
252 (progn 397 (progn
253 (setq mark-active t) 398 (mouse-sel-region-to-primary orig-window)
254 (goto-char (car object-bounds)) 399 (setq direction (mouse-extend-internal 'PRIMARY event)))
255 (set-mark (cdr object-bounds))) 400 (mouse-sel-primary-to-region direction))))
256 (deactivate-mark))) 401
257 (mouse-extend (if mouse-sel-selection-type EVENT))) 402 (defun mouse-extend-secondary (event)
258 403 "Extend secondary selection using the mouse."
259 (defun mouse-extend (&optional EVENT)
260 "Extend region/selection using the mouse.
261
262 See documentation for mouse-select for more details.
263
264 This should be bound to a down-mouse event."
265 (interactive "e") 404 (interactive "e")
266 (if EVENT (select-window (posn-window (event-end EVENT)))) 405 (save-window-excursion
267 (let* ((use-region (and (or EVENT transient-mark-mode) mark-active)) 406 (mouse-extend-internal 'SECONDARY event)))
268 (min (if use-region (region-beginning) (point))) 407
269 (max (if use-region (region-end) (point))) 408 (defun mouse-extend-internal (selection &optional initial-event)
270 (orig-window (selected-window)) 409 "Extend specified SELECTION using the mouse.
271 (orig-window-frame (window-frame orig-window)) 410 Track mouse-motion events, adjusting the SELECTION appropriately.
272 (top (nth 1 (window-edges orig-window))) 411 Optional argument INITIAL-EVENT specifies an initial down-mouse event to
273 (bottom (nth 3 (window-edges orig-window))) 412 process.
274 (orig-cursor-type 413
275 (cdr (assoc 'cursor-type (frame-parameters (selected-frame))))) 414 See documentation for mouse-select-internal for more details."
276 direction 415 (mouse-sel-eval-at-event-end initial-event
277 event) 416 (let ((orig-cursor-type
278 417 (cdr (assoc 'cursor-type (frame-parameters (selected-frame))))))
279 ;; Inhibit normal region highlight 418 (unwind-protect
280 (setq mark-active nil) 419
281 420 (let* ((thing-symbol (mouse-sel-selection-thing selection))
282 ;; Highlight region (forcing re-highlight) 421 (overlay (mouse-sel-selection-overlay selection))
283 (move-overlay mouse-drag-overlay min max (current-buffer)) 422 (orig-window (selected-window))
284 (overlay-put mouse-drag-overlay 'face 423 (orig-window-frame (window-frame orig-window))
285 (overlay-get mouse-drag-overlay 'face)) 424 (top (nth 1 (window-edges orig-window)))
286 425 (bottom (nth 3 (window-edges orig-window)))
287 ;; Bar cursor 426 (mark-active nil) ; inhibit normal region highlight
288 (if (fboundp 'modify-frame-parameters) 427 (echo-keystrokes 0) ; don't echo mouse events
289 (modify-frame-parameters (selected-frame) '((cursor-type . bar)))) 428 min max
290 429 direction
291 ;; Handle dragging 430 event)
292 (unwind-protect 431
293 (progn 432 ;; Get current bounds of overlay
294 (track-mouse 433 (if (eq (overlay-buffer overlay) (current-buffer))
434 (setq min (overlay-start overlay)
435 max (overlay-end overlay))
436 (setq min (point)
437 max min)
438 (set thing-symbol nil))
439
440
441 ;; Bar cursor
442 (if (fboundp 'modify-frame-parameters)
443 (modify-frame-parameters (selected-frame)
444 '((cursor-type . bar))))
295 445
296 (while (if EVENT ; Use initial event 446 ;; Handle dragging
297 (prog1 447 (track-mouse
298 (setq event EVENT) 448
299 (setq EVENT nil)) 449 (while (if initial-event ; Use initial event
300 (setq event (read-event)) 450 (prog1
301 (and (consp event) 451 (setq event initial-event)
302 (memq (car event) '(mouse-movement switch-frame)))) 452 (setq initial-event nil))
453 (setq event (read-event))
454 (and (consp event)
455 (memq (car event) '(mouse-movement switch-frame))))
456
457 (let ((selection-thing (symbol-value thing-symbol))
458 (end (event-end event)))
459
460 (cond
461
462 ;; Ignore any movement outside the frame
463 ((eq (car-safe event) 'switch-frame) nil)
464 ((and (posn-window end)
465 (not (eq (let ((posn-w (posn-window end)))
466 (if (windowp posn-w)
467 (window-frame posn-w)
468 posn-w))
469 (window-frame orig-window)))) nil)
470
471 ;; Different window, same frame
472 ((not (eq (posn-window end) orig-window))
473 (let ((end-row (cdr (cdr (mouse-position)))))
474 (cond
475 ((and end-row (not (bobp)) (< end-row top))
476 (mouse-scroll-subr orig-window (- end-row top)
477 overlay max))
478 ((and end-row (not (eobp)) (>= end-row bottom))
479 (mouse-scroll-subr orig-window (1+ (- end-row bottom))
480 overlay min))
481 )))
482
483 ;; On the mode line
484 ((eq (posn-point end) 'mode-line)
485 (mouse-scroll-subr orig-window 1 overlay min))
486
487 ;; In original window
488 (t (goto-char (posn-point end)))
489
490 )
303 491
304 (let ((end (event-end event))) 492 ;; Determine direction of drag
493 (cond
494 ((and (not direction) (not (eq min max)))
495 (setq direction (if (< (point) (/ (+ min max) 2)) -1 1)))
496 ((and (not (eq direction -1)) (<= (point) min))
497 (setq direction -1))
498 ((and (not (eq direction 1)) (>= (point) max))
499 (setq direction 1)))
500
501 (if (not selection-thing) nil
305 502
503 ;; If dragging forward, goal is next character
504 (if (and (eq direction 1) (not (eobp))) (forward-char 1))
505
506 ;; Move to start/end of selected thing
507 (let ((goal (point))
508 last)
509 (goto-char (if (eq 1 direction) min max))
510 (condition-case nil
511 (progn
512 (while (> (* direction (- goal (point))) 0)
513 (setq last (point))
514 (forward-thing selection-thing direction))
515 (let ((end (point)))
516 (forward-thing selection-thing (- direction))
517 (goto-char
518 (if (> (* direction (- goal (point))) 0)
519 end last))))
520 (error))))
521
522 ;; Move overlay
523 (move-overlay overlay
524 (if (eq 1 direction) min (point))
525 (if (eq -1 direction) max (point))
526 (current-buffer))
527
528 ))) ; end track-mouse
529
530 ;; Finish up after dragging
531 (let ((overlay-start (overlay-start overlay))
532 (overlay-end (overlay-end overlay)))
533
534 ;; Set selection
535 (if (not (eq overlay-start overlay-end))
536 (mouse-sel-set-selection
537 selection
538 (buffer-substring overlay-start overlay-end)))
539
540 ;; Handle copy/kill
541 (let (this-command)
306 (cond 542 (cond
307 543 ((eq (event-basic-type last-input-event) 'mouse-2)
308 ;; Ignore any movement outside the frame 544 (copy-region-as-kill overlay-start overlay-end)
309 ((eq (car-safe event) 'switch-frame) nil) 545 (read-event) (read-event))
310 ((and (posn-window end) 546 ((and (memq (event-basic-type last-input-event)
311 (not (eq (let ((posn-w (posn-window end))) 547 '(mouse-1 mouse-3))
312 (if (windowp posn-w) 548 (memq 'down (event-modifiers last-input-event)))
313 (window-frame posn-w) 549 (kill-region overlay-start overlay-end)
314 posn-w)) 550 (move-overlay overlay overlay-start overlay-start)
315 (window-frame orig-window)))) nil) 551 (read-event) (read-event))
316 552 ((and (eq (event-basic-type last-input-event) 'mouse-3)
317 ;; Different window, same frame 553 (memq 'double (event-modifiers last-input-event)))
318 ((not (eq (posn-window end) orig-window)) 554 (kill-region overlay-start overlay-end)
319 (let ((end-row (cdr (cdr (mouse-position))))) 555 (move-overlay overlay overlay-start overlay-start)))))
320 (cond 556
321 ((and end-row (not (bobp)) (< end-row top)) 557 direction)
322 (mouse-scroll-subr orig-window (- end-row top) 558
323 mouse-drag-overlay max)) 559 ;; Restore cursor
324 ((and end-row (not (eobp)) (>= end-row bottom)) 560 (if (fboundp 'modify-frame-parameters)
325 (mouse-scroll-subr orig-window (1+ (- end-row bottom)) 561 (modify-frame-parameters
326 mouse-drag-overlay min)) 562 (selected-frame) (list (cons 'cursor-type orig-cursor-type))))
327 ))) 563
328 564 ))))
329 ;; On the mode line 565
330 ((eq (posn-point end) 'mode-line) 566 ;;=== Paste ===============================================================
331 (mouse-scroll-subr orig-window 1 mouse-drag-overlay min)) 567
332 568 (defun mouse-insert-selection (event)
333 ;; In original window 569 "Insert the contents of the PRIMARY selection at mouse click.
334 (t (goto-char (posn-point end)))
335
336 )
337 ;; Determine direction of drag
338 (cond
339 ((and (not direction) (not (eq min max)))
340 (setq direction (if (< (point) (/ (+ min max) 2)) -1 1)))
341 ((and (not (eq direction -1)) (<= (point) min))
342 (setq direction -1))
343 ((and (not (eq direction 1)) (>= (point) max))
344 (setq direction 1)))
345
346 (if (not mouse-sel-selection-type) nil
347
348 ;; If dragging forward, goal is next character
349 (if (and (eq direction 1) (not (eobp))) (forward-char 1))
350
351 ;; Move to start/end of selected thing
352 (let ((goal (point))
353 last)
354 (goto-char (if (eq 1 direction) min max))
355 (condition-case nil
356 (progn
357 (while (> (* direction (- goal (point))) 0)
358 (setq last (point))
359 (forward-thing mouse-sel-selection-type
360 direction))
361 (let ((end (point)))
362 (forward-thing mouse-sel-selection-type
363 (- direction))
364 (goto-char
365 (if (> (* direction (- goal (point))) 0)
366 end last))))
367 (error))))
368
369 ;; Move overlay
370 (move-overlay mouse-drag-overlay
371 (if (eq 1 direction) min (point))
372 (if (eq -1 direction) max (point))
373 (current-buffer))
374
375 ))) ; end track-mouse
376
377 (let ((overlay-start (overlay-start mouse-drag-overlay))
378 (overlay-end (overlay-end mouse-drag-overlay)))
379
380 ;; Set region
381 (if (eq overlay-start overlay-end)
382 (deactivate-mark)
383 (if (and mouse-sel-leave-point-near-mouse (eq direction 1))
384 (progn
385 (set-mark overlay-start)
386 (goto-char overlay-end))
387 (set-mark overlay-end)
388 (goto-char overlay-start)))
389
390 ;; Set selection
391 (if (and mark-active mouse-sel-set-selection-function)
392 (funcall mouse-sel-set-selection-function
393 (buffer-substring overlay-start overlay-end)))
394
395 ;; Handle copy/kill
396 (cond
397 ((eq (car-safe last-input-event) 'down-mouse-2)
398 (copy-region-as-kill overlay-start overlay-end)
399 (read-event) (read-event))
400 ((memq (car-safe last-input-event) '(down-mouse-1 down-mouse-3))
401 (kill-region overlay-start overlay-end)
402 (deactivate-mark)
403 (read-event) (read-event))
404 ((eq (car-safe last-input-event) 'double-mouse-3)
405 (kill-region overlay-start overlay-end)
406 (deactivate-mark)))))
407
408 ;; Restore cursor
409 (if (fboundp 'modify-frame-parameters)
410 (modify-frame-parameters
411 (selected-frame) (list (cons 'cursor-type orig-cursor-type))))
412
413 ;; Remove overlay
414 (or mouse-sel-retain-highlight
415 (delete-overlay mouse-drag-overlay)))))
416
417 (defun mouse-insert-selection (click)
418 "Insert the contents of the selection at mouse click.
419 If `mouse-yank-at-point' is non-nil, insert at point instead." 570 If `mouse-yank-at-point' is non-nil, insert at point instead."
420 (interactive "e") 571 (interactive "e")
572 (mouse-insert-selection-internal 'PRIMARY event))
573
574 (defun mouse-insert-secondary (event)
575 "Insert the contents of the SECONDARY selection at mouse click.
576 If `mouse-yank-at-point' is non-nil, insert at point instead."
577 (interactive "e")
578 (mouse-insert-selection-internal 'SECONDARY event))
579
580 (defun mouse-insert-selection-internal (selection event)
581 "Insert the contents of the named SELECTION at mouse click.
582 If `mouse-yank-at-point' is non-nil, insert at point instead."
421 (or mouse-yank-at-point 583 (or mouse-yank-at-point
422 (mouse-set-point click)) 584 (mouse-set-point event))
423 (deactivate-mark)
424 (if mouse-sel-get-selection-function 585 (if mouse-sel-get-selection-function
425 (insert (or (funcall mouse-sel-get-selection-function) "")))) 586 (progn
587 (push-mark (point) 'nomsg)
588 (insert (or (funcall mouse-sel-get-selection-function selection) "")))))
589
590 ;;=== Validate selection ==================================================
426 591
427 (defun mouse-sel-validate-selection () 592 (defun mouse-sel-validate-selection ()
428 "Remove selection highlight if emacs no longer owns the primary selection." 593 "Validate selections in mouse-sel-selection-alist.
429 (or (not mouse-sel-check-selection-function) 594 For each listed selection, remove the selection overlay if Emacs no longer
430 (funcall mouse-sel-check-selection-function) 595 owns the selection."
431 (delete-overlay mouse-drag-overlay))) 596 (let ((owner-p-function mouse-sel-selection-owner-p-function)
597 (alist mouse-sel-selection-alist)
598 selection overlay)
599 (if owner-p-function
600 (while alist
601 (setq selection (car (car alist))
602 overlay (symbol-value (nth 1 (car alist)))
603 alist (cdr alist))
604 (or (funcall owner-p-function selection)
605 (delete-overlay overlay))))))
432 606
433 (add-hook 'pre-command-hook 'mouse-sel-validate-selection) 607 (add-hook 'pre-command-hook 'mouse-sel-validate-selection)
434 608
435 ;;=== Key bindings ======================================================== 609 ;;=== Key bindings ========================================================
436 610
440 (global-unset-key [drag-mouse-1]) 614 (global-unset-key [drag-mouse-1])
441 (global-unset-key [mouse-3]) 615 (global-unset-key [mouse-3])
442 616
443 (global-set-key [down-mouse-1] 'mouse-select) 617 (global-set-key [down-mouse-1] 'mouse-select)
444 (global-set-key [down-mouse-3] 'mouse-extend) 618 (global-set-key [down-mouse-3] 'mouse-extend)
619
620 (global-unset-key [M-mouse-1])
621 (global-unset-key [M-drag-mouse-1])
622 (global-unset-key [M-mouse-3])
445 623
624 (global-set-key [M-down-mouse-1] 'mouse-select-secondary)
625 (global-set-key [M-down-mouse-3] 'mouse-extend-secondary)
626
446 (if (eq mouse-sel-default-bindings 'interprogram-cut-paste) nil 627 (if (eq mouse-sel-default-bindings 'interprogram-cut-paste) nil
447 628
448 (global-set-key [mouse-2] 'mouse-insert-selection) 629 (global-set-key [mouse-2] 'mouse-insert-selection)
630
449 (setq interprogram-cut-function nil 631 (setq interprogram-cut-function nil
450 interprogram-paste-function nil)) 632 interprogram-paste-function nil))
451 633
634 (global-set-key [M-mouse-2] 'mouse-insert-secondary)
635
452 ) 636 )
453 637
638 ;;=== Bug reporting =======================================================
639
640 (defconst mouse-sel-maintainer-address "mikew@gopher.dosli.govt.nz")
641
642 (defun mouse-sel-submit-bug-report ()
643 "Submit a bug report on mouse-sel.el via mail."
644 (interactive)
645 (require 'reporter)
646 (reporter-submit-bug-report
647 mouse-sel-maintainer-address
648 (concat "mouse-sel.el "
649 (or (condition-case nil mouse-sel-version (error))
650 "(distributed with Emacs)"))
651 (list 'transient-mark-mode
652 'delete-selection-mode
653 'mouse-sel-default-bindings
654 'mouse-sel-leave-point-near-mouse
655 'mouse-sel-cycle-clicks
656 'mouse-sel-selection-alist
657 'mouse-sel-set-selection-function
658 'mouse-sel-get-selection-function
659 'mouse-sel-selection-owner-p-function
660 'mouse-yank-at-point)))
661
454 ;; mouse-sel.el ends here. 662 ;; mouse-sel.el ends here.