diff --git a/README.org b/README.org index 48f8f5ad..7257ee24 100644 --- a/README.org +++ b/README.org @@ -944,6 +944,10 @@ Pixel data is rendered through Emacs's built-in image support: PNG payloads are decoded by a vendored stb_image, and raw RGB/RGBA/Gray/GrayAlpha transmissions are converted to PPM in the native module - no external ImageMagick dependency. +Images need a graphical frame. Buffers created in a terminal frame (=emacs +-nw=, =emacsclient -t=) do not advertise the protocol, so apps that probe for +it fall back to their own text rendering. + XTWINOPS size queries (CSI 14 / 16 / 18 t) are answered so apps can detect graphics support and pick image dimensions; without that, =timg= falls back to half-block rendering even when =TERM_PROGRAM=ghostty=. diff --git a/lisp/ghostel.el b/lisp/ghostel.el index e18132a9..b7ad8923 100644 --- a/lisp/ghostel.el +++ b/lisp/ghostel.el @@ -5285,10 +5285,15 @@ spawn after initialization." (if (window-live-p w) (window-max-chars-per-line w) 80))))) + ;; A TTY frame cannot show images: disable the protocol so apps' + ;; support probes fail and they fall back to text rendering. (setq ghostel--term (ghostel--new height width ghostel-max-scrollback - ghostel-kitty-graphics-storage-limit + (if (or (display-graphic-p (window-frame w)) + (ghostel--daemon-dummy-frame-p (window-frame w))) + ghostel-kitty-graphics-storage-limit + 0) (ghostel--kitty-mediums-bits))) ;; Seed libghostty's cell dimensions before the process starts — ;; otherwise kitty graphics placements arriving in the very first diff --git a/test/ghostel-exec-test.el b/test/ghostel-exec-test.el index e7f4d65c..0873b91e 100644 --- a/test/ghostel-exec-test.el +++ b/test/ghostel-exec-test.el @@ -53,6 +53,7 @@ buffer eventually shows up." ;; Sanity: the buffer is not displayed in any window. (should-not (get-buffer-window buf t)) (cl-letf (((symbol-function 'ghostel--load-module) #'ignore) + ((symbol-function 'display-graphic-p) (lambda (&rest _) t)) ((symbol-function 'ghostel--new) (lambda (&rest args) (setq captured args) 'fake-term)) ((symbol-function 'ghostel--set-size-with-cell-dims) #'ignore) diff --git a/test/ghostel-kitty-test.el b/test/ghostel-kitty-test.el index cc012e5f..51b7ce73 100644 --- a/test/ghostel-kitty-test.el +++ b/test/ghostel-kitty-test.el @@ -25,6 +25,30 @@ they do under a `default' face remap." ((symbol-function 'default-font-height) (lambda () 16))) (funcall body)))) +(defun ghostel-test--kitty-init-storage-limit (graphic &optional dummy) + "Return the storage limit `ghostel--init-buffer' passes on a GRAPHIC frame. +DUMMY non-nil fakes the daemon's initial frame." + (let (limit) + (with-temp-buffer + (cl-letf (((symbol-function 'display-graphic-p) (lambda (&rest _) graphic)) + ((symbol-function 'ghostel--daemon-dummy-frame-p) (lambda (_) dummy)) + ((symbol-function 'ghostel--new) + (lambda (_h _w _sb storage _mediums) + (setq limit storage) 'fake-term)) + ((symbol-function 'ghostel--set-size-with-cell-dims) #'ignore) + ((symbol-function 'ghostel--apply-palette) #'ignore) + ((symbol-function 'ghostel--apply-bold-config) #'ignore)) + (ghostel--init-buffer (current-buffer) 24 80))) + limit)) + +(ert-deftest ghostel-test-kitty-disabled-on-tty-frame () + "A terminal frame creates the terminal with kitty graphics disabled." + (should (eql 0 (ghostel-test--kitty-init-storage-limit nil))) + (should (eql ghostel-kitty-graphics-storage-limit + (ghostel-test--kitty-init-storage-limit t))) + (should (eql ghostel-kitty-graphics-storage-limit + (ghostel-test--kitty-init-storage-limit nil t)))) + (ert-deftest ghostel-test-detect-cell-pixel-scale-standard-dpi () "96 DPI display resolves to ~1.0 (no scaling)." (cl-letf (((symbol-function 'display-graphic-p) (lambda () t))