;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
(defvar xterm-mouse-debug-buffer nil)
-(define-key function-key-map "\e[M" 'xterm-mouse-translate)
-
(defvar xterm-mouse-last)
;; Mouse events symbols must have an 'event-kind property with
(error "Unexpected escape sequence from XTerm")))
(let* ((click (if is-click down (xterm-mouse-event)))
- (click-command (nth 0 click))
+ ;; (click-command (nth 0 click))
(click-data (nth 1 click))
(click-where (nth 1 click-data)))
(if (memq down-binding '(nil ignore))
(vector (list down-where down-data) down)
(vector down))))))))
-(defvar xterm-mouse-x 0
- "Position of last xterm mouse event relative to the frame.")
-
-(defvar xterm-mouse-y 0
- "Position of last xterm mouse event relative to the frame.")
+;; These two variables have been converted to terminal parameters.
+;;
+;;(defvar xterm-mouse-x 0
+;; "Position of last xterm mouse event relative to the frame.")
+;;
+;;(defvar xterm-mouse-y 0
+;; "Position of last xterm mouse event relative to the frame.")
(defvar xt-mouse-epoch nil)
(defun xterm-mouse-position-function (pos)
"Bound to `mouse-position-function' in XTerm mouse mode."
- (setcdr pos (cons xterm-mouse-x xterm-mouse-y))
+ (when (terminal-parameter nil 'xterm-mouse-x)
+ (setcdr pos (cons (terminal-parameter nil 'xterm-mouse-x)
+ (terminal-parameter nil 'xterm-mouse-y))))
pos)
;; read xterm sequences above ascii 127 (#x7f)
(+ c #x8000000 128)
c)))
+(defun xterm-mouse-truncate-wrap (f)
+ "Truncate with wrap-around."
+ (condition-case nil
+ ;; First try the built-in truncate, in case there's no overflow.
+ (truncate f)
+ ;; In case of overflow, do wraparound by hand.
+ (range-error
+ ;; In our case, we wrap around every 3 days or so, so if we assume
+ ;; a maximum of 65536 wraparounds, we're safe for a couple years.
+ ;; Using a power of 2 makes rounding errors less likely.
+ (let* ((maxwrap (* 65536 2048))
+ (dbig (truncate (/ f maxwrap)))
+ (fdiff (- f (* 1.0 maxwrap dbig))))
+ (+ (truncate fdiff) (* maxwrap dbig))))))
+
(defun xterm-mouse-event ()
"Convert XTerm mouse event to Emacs mouse event."
(let* ((type (- (xterm-mouse-event-read) #o40))
(y (- (xterm-mouse-event-read) #o40 1))
;; Emulate timestamp information. This is accurate enough
;; for default value of mouse-1-click-follows-link (450msec).
- (timestamp (truncate
- (* 1000
- (- (float-time)
- (or xt-mouse-epoch
- (setq xt-mouse-epoch (float-time)))))))
- (mouse (intern
+ (timestamp (xterm-mouse-truncate-wrap
+ (* 1000
+ (- (float-time)
+ (or xt-mouse-epoch
+ (setq xt-mouse-epoch (float-time)))))))
+ (mouse (intern
;; For buttons > 3, the release-event looks
;; differently (see xc/programs/xterm/button.c,
;; function EditorButton), and there seems to come in
(left (nth 0 ltrb))
(top (nth 1 ltrb)))
- (setq xterm-mouse-x x
- xterm-mouse-y y)
+ (set-terminal-parameter nil 'xterm-mouse-x x)
+ (set-terminal-parameter nil 'xterm-mouse-y y)
(setq
last-input-event
(list mouse
;;;###autoload
(define-minor-mode xterm-mouse-mode
"Toggle XTerm mouse mode.
-With prefix arg, turn XTerm mouse mode on iff arg is positive.
+With prefix arg, turn XTerm mouse mode on if arg is positive, otherwise turn
+it off.
Turn it on to use Emacs mouse commands, and off to use xterm mouse commands.
This works in terminal emulators compatible with xterm. It only
:global t :group 'mouse
(if xterm-mouse-mode
;; Turn it on
- (unless window-system
+ (progn
+ ;; Frame creation and deletion.
+ (add-hook 'terminal-init-xterm-hook
+ 'turn-on-xterm-mouse-tracking-on-terminal)
+
+ (add-hook 'delete-frame-functions 'xterm-mouse-handle-delete-frame)
+
+ ;; Restore normal mouse behaviour outside Emacs.
+ (add-hook 'suspend-tty-functions
+ 'turn-off-xterm-mouse-tracking-on-terminal)
+ (add-hook 'resume-tty-functions
+ 'turn-on-xterm-mouse-tracking-on-terminal)
+ (add-hook 'suspend-hook 'turn-off-xterm-mouse-tracking)
+ (add-hook 'suspend-resume-hook 'turn-on-xterm-mouse-tracking)
+ (add-hook 'kill-emacs-hook 'turn-off-xterm-mouse-tracking)
(setq mouse-position-function #'xterm-mouse-position-function)
(turn-on-xterm-mouse-tracking))
;; Turn it off
+ (remove-hook 'delete-frame-functions 'xterm-mouse-handle-delete-frame)
+ (remove-hook 'suspend-tty-functions
+ 'turn-off-xterm-mouse-tracking-on-terminal)
+ (remove-hook 'resume-tty-functions
+ 'turn-on-xterm-mouse-tracking-on-terminal)
+ (remove-hook 'suspend-hook 'turn-off-xterm-mouse-tracking)
+ (remove-hook 'suspend-resume-hook 'turn-on-xterm-mouse-tracking)
+ (remove-hook 'kill-emacs-hook 'turn-off-xterm-mouse-tracking)
(turn-off-xterm-mouse-tracking 'force)
(setq mouse-position-function nil)))
(defun turn-on-xterm-mouse-tracking ()
"Enable Emacs mouse tracking in xterm."
- (if xterm-mouse-mode
- (send-string-to-terminal "\e[?1000h")))
+ (dolist (terminal (delete-dups (mapcar 'frame-terminal (frame-list))))
+ (turn-on-xterm-mouse-tracking-on-terminal terminal)))
(defun turn-off-xterm-mouse-tracking (&optional force)
"Disable Emacs mouse tracking in xterm."
- (if (or force xterm-mouse-mode)
- (send-string-to-terminal "\e[?1000l")))
-
-;; Restore normal mouse behaviour outside Emacs.
-(add-hook 'suspend-hook 'turn-off-xterm-mouse-tracking)
-(add-hook 'suspend-resume-hook 'turn-on-xterm-mouse-tracking)
-(add-hook 'kill-emacs-hook 'turn-off-xterm-mouse-tracking)
+ (dolist (terminal (delete-dups (mapcar 'frame-terminal (frame-list))))
+ (turn-off-xterm-mouse-tracking-on-terminal terminal)))
+
+(defun turn-on-xterm-mouse-tracking-on-terminal (&optional terminal)
+ "Enable xterm mouse tracking on TERMINAL."
+ (when (and xterm-mouse-mode (eq t (terminal-live-p terminal)))
+ (unless (terminal-parameter terminal 'xterm-mouse-mode)
+ ;; Simulate selecting a terminal by selecting one of its frames ;-(
+ (with-selected-frame (car (frames-on-display-list terminal))
+ (define-key input-decode-map "\e[M" 'xterm-mouse-translate))
+ (set-terminal-parameter terminal 'xterm-mouse-mode t))
+ (send-string-to-terminal "\e[?1000h" terminal)))
+
+(defun turn-off-xterm-mouse-tracking-on-terminal (terminal)
+ "Disable xterm mouse tracking on TERMINAL."
+ ;; Only send the disable command to those terminals to which we've already
+ ;; sent the enable command.
+ (when (and (terminal-parameter terminal 'xterm-mouse-mode)
+ (eq t (terminal-live-p terminal)))
+ ;; We could remove the key-binding and unset the `xterm-mouse-mode'
+ ;; terminal parameter, but it seems less harmful to send this escape
+ ;; command too many times (or to catch an unintended key sequence), than
+ ;; to send it too few times (or to fail to let xterm-mouse events
+ ;; pass by untranslated).
+ (send-string-to-terminal "\e[?1000l" terminal)))
+
+(defun xterm-mouse-handle-delete-frame (frame)
+ "Turn off xterm mouse tracking if FRAME is the last frame on its device."
+ (when (and (eq t (frame-live-p frame))
+ (<= 1 (length (frames-on-display-list (frame-terminal frame)))))
+ (turn-off-xterm-mouse-tracking-on-terminal frame)))
(provide 'xt-mouse)
-;;; arch-tag: 84962d4e-fae9-4c13-a9d7-ef4925a4ac03
+;; arch-tag: 84962d4e-fae9-4c13-a9d7-ef4925a4ac03
;;; xt-mouse.el ends here