diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 77e05b092..f93ec999c 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -257,6 +257,12 @@ pub const Options = struct { /// screen. Kitty image storage is per-screen. kitty_image_storage_limit: usize = 320 * 1000 * 1000, // 320MB + /// The limits for what medium types are allowed for Kitty image loading. + kitty_image_loading_limits: if (build_options.kitty_graphics) + kitty.graphics.LoadingImage.Limits + else + void = if (build_options.kitty_graphics) .direct else {}, + /// A simple, default terminal. If you rely on specific dimensions or /// scrollback (or lack of) then do not use this directly. This is just /// for callers that need some defaults. @@ -313,6 +319,7 @@ pub fn init( &result, opts.kitty_image_storage_limit, ) catch unreachable; + result.kitty_images.image_limits = opts.kitty_image_loading_limits; } return result; diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 99536e7ab..0dfde8236 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -2693,6 +2693,34 @@ pub fn kittyGraphics( return kitty.graphics.execute(alloc, self, cmd); } +/// Set the storage size limit for Kitty graphics across all screens. +pub fn setKittyGraphicsSizeLimit( + self: *Terminal, + alloc: Allocator, + limit: usize, +) !void { + if (comptime !build_options.kitty_graphics) return; + var it = self.screens.all.iterator(); + while (it.next()) |entry| { + const screen: *Screen = entry.value.*; + try screen.kitty_images.setLimit(alloc, screen, limit); + } +} + +/// Set the allowed medium types for Kitty graphics image loading +/// across all screens. +pub fn setKittyGraphicsLoadingLimits( + self: *Terminal, + limits: kitty.graphics.LoadingImage.Limits, +) void { + if (comptime !build_options.kitty_graphics) return; + var it = self.screens.all.iterator(); + while (it.next()) |entry| { + const screen: *Screen = entry.value.*; + screen.kitty_images.image_limits = limits; + } +} + /// Set a style attribute. pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void { try self.screens.active.setAttribute(attr); @@ -2941,12 +2969,15 @@ pub fn switchScreen(self: *Terminal, key: ScreenSet.Key) !?*Screen { .alternate => 0, }, - // Inherit our Kitty image storage limit from the primary + // Inherit our Kitty image settings from the primary // screen if we have to initialize. .kitty_image_storage_limit = if (comptime build_options.kitty_graphics) primary.kitty_images.total_limit else 0, + .kitty_image_loading_limits = if (comptime build_options.kitty_graphics) + primary.kitty_images.image_limits + else {}, }, ); }; diff --git a/src/terminal/kitty/graphics.zig b/src/terminal/kitty/graphics.zig index c710f81a1..6659cd310 100644 --- a/src/terminal/kitty/graphics.zig +++ b/src/terminal/kitty/graphics.zig @@ -25,6 +25,7 @@ pub const unicode = @import("graphics_unicode.zig"); pub const Command = command.Command; pub const CommandParser = command.Parser; pub const Image = image.Image; +pub const LoadingImage = image.LoadingImage; pub const ImageStorage = storage.ImageStorage; pub const RenderPlacement = render.Placement; pub const Response = command.Response; diff --git a/src/terminal/kitty/graphics_exec.zig b/src/terminal/kitty/graphics_exec.zig index faac9ab75..a6a879e58 100644 --- a/src/terminal/kitty/graphics_exec.zig +++ b/src/terminal/kitty/graphics_exec.zig @@ -44,7 +44,7 @@ pub fn execute( var quiet = cmd.quiet; const resp_: ?Response = switch (cmd.control) { - .query => query(alloc, cmd), + .query => query(alloc, terminal, cmd), .display => display(alloc, terminal, cmd), .delete => delete(alloc, terminal, cmd), @@ -94,7 +94,11 @@ pub fn execute( /// This command is used to attempt to load an image and respond with /// success/error but does not persist any of the command to the terminal /// state. -fn query(alloc: Allocator, cmd: *const Command) Response { +fn query( + alloc: Allocator, + terminal: *const Terminal, + cmd: *const Command, +) Response { const t = cmd.control.query; // Query requires image ID. We can't actually send a response without @@ -112,7 +116,8 @@ fn query(alloc: Allocator, cmd: *const Command) Response { }; // Attempt to load the image. If we cannot, then set an appropriate error. - var loading = LoadingImage.init(alloc, cmd, .all) catch |err| { + const storage = &terminal.screens.active.kitty_images; + var loading = LoadingImage.init(alloc, cmd, storage.image_limits) catch |err| { encodeError(&result, err); return result; }; @@ -322,7 +327,7 @@ fn loadAndAddImage( } break :loading loading.*; - } else try .init(alloc, cmd, .all); + } else try .init(alloc, cmd, storage.image_limits); // We only want to deinit on error. If we're chunking, then we don't // want to deinit at all. If we're not chunking, then we'll deinit diff --git a/src/terminal/kitty/graphics_storage.zig b/src/terminal/kitty/graphics_storage.zig index 8ff68e3fa..65c26dc85 100644 --- a/src/terminal/kitty/graphics_storage.zig +++ b/src/terminal/kitty/graphics_storage.zig @@ -51,6 +51,9 @@ pub const ImageStorage = struct { /// Non-null if there is an in-progress loading image. loading: ?*LoadingImage = null, + /// The limits of what medium types are allowed for image loading. + image_limits: LoadingImage.Limits = .direct, + /// The total bytes of image data that have been loaded and the limit. /// If the limit is reached, the oldest images will be evicted to make /// space. Unused images take priority. @@ -89,8 +92,9 @@ pub const ImageStorage = struct { ) !void { // Special case disabling by quickly deleting all if (limit == 0) { + const image_limits = self.image_limits; self.deinit(alloc, s); - self.* = .{}; + self.* = .{ .image_limits = image_limits }; } // If we re lowering our limit, check if we need to evict. diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig index 75ccb94b5..1b446e268 100644 --- a/src/termio/Termio.zig +++ b/src/termio/Termio.zig @@ -259,16 +259,9 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void { }); errdefer term.deinit(alloc); - // Set the image size limits - var it = term.screens.all.iterator(); - while (it.next()) |entry| { - const screen: *terminalpkg.Screen = entry.value.*; - try screen.kitty_images.setLimit( - alloc, - screen, - opts.config.image_storage_limit, - ); - } + // Set the Kitty image settings + try term.setKittyGraphicsSizeLimit(alloc, opts.config.image_storage_limit); + term.setKittyGraphicsLoadingLimits(.all); // Set our default cursor style term.screens.active.cursor.cursor_style = opts.config.cursor_style; @@ -463,16 +456,9 @@ pub fn changeConfig(self: *Termio, td: *ThreadData, config: *DerivedConfig) !voi break :cursor color.toTerminalRGB() orelse break :cursor null; }; - // Set the image size limits - var it = self.terminal.screens.all.iterator(); - while (it.next()) |entry| { - const screen: *terminalpkg.Screen = entry.value.*; - try screen.kitty_images.setLimit( - self.alloc, - screen, - config.image_storage_limit, - ); - } + // Set the image limits + try self.terminal.setKittyGraphicsSizeLimit(self.alloc, config.image_storage_limit); + self.terminal.setKittyGraphicsLoadingLimits(.all); } /// Resize the terminal.