summaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp')
-rw-r--r--lisp/xterm-kitty.el74
1 files changed, 73 insertions, 1 deletions
diff --git a/lisp/xterm-kitty.el b/lisp/xterm-kitty.el
index 6610e86..ea88cc2 100644
--- a/lisp/xterm-kitty.el
+++ b/lisp/xterm-kitty.el
@@ -385,7 +385,79 @@ function is almost equivalent to 'event-convert-list'."
"This one should be replaced by init-terminal-xterm-kitty; just a hack for now."
(when xterm-kitty-in-use
(setq xterm-extra-capabilities '(reportBackground getSelection setSelection))
- (add-hook 'terminal-init-xterm-hook 'xterm-kitty-apply-keyboard)))
+ (add-hook 'terminal-init-xterm-hook 'xterm-kitty-apply-keyboard)
+ (add-hook 'terminal-init-xterm-hook 'xterm-kitty-save-window-id)
+ (xterm-kitty-add-select-frame-set-input-focus-advice)))
+
+(defvar xterm-kitty--window-id-hash-table ; private storage
+ (make-hash-table :test #'equal)
+ "Map of terminals (windows in kitty parlance) to kitty window ids")
+(defun xterm-kitty-window-id (&optional terminal) ; public API
+ (gethash (terminal-name terminal) xterm-kitty--window-id-hash-table))
+
+(defun xterm-kitty--remote-control-response ()
+ (let ((str "")
+ prev-chr
+ chr
+ parsed
+ payload)
+ ;; The reply should be: \eP@kitty-cmd{"ok": true, "data": payload}\e\\
+ (while (and (setq chr (xterm--read-event-for-query))
+ (not (and (equal prev-chr ?\e) (equal chr ?\\))))
+ (when prev-chr (setq str (concat str (string prev-chr))))
+ (setq prev-chr chr))
+ (setq parsed-data (json-parse-string str))
+ (when (and (hash-table-p parsed-data) (eql (gethash "ok" parsed-data) t))
+ (setq payload (gethash "data" parsed-data)))
+ payload))
+
+(defun xterm-kitty--elem-has-focus (h)
+ (eq (gethash "is_focused" h) t))
+(defun xterm-kitty--save-kitty-window-id ()
+ (let* ((kitty-response (xterm-kitty--remote-control-response))
+ (response-json (json-parse-string kitty-response))
+ (os-win (seq-find 'xterm-kitty--elem-has-focus response-json))
+ (win-tab (and os-win (seq-find 'xterm-kitty--elem-has-focus (gethash "tabs" os-win))))
+ (win (and win-tab (seq-find 'xterm-kitty--elem-has-focus (gethash "windows" win-tab))))
+ (window-id (and win (gethash "id" win))))
+ (puthash (terminal-name) window-id xterm-kitty--window-id-hash-table)))
+
+(defun xterm-kitty-save-window-id ()
+ "Save kitty window ID of current terminal"
+ (when xterm-kitty-in-use
+ (xterm--query "\eP@kitty-cmd{\"cmd\":\"ls\",\"version\":[0,19,3]}\e\\"
+ '(("\eP@kitty-cmd" . xterm-kitty--save-kitty-window-id)))))
+
+(defvar xterm-kitty--focus-window-command-string
+ "\eP@kitty-cmd{\"cmd\":\"focus-window\",\"version\":[0,19,3],\"no_response\":true,\"payload\":{\"match\":\"id:%d\"}}\e\\"
+ "Command string to send to kitty to focus kitty window; must have a single placeholder %d")
+(defun xterm-kitty-focus (frame-or-window)
+ "Set focus to terminal containing FRAME-OR-WINDOW
+
+ FRAME-OR-WINDOW can be a terminal, a frame, or a window"
+ (let* ((frame (if (windowp frame-or-window)
+ (window-frame frame-or-window)
+ frame-or-window))
+ (kitty-window-id (and xterm-kitty-in-use (xterm-kitty-window-id frame))))
+ ;; (message "Window id %d for %s" kitty-window-id frame)
+ (when kitty-window-id
+ (send-string-to-terminal (format xterm-kitty--focus-window-command-string kitty-window-id)))))
+(defun xterm-kitty-select-frame-set-input-focus-advice (old-function frame &optional no-record)
+ (or (when xterm-kitty-in-use
+ ;; (message "Switching to frame: %s" frame)
+ (xterm-kitty-focus frame)
+ (select-frame frame no-record))
+ (funcall old-function frame no-record)))
+(defun xterm-kitty-visible-window-advice (old-function &optional window minibuf all-frames)
+ (when xterm-kitty-in-use
+ ;; Terminal emacs thinks that only one frame is ever visible
+ (funcall old-function window minibuf (if (eql all-frames 'visible) t all-frames))))
+(defun xterm-kitty-add-select-frame-set-input-focus-advice ()
+ "Advise SELECT-FRAME-SET-INPUT-FOCUS to handle xterm-kitty terminal windows"
+ (interactive)
+ (advice-add 'select-frame-set-input-focus :around #'xterm-kitty-select-frame-set-input-focus-advice)
+ (advice-add 'next-window :around #'xterm-kitty-visible-window-advice)
+ (advice-add 'previous-window :around #'xterm-kitty-visible-window-advice))
(provide 'xterm-kitty)
;;; xterm-kitty.el ends here