summaryrefslogtreecommitdiff
path: root/lisp/mouse.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/mouse.el')
-rw-r--r--lisp/mouse.el219
1 files changed, 213 insertions, 6 deletions
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 8732fb80866..d2a5200d8de 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -119,7 +119,9 @@ Expects to be bound to `(double-)mouse-1' in `key-translation-map'."
(time-since (cdr mouse--last-down))
(/ (abs mouse-1-click-follows-link) 1000.0))))))
(eq (car mouse--last-down)
- (event-convert-list (list 'down (car-safe last-input-event))))
+ (event-convert-list
+ `(down ,@(event-modifiers last-input-event)
+ ,(event-basic-type last-input-event))))
(let* ((action (mouse-on-link-p (event-start last-input-event))))
(when (and action
(or mouse-1-click-in-non-selected-windows
@@ -178,7 +180,7 @@ items `Turn Off' and `Help'."
`(keymap
,(format "%s - %s" indicator
(capitalize
- (replace-regexp-in-string
+ (string-replace
"-" " " (format "%S" minor-mode))))
(turn-off menu-item "Turn off minor mode" ,mm-fun)
(help menu-item "Help for minor mode"
@@ -275,6 +277,194 @@ not it is actually displayed."
minor-mode-menus)))
+;; Context menus.
+
+(defcustom context-menu-functions '(context-menu-undo
+ context-menu-region
+ context-menu-local
+ context-menu-minor)
+ "List of functions that produce the contents of the context menu.
+Each function receives the menu as its argument and should return
+the same menu with changes such as added new menu items."
+ :type '(repeat
+ (choice (function-item context-menu-undo)
+ (function-item context-menu-region)
+ (function-item context-menu-global)
+ (function-item context-menu-local)
+ (function-item context-menu-minor)
+ (function-item context-menu-vc)
+ (function-item context-menu-ffap)
+ (function :tag "Custom function")))
+ :version "28.1")
+
+(defcustom context-menu-filter-function nil
+ "Function that can filter the list produced by `context-menu-functions'."
+ :type '(choice (const nil) function)
+ :version "28.1")
+
+(defun context-menu-map ()
+ "Return composite menu map."
+ (let ((menu (make-sparse-keymap)))
+ (run-hook-wrapped 'context-menu-functions
+ (lambda (fun)
+ (setq menu (funcall fun menu))
+ nil))
+ (when (functionp context-menu-filter-function)
+ (setq menu (funcall context-menu-filter-function menu)))
+ menu))
+
+(defun context-menu-global (menu)
+ "Global submenus."
+ (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
+ (define-key-after menu [separator-global] menu-bar-separator)
+ (map-keymap (lambda (key binding)
+ (when (consp binding)
+ (define-key-after menu (vector key)
+ (copy-sequence binding))))
+ (lookup-key global-map [menu-bar]))
+ menu)
+
+(defun context-menu-local (menu)
+ "Major mode submenus."
+ (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
+ (define-key-after menu [separator-local] menu-bar-separator)
+ (let ((keymap (local-key-binding [menu-bar])))
+ (when keymap
+ (map-keymap (lambda (key binding)
+ (when (consp binding)
+ (define-key-after menu (vector key)
+ (copy-sequence binding))))
+ keymap)))
+ menu)
+
+(defun context-menu-minor (menu)
+ "Minor modes submenus."
+ (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
+ (define-key-after menu [separator-minor] menu-bar-separator)
+ (dolist (mode (reverse (minor-mode-key-binding [menu-bar])))
+ (when (and (consp mode) (symbol-value (car mode)))
+ (map-keymap (lambda (key binding)
+ (when (consp binding)
+ (define-key-after menu (vector key)
+ (copy-sequence binding))))
+ (cdr mode))))
+ menu)
+
+(defun context-menu-vc (menu)
+ "Version Control menu."
+ (define-key-after menu [separator-vc] menu-bar-separator)
+ (define-key-after menu [vc-menu] vc-menu-entry)
+ menu)
+
+(defun context-menu-undo (menu)
+ "Undo menu."
+ (when (cddr menu)
+ (define-key-after menu [separator-undo] menu-bar-separator))
+ (define-key-after menu [undo]
+ '(menu-item "Undo" undo
+ :visible (and (not buffer-read-only)
+ (not (eq t buffer-undo-list))
+ (if (eq last-command 'undo)
+ (listp pending-undo-list)
+ (consp buffer-undo-list)))
+ :help "Undo last edits"))
+ (define-key-after menu [undo-redo]
+ '(menu-item "Redo" undo-redo
+ :visible (and (not buffer-read-only)
+ (undo--last-change-was-undo-p buffer-undo-list))
+ :help "Redo last undone edits"))
+ menu)
+
+(defun context-menu-region (menu)
+ "Region commands menu."
+ (when (cddr menu)
+ (define-key-after menu [separator-region] menu-bar-separator))
+ (define-key-after menu [cut]
+ '(menu-item "Cut" kill-region
+ :visible (and mark-active (not buffer-read-only))
+ :help
+ "Cut (kill) text in region between mark and current position"))
+ (define-key-after menu [copy]
+ ;; ns-win.el said: Substitute a Copy function that works better
+ ;; under X (for GNUstep).
+ `(menu-item "Copy" ,(if (featurep 'ns)
+ 'ns-copy-including-secondary
+ 'kill-ring-save)
+ :visible mark-active
+ :help "Copy text in region between mark and current position"
+ :keys ,(if (featurep 'ns)
+ "\\[ns-copy-including-secondary]"
+ "\\[kill-ring-save]")))
+ (define-key-after menu [paste]
+ `(menu-item "Paste" mouse-yank-primary
+ :visible (funcall
+ ',(lambda ()
+ (and (or
+ (gui-backend-selection-exists-p 'CLIPBOARD)
+ (if (featurep 'ns) ; like paste-from-menu
+ (cdr yank-menu)
+ kill-ring))
+ (not buffer-read-only))))
+ :help "Paste (yank) text most recently cut/copied"))
+ (define-key-after menu (if (featurep 'ns) [select-paste]
+ [paste-from-menu])
+ ;; ns-win.el said: Change text to be more consistent with
+ ;; surrounding menu items `paste', etc."
+ `(menu-item ,(if (featurep 'ns) "Select and Paste" "Paste from Kill Menu")
+ yank-menu
+ :visible (and (cdr yank-menu) (not buffer-read-only))
+ :help "Choose a string from the kill ring and paste it"))
+ (define-key-after menu [clear]
+ '(menu-item "Clear" delete-active-region
+ :visible (and mark-active
+ (not buffer-read-only))
+ :help
+ "Delete the text in region between mark and current position"))
+ (define-key-after menu [mark-whole-buffer]
+ '(menu-item "Select All" mark-whole-buffer
+ :help "Mark the whole buffer for a subsequent cut/copy"))
+ menu)
+
+(defun context-menu-ffap (menu)
+ "File at point menu."
+ (save-excursion
+ (mouse-set-point last-input-event)
+ (when (ffap-guess-file-name-at-point)
+ (define-key menu [ffap-separator] menu-bar-separator)
+ (define-key menu [ffap-at-mouse]
+ '(menu-item "Find File or URL" ffap-at-mouse
+ :help "Find file or URL guessed from text around mouse click"))))
+ menu)
+
+(defvar context-menu-entry
+ `(menu-item ,(purecopy "Context Menu") ignore
+ :filter (lambda (_) (context-menu-map))))
+
+(defvar context-menu--old-down-mouse-3 nil)
+(defvar context-menu--old-mouse-3 nil)
+
+(define-minor-mode context-menu-mode
+ "Toggle Context Menu mode.
+
+When Context Menu mode is enabled, clicking the mouse button down-mouse-3
+activates the menu whose contents depends on its surrounding context."
+ :global t :group 'mouse
+ (cond
+ (context-menu-mode
+ (setq context-menu--old-mouse-3 (global-key-binding [mouse-3]))
+ (global-unset-key [mouse-3])
+ (setq context-menu--old-down-mouse-3 (global-key-binding [down-mouse-3]))
+ (global-set-key [down-mouse-3] context-menu-entry))
+ (t
+ (if (not context-menu--old-down-mouse-3)
+ (global-unset-key [down-mouse-3])
+ (global-set-key [down-mouse-3] context-menu--old-down-mouse-3)
+ (setq context-menu--old-down-mouse-3 nil))
+ (when context-menu--old-mouse-3
+ (global-set-key [mouse-3] context-menu--old-mouse-3)
+ (setq context-menu--old-mouse-3 nil)))))
+
+
;; Commands that operate on windows.
(defun mouse-minibuffer-check (event)
@@ -413,7 +603,7 @@ must be one of the symbols `header', `mode', or `vertical'."
(when (window-live-p (setq posn-window (posn-window start)))
;; Add left edge of `posn-window' to `position'.
(setq position (+ (window-pixel-left posn-window) position))
- (unless (nth 1 start)
+ (unless (posn-area start)
;; Add width of objects on the left of the text area to
;; `position'.
(when (eq (window-current-scroll-bars posn-window) 'left)
@@ -492,9 +682,11 @@ must be one of the symbols `header', `mode', or `vertical'."
(define-key map [header-line] map)
(define-key map [vertical-line] map)
;; ... and some maybe even with a right- or bottom-divider
- ;; prefix.
+ ;; or left- or right-margin prefix ...
(define-key map [right-divider] map)
(define-key map [bottom-divider] map)
+ (define-key map [left-margin] map)
+ (define-key map [right-margin] map)
map)
t (lambda () (setq track-mouse old-track-mouse)))))))
@@ -546,6 +738,18 @@ the frame instead."
(when (frame-parameter frame 'drag-with-header-line)
(mouse-drag-frame-move start-event))))))
+(defun mouse-drag-tab-line (start-event)
+ "Drag frame with tab line in its topmost window.
+START-EVENT is the starting mouse event of the drag action."
+ (interactive "e")
+ (let* ((start (event-start start-event))
+ (window (posn-window start)))
+ (when (and (window-live-p window)
+ (window-at-side-p window 'top))
+ (let ((frame (window-frame window)))
+ (when (frame-parameter frame 'drag-with-tab-line)
+ (mouse-drag-frame-move start-event))))))
+
(defun mouse-drag-vertical-line (start-event)
"Change the width of a window by dragging on a vertical line.
START-EVENT is the starting mouse event of the drag action."
@@ -674,6 +878,7 @@ frame with the mouse."
;; with a mode-line, header-line or vertical-line prefix ...
(define-key map [mode-line] map)
(define-key map [header-line] map)
+ (define-key map [tab-line] map)
(define-key map [vertical-line] map)
;; ... and some maybe even with a right- or bottom-divider
;; prefix.
@@ -900,6 +1105,7 @@ frame with the mouse."
;; with a mode-line, header-line or vertical-line prefix ...
(define-key map [mode-line] map)
(define-key map [header-line] map)
+ (define-key map [tab-line] map)
(define-key map [vertical-line] map)
;; ... and some maybe even with a right- or bottom-divider
;; prefix.
@@ -1190,7 +1396,7 @@ overlay property, the value of that property determines what to do.
for the `follow-link' event, the binding of that event determines
what to do.
-The resulting value determine whether POS is inside a link:
+The resulting value determines whether POS is inside a link:
- If the value is `mouse-face', POS is inside a link if there
is a non-nil `mouse-face' property at POS. Return t in this case.
@@ -2863,8 +3069,8 @@ is copied instead of being cut."
(set-marker (nth 2 state) nil))
(with-current-buffer (window-buffer window)
(setq cursor-type (nth 3 state)))))))
-
+
;;; Bindings for mouse commands.
(global-set-key [down-mouse-1] 'mouse-drag-region)
@@ -2904,6 +3110,7 @@ is copied instead of being cut."
;; versions.
(global-set-key [header-line down-mouse-1] 'mouse-drag-header-line)
(global-set-key [header-line mouse-1] 'mouse-select-window)
+(global-set-key [tab-line down-mouse-1] 'mouse-drag-tab-line)
(global-set-key [tab-line mouse-1] 'mouse-select-window)
;; (global-set-key [mode-line drag-mouse-1] 'mouse-select-window)
(global-set-key [mode-line down-mouse-1] 'mouse-drag-mode-line)