#15882·warp

Mouse events are dropped for cells covered by a kitty graphics image in alt-screen apps

Author: rchouguleCreated Sep 9, 2026Updated Sep 16, 2026
Labelsbugtriagedrepro:highos:macarea:shell-terminalarea:ui-frameworkarea:terminal-inputwarp:auto-triage-review

Pre-submit Checks

  • I have searched Warp bugs and there are no duplicates
  • I have searched Warp known issues page and my issue is not there
  • I have an issue with AI and have included the debugging ID
  • I have technical issue and have included the logs

Describe the bug

When an alternate-screen application has mouse reporting enabled and displays a kitty graphics image, Warp stops delivering mouse events whose pointer position falls inside the image's rectangle. The application receives nothing at all for those events: no wheel reports, no clicks. Events land normally one column outside the image, and resume the moment the image is deleted. A fully transparent image behaves the same way, so the trigger is the placement itself, not its pixels. kitty, WezTerm and Ghostty deliver these events regardless of images.

In practice this means any TUI that draws an image over its text, for example a highlight band or a preview, loses scrolling and clicking under that image.

To reproduce

  1. Save the script below as repro.py (Python 3 with Pillow, no other dependencies).
  2. Run python3 repro.py in Warp. It enters the alternate screen, enables SGR mouse reporting, prints a numbered ruler and logs every mouse report it receives.
  3. Scroll the wheel over the ruler: report lines appear.
  4. Press i. A framed, transparent kitty image is placed over the pointer's row.
  5. Scroll again with the pointer inside the frame: no report lines. Move the pointer outside the frame on the same row: reports resume.
  6. Press c to delete the image: reports resume everywhere.
repro.py
#!/usr/bin/env python3
"""
Minimal reproduction: Warp swallows ALL mouse reports for cells covered by a
kitty-graphics image placement.

Run it in Warp (needs Pillow):   python3 repro.py
Then follow the on-screen instructions with a real mouse/trackpad.

Expected (correct) behaviour, as in kitty/WezTerm/Ghostty: every scroll notch and
click prints a report line, whether or not it lands on the image.
Observed in Warp 0.2026.07.22.09.01.01: reports stop entirely while the pointer is
inside the image rectangle, and resume the moment it leaves it or the image is deleted.
"""
import base64, io, os, re, select, sys, termios, tty

def png(w, h):
    from PIL import Image
    im = Image.new("RGBA", (w, h), (0, 0, 0, 0))          # fully transparent interior
    for x in range(w):
        im.putpixel((x, 0), (255, 0, 0, 200)); im.putpixel((x, h - 1), (255, 0, 0, 200))
    for y in range(h):
        im.putpixel((0, y), (255, 0, 0, 200)); im.putpixel((w - 1, y), (255, 0, 0, 200))
    b = io.BytesIO(); im.save(b, "PNG"); return base64.standard_b64encode(b.getvalue()).decode()

o = sys.stdout
def w(s): o.write(s); o.flush()

fd = sys.stdin.fileno(); old = termios.tcgetattr(fd); tty.setraw(fd)
w("\x1b[?1049h\x1b[2J\x1b[H\x1b[?1000h\x1b[?1006h")     # alt screen + SGR mouse
try:
    for i in range(1, 25):
        w("row %02d %s\r\n" % (i, "." * 60))
    # a 700x320px translucent placement anchored at row 8, col 3 (a=T, f=100, C=1)
    data = png(700, 320)
    w("\x1b7\x1b[8;3H")
    w("\x1b_Ga=T,f=100,C=1,m=0;%s\x1b\\" % data)
    w("\x1b8\x1b[26;1H")
    w("image placed (red outline). scroll INSIDE it -> no reports; scroll OUTSIDE -> reports.\r\n")
    w("press 'd' to delete the image (reports resume everywhere), 'q' to quit.\r\n")
    sgr = re.compile(rb"\x1b\[<(\d+);(\d+);(\d+)([Mm])")
    n = 0
    while True:
        if not select.select([fd], [], [], 0.2)[0]:
            continue
        b = os.read(fd, 4096)
        if b"q" in b: break
        if b"d" in b: w("\x1b_Ga=d\x1b\\"); w("\r\nimages deleted\r\n")
        for m in sgr.finditer(b):
            n += 1
            w("\r\n#%d  b=%s col=%s row=%s %s" %
              (n, m.group(1).decode(), m.group(2).decode(),
               m.group(3).decode(), m.group(4).decode()))
finally:
    w("\x1b_Ga=d\x1b\\\x1b[?1006l\x1b[?1000l\x1b[?1049l")
    termios.tcsetattr(fd, termios.TCSADRAIN, old)
    print("total mouse reports received: %d" % n)

Expected behavior

Mouse reports are delivered to the application regardless of whether the pointer is over an image placement. Images are decorative and should not capture input.

Where it appears to happen

From reading the source at the current master: app/src/terminal/grid_renderer.rs:593-594 starts a new scene layer for foreground kitty placements, and crates/warpui_core/src/scene.rs:609 records each image's rect into that layer's hit map with click_through false. AltScreenElement::paint captured its own z-index earlier at app/src/terminal/alt_screen/alt_screen_element.rs:686, so Scene::is_covered (scene.rs:400-420) judges the event as covered by an overlay and the element returns false at alt_screen_element.rs:846-849, before the scroll-or-report decision in view.rs is reached. Calling the existing set_active_layer_click_through() right after the image layer is started looks like the fix; I'm happy to open a PR with a regression test if that is welcome.

Screenshots, videos, and logs

None needed; the script above reproduces it in under a minute.

Operating system (OS)

macOS

Operating system and version

macOS 15.5 (24F74)

Shell Version

zsh 5.9

Current Warp version

v0.2026.07.22.09.01.01