From: Olaf Wintermann Date: Sat, 21 Jun 2025 13:55:49 +0000 (+0200) Subject: add UiList java wrapper (wip) X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=335d4c1ff714eb4bc9a083e6f8b6348e18b89857;p=rssreader.git add UiList java wrapper (wip) --- diff --git a/ui-java/src/main/java/de/unixwork/ui/Context.java b/ui-java/src/main/java/de/unixwork/ui/Context.java index c42ec8a..936668c 100644 --- a/ui-java/src/main/java/de/unixwork/ui/Context.java +++ b/ui-java/src/main/java/de/unixwork/ui/Context.java @@ -2,14 +2,19 @@ package de.unixwork.ui; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.util.ArrayList; public abstract class Context { private MemorySegment ptr; private Arena arena = Arena.ofShared(); + private ArrayList lists = new ArrayList<>(); + protected void setCtx(MemorySegment ptr) { this.ptr = ptr; + Toolkit.getInstance().registerContext(this); } public MemorySegment getCtx() { @@ -32,6 +37,24 @@ public abstract class Context { return new UiInteger(this, name); } + public UiList list() { + UiList ls = list(null); + return ls; + } + + public UiList list(String name) { + // create a list object, that will be used as list->data + // listObj contains the context pointer and the list index + // ctx+index will be used to lookup the UiList java object + MemorySegment listObj = arena.allocate(ValueLayout.JAVA_LONG, 2); + listObj.setAtIndex(ValueLayout.JAVA_LONG, 0, ptr.address()); + listObj.setAtIndex(ValueLayout.JAVA_LONG, 1, lists.size()); + var ls = new UiList(this, name, listObj); + lists.add(ls); + return ls; + } + + public void attach(Document doc) { ToolkitFuncs ui = ToolkitFuncs.getInstance(); try { @@ -40,4 +63,8 @@ public abstract class Context { throw new RuntimeException(e); } } + + public Arena getArena() { + return arena; + } } diff --git a/ui-java/src/main/java/de/unixwork/ui/Toolkit.java b/ui-java/src/main/java/de/unixwork/ui/Toolkit.java index b515588..58b327c 100644 --- a/ui-java/src/main/java/de/unixwork/ui/Toolkit.java +++ b/ui-java/src/main/java/de/unixwork/ui/Toolkit.java @@ -13,6 +13,7 @@ public class Toolkit { private HashMap toplevelObjects = new HashMap<>(); private HashMap documents = new HashMap<>(); + private HashMap contexts = new HashMap<>(); // TODO: maybe we can replace the UiObject and Doument maps with just this context map // used for all strings and other memory, that is expected to be const // and the UI toolkit does not create copies @@ -23,6 +24,11 @@ public class Toolkit { private SymbolLookup lib; private MethodHandle mainFunc; + protected MemorySegment listFirst; + protected MemorySegment listNext; + protected MemorySegment listGet; + protected MemorySegment listCount; + private Toolkit(String appName) { // load shared library System.loadLibrary("uitk"); @@ -50,9 +56,53 @@ public class Toolkit { private void initFunctions() { FunctionDescriptor sigv_v = FunctionDescriptor.ofVoid(); // void func(void) + FunctionDescriptor sigm_m = FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS); // void* func(void*) + FunctionDescriptor sigm_mi = FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT); // void* func(void*, int) + FunctionDescriptor sigi_m = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS); // int func(void*) MemorySegment ui_main_addr = lib.find("ui_main").orElseThrow(); mainFunc = linker.downcallHandle(ui_main_addr, sigv_v); + + // init java based UiList implementation + try { + MethodHandle listFirstMethod = MethodHandles.lookup().findStatic( + UiList.class, + "first", + MethodType.methodType(MemorySegment.class, MemorySegment.class)); + MethodHandle listNextMethod = MethodHandles.lookup().findStatic( + UiList.class, + "next", + MethodType.methodType(MemorySegment.class, MemorySegment.class)); + MethodHandle listGetMethod = MethodHandles.lookup().findStatic( + UiList.class, + "get", + MethodType.methodType(MemorySegment.class, MemorySegment.class, int.class)); + MethodHandle listCountMethod = MethodHandles.lookup().findStatic( + UiList.class, + "count", + MethodType.methodType(int.class, MemorySegment.class)); + + listFirst = linker.upcallStub( + listFirstMethod, + sigm_m, + staticArena); + listNext = linker.upcallStub( + listNextMethod, + sigm_m, + staticArena); + listGet = linker.upcallStub( + listGetMethod, + sigm_mi, + staticArena); + listCount = linker.upcallStub( + listCountMethod, + sigi_m, + staticArena); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } } public static Toolkit getInstance() { @@ -231,4 +281,12 @@ public class Toolkit { public Document getDocument(long address) { return documents.get(address); } + + public void registerContext(Context ctx) { + contexts.put(ctx.getCtx().address(), ctx); + } + + public Context getContext(long address) { + return contexts.get(address); + } } diff --git a/ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java b/ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java index 4d5660a..8779c34 100644 --- a/ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java +++ b/ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java @@ -28,6 +28,8 @@ public class ToolkitFuncs { public MethodHandle text_new; public MethodHandle range_new; public MethodHandle generic_new; + public MethodHandle list_new; + public MethodHandle list_new2; public MethodHandle string_set; public MethodHandle string_get; @@ -68,6 +70,8 @@ public class ToolkitFuncs { MemorySegment text_new_addr = lib.find("ui_text_new").orElseThrow(); MemorySegment range_new_addr = lib.find("ui_range_new").orElseThrow(); MemorySegment generic_new_addr = lib.find("ui_generic_new").orElseThrow(); + MemorySegment list_new_addr = lib.find("ui_list_new").orElseThrow(); + MemorySegment list_new2_addr = lib.find("ui_list_new2").orElseThrow(); MemorySegment string_set_addr = lib.find("ui_string_set").orElseThrow(); MemorySegment string_get_addr = lib.find("ui_string_get").orElseThrow(); @@ -101,6 +105,8 @@ public class ToolkitFuncs { text_new = linker.downcallHandle(text_new_addr, sigm_mm); range_new = linker.downcallHandle(range_new_addr, sigm_mm); generic_new = linker.downcallHandle(generic_new_addr, sigm_mm); + list_new = linker.downcallHandle(list_new_addr, sigm_mm); + list_new2 = linker.downcallHandle(list_new_addr, FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS)); string_set = linker.downcallHandle(string_set_addr, sigv_mm); string_get = linker.downcallHandle(string_get_addr, sigm_m); diff --git a/ui-java/src/main/java/de/unixwork/ui/UiList.java b/ui-java/src/main/java/de/unixwork/ui/UiList.java new file mode 100644 index 0000000..fc1296f --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/UiList.java @@ -0,0 +1,67 @@ +package de.unixwork.ui; + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; + +public class UiList extends ArrayList { + protected MemorySegment valuePtr; + protected MemorySegment dataPtr; + + protected UiList(Context ctx, String name, MemorySegment listObj) { + super(); + + ToolkitFuncs ui = ToolkitFuncs.getInstance(); + Toolkit toolkit = Toolkit.getInstance(); + + MemorySegment nameCStr = MemorySegment.NULL; + try (Arena arena = Arena.ofConfined()) { + if(name != null) { + nameCStr = arena.allocateFrom(name); + } + + // instead of the default toolkit UiList implementation, we want to use a java based + // implementation, therefore we need to pass a list init function pointer + MethodHandle listInitMethod = MethodHandles.lookup().findStatic( + UiList.class, + "initList", + MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, MemorySegment.class)); + FunctionDescriptor sig = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS); + MemorySegment initFunc = toolkit.getLinker().upcallStub( + listInitMethod, + sig, + arena); + + valuePtr = (MemorySegment) ui.list_new2.invoke(ctx.getCtx(), nameCStr, initFunc, listObj); + dataPtr = listObj; + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + private static void initList(MemorySegment ctx, MemorySegment list, MemorySegment userData) { + // TODO + } + + protected static MemorySegment first(MemorySegment list) { + return MemorySegment.NULL; + } + + protected static MemorySegment next(MemorySegment list) { + return MemorySegment.NULL; + } + + protected static MemorySegment get(MemorySegment list, int index) { + return MemorySegment.NULL; + } + + protected static int count(MemorySegment list) { + return 0; + } + +}