kitty graphics support
This commit is contained in:
63
src/main/java/dev/jlibghostty/KittyGraphics.java
Normal file
63
src/main/java/dev/jlibghostty/KittyGraphics.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
import dev.jlibghostty.internal.GhosttyLibrary;
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class KittyGraphics {
|
||||
private final GhosttyLibrary library;
|
||||
private final MemorySegment terminal;
|
||||
private final MemorySegment graphics;
|
||||
|
||||
KittyGraphics(GhosttyLibrary library, MemorySegment terminal, MemorySegment graphics) {
|
||||
this.library = library;
|
||||
this.terminal = terminal;
|
||||
this.graphics = graphics;
|
||||
}
|
||||
|
||||
public Optional<KittyImage> image(long imageId) {
|
||||
MemorySegment image = library.kittyGraphicsImage(graphics, imageId);
|
||||
if (image.address() == 0) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(new KittyImage(library, image));
|
||||
}
|
||||
|
||||
public List<KittyPlacement> placements() {
|
||||
return placements(KittyPlacementLayer.ALL);
|
||||
}
|
||||
|
||||
public List<KittyPlacement> placements(KittyPlacementLayer layer) {
|
||||
try (KittyPlacementIterator iterator = KittyPlacementIterator.open(library, graphics, layer)) {
|
||||
List<KittyPlacement> placements = new ArrayList<>();
|
||||
while (iterator.next()) {
|
||||
long imageId = iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID);
|
||||
Optional<KittyImage> image = image(imageId);
|
||||
KittyRenderInfo renderInfo = image
|
||||
.flatMap(value -> library.kittyPlacementRenderInfo(iterator.handle(), value.handle(), terminal))
|
||||
.orElse(null);
|
||||
|
||||
placements.add(new KittyPlacement(
|
||||
imageId,
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID),
|
||||
iterator.getBoolean(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL),
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_X_OFFSET),
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_Y_OFFSET),
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_X),
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_Y),
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_WIDTH),
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_HEIGHT),
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_COLUMNS),
|
||||
iterator.getU32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_ROWS),
|
||||
iterator.getI32(GhosttyLibrary.KITTY_GRAPHICS_PLACEMENT_DATA_Z),
|
||||
image.map(KittyImage::snapshot),
|
||||
Optional.ofNullable(renderInfo)
|
||||
));
|
||||
}
|
||||
return List.copyOf(placements);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/main/java/dev/jlibghostty/KittyImage.java
Normal file
31
src/main/java/dev/jlibghostty/KittyImage.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
import dev.jlibghostty.internal.GhosttyLibrary;
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
|
||||
public final class KittyImage {
|
||||
private final GhosttyLibrary library;
|
||||
private final MemorySegment handle;
|
||||
|
||||
KittyImage(GhosttyLibrary library, MemorySegment handle) {
|
||||
this.library = library;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public KittyImageSnapshot snapshot() {
|
||||
return new KittyImageSnapshot(
|
||||
library.kittyImageGetU32(handle, GhosttyLibrary.KITTY_IMAGE_DATA_ID),
|
||||
library.kittyImageGetU32(handle, GhosttyLibrary.KITTY_IMAGE_DATA_NUMBER),
|
||||
library.kittyImageGetU32(handle, GhosttyLibrary.KITTY_IMAGE_DATA_WIDTH),
|
||||
library.kittyImageGetU32(handle, GhosttyLibrary.KITTY_IMAGE_DATA_HEIGHT),
|
||||
KittyImageFormat.fromNative(library.kittyImageGetI32(handle, GhosttyLibrary.KITTY_IMAGE_DATA_FORMAT)),
|
||||
KittyImageCompression.fromNative(library.kittyImageGetI32(handle, GhosttyLibrary.KITTY_IMAGE_DATA_COMPRESSION)),
|
||||
library.kittyImageData(handle)
|
||||
);
|
||||
}
|
||||
|
||||
MemorySegment handle() {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
25
src/main/java/dev/jlibghostty/KittyImageCompression.java
Normal file
25
src/main/java/dev/jlibghostty/KittyImageCompression.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
public enum KittyImageCompression {
|
||||
NONE(0),
|
||||
ZLIB_DEFLATE(1);
|
||||
|
||||
private final int nativeValue;
|
||||
|
||||
KittyImageCompression(int nativeValue) {
|
||||
this.nativeValue = nativeValue;
|
||||
}
|
||||
|
||||
public int nativeValue() {
|
||||
return nativeValue;
|
||||
}
|
||||
|
||||
static KittyImageCompression fromNative(int value) {
|
||||
for (KittyImageCompression compression : values()) {
|
||||
if (compression.nativeValue == value) {
|
||||
return compression;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown Kitty image compression: " + value);
|
||||
}
|
||||
}
|
||||
28
src/main/java/dev/jlibghostty/KittyImageFormat.java
Normal file
28
src/main/java/dev/jlibghostty/KittyImageFormat.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
public enum KittyImageFormat {
|
||||
RGB(0),
|
||||
RGBA(1),
|
||||
PNG(2),
|
||||
GRAY_ALPHA(3),
|
||||
GRAY(4);
|
||||
|
||||
private final int nativeValue;
|
||||
|
||||
KittyImageFormat(int nativeValue) {
|
||||
this.nativeValue = nativeValue;
|
||||
}
|
||||
|
||||
public int nativeValue() {
|
||||
return nativeValue;
|
||||
}
|
||||
|
||||
static KittyImageFormat fromNative(int value) {
|
||||
for (KittyImageFormat format : values()) {
|
||||
if (format.nativeValue == value) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown Kitty image format: " + value);
|
||||
}
|
||||
}
|
||||
20
src/main/java/dev/jlibghostty/KittyImageSnapshot.java
Normal file
20
src/main/java/dev/jlibghostty/KittyImageSnapshot.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
public record KittyImageSnapshot(
|
||||
long id,
|
||||
long number,
|
||||
long width,
|
||||
long height,
|
||||
KittyImageFormat format,
|
||||
KittyImageCompression compression,
|
||||
byte[] data
|
||||
) {
|
||||
public KittyImageSnapshot {
|
||||
data = data.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] data() {
|
||||
return data.clone();
|
||||
}
|
||||
}
|
||||
21
src/main/java/dev/jlibghostty/KittyPlacement.java
Normal file
21
src/main/java/dev/jlibghostty/KittyPlacement.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record KittyPlacement(
|
||||
long imageId,
|
||||
long placementId,
|
||||
boolean virtual,
|
||||
long xOffset,
|
||||
long yOffset,
|
||||
long sourceX,
|
||||
long sourceY,
|
||||
long sourceWidth,
|
||||
long sourceHeight,
|
||||
long columns,
|
||||
long rows,
|
||||
int z,
|
||||
Optional<KittyImageSnapshot> image,
|
||||
Optional<KittyRenderInfo> renderInfo
|
||||
) {
|
||||
}
|
||||
56
src/main/java/dev/jlibghostty/KittyPlacementIterator.java
Normal file
56
src/main/java/dev/jlibghostty/KittyPlacementIterator.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
import dev.jlibghostty.internal.GhosttyLibrary;
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
|
||||
final class KittyPlacementIterator implements AutoCloseable {
|
||||
private final GhosttyLibrary library;
|
||||
private final MemorySegment handle;
|
||||
private boolean closed;
|
||||
|
||||
private KittyPlacementIterator(GhosttyLibrary library, MemorySegment handle) {
|
||||
this.library = library;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
static KittyPlacementIterator open(GhosttyLibrary library, MemorySegment graphics, KittyPlacementLayer layer) {
|
||||
MemorySegment handle = library.kittyPlacementIteratorNew();
|
||||
try {
|
||||
library.kittyGraphicsPopulatePlacementIterator(graphics, handle);
|
||||
library.kittyPlacementIteratorSetLayer(handle, layer.nativeValue());
|
||||
return new KittyPlacementIterator(library, handle);
|
||||
} catch (RuntimeException | Error e) {
|
||||
library.kittyPlacementIteratorFree(handle);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
boolean next() {
|
||||
return library.kittyPlacementNext(handle);
|
||||
}
|
||||
|
||||
long getU32(int key) {
|
||||
return library.kittyPlacementGetU32(handle, key);
|
||||
}
|
||||
|
||||
int getI32(int key) {
|
||||
return library.kittyPlacementGetI32(handle, key);
|
||||
}
|
||||
|
||||
boolean getBoolean(int key) {
|
||||
return library.kittyPlacementGetBoolean(handle, key);
|
||||
}
|
||||
|
||||
MemorySegment handle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
library.kittyPlacementIteratorFree(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/main/java/dev/jlibghostty/KittyPlacementLayer.java
Normal file
18
src/main/java/dev/jlibghostty/KittyPlacementLayer.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
public enum KittyPlacementLayer {
|
||||
ALL(0),
|
||||
BELOW_BACKGROUND(1),
|
||||
BELOW_TEXT(2),
|
||||
ABOVE_TEXT(3);
|
||||
|
||||
private final int nativeValue;
|
||||
|
||||
KittyPlacementLayer(int nativeValue) {
|
||||
this.nativeValue = nativeValue;
|
||||
}
|
||||
|
||||
int nativeValue() {
|
||||
return nativeValue;
|
||||
}
|
||||
}
|
||||
16
src/main/java/dev/jlibghostty/KittyRenderInfo.java
Normal file
16
src/main/java/dev/jlibghostty/KittyRenderInfo.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package dev.jlibghostty;
|
||||
|
||||
public record KittyRenderInfo(
|
||||
long pixelWidth,
|
||||
long pixelHeight,
|
||||
long gridColumns,
|
||||
long gridRows,
|
||||
int viewportColumn,
|
||||
int viewportRow,
|
||||
boolean viewportVisible,
|
||||
long sourceX,
|
||||
long sourceY,
|
||||
long sourceWidth,
|
||||
long sourceHeight
|
||||
) {
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import dev.jlibghostty.internal.GhosttyLibrary;
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public final class Terminal implements AutoCloseable {
|
||||
@@ -40,6 +41,38 @@ public final class Terminal implements AutoCloseable {
|
||||
library.terminalResize(handle, columns, rows, cellWidthPx, cellHeightPx);
|
||||
}
|
||||
|
||||
public void setKittyImageStorageLimit(long bytes) {
|
||||
ensureOpen();
|
||||
library.terminalSetU64(handle, GhosttyLibrary.TERMINAL_OPT_KITTY_IMAGE_STORAGE_LIMIT, bytes);
|
||||
}
|
||||
|
||||
public void setKittyImageMediumFile(boolean enabled) {
|
||||
ensureOpen();
|
||||
library.terminalSetBoolean(handle, GhosttyLibrary.TERMINAL_OPT_KITTY_IMAGE_MEDIUM_FILE, enabled);
|
||||
}
|
||||
|
||||
public void setKittyImageMediumTemporaryFile(boolean enabled) {
|
||||
ensureOpen();
|
||||
library.terminalSetBoolean(handle, GhosttyLibrary.TERMINAL_OPT_KITTY_IMAGE_MEDIUM_TEMP_FILE, enabled);
|
||||
}
|
||||
|
||||
public void setKittyImageMediumSharedMemory(boolean enabled) {
|
||||
ensureOpen();
|
||||
library.terminalSetBoolean(handle, GhosttyLibrary.TERMINAL_OPT_KITTY_IMAGE_MEDIUM_SHARED_MEM, enabled);
|
||||
}
|
||||
|
||||
public Optional<KittyGraphics> kittyGraphics() {
|
||||
ensureOpen();
|
||||
MemorySegment graphics = library.terminalGetPointerOrNull(
|
||||
handle,
|
||||
GhosttyLibrary.TERMINAL_DATA_KITTY_GRAPHICS
|
||||
);
|
||||
if (graphics.address() == 0) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(new KittyGraphics(library, handle, graphics));
|
||||
}
|
||||
|
||||
public TerminalSnapshot snapshot() {
|
||||
ensureOpen();
|
||||
return new TerminalSnapshot(
|
||||
|
||||
@@ -26,6 +26,36 @@ public final class GhosttyLibrary {
|
||||
public static final int TERMINAL_DATA_CURSOR_VISIBLE = 7;
|
||||
public static final int TERMINAL_DATA_TITLE = 12;
|
||||
public static final int TERMINAL_DATA_PWD = 13;
|
||||
public static final int TERMINAL_DATA_KITTY_GRAPHICS = 30;
|
||||
|
||||
public static final int TERMINAL_OPT_KITTY_IMAGE_STORAGE_LIMIT = 15;
|
||||
public static final int TERMINAL_OPT_KITTY_IMAGE_MEDIUM_FILE = 16;
|
||||
public static final int TERMINAL_OPT_KITTY_IMAGE_MEDIUM_TEMP_FILE = 17;
|
||||
public static final int TERMINAL_OPT_KITTY_IMAGE_MEDIUM_SHARED_MEM = 18;
|
||||
|
||||
public static final int KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR = 1;
|
||||
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID = 1;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID = 2;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL = 3;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_X_OFFSET = 4;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_Y_OFFSET = 5;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_X = 6;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_Y = 7;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_WIDTH = 8;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_HEIGHT = 9;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_COLUMNS = 10;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_ROWS = 11;
|
||||
public static final int KITTY_GRAPHICS_PLACEMENT_DATA_Z = 12;
|
||||
|
||||
public static final int KITTY_IMAGE_DATA_ID = 1;
|
||||
public static final int KITTY_IMAGE_DATA_NUMBER = 2;
|
||||
public static final int KITTY_IMAGE_DATA_WIDTH = 3;
|
||||
public static final int KITTY_IMAGE_DATA_HEIGHT = 4;
|
||||
public static final int KITTY_IMAGE_DATA_FORMAT = 5;
|
||||
public static final int KITTY_IMAGE_DATA_COMPRESSION = 6;
|
||||
public static final int KITTY_IMAGE_DATA_DATA_PTR = 7;
|
||||
public static final int KITTY_IMAGE_DATA_DATA_LEN = 8;
|
||||
|
||||
private static final int GHOSTTY_SUCCESS = 0;
|
||||
private static final int GHOSTTY_OUT_OF_SPACE = -3;
|
||||
@@ -36,6 +66,7 @@ public final class GhosttyLibrary {
|
||||
private static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) LINKER.canonicalLayouts().get("bool");
|
||||
private static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) LINKER.canonicalLayouts().get("short");
|
||||
private static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) LINKER.canonicalLayouts().get("int");
|
||||
private static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) LINKER.canonicalLayouts().get("long long");
|
||||
private static final ValueLayout.OfLong C_SIZE_T = sizeTLayout();
|
||||
|
||||
private static final GroupLayout TERMINAL_OPTIONS = MemoryLayout.structLayout(
|
||||
@@ -50,14 +81,41 @@ public final class GhosttyLibrary {
|
||||
C_SIZE_T.withName("len")
|
||||
);
|
||||
|
||||
private static final GroupLayout KITTY_RENDER_INFO = MemoryLayout.structLayout(
|
||||
C_SIZE_T.withName("size"),
|
||||
C_INT.withName("pixel_width"),
|
||||
C_INT.withName("pixel_height"),
|
||||
C_INT.withName("grid_cols"),
|
||||
C_INT.withName("grid_rows"),
|
||||
C_INT.withName("viewport_col"),
|
||||
C_INT.withName("viewport_row"),
|
||||
C_BOOL.withName("viewport_visible"),
|
||||
MemoryLayout.paddingLayout(3),
|
||||
C_INT.withName("source_x"),
|
||||
C_INT.withName("source_y"),
|
||||
C_INT.withName("source_width"),
|
||||
C_INT.withName("source_height"),
|
||||
MemoryLayout.paddingLayout(4)
|
||||
);
|
||||
|
||||
private final MethodHandle terminalNew;
|
||||
private final MethodHandle terminalFree;
|
||||
private final MethodHandle terminalReset;
|
||||
private final MethodHandle terminalResize;
|
||||
private final MethodHandle terminalVtWrite;
|
||||
private final MethodHandle terminalSet;
|
||||
private final MethodHandle terminalGet;
|
||||
private final MethodHandle pasteIsSafe;
|
||||
private final MethodHandle pasteEncode;
|
||||
private final MethodHandle kittyGraphicsGet;
|
||||
private final MethodHandle kittyGraphicsImage;
|
||||
private final MethodHandle kittyGraphicsImageGet;
|
||||
private final MethodHandle kittyGraphicsPlacementIteratorNew;
|
||||
private final MethodHandle kittyGraphicsPlacementIteratorFree;
|
||||
private final MethodHandle kittyGraphicsPlacementIteratorSet;
|
||||
private final MethodHandle kittyGraphicsPlacementNext;
|
||||
private final MethodHandle kittyGraphicsPlacementGet;
|
||||
private final MethodHandle kittyGraphicsPlacementRenderInfo;
|
||||
|
||||
private GhosttyLibrary(Path libraryPath) {
|
||||
try {
|
||||
@@ -73,12 +131,32 @@ public final class GhosttyLibrary {
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_SHORT, C_SHORT, C_INT, C_INT));
|
||||
terminalVtWrite = downcall(symbols, "ghostty_terminal_vt_write",
|
||||
FunctionDescriptor.ofVoid(C_POINTER, C_POINTER, C_SIZE_T));
|
||||
terminalSet = downcall(symbols, "ghostty_terminal_set",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||
terminalGet = downcall(symbols, "ghostty_terminal_get",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||
pasteIsSafe = downcall(symbols, "ghostty_paste_is_safe",
|
||||
FunctionDescriptor.of(C_BOOL, C_POINTER, C_SIZE_T));
|
||||
pasteEncode = downcall(symbols, "ghostty_paste_encode",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_SIZE_T, C_BOOL, C_POINTER, C_SIZE_T, C_POINTER));
|
||||
kittyGraphicsGet = downcall(symbols, "ghostty_kitty_graphics_get",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||
kittyGraphicsImage = downcall(symbols, "ghostty_kitty_graphics_image",
|
||||
FunctionDescriptor.of(C_POINTER, C_POINTER, C_INT));
|
||||
kittyGraphicsImageGet = downcall(symbols, "ghostty_kitty_graphics_image_get",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||
kittyGraphicsPlacementIteratorNew = downcall(symbols, "ghostty_kitty_graphics_placement_iterator_new",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER));
|
||||
kittyGraphicsPlacementIteratorFree = downcall(symbols, "ghostty_kitty_graphics_placement_iterator_free",
|
||||
FunctionDescriptor.ofVoid(C_POINTER));
|
||||
kittyGraphicsPlacementIteratorSet = downcall(symbols, "ghostty_kitty_graphics_placement_iterator_set",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||
kittyGraphicsPlacementNext = downcall(symbols, "ghostty_kitty_graphics_placement_next",
|
||||
FunctionDescriptor.of(C_BOOL, C_POINTER));
|
||||
kittyGraphicsPlacementGet = downcall(symbols, "ghostty_kitty_graphics_placement_get",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||
kittyGraphicsPlacementRenderInfo = downcall(symbols, "ghostty_kitty_graphics_placement_render_info",
|
||||
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_POINTER, C_POINTER));
|
||||
} catch (IllegalCallerException e) {
|
||||
throw new IllegalStateException(
|
||||
"FFM native access is disabled. Run with --enable-native-access=dev.jlibghostty "
|
||||
@@ -159,6 +237,28 @@ public final class GhosttyLibrary {
|
||||
}
|
||||
}
|
||||
|
||||
public void terminalSetU64(MemorySegment terminal, int key, long value) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment nativeValue = arena.allocate(C_LONG_LONG);
|
||||
nativeValue.set(C_LONG_LONG, 0, value);
|
||||
int result = (int) terminalSet.invoke(terminal, key, nativeValue);
|
||||
checkResult("ghostty_terminal_set", result);
|
||||
} catch (Throwable t) {
|
||||
rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void terminalSetBoolean(MemorySegment terminal, int key, boolean value) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment nativeValue = arena.allocate(C_BOOL);
|
||||
nativeValue.set(C_BOOL, 0, value);
|
||||
int result = (int) terminalSet.invoke(terminal, key, nativeValue);
|
||||
checkResult("ghostty_terminal_set", result);
|
||||
} catch (Throwable t) {
|
||||
rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public int terminalGetU16(MemorySegment terminal, int key) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment out = arena.allocate(C_SHORT);
|
||||
@@ -203,6 +303,20 @@ public final class GhosttyLibrary {
|
||||
}
|
||||
}
|
||||
|
||||
public MemorySegment terminalGetPointerOrNull(MemorySegment terminal, int key) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment out = arena.allocate(C_POINTER);
|
||||
int result = (int) terminalGet.invoke(terminal, key, out);
|
||||
if (result == GHOSTTY_NO_VALUE) {
|
||||
return MemorySegment.NULL;
|
||||
}
|
||||
checkResult("ghostty_terminal_get", result);
|
||||
return out.get(C_POINTER, 0);
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean pasteIsSafe(byte[] data) {
|
||||
if (data.length == 0) {
|
||||
return true;
|
||||
@@ -261,6 +375,163 @@ public final class GhosttyLibrary {
|
||||
}
|
||||
}
|
||||
|
||||
public void kittyGraphicsPopulatePlacementIterator(MemorySegment graphics, MemorySegment iterator) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment out = arena.allocate(C_POINTER);
|
||||
out.set(C_POINTER, 0, iterator);
|
||||
int result = (int) kittyGraphicsGet.invoke(graphics, KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR, out);
|
||||
checkResult("ghostty_kitty_graphics_get", result);
|
||||
} catch (Throwable t) {
|
||||
rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public MemorySegment kittyGraphicsImage(MemorySegment graphics, long imageId) {
|
||||
try {
|
||||
return (MemorySegment) kittyGraphicsImage.invoke(graphics, (int) imageId);
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public long kittyImageGetU32(MemorySegment image, int key) {
|
||||
return Integer.toUnsignedLong(kittyImageGetI32(image, key));
|
||||
}
|
||||
|
||||
public int kittyImageGetI32(MemorySegment image, int key) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment out = arena.allocate(C_INT);
|
||||
int result = (int) kittyGraphicsImageGet.invoke(image, key, out);
|
||||
checkResult("ghostty_kitty_graphics_image_get", result);
|
||||
return out.get(C_INT, 0);
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] kittyImageData(MemorySegment image) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment outPtr = arena.allocate(C_POINTER);
|
||||
MemorySegment outLen = arena.allocate(C_SIZE_T);
|
||||
|
||||
int result = (int) kittyGraphicsImageGet.invoke(image, KITTY_IMAGE_DATA_DATA_PTR, outPtr);
|
||||
checkResult("ghostty_kitty_graphics_image_get", result);
|
||||
result = (int) kittyGraphicsImageGet.invoke(image, KITTY_IMAGE_DATA_DATA_LEN, outLen);
|
||||
checkResult("ghostty_kitty_graphics_image_get", result);
|
||||
|
||||
MemorySegment ptr = outPtr.get(C_POINTER, 0);
|
||||
long len = outLen.get(C_SIZE_T, 0);
|
||||
if (ptr.address() == 0 || len == 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
return ptr.reinterpret(len).toArray(JAVA_BYTE);
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public MemorySegment kittyPlacementIteratorNew() {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment out = arena.allocate(C_POINTER);
|
||||
int result = (int) kittyGraphicsPlacementIteratorNew.invoke(MemorySegment.NULL, out);
|
||||
checkResult("ghostty_kitty_graphics_placement_iterator_new", result);
|
||||
|
||||
MemorySegment iterator = out.get(C_POINTER, 0);
|
||||
if (iterator.address() == 0) {
|
||||
throw new IllegalStateException("ghostty_kitty_graphics_placement_iterator_new returned null");
|
||||
}
|
||||
return iterator;
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void kittyPlacementIteratorFree(MemorySegment iterator) {
|
||||
try {
|
||||
kittyGraphicsPlacementIteratorFree.invoke(iterator);
|
||||
} catch (Throwable t) {
|
||||
rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void kittyPlacementIteratorSetLayer(MemorySegment iterator, int layer) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment nativeLayer = arena.allocate(C_INT);
|
||||
nativeLayer.set(C_INT, 0, layer);
|
||||
int result = (int) kittyGraphicsPlacementIteratorSet.invoke(iterator, 0, nativeLayer);
|
||||
checkResult("ghostty_kitty_graphics_placement_iterator_set", result);
|
||||
} catch (Throwable t) {
|
||||
rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean kittyPlacementNext(MemorySegment iterator) {
|
||||
try {
|
||||
return (boolean) kittyGraphicsPlacementNext.invoke(iterator);
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public long kittyPlacementGetU32(MemorySegment iterator, int key) {
|
||||
return Integer.toUnsignedLong(kittyPlacementGetI32(iterator, key));
|
||||
}
|
||||
|
||||
public int kittyPlacementGetI32(MemorySegment iterator, int key) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment out = arena.allocate(C_INT);
|
||||
int result = (int) kittyGraphicsPlacementGet.invoke(iterator, key, out);
|
||||
checkResult("ghostty_kitty_graphics_placement_get", result);
|
||||
return out.get(C_INT, 0);
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean kittyPlacementGetBoolean(MemorySegment iterator, int key) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment out = arena.allocate(C_BOOL);
|
||||
int result = (int) kittyGraphicsPlacementGet.invoke(iterator, key, out);
|
||||
checkResult("ghostty_kitty_graphics_placement_get", result);
|
||||
return out.get(C_BOOL, 0);
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public java.util.Optional<dev.jlibghostty.KittyRenderInfo> kittyPlacementRenderInfo(
|
||||
MemorySegment iterator,
|
||||
MemorySegment image,
|
||||
MemorySegment terminal
|
||||
) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment out = arena.allocate(KITTY_RENDER_INFO);
|
||||
out.set(C_SIZE_T, 0, KITTY_RENDER_INFO.byteSize());
|
||||
|
||||
int result = (int) kittyGraphicsPlacementRenderInfo.invoke(iterator, image, terminal, out);
|
||||
if (result == GHOSTTY_NO_VALUE) {
|
||||
return java.util.Optional.empty();
|
||||
}
|
||||
checkResult("ghostty_kitty_graphics_placement_render_info", result);
|
||||
|
||||
return java.util.Optional.of(new dev.jlibghostty.KittyRenderInfo(
|
||||
Integer.toUnsignedLong(out.get(C_INT, 8)),
|
||||
Integer.toUnsignedLong(out.get(C_INT, 12)),
|
||||
Integer.toUnsignedLong(out.get(C_INT, 16)),
|
||||
Integer.toUnsignedLong(out.get(C_INT, 20)),
|
||||
out.get(C_INT, 24),
|
||||
out.get(C_INT, 28),
|
||||
out.get(C_BOOL, 32),
|
||||
Integer.toUnsignedLong(out.get(C_INT, 36)),
|
||||
Integer.toUnsignedLong(out.get(C_INT, 40)),
|
||||
Integer.toUnsignedLong(out.get(C_INT, 44)),
|
||||
Integer.toUnsignedLong(out.get(C_INT, 48))
|
||||
));
|
||||
} catch (Throwable t) {
|
||||
return rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodHandle downcall(SymbolLookup symbols, String name, FunctionDescriptor descriptor) {
|
||||
MemorySegment symbol = symbols.find(name)
|
||||
.orElseThrow(() -> new UnsatisfiedLinkError("Missing libghostty-vt symbol: " + name));
|
||||
|
||||
@@ -46,6 +46,14 @@
|
||||
"void*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"returnType": "int",
|
||||
"parameterTypes": [
|
||||
"void*",
|
||||
"int",
|
||||
"void*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"returnType": "bool",
|
||||
"parameterTypes": [
|
||||
@@ -63,6 +71,35 @@
|
||||
"size_t",
|
||||
"void*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"returnType": "void*",
|
||||
"parameterTypes": [
|
||||
"void*",
|
||||
"int"
|
||||
]
|
||||
},
|
||||
{
|
||||
"returnType": "int",
|
||||
"parameterTypes": [
|
||||
"void*",
|
||||
"void*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"returnType": "bool",
|
||||
"parameterTypes": [
|
||||
"void*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"returnType": "int",
|
||||
"parameterTypes": [
|
||||
"void*",
|
||||
"void*",
|
||||
"void*",
|
||||
"void*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user