diff options
| -rw-r--r-- | lisp/xterm-kitty.el | 74 |
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 |
