Currently, only iTerm2's proprietary format is supported to show icons when you usethe frida-ps command. Modern terminals such as ghostty uses kitty image protocol. By using Claude, I added the kitty image protocol. Git diff is attached.
diff --git a/env/lib/python3.13/site-packages/frida_tools/ps_old.py b/env/lib/python3.13/site-packages/frida_tools/ps.py
index cbdef69..b63b838 100644
--- a/env/lib/python3.13/site-packages/frida_tools/ps_old.py
+++ b/env/lib/python3.13/site-packages/frida_tools/ps.py
@@ -3,6 +3,7 @@ def main() -> None:
import functools
import json
import math
+ import os
import platform
import sys
from base64 import b64encode
@@ -72,7 +73,8 @@ def main() -> None:
self._list_processes()
def _list_processes(self) -> None:
- if not self._exclude_icons and self._output_format == "text" and self._terminal_type == "iterm2":
+ supports_icons = self._terminal_type in ("iterm2", "ghostty")
+ if not self._exclude_icons and self._output_format == "text" and supports_icons:
scope = "full"
else:
scope = "minimal"
@@ -121,7 +123,8 @@ def main() -> None:
self._exit(0)
def _list_applications(self) -> None:
- if not self._exclude_icons and self._output_format == "text" and self._terminal_type == "iterm2":
+ supports_icons = self._terminal_type in ("iterm2", "ghostty")
+ if not self._exclude_icons and self._output_format == "text" and supports_icons:
scope = "full"
else:
scope = "minimal"
@@ -191,14 +194,81 @@ def main() -> None:
self._exit(0)
def _render_icon(self, icon) -> str:
+ if self._terminal_type == "ghostty":
+ return self._render_icon_kitty(icon)
+ # iTerm2 inline image protocol
return "\033]1337;File=inline=1;width={}px;height={}px;:{}\007".format(
self._icon_size, self._icon_size, b64encode(icon["image"]).decode("ascii")
)
+ def _render_icon_kitty(self, icon) -> str:
+ image_data = b64encode(icon["image"]).decode("ascii")
+ # Split payload into ≤4096-byte chunks as required by the protocol.
+ chunk_size = 4096
+ chunks = [image_data[i:i + chunk_size] for i in range(0, len(image_data), chunk_size)]
+
+ result = ""
+ for idx, chunk in enumerate(chunks):
+ is_last = idx == len(chunks) - 1
+ more = 0 if is_last else 1
+ if idx == 0:
+ # First chunk: include all display parameters.
+ # a=T – transmit and display immediately
+ # f=100 – PNG format
+ # c=1,r=1 – occupy exactly 1 column × 1 row in the grid
+ # m=<more> – continuation flag
+ header = f"a=T,f=100,c=2,r=1,m={more}"
+ else:
+ header = f"a=T,m={more}"
+ result += f"\033_G{header};{chunk}\033\\"
+
+ return result
+
def _detect_terminal(self) -> Tuple[str, int]:
icon_size = 0
- if not self._have_terminal or self._plain_terminal or platform.system() != "Darwin":
+ if not self._have_terminal or self._plain_terminal:
+ return ("simple", icon_size)
+
+ # ------------------------------------------------------------------
+ # Ghostty detection: it sets TERM_PROGRAM=ghostty and supports the
+ # Kitty graphics protocol. We query the cell size in pixels with
+ # the XTWINOPS escape \033[16t which returns \033[6;<h>;<w>t so we
+ # can compute a reasonable icon_size (one cell tall).
+ # Ghostty runs on Linux and macOS so we skip the Darwin-only guard.
+ # ------------------------------------------------------------------
+ if os.environ.get("TERM_PROGRAM") == "ghostty":
+ try:
+ fd = sys.stdin.fileno()
+ old_attributes = termios.tcgetattr(fd)
+ try:
+ tty.setraw(fd)
+ new_attributes = termios.tcgetattr(fd)
+ new_attributes[3] = new_attributes[3] & ~termios.ICANON & ~termios.ECHO
+ termios.tcsetattr(fd, termios.TCSANOW, new_attributes)
+
+ # Query cell size in pixels: response is ESC[6;<height>;<width>t
+ sys.stdout.write("\033[16t")
+ sys.stdout.flush()
+ cell_response = self._read_terminal_response("t")
+ # cell_response looks like "6;<height>;<width>"
+ parts = cell_response.split(";")
+ if len(parts) >= 2:
+ cell_height_px = int(parts[1])
+ icon_size = max(cell_height_px, 16) # at least 16 px
+ else:
+ icon_size = 16
+ finally:
+ termios.tcsetattr(fd, termios.TCSANOW, old_attributes)
+ except Exception:
+ icon_size = 16 # safe fallback
+
+ return ("ghostty", icon_size)
+
+ # ------------------------------------------------------------------
+ # Original iTerm2 detection (Darwin only)
+ # ------------------------------------------------------------------
+ if platform.system() != "Darwin":
return ("simple", icon_size)
fd = sys.stdin.fileno()
@@ -291,4 +361,4 @@ if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
- pass
+ pass
\ No newline at end of file
Currently, only iTerm2's proprietary format is supported to show icons when you usethe
frida-pscommand. Modern terminals such as ghostty uses kitty image protocol. By using Claude, I added the kitty image protocol. Git diff is attached.