mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00
terminal/kitty-gfx: placement now works properly
This commit is contained in:
@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const point = @import("../point.zig");
|
||||||
const Terminal = @import("../Terminal.zig");
|
const Terminal = @import("../Terminal.zig");
|
||||||
const command = @import("graphics_command.zig");
|
const command = @import("graphics_command.zig");
|
||||||
const image = @import("graphics_image.zig");
|
const image = @import("graphics_image.zig");
|
||||||
@ -9,6 +10,11 @@ const Command = command.Command;
|
|||||||
const Response = command.Response;
|
const Response = command.Response;
|
||||||
const Image = image.Image;
|
const Image = image.Image;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - image ids need to be assigned, can't just be zero
|
||||||
|
// - delete
|
||||||
|
// (not exhaustive, almost every op is ignoring additional config)
|
||||||
|
|
||||||
/// Execute a Kitty graphics command against the given terminal. This
|
/// Execute a Kitty graphics command against the given terminal. This
|
||||||
/// will never fail, but the response may indicate an error and the
|
/// will never fail, but the response may indicate an error and the
|
||||||
/// terminal state may not be updated to reflect the command. This will
|
/// terminal state may not be updated to reflect the command. This will
|
||||||
@ -112,16 +118,47 @@ fn display(
|
|||||||
cmd: *Command,
|
cmd: *Command,
|
||||||
) Response {
|
) Response {
|
||||||
const d = cmd.display().?;
|
const d = cmd.display().?;
|
||||||
|
|
||||||
|
// Display requires image ID or number.
|
||||||
|
if (d.image_id == 0 and d.image_number == 0) {
|
||||||
|
return .{ .message = "EINVAL: image ID or number required" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build up our response
|
||||||
var result: Response = .{
|
var result: Response = .{
|
||||||
.id = d.image_id,
|
.id = d.image_id,
|
||||||
.image_number = d.image_number,
|
.image_number = d.image_number,
|
||||||
.placement_id = d.placement_id,
|
.placement_id = d.placement_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO
|
// Verify the requested image exists if we have an ID
|
||||||
|
const storage = &terminal.screen.kitty_images;
|
||||||
|
const img_: ?Image = if (d.image_id != 0)
|
||||||
|
storage.imageById(d.image_id)
|
||||||
|
else
|
||||||
|
storage.imageByNumber(d.image_number);
|
||||||
|
const img = img_ orelse {
|
||||||
|
result.message = "EINVAL: image not found";
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure our response has the image id in case we looked up by number
|
||||||
|
result.id = img.id;
|
||||||
|
|
||||||
|
// Determine the screen point for the placement.
|
||||||
|
const placement_point = (point.Viewport{
|
||||||
|
.x = terminal.screen.cursor.x,
|
||||||
|
.y = terminal.screen.cursor.y,
|
||||||
|
}).toScreen(&terminal.screen);
|
||||||
|
|
||||||
|
// Add the placement
|
||||||
|
storage.addPlacement(alloc, img.id, d.placement_id, .{
|
||||||
|
.point = placement_point,
|
||||||
|
}) catch |err| {
|
||||||
|
encodeError(&result, err);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
_ = alloc;
|
|
||||||
_ = terminal;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,22 @@ pub const ImageStorage = struct {
|
|||||||
/// 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 {
|
||||||
|
// Do the gop op first so if it fails we don't get a partial state
|
||||||
const gop = try self.images.getOrPut(alloc, img.id);
|
const gop = try self.images.getOrPut(alloc, img.id);
|
||||||
|
|
||||||
|
// If the image has an image number, we need to invalidate the last
|
||||||
|
// image with that same number.
|
||||||
|
if (img.number > 0) {
|
||||||
|
var it = self.images.iterator();
|
||||||
|
while (it.next()) |kv| {
|
||||||
|
if (kv.value_ptr.number == img.number) {
|
||||||
|
kv.value_ptr.number = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write our new image
|
||||||
if (gop.found_existing) gop.value_ptr.deinit(alloc);
|
if (gop.found_existing) gop.value_ptr.deinit(alloc);
|
||||||
gop.value_ptr.* = img;
|
gop.value_ptr.* = img;
|
||||||
}
|
}
|
||||||
@ -59,6 +74,16 @@ pub const ImageStorage = struct {
|
|||||||
return self.images.get(image_id);
|
return self.images.get(image_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an image by its number. If the image doesn't exist, return null.
|
||||||
|
pub fn imageByNumber(self: *ImageStorage, image_number: u32) ?Image {
|
||||||
|
var it = self.images.iterator();
|
||||||
|
while (it.next()) |kv| {
|
||||||
|
if (kv.value_ptr.number == image_number) return kv.value_ptr.*;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Every placement is uniquely identified by the image ID and the
|
/// 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.
|
/// 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.
|
/// Likewise, if a placement ID isn't specified it is assumed to be 0.
|
||||||
|
Reference in New Issue
Block a user