diff --git a/src/terminal/kitty/graphics_command.zig b/src/terminal/kitty/graphics_command.zig index a52392276..afc911cd2 100644 --- a/src/terminal/kitty/graphics_command.zig +++ b/src/terminal/kitty/graphics_command.zig @@ -294,6 +294,15 @@ pub const Command = struct { }; } + /// Returns the display data if it has any. + pub fn display(self: Command) ?Display { + return switch (self.control) { + .display => |d| d, + .transmit_and_display => |t| t.display, + else => null, + }; + } + pub fn deinit(self: Command, alloc: Allocator) void { if (self.data.len > 0) alloc.free(self.data); } @@ -399,6 +408,7 @@ pub const Transmission = struct { pub const Display = struct { image_id: u32 = 0, // i image_number: u32 = 0, // I + placement_id: u32 = 0, // p x: u32 = 0, // x y: u32 = 0, // y width: u32 = 0, // w @@ -427,6 +437,10 @@ pub const Display = struct { result.image_number = v; } + if (kv.get('p')) |v| { + result.placement_id = v; + } + if (kv.get('x')) |v| { result.x = v; } diff --git a/src/terminal/kitty/graphics_exec.zig b/src/terminal/kitty/graphics_exec.zig index 1c88aa5a0..c0ac58f2c 100644 --- a/src/terminal/kitty/graphics_exec.zig +++ b/src/terminal/kitty/graphics_exec.zig @@ -111,10 +111,18 @@ fn display( terminal: *Terminal, cmd: *Command, ) Response { + const d = cmd.display().?; + var result: Response = .{ + .id = d.image_id, + .image_number = d.image_number, + .placement_id = d.placement_id, + }; + + // TODO + _ = alloc; _ = terminal; - _ = cmd; - return .{}; + return result; } /// A combination of transmit and display. Nothing special. @@ -138,7 +146,7 @@ fn loadAndAddImage( errdefer img.deinit(alloc); // Store our image - try terminal.screen.kitty_images.add(alloc, img); + try terminal.screen.kitty_images.addImage(alloc, img); return img; } diff --git a/src/terminal/kitty/graphics_image.zig b/src/terminal/kitty/graphics_image.zig index 006c4962c..5ac7cf095 100644 --- a/src/terminal/kitty/graphics_image.zig +++ b/src/terminal/kitty/graphics_image.zig @@ -10,6 +10,7 @@ const max_dimension = 10000; pub const Image = struct { id: u32 = 0, + number: u32 = 0, data: []const u8, pub const Error = error{ @@ -58,6 +59,7 @@ pub const Image = struct { return Image{ .id = t.image_id, + .number = t.image_number, .data = data, }; } diff --git a/src/terminal/kitty/graphics_storage.zig b/src/terminal/kitty/graphics_storage.zig index eb3affe35..7355bbacf 100644 --- a/src/terminal/kitty/graphics_storage.zig +++ b/src/terminal/kitty/graphics_storage.zig @@ -3,35 +3,72 @@ const assert = std.debug.assert; const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; -const Image = @import("graphics_image.zig").Image; +const point = @import("../point.zig"); const command = @import("graphics_command.zig"); +const Image = @import("graphics_image.zig").Image; const Command = command.Command; +const ScreenPoint = point.ScreenPoint; /// An image storage is associated with a terminal screen (i.e. main /// screen, alt screen) and contains all the transmitted images and /// placements. pub const ImageStorage = struct { - /// The hash map type used to store our images. The key is the image ID - /// and the value is the image itself. - /// - /// Note that the image ID is optional when transmitting images, in - /// which case the image ID is always 0. - const HashMap = std.AutoHashMapUnmanaged(u32, Image); + const ImageMap = std.AutoHashMapUnmanaged(u32, Image); + const PlacementMap = std.AutoHashMapUnmanaged(PlacementKey, Placement); /// The set of images that are currently known. - images: HashMap = .{}, + images: ImageMap = .{}, + + /// The set of placements for loaded images. + placements: PlacementMap = .{}, + + pub fn deinit(self: *ImageStorage, alloc: Allocator) void { + var it = self.images.iterator(); + while (it.next()) |kv| kv.value_ptr.deinit(alloc); + + self.images.deinit(alloc); + self.placements.deinit(alloc); + } /// Add an already-loaded image to the storage. This will automatically /// free any existing image with the same ID. - pub fn add(self: *ImageStorage, alloc: Allocator, img: Image) !void { + pub fn addImage(self: *ImageStorage, alloc: Allocator, img: Image) Allocator.Error!void { const gop = try self.images.getOrPut(alloc, img.id); if (gop.found_existing) gop.value_ptr.deinit(alloc); gop.value_ptr.* = img; } - pub fn deinit(self: *ImageStorage, alloc: Allocator) void { - var it = self.images.iterator(); - while (it.next()) |kv| kv.value_ptr.deinit(alloc); - self.images.deinit(alloc); + /// Add a placement for a given image. The caller must verify in advance + /// the image exists to prevent memory corruption. + pub fn addPlacement( + self: *ImageStorage, + alloc: Allocator, + image_id: u32, + placement_id: u32, + p: Placement, + ) !void { + assert(self.images.get(image_id) != null); + + const key: PlacementKey = .{ .image_id = image_id, .placement_id = placement_id }; + const gop = try self.placements.getOrPut(alloc, key); + gop.value_ptr.* = p; } + + /// Get an image by its ID. If the image doesn't exist, null is returned. + pub fn imageById(self: *ImageStorage, image_id: u32) ?Image { + return self.images.get(image_id); + } + + /// Every placement is uniquely identified by the image ID and the + /// placement ID. If an image ID isn't specified it is assumed to be 0. + /// Likewise, if a placement ID isn't specified it is assumed to be 0. + pub const PlacementKey = struct { + image_id: u32, + placement_id: u32, + }; + + pub const Placement = struct { + /// The location of the image on the screen. + point: ScreenPoint, + }; };