aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/term
diff options
context:
space:
mode:
authorJared Finder2025-12-29 12:35:24 -0800
committerSean Whitton2026-01-10 12:49:43 +0000
commit4e779d20f1840fef380f5688ceb2cd80658bde0b (patch)
tree79ad054524a73dced6d382a99d0a6a476f7ad1f9 /lisp/term
parent88d3101fdd10f5e922aae9d99fcfd103a33747db (diff)
downloademacs-4e779d20f1840fef380f5688ceb2cd80658bde0b.tar.gz
emacs-4e779d20f1840fef380f5688ceb2cd80658bde0b.zip
Update cursor display using Xterm escape sequences
* lisp/term/xterm.el (xterm-update-cursor): New user option. (xterm--init): Use it. (xterm--post-command-hook): New function for all xterm functionality installed in 'post-command-hook'. (xterm--init-frame-title): Install it. (xterm--init-update-cursor, xterm--set-cursor-type) (xterm--update-cursor-type, xterm--update-cursor-color): New functions. (xterm--cursor-type-to-int): New constant. * doc/emacs/display.texi (Cursor Display): * etc/NEWS: Document the new feature.
Diffstat (limited to 'lisp/term')
-rw-r--r--lisp/term/xterm.el111
1 files changed, 110 insertions, 1 deletions
diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index dd179c4e3eb..47e82decb03 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -80,6 +80,20 @@ capabilities, and only when that terminal understands bracketed paste."
80 :version "28.1" 80 :version "28.1"
81 :type 'boolean) 81 :type 'boolean)
82 82
83(defcustom xterm-update-cursor nil
84 "If non-nil, try to update the cursor's appearance on XTerm terminals.
85
86If set to t all supported attributes of the cursor are updated.
87If set to `type' only the cursor type is updated. This uses the CSI
88DECSCUSR escape sequence.
89If set to `color' only the cursor color is updated. This uses the OSC
9012 escape sequence."
91 :version "31.1"
92 :type '(radio (const :tag "Do not update" nil)
93 (const :tag "Update" t)
94 (const :tag "Update type only" type)
95 (const :tag "Update color only" color)))
96
83(defconst xterm-paste-ending-sequence "\e[201~" 97(defconst xterm-paste-ending-sequence "\e[201~"
84 "Characters sent by the terminal to end a bracketed paste.") 98 "Characters sent by the terminal to end a bracketed paste.")
85 99
@@ -988,6 +1002,8 @@ We run the first FUNCTION whose STRING matches the input events."
988 1002
989 (when xterm-set-window-title 1003 (when xterm-set-window-title
990 (xterm--init-frame-title)) 1004 (xterm--init-frame-title))
1005 (when xterm-update-cursor
1006 (xterm--init-update-cursor))
991 1007
992 (let ((bg-color (terminal-parameter nil 'xterm--background-color)) 1008 (let ((bg-color (terminal-parameter nil 'xterm--background-color))
993 (fg-color (terminal-parameter nil 'xterm--foreground-color))) 1009 (fg-color (terminal-parameter nil 'xterm--foreground-color)))
@@ -1025,6 +1041,17 @@ We run the first FUNCTION whose STRING matches the input events."
1025 ;; We likewise unconditionally enable support for focus tracking. 1041 ;; We likewise unconditionally enable support for focus tracking.
1026 (xterm--init-focus-tracking)) 1042 (xterm--init-focus-tracking))
1027 1043
1044(defun xterm--post-command-hook ()
1045 "Hook for xterm features that need to be frequently updated."
1046
1047 (unless (display-graphic-p)
1048 (when xterm-set-window-title
1049 (xterm-set-window-title))
1050 (when (memq xterm-update-cursor '(t type))
1051 (xterm--update-cursor-type))
1052 (when (memq xterm-update-cursor '(t color))
1053 (xterm--update-cursor-color))))
1054
1028(defun terminal-init-xterm () 1055(defun terminal-init-xterm ()
1029 "Terminal initialization function for xterm." 1056 "Terminal initialization function for xterm."
1030 (unwind-protect 1057 (unwind-protect
@@ -1067,7 +1094,7 @@ We run the first FUNCTION whose STRING matches the input events."
1067 (xterm-set-window-title) 1094 (xterm-set-window-title)
1068 (add-hook 'after-make-frame-functions 'xterm-set-window-title-flag) 1095 (add-hook 'after-make-frame-functions 'xterm-set-window-title-flag)
1069 (add-hook 'window-configuration-change-hook 'xterm-unset-window-title-flag) 1096 (add-hook 'window-configuration-change-hook 'xterm-unset-window-title-flag)
1070 (add-hook 'post-command-hook 'xterm-set-window-title) 1097 (add-hook 'post-command-hook 'xterm--post-command-hook)
1071 (add-hook 'minibuffer-exit-hook 'xterm-set-window-title)) 1098 (add-hook 'minibuffer-exit-hook 'xterm-set-window-title))
1072 1099
1073(defvar xterm-window-title-flag nil 1100(defvar xterm-window-title-flag nil
@@ -1300,6 +1327,88 @@ versions of xterm."
1300 (b (caddr fg-color))) 1327 (b (caddr fg-color)))
1301 (set-face-foreground 'default (format "#%04x%04x%04x" r g b) frame))))) 1328 (set-face-foreground 'default (format "#%04x%04x%04x" r g b) frame)))))
1302 1329
1330(defun xterm--init-update-cursor ()
1331 "Register hooks to run `xterm--update-cursor-type' appropriately."
1332
1333 (when (memq xterm-update-cursor '(color t))
1334 (xterm--query
1335 "\e]12;?\e\\"
1336 '(("\e]12;" . (lambda ()
1337 (let ((str (xterm--read-string ?\e ?\\)))
1338 ;; The response is specifically formated to set the
1339 ;; color
1340 (push
1341 (concat "\e]12;" str "\e\\")
1342 (terminal-parameter nil 'tty-mode-reset-strings)))))))
1343 ;; No need to set tty-mode-set-strings because
1344 ;; xterm--post-command-hook handles restoring the cursor color.
1345
1346 (xterm--update-cursor-color))
1347
1348 (when (memq xterm-update-cursor '(type t))
1349 (xterm--update-cursor-type))
1350
1351 (add-hook 'post-command-hook 'xterm--post-command-hook))
1352
1353(defconst xterm--cursor-type-to-int
1354 '(nil 0
1355 box 1
1356 hollow 1
1357 bar 5
1358 hbar 3)
1359 "Mapping of cursor type symbols to control sequence integers.
1360
1361Cursor type symbols are the same as for `cursor-type'.")
1362
1363(defun xterm--set-cursor-type (terminal type)
1364 (let ((type-int (or (plist-get xterm--cursor-type-to-int type) 1))
1365 (old (terminal-parameter terminal 'xterm--cursor-style)))
1366
1367 (when old
1368 (set-terminal-parameter
1369 terminal
1370 'tty-mode-set-strings
1371 (delete (format "\e[%d q" old)
1372 (terminal-parameter terminal 'tty-mode-set-strings))))
1373 (let ((set-string (format "\e[%d q" type-int)))
1374 (push set-string (terminal-parameter terminal 'tty-mode-set-strings))
1375 (send-string-to-terminal set-string terminal))
1376 (unless old
1377 ;; Assume that the default cursor is appropriate when exiting Emacs.
1378 (push "\e[0 q" (terminal-parameter terminal 'tty-mode-reset-strings)))
1379
1380 (set-terminal-parameter terminal 'xterm--cursor-type type-int)))
1381
1382(defun xterm--update-cursor-type ()
1383 "Update the cursor type for Xterm-compatible terminals.
1384This updates the selected frame's terminal based on `cursor-type'."
1385 (let ((buffer-cursor cursor-type)
1386 (window-cursor (window-cursor-type))
1387 (frame-cursor (frame-parameter nil 'cursor-type))
1388 type)
1389 ;; All of them can be conses, in which case the type symbol is the car.
1390 (when (consp buffer-cursor) (setf buffer-cursor (car buffer-cursor)))
1391 (when (consp window-cursor) (setf window-cursor (car window-cursor)))
1392 (when (consp frame-cursor) (setf frame-cursor (car frame-cursor)))
1393
1394 (cond
1395 ((not (eq window-cursor t))
1396 (setf type window-cursor))
1397 ((not (eq buffer-cursor t))
1398 (setf type buffer-cursor))
1399 (t
1400 (setf type frame-cursor)))
1401 (xterm--set-cursor-type nil type)))
1402
1403(defun xterm--update-cursor-color ()
1404 "Update the cursor color for Xterm-compatible terminals.
1405This updates the selected frame's terminal based on the face `cursor'."
1406 (let* ((color (color-values (face-background 'cursor)))
1407 (r (nth 0 color))
1408 (g (nth 1 color))
1409 (b (nth 2 color)))
1410 (send-string-to-terminal (format "\e]12;rgb:%04x/%04x/%04x\e\\" r g b))))
1411
1303(provide 'xterm) ;Backward compatibility. 1412(provide 'xterm) ;Backward compatibility.
1304(provide 'term/xterm) 1413(provide 'term/xterm)
1305;;; xterm.el ends here 1414;;; xterm.el ends here