]> uap-core.de Git - rssreader.git/commitdiff
add UiList java wrapper (wip)
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 21 Jun 2025 13:55:49 +0000 (15:55 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 21 Jun 2025 13:55:49 +0000 (15:55 +0200)
ui-java/src/main/java/de/unixwork/ui/Context.java
ui-java/src/main/java/de/unixwork/ui/Toolkit.java
ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java
ui-java/src/main/java/de/unixwork/ui/UiList.java [new file with mode: 0644]

index c42ec8a62b670032db07ee73fe0f2593969aa74a..936668c1f3223bf4a22fcc25227fa712fc44569b 100644 (file)
@@ -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<UiList> 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 <T> UiList<T> list() {
+        UiList<T> ls = list(null);
+        return ls;
+    }
+
+    public <T> UiList<T> 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<T>(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;
+    }
 }
index b515588de0bd84d631293d664329ab740a57f20c..58b327ced3c74fee990e9411368e81ecc466f288 100644 (file)
@@ -13,6 +13,7 @@ public class Toolkit {
 
     private HashMap<Long, UiObject> toplevelObjects = new HashMap<>();
     private HashMap<Long, Document> documents = new HashMap<>();
+    private HashMap<Long, Context> 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);
+    }
 }
index 4d5660a228576a6647633e8b6dd0bea1ef1ecce1..8779c34bc38423be01c3c8fd1d06b3f13a9132d2 100644 (file)
@@ -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 (file)
index 0000000..fc1296f
--- /dev/null
@@ -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<T> extends ArrayList<T> {
+    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;
+    }
+
+}