diff --git a/lisp/mouse.el b/lisp/mouse.el index 89e5d7c48a..febda78212 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -156,6 +156,82 @@ key-translation-map (define-key key-translation-map [double-mouse-1] #'mouse--click-1-maybe-follows-link) + +(defcustom mouse-3-down-context-menu 450 + "Non-nil means that holding down Mouse-3 shows context menu. + +With the default setting, holding down the Mouse-3 button +for more than 450 milliseconds performs the same action as S-Down-Mouse-3 +\(which shows the menu), while an ordinary Mouse-3 click performs the +original Mouse-3 binding (which typically sets the region where you +click the mouse). + +If value is an integer, the time elapsed between pressing and +releasing the mouse button determines whether to show the menu +or perform the normal Mouse-3 action (typically set the region). +The absolute numeric value specifies the maximum duration of a +\"short click\" in milliseconds. A positive value means that a +short click shows the menu, and a longer click performs the +normal action. + +Otherwise, a single Mouse-3 click unconditionally shows the menu." + :version "28.1" + :type '(choice (const :tag "Disabled" nil) + (number :tag "Single click time limit" :value 450) + (other :tag "Single click" t))) + +(defvar mouse--down-3-timer nil) + +(defun mouse-maybe-context-menu (event) + (interactive "@e") + (cond + ;; Delay context menu display. + ((numberp mouse-3-down-context-menu) + (when (timerp mouse--down-3-timer) + (cancel-timer mouse--down-3-timer)) + (setq mouse--down-3-timer + (run-with-timer + (/ (abs mouse-3-down-context-menu) 1000.0) nil + (lambda () + (setq mouse--down-3-timer t) + (unless (eq (posn-window (event-end event)) (selected-window)) + (select-window (posn-window (event-end event)))) + (mouse-context-menu event)))) + nil) + ;; Immediately pop up context menu. + (mouse-3-down-context-menu + (unless (eq (posn-window (event-end event)) (selected-window)) + (select-window (posn-window (event-end event)))) + (mouse-context-menu event)))) + +(defun mouse--click-3-maybe-context-menu (&optional _prompt) + (cond + ((numberp mouse-3-down-context-menu) + (cond + ((timerp mouse--down-3-timer) + ;; Don't wait for context menu and fall back to mouse-save-then-kill. + (cancel-timer mouse--down-3-timer) + (setq mouse--down-3-timer nil) + nil) + (mouse--down-3-timer + ;; Context menu was displayed after delay. + (setq mouse--down-3-timer nil) + []))) + ;; Context menu was displayed immediately. + (mouse-3-down-context-menu + []))) + +(define-key key-translation-map [mouse-3] + #'mouse--click-3-maybe-context-menu) + +(defun mouse-context-menu-map () + (cddr (assq 'edit (lookup-key global-map [menu-bar])))) + +(defun mouse-context-menu (event) + "Show a context menu for the current buffer." + (interactive "@e") + (popup-menu (mouse-context-menu-map) event)) + ;; Provide a mode-specific menu on a mouse button. @@ -1672,7 +1748,7 @@ mouse-save-then-kill ((not (numberp click-pt)) nil) ;; If the user clicked without moving point, kill the region. ;; This also resets `mouse-selection-click-count'. - ((and (eq last-command 'mouse-save-then-kill) + ((and (memq last-command '(mouse-save-then-kill mouse-maybe-context-menu)) (eq click-pt mouse-save-then-kill-posn) (eq window (selected-window))) (if mouse-drag-copy-region @@ -2899,6 +2975,8 @@ function-key-map ;; Allow yanking also when the corresponding cursor is "in the fringe". (define-key function-key-map [right-fringe mouse-2] 'mouse--strip-first-event) (define-key function-key-map [left-fringe mouse-2] 'mouse--strip-first-event) + +(global-set-key [down-mouse-3] 'mouse-maybe-context-menu) (global-set-key [mouse-3] 'mouse-save-then-kill) (define-key function-key-map [right-fringe mouse-3] 'mouse--strip-first-event) (define-key function-key-map [left-fringe mouse-3] 'mouse--strip-first-event) diff --git a/lisp/vc/smerge-mode.el b/lisp/vc/smerge-mode.el index 694d4529b9..3aa7399dd5 100644 --- a/lisp/vc/smerge-mode.el +++ b/lisp/vc/smerge-mode.el @@ -385,6 +385,8 @@ smerge-remove-props (defun smerge-popup-context-menu (event) "Pop up the Smerge mode context menu under mouse." (interactive "e") + (unless (eq (posn-window (event-end event)) (selected-window)) + (select-window (posn-window (event-end event)))) (if (and smerge-mode (save-excursion (posn-set-point (event-end event)) (smerge-check 1))) (progn