diff options
Diffstat (limited to 'src/tty/tty.zig')
| -rw-r--r-- | src/tty/tty.zig | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/src/tty/tty.zig b/src/tty/tty.zig index e2fe10e8..f0013020 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -143,7 +143,12 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void { // pane unless this is in the env BEFORE bash starts (the rc is too late) if (comptime builtin.os.tag.isDarwin()) _ = setenv("BASH_SILENCE_DEPRECATION_WARNING", "1", 1); - var kitty_handles: [pardes.MAX_PANES]?vaxis.Image = @splat(null); + const KittyCached = struct { serial: u32, image: vaxis.Image }; + var kitty_handles: [pardes.MAX_PANES]?KittyCached = @splat(null); + defer for (&kitty_handles) |*slot| if (slot.*) |cached| { + vx.freeImage(tty.writer(), cached.image.id); + slot.* = null; + }; var ptys: [pardes.MAX_PANES]?Pty = @splat(null); // per-slot spawn generation: a reused pane id ignores the old shell's // late pty_eof (which would otherwise close the NEW pty on that slot) @@ -392,7 +397,11 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void { // `watch off` effects go into a queue nobody drains — drop the lot // here. The new core emits its own `on`s as it builds its panes. for (0..watches.len) |wid| watchPane(inotify_fd, &watches, @intCast(wid), null, 0); - kitty_handles = @splat(null); + for (&kitty_handles) |*slot| if (slot.*) |cached| { + vx.freeImage(tty.writer(), cached.image.id); + slot.* = null; + }; + nc.native_images = vx.caps.kitty_graphics; core.deinit(); core = nc; } @@ -414,6 +423,10 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void { if (caps_pending and vx.queries_done.load(.unordered)) { caps_pending = false; vx.enableDetectedFeatures(tty.writer()) catch {}; + // The core was constructed before the asynchronous handshake. + // Advertise native pixels only now, after every reply preceding + // DA1 has updated the capability set. + core.native_images = vx.caps.kitty_graphics; vx.queueRefresh(); } @@ -438,23 +451,39 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void { } } tz_cells.end(); - // pixel attachments (kitty graphics): transmit once per pane, then - // re-place every frame (placements aren't persistent) + // Pixel attachments (kitty graphics): transmit once per pane + // generation, then re-place every frame (placements aren't + // persistent). A slot can be closed and reused for an unrelated pane, + // so the pane number by itself is not a cache key. + var kitty_seen: [pardes.MAX_PANES]bool = @splat(false); for (surface.images[0..surface.nimages]) |maybe| { const place = maybe orelse continue; + kitty_seen[place.pane] = true; + if (kitty_handles[place.pane]) |cached| if (cached.serial != place.serial) { + vx.freeImage(tty.writer(), cached.image.id); + kitty_handles[place.pane] = null; + }; if (kitty_handles[place.pane] == null and vx.caps.kitty_graphics) { const enc = std.base64.standard.Encoder; if (gpa.alloc(u8, enc.calcSize(place.rgba.len))) |b64| { defer gpa.free(b64); _ = enc.encode(b64, place.rgba); - kitty_handles[place.pane] = vx.transmitPreEncodedImage(tty.writer(), b64, @intCast(place.iw), @intCast(place.ih), .rgba) catch null; + if (vx.transmitPreEncodedImage(tty.writer(), b64, @intCast(place.iw), @intCast(place.ih), .rgba) catch null) |handle| + kitty_handles[place.pane] = .{ .serial = place.serial, .image = handle }; } else |_| {} } - if (kitty_handles[place.pane]) |h| { + if (kitty_handles[place.pane]) |cached| { const child = win.child(.{ .x_off = place.x, .y_off = place.y, .width = place.w, .height = place.h }); - h.draw(child, .{ .scale = .contain }) catch {}; + cached.image.draw(child, .{ .scale = .contain }) catch {}; } } + // Toggling PETSCII or closing a pane removes its attachment from the + // Surface. Release the terminal-side image then, not merely when that + // numeric pane slot happens to be reused. + for (&kitty_handles, kitty_seen) |*slot, seen| if (!seen) if (slot.*) |cached| { + vx.freeImage(tty.writer(), cached.image.id); + slot.* = null; + }; if (surface.cursor) |cur| { win.showCursor(cur.x, cur.y); // insert = beam, everything else = the terminal's default shape |
