package de.unixwork.ui;
+import java.io.*;
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Properties;
public class Toolkit {
private static Toolkit instance;
private Application app;
+ private Properties appProperties = new Properties();
+ byte[] propertiesData;
+
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 Document maps with just this context map
private ArrayList<Menu> sourceListMenuBuilderCache = new ArrayList<>();
private Toolkit(String appName) {
+ try {
+ loadAppProperties(appName);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
// load shared library
System.loadLibrary("uitk");
linker = Linker.nativeLinker();
lib = SymbolLookup.loaderLookup();
+ // set properties data if available
+ if(propertiesData != null) {
+ MemorySegment ui_set_properties_data_addr = lib.find("ui_set_properties_data").orElseThrow();
+ MethodHandle ui_set_properties_data = linker.downcallHandle(ui_set_properties_data_addr, FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.JAVA_LONG));
+
+ try (Arena arena = Arena.ofShared()){
+ MemorySegment segment = arena.allocate(propertiesData.length);
+ segment.asByteBuffer().put(propertiesData);
+ ui_set_properties_data.invoke(segment, (long)propertiesData.length);
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ propertiesData = null;
+ }
+
// 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);
}
}
+ public void loadAppProperties(String appName) throws IOException {
+ String path = Toolkit.getAppConfigPath(appName);
+ if(path == null) {
+ return;
+ }
+ if(path != null) {
+ File f = new File(path);
+ if(!f.exists()) {
+ return;
+ }
+ try {
+ propertiesData = Files.readAllBytes(Path.of(path));
+ } catch (IOException e) {
+ throw e;
+ }
+
+ try (ByteArrayInputStream in = new ByteArrayInputStream(propertiesData)) {
+ appProperties.load(in);
+ } catch (IOException e) {
+ throw e;
+ }
+ }
+ }
+
+ public Properties getAppProperties() {
+ return appProperties;
+ }
+
public void setIsObjRegEnabled(boolean value) {
isObjRegEnabled = value;
}
}
}
+ public static String getAppDir(String appName) {
+ if(appName == null || appName.isEmpty()) {
+ return null;
+ }
+
+ String home = System.getProperty("user.home");
+ String os = System.getProperty("os.name");
+ if(os.startsWith("Windows")) {
+ // windows
+ return home + "\\AppData\\Roaming\\" + appName;
+ } else if(os.startsWith("Mac OS X")) {
+ // macOS
+ return home + "/Library/Application Support/" + appName;
+ }
+
+ // unix
+ String xdgConfigHome = System.getenv("XDG_CONFIG_HOME");
+ if(xdgConfigHome != null) {
+ if(xdgConfigHome.endsWith("/")) {
+ xdgConfigHome = xdgConfigHome.substring(0, xdgConfigHome.length()-1);
+ }
+ return xdgConfigHome + "/" + appName;
+ } else {
+ return home + "/.config/" + appName;
+ }
+ }
+
+ public static String getAppConfigPath(String appName) {
+ String configPath = getAppDir(appName);
+ if(configPath == null) {
+ return null;
+ }
+ return configPath + File.separator + "application.properties";
+ }
+
public static String getConfigPath() {
ToolkitFuncs ui = ToolkitFuncs.getInstance();
try {