config: image-storage-limit to set maximum image memory per terminal

This commit is contained in:
Mitchell Hashimoto
2023-08-23 16:58:16 -07:00
parent 79ea2ff2db
commit 46ba3189f6
4 changed files with 58 additions and 0 deletions

View File

@ -186,6 +186,15 @@ pub const Config = struct {
/// This does not affect data sent to the clipboard via "clipboard-write". /// This does not affect data sent to the clipboard via "clipboard-write".
@"clipboard-trim-trailing-spaces": bool = true, @"clipboard-trim-trailing-spaces": bool = true,
/// The total amount of bytes that can be used for image data (i.e.
/// the Kitty image protocol) per terminal scren. The maximum value
/// is 4,294,967,295 (4GB). The default is 320MB. If this is set to zero,
/// then all image protocols will be disabled.
///
/// This value is separate for primary and alternate screens so the
/// effective limit per surface is double.
@"image-storage-limit": u32 = 320 * 1000 * 1000,
/// Whether to automatically copy selected text to the clipboard. "true" /// Whether to automatically copy selected text to the clipboard. "true"
/// will only copy on systems that support a selection clipboard. /// will only copy on systems that support a selection clipboard.
/// ///

View File

@ -26,6 +26,11 @@ pub fn execute(
terminal: *Terminal, terminal: *Terminal,
cmd: *Command, cmd: *Command,
) ?Response { ) ?Response {
// If storage is disabled then we disable the full protocol. This means
// we don't even respond to queries so the terminal completely acts as
// if this feature is not supported.
if (!terminal.screen.kitty_images.enabled()) return null;
log.debug("executing kitty graphics command: {}", .{cmd.control}); log.debug("executing kitty graphics command: {}", .{cmd.control});
const resp_: ?Response = switch (cmd.control) { const resp_: ?Response = switch (cmd.control) {

View File

@ -57,6 +57,34 @@ pub const ImageStorage = struct {
self.placements.deinit(alloc); self.placements.deinit(alloc);
} }
/// Kitty image protocol is enabled if we have a non-zero limit.
pub fn enabled(self: *const ImageStorage) bool {
return self.total_limit != 0;
}
/// Sets the limit in bytes for the total amount of image data that
/// can be loaded. If this limit is lower, this will do an eviction
/// if necessary. If the value is zero, then Kitty image protocol will
/// be disabled.
pub fn setLimit(self: *ImageStorage, alloc: Allocator, limit: usize) !void {
// Special case disabling by quickly deleting all
if (limit == 0) {
self.deinit(alloc);
self.* = .{};
}
// If we re lowering our limit, check if we need to evict.
if (limit < self.total_bytes) {
const req_bytes = self.total_bytes - limit;
log.info("evicting images to lower limit, evicting={}", .{req_bytes});
if (!try self.evictImage(alloc, req_bytes)) {
log.warn("failed to evict enough images for required bytes", .{});
}
}
self.total_limit = limit;
}
/// Add an already-loaded image to the storage. This will automatically /// Add an already-loaded image to the storage. This will automatically
/// free any existing image with the same ID. /// free any existing image with the same ID.
pub fn addImage(self: *ImageStorage, alloc: Allocator, img: Image) Allocator.Error!void { pub fn addImage(self: *ImageStorage, alloc: Allocator, img: Image) Allocator.Error!void {

View File

@ -71,6 +71,7 @@ data: ?*EventData,
/// pass around Config pointers which makes memory management a pain. /// pass around Config pointers which makes memory management a pain.
pub const DerivedConfig = struct { pub const DerivedConfig = struct {
palette: terminal.color.Palette, palette: terminal.color.Palette,
image_storage_limit: usize,
pub fn init( pub fn init(
alloc_gpa: Allocator, alloc_gpa: Allocator,
@ -80,6 +81,7 @@ pub const DerivedConfig = struct {
return .{ return .{
.palette = config.palette.value, .palette = config.palette.value,
.image_storage_limit = config.@"image-storage-limit",
}; };
} }
@ -106,6 +108,10 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec {
term.width_px = opts.screen_size.width; term.width_px = opts.screen_size.width;
term.height_px = opts.screen_size.height; term.height_px = opts.screen_size.height;
// Set the image size limits
try term.screen.kitty_images.setLimit(alloc, opts.config.image_storage_limit);
try term.secondary_screen.kitty_images.setLimit(alloc, opts.config.image_storage_limit);
var subprocess = try Subprocess.init(alloc, opts); var subprocess = try Subprocess.init(alloc, opts);
errdefer subprocess.deinit(); errdefer subprocess.deinit();
@ -244,6 +250,16 @@ pub fn changeConfig(self: *Exec, config: *DerivedConfig) !void {
// Update the palette. Note this will only apply to new colors drawn // Update the palette. Note this will only apply to new colors drawn
// since we decode all palette colors to RGB on usage. // since we decode all palette colors to RGB on usage.
self.terminal.color_palette = config.palette; self.terminal.color_palette = config.palette;
// Set the image size limits
try self.terminal.screen.kitty_images.setLimit(
self.alloc,
config.image_storage_limit,
);
try self.terminal.secondary_screen.kitty_images.setLimit(
self.alloc,
config.image_storage_limit,
);
} }
/// Resize the terminal. /// Resize the terminal.