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() {
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 {
throw new RuntimeException(e);
}
}
+
+ public Arena getArena() {
+ return arena;
+ }
}
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
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");
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() {
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);
+ }
}
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;
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();
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);
--- /dev/null
+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;
+ }
+
+}