diff --git a/src/terminal/c/terminal.zig b/src/terminal/c/terminal.zig index 5bf2c750c..aed48e25f 100644 --- a/src/terminal/c/terminal.zig +++ b/src/terminal/c/terminal.zig @@ -105,9 +105,10 @@ const TerminalWrapper = struct { /// created by `new` or transferred from snapshot decoding until `free`. /// Freestanding owners contain no native allocation and expose failing I/O. io: Io, - /// We also need to store a temp dir path for some operations (e.g., kitty - /// graphics). This provides stable storage for the API calls. - tmp_dir_path: [max_path_bytes]u8, + /// Allocator-owned copy of the temporary directory path for some + /// operations (e.g. kitty graphics). This is only allocated once the + /// embedder sets the option. + tmp_dir_path: ?[]u8 = null, /// The terminfo name reported for XTGETTCAP "TN". The stream handler holds /// a slice into this. terminfo_name_buf: [Handler.max_terminfo_name_bytes]u8, @@ -728,7 +729,6 @@ fn wrap( wrapper.* = .{ .terminal = t, .io = io, - .tmp_dir_path = undefined, .terminfo_name_buf = undefined, .stream = Stream.init(.{ .allocator = alloc, @@ -1393,22 +1393,31 @@ fn setTyped( }, .kitty_image_medium_temp_file => { if (comptime !build_options.kitty_graphics) return .success; + const alloc = wrapper.terminal.gpa(); if (value) |v| { - if (v.len > wrapper.tmp_dir_path.len) return .out_of_memory; - @memcpy(wrapper.tmp_dir_path[0..v.len], v.ptr[0..v.len]); + if (v.len > max_path_bytes) return .out_of_memory; + const path = alloc.dupe(u8, v.ptr[0..v.len]) catch + return .out_of_memory; var it = wrapper.terminal.screens.all.iterator(); while (it.next()) |entry| { const screen = entry.value.*; screen.kitty_images.image_limits.temporary_file = .{ - .enabled = .{ .directory = wrapper.tmp_dir_path[0..v.len] }, + .enabled = .{ .directory = path }, }; } + + // Every screen points at the new copy now so the previous + // one can be released. + if (wrapper.tmp_dir_path) |old| alloc.free(old); + wrapper.tmp_dir_path = path; } else { var it = wrapper.terminal.screens.all.iterator(); while (it.next()) |entry| { const screen = entry.value.*; screen.kitty_images.image_limits.temporary_file = .disabled; } + if (wrapper.tmp_dir_path) |old| alloc.free(old); + wrapper.tmp_dir_path = null; } }, .apc_max_bytes => { @@ -1861,6 +1870,7 @@ pub fn free(terminal_: Terminal) callconv(lib.calling_conv) void { wrapper.searches.deinit(alloc); wrapper.stream.deinit(); t.deinit(alloc); + if (wrapper.tmp_dir_path) |path| alloc.free(path); wrapper.io.deinit(alloc); alloc.destroy(t); alloc.destroy(wrapper);