From: Olaf Wintermann Date: Fri, 6 Jun 2025 16:54:33 +0000 (+0200) Subject: add initial build system and some code X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=013e533e1d1fe90d4b9e9a6fb855d4dd9700178b;p=rssreader.git add initial build system and some code --- 013e533e1d1fe90d4b9e9a6fb855d4dd9700178b diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f5d5fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.idea/ +*.iml +*.iws +out/ +.idea_modules/ +.DS_Store +/target/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c99dc62 --- /dev/null +++ b/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + de.unixwork + rssreader + 1.0-SNAPSHOT + pom + + rssreader + http://unixwork.de/ + + + UTF-8 + 24 + + + + ui-java + ui-kotlin + rss-application + + + + + + + + + + + + + + + + + + diff --git a/rss-application/.gitignore b/rss-application/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/rss-application/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/rss-application/pom.xml b/rss-application/pom.xml new file mode 100644 index 0000000..2599412 --- /dev/null +++ b/rss-application/pom.xml @@ -0,0 +1,100 @@ + + + 4.0.0 + + de.unixwork + rss-application + 1.0-SNAPSHOT + + + rssreader + de.unixwork + 1.0-SNAPSHOT + + + + UTF-8 + official + 1.8 + + + + + mavenCentral + https://repo1.maven.org/maven2/ + + + + + src/main/kotlin + src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + 2.1.20 + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + maven-surefire-plugin + 2.22.2 + + + maven-failsafe-plugin + 2.22.2 + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + MainKt + + + + + + + + org.jetbrains.kotlin + kotlin-test-junit5 + 2.1.20 + test + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.jetbrains.kotlin + kotlin-stdlib + 2.1.20 + + + + de.unixwork + ui-kotlin + 1.0-SNAPSHOT + + + + diff --git a/rss-application/src/main/kotlin/Main.kt b/rss-application/src/main/kotlin/Main.kt new file mode 100644 index 0000000..732b21a --- /dev/null +++ b/rss-application/src/main/kotlin/Main.kt @@ -0,0 +1,16 @@ +package de.unixwork + +//TIP To Run code, press or +// click the icon in the gutter. +fun main() { + val name = "Kotlin" + //TIP Press with your caret at the highlighted text + // to see how IntelliJ IDEA suggests fixing it. + println("Hello, " + name + "!") + + for (i in 1..5) { + //TIP Press to start debugging your code. We have set one breakpoint + // for you, but you can always add more by pressing . + println("i = $i") + } +} \ No newline at end of file diff --git a/ui-java/.gitignore b/ui-java/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/ui-java/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/ui-java/pom.xml b/ui-java/pom.xml new file mode 100644 index 0000000..0ac706d --- /dev/null +++ b/ui-java/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + de.unixwork + ui-java + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 24 + 24 + + --enable-preview + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + + java + + + + + de.unixwork.ui.demo.Main + test + + + + + + + rssreader + de.unixwork + 1.0-SNAPSHOT + + + + 24 + 24 + UTF-8 + + + diff --git a/ui-java/src/main/java/de/unixwork/ui/Application.java b/ui-java/src/main/java/de/unixwork/ui/Application.java new file mode 100644 index 0000000..f2e31f3 --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/Application.java @@ -0,0 +1,10 @@ +package de.unixwork.ui; + +public interface Application { + + void startup(); + + default void shutdown() { + + } +} diff --git a/ui-java/src/main/java/de/unixwork/ui/Toolkit.java b/ui-java/src/main/java/de/unixwork/ui/Toolkit.java new file mode 100644 index 0000000..38925da --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/Toolkit.java @@ -0,0 +1,159 @@ +package de.unixwork.ui; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class Toolkit { + private static Toolkit instance; + + private Application app; + + // used for all strings and other memory, that is expected to be const + // and the UI toolkit does not create copies + private final Arena staticArena = Arena.ofShared(); + + private Linker linker; + + private SymbolLookup lib; + private MethodHandle mainFunc; + + private Toolkit(String appName) { + // load shared library + System.loadLibrary("uitk"); + linker = Linker.nativeLinker(); + lib = SymbolLookup.loaderLookup(); + + // get init function + MemorySegment ui_init_addr = lib.find("ui_init").orElseThrow(); + FunctionDescriptor ui_init_sig = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.ADDRESS); + MethodHandle ui_init = linker.downcallHandle(ui_init_addr, ui_init_sig); + + // create static/const C string + MemorySegment appNameCStr = staticArena.allocateFrom(appName); + try { + ui_init.invoke(appNameCStr, 0, MemorySegment.NULL); + } catch (Throwable e) { + e.printStackTrace(); + System.exit(1); + } + + initFunctions(); + + UiObjectFuncs.init(linker, lib); + } + + private void initFunctions() { + FunctionDescriptor sigv_v = FunctionDescriptor.ofVoid(); // void func(void) + + MemorySegment ui_main_addr = lib.find("ui_main").orElseThrow(); + mainFunc = linker.downcallHandle(ui_main_addr, sigv_v); + } + + private static Toolkit getInstance() { + if(Toolkit.instance == null) { + Toolkit.init("app1"); + } + return Toolkit.instance; + } + + public static void init(String appName) { + if(Toolkit.instance != null) { + return; + } + Toolkit.instance = new Toolkit(appName); + } + + private static void onStartup(MemorySegment unused1, MemorySegment unused2) { + Toolkit toolkit = Toolkit.getInstance(); + if(toolkit.app != null) { + toolkit.app.startup(); + } + } + + private static void onShutdown(MemorySegment unused1, MemorySegment unused2) { + Toolkit toolkit = Toolkit.getInstance(); + if(toolkit.app != null) { + toolkit.app.shutdown(); + } + } + + private static void onOpen(MemorySegment unused1, MemorySegment unused2) { + Toolkit toolkit = Toolkit.getInstance(); + if(toolkit.app != null) { + // TODO + } + } + + public static void runApplication(Application app) { + Toolkit toolkit = Toolkit.getInstance(); + toolkit.app = app; + + // create method handles for native functions + FunctionDescriptor handlerSig = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS); + MethodHandle onstartup = toolkit.linker.downcallHandle(toolkit.lib.find("ui_onstartup").orElseThrow(), handlerSig); + MethodHandle onshutdown = toolkit.linker.downcallHandle(toolkit.lib.find("ui_onexit").orElseThrow(), handlerSig); + MethodHandle onopen = toolkit.linker.downcallHandle(toolkit.lib.find("ui_onopen").orElseThrow(), handlerSig); + + // get java wrapper method handles + MethodHandle onstartupCallback = null; + MethodHandle onshutdownCallback = null; + MethodHandle onopenCallback = null; + try { + onstartupCallback = MethodHandles.lookup().findStatic( + Toolkit.class, + "onStartup", + MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); + onshutdownCallback = MethodHandles.lookup().findStatic( + Toolkit.class, + "onShutdown", + MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); + onopenCallback = MethodHandles.lookup().findStatic( + Toolkit.class, + "onOpen", + MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + System.exit(1); + } + + try (Arena arena = Arena.ofConfined()) { + // create native function pointers for java methods + FunctionDescriptor callbackDescriptor = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS); + MemorySegment onStartupFunc = toolkit.linker.upcallStub( + onstartupCallback, + callbackDescriptor, + arena); + MemorySegment onShutdownFunc = toolkit.linker.upcallStub( + onshutdownCallback, + callbackDescriptor, + arena); + MemorySegment onOpenFunc = toolkit.linker.upcallStub( + onopenCallback, + callbackDescriptor, + arena); + + // register java application callbacks + onstartup.invoke(onStartupFunc, MemorySegment.NULL); + onshutdown.invoke(onShutdownFunc, MemorySegment.NULL); + onopen.invoke(onOpenFunc, MemorySegment.NULL); + + // run ui_main(), which invokes the application callback functions + Toolkit.mainloop(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + /* + * usually this should not be called directly, use runApplication instead + */ + public static void mainloop() { + try { + Toolkit.getInstance().mainFunc.invoke(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/ui-java/src/main/java/de/unixwork/ui/UiObject.java b/ui-java/src/main/java/de/unixwork/ui/UiObject.java new file mode 100644 index 0000000..374f76d --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/UiObject.java @@ -0,0 +1,19 @@ +package de.unixwork.ui; + +import java.lang.foreign.MemorySegment; + +public class UiObject { + MemorySegment ptr; + + UiObject(MemorySegment ptr) { + this.ptr = ptr; + } + + public static UiObject createWindow(String title) { + return UiObjectFuncs.instance.window(title); + } + + public void show() { + UiObjectFuncs.instance.show(this); + } +} diff --git a/ui-java/src/main/java/de/unixwork/ui/UiObjectFuncs.java b/ui-java/src/main/java/de/unixwork/ui/UiObjectFuncs.java new file mode 100644 index 0000000..4f2071e --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/UiObjectFuncs.java @@ -0,0 +1,49 @@ +package de.unixwork.ui; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; + +class UiObjectFuncs { + static UiObjectFuncs instance; + + MethodHandle ui_show; + MethodHandle ui_window; + + private UiObjectFuncs(Linker linker, SymbolLookup lib) { + // void* func(void*, void*) + FunctionDescriptor sigm_mm = FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS); + // void func(void*) + FunctionDescriptor sigv_m = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS); + + MemorySegment ui_show_addr = lib.find("ui_show").orElseThrow(); + MemorySegment ui_window_addr = lib.find("ui_window").orElseThrow(); + + ui_show = linker.downcallHandle(ui_show_addr, sigv_m); + ui_window = linker.downcallHandle(ui_window_addr, sigm_mm); + } + + // must be called by the Toolkit constructor + static void init(Linker linker, SymbolLookup lib) { + UiObjectFuncs.instance = new UiObjectFuncs(linker, lib); + } + + UiObject window(String title) { + MemorySegment obj = null; + try (Arena arena = Arena.ofConfined()) { + MemorySegment cstr = arena.allocateFrom(title); + obj = (MemorySegment) ui_window.invoke(cstr, MemorySegment.NULL); + } catch (Throwable e) { + throw new RuntimeException(e); + } + + return new UiObject(obj); + } + + void show(UiObject obj) { + try { + ui_show.invoke(obj.ptr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/ui-java/src/test/java/de/unixwork/ui/demo/Main.java b/ui-java/src/test/java/de/unixwork/ui/demo/Main.java new file mode 100644 index 0000000..bda29de --- /dev/null +++ b/ui-java/src/test/java/de/unixwork/ui/demo/Main.java @@ -0,0 +1,17 @@ +package de.unixwork.ui.demo; + +import de.unixwork.ui.*; + +public class Main implements Application{ + public void startup() { + UiObject window = UiObject.createWindow("Test Window"); + window.show(); + } + + public static void main(String[] args) { + System.out.println("UI Demo"); + Toolkit.init("testapp"); + + Toolkit.runApplication(new Main()); + } +} diff --git a/ui-kotlin/.gitignore b/ui-kotlin/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/ui-kotlin/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/ui-kotlin/pom.xml b/ui-kotlin/pom.xml new file mode 100644 index 0000000..df08ad2 --- /dev/null +++ b/ui-kotlin/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + de.unixwork + ui-kotlin + 1.0-SNAPSHOT + + + rssreader + de.unixwork + 1.0-SNAPSHOT + + + + UTF-8 + official + 1.8 + + + + + mavenCentral + https://repo1.maven.org/maven2/ + + + + + src/main/kotlin + src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + 2.1.20 + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + maven-surefire-plugin + 2.22.2 + + + maven-failsafe-plugin + 2.22.2 + + + + + + + org.jetbrains.kotlin + kotlin-test-junit5 + 2.1.20 + test + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.jetbrains.kotlin + kotlin-stdlib + 2.1.20 + + + + de.unixwork + ui-java + 1.0-SNAPSHOT + + + +