]> uap-core.de Git - rssreader.git/commitdiff
implement global (menu) event handling
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Mon, 7 Jul 2025 18:32:04 +0000 (20:32 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Mon, 7 Jul 2025 18:32:04 +0000 (20:32 +0200)
ui-java/src/main/java/de/unixwork/ui/AppMenu.java
ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java
ui-java/src/main/java/de/unixwork/ui/EventWrapper.java
ui-java/src/main/java/de/unixwork/ui/Toolkit.java
ui-java/src/test/java/de/unixwork/ui/demo/Main.java

index d98a751fb4d7b4cf7c20339f8433c7be1468fbf9..184d0881d9e5b6d8b553b28a61132477e76a5b0a 100644 (file)
@@ -40,7 +40,11 @@ public class AppMenu {
                 a.menuitem_args_set_icon.invoke(args, cstr);
             }
             if(onClick != null) {
-                // TODO
+                EventWrapper event = new EventWrapper(onClick);
+
+                // set toolkit args
+                a.menuitem_args_set_onclick.invoke(args, event.getCallback());
+                a.menuitem_args_set_onclickdata.invoke(args, event.getUserData());
             }
             ui.menuitem_create.invoke(args);
             a.menuitem_args_free.invoke(args);
index aa70c3e1c5d894a1ccaa195304f1c65437d33d4a..be12f851b56966097ced1a9663034906073a98d1 100644 (file)
@@ -10,6 +10,8 @@ class ArgFuncs {
     MethodHandle menuitem_args_set_label;
     MethodHandle menuitem_args_set_stockid;
     MethodHandle menuitem_args_set_icon;
+    MethodHandle menuitem_args_set_onclick;
+    MethodHandle menuitem_args_set_onclickdata;
     MethodHandle menuitem_args_free;
 
     MethodHandle menutoggleitem_args_new;
@@ -310,6 +312,8 @@ class ArgFuncs {
         menuitem_args_set_label = linker.downcallHandle(ui_menuitem_args_set_label_addr, sigv_mm);
         menuitem_args_set_stockid = linker.downcallHandle(ui_menuitem_args_set_stockid_addr, sigv_mm);
         menuitem_args_set_icon = linker.downcallHandle(ui_menuitem_args_set_icon_addr, sigv_mm);
+        menuitem_args_set_onclick = linker.downcallHandle(ui_menuitem_args_set_onclick_addr, sigv_mm);
+        menuitem_args_set_onclickdata = linker.downcallHandle(ui_menuitem_args_set_onclickdata_addr, sigv_mm);
         menuitem_args_free = linker.downcallHandle(ui_menuitem_args_free_addr, sigv_m);
 
         menutoggleitem_args_new = linker.downcallHandle(ui_menutoggleitem_args_new_addr, sigm);
index a2d34b8c86740866a738b0e3df53514c641b0906..b018454328e0e3f471f9e35403322abdddac7028 100644 (file)
@@ -1,5 +1,6 @@
 package de.unixwork.ui;
 
+import javax.tools.Tool;
 import java.lang.foreign.Arena;
 import java.lang.foreign.FunctionDescriptor;
 import java.lang.foreign.MemorySegment;
@@ -13,11 +14,27 @@ public class EventWrapper {
     private MemorySegment userdata;
 
     public EventWrapper(UiObject obj, EventHandler handler) {
-        // We need to create an upcall stub for the static ButtonBuilder.eventHandler method
+        // We need to create an upcall stub for the static EventWrapper.eventHandler method
         // Also, the event handler must be registered in the object and the returned index
         // is used as callback userdata. This way we can map the userdata to the java
         // EventHandler object
 
+        Arena objArena = obj.getArena(); // very important to use the obj arena
+        initCallback(objArena, "eventHandler");
+
+        long index = obj.addEventHandler(handler);
+        // use index as callback userdata, like casting it to intptr_t/void*
+        userdata = MemorySegment.ofAddress(index);
+    }
+
+    public EventWrapper(EventHandler handler) {
+        Toolkit toolkit = Toolkit.getInstance();
+        initCallback(toolkit.getStaticArena(), "globalEventHandler");
+        long index = toolkit.addEventHandler(handler);
+        userdata = MemorySegment.ofAddress(index);
+    }
+
+    private void initCallback(Arena arena, String methodName) {
         Toolkit toolkit = Toolkit.getInstance();
         // void callback(UiEvent *event, void *userdata)
         FunctionDescriptor handlerSig = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS);
@@ -26,22 +43,18 @@ public class EventWrapper {
         try {
             callbackMethod = MethodHandles.lookup().findStatic(
                     EventWrapper.class,
-                    "eventHandler",
+                    methodName,
                     MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class));
         } catch (NoSuchMethodException e) {
             throw new RuntimeException(e);
         } catch (IllegalAccessException e) {
             throw new RuntimeException(e);
         }
-        Arena objArena = obj.getArena();
+
         callback = toolkit.getLinker().upcallStub(
                 callbackMethod,
                 handlerSig,
-                obj.getArena()); // very important to use the obj arena
-
-        long index = obj.addEventHandler(handler);
-        // use index as callback userdata, like casting it to intptr_t/void*
-        userdata = MemorySegment.ofAddress(index);
+                arena);
     }
 
     public MemorySegment getCallback() {
@@ -58,6 +71,19 @@ public class EventWrapper {
         Event e = new Event(event);
         UiObject obj = e.getObject();
         EventHandler handler = obj.getEventHandler(eventHandlerIndex);
-        handler.callback(e);
+        if(handler != null) {
+            handler.callback(e);
+        } // else: error?
+    }
+
+    public static void globalEventHandler(MemorySegment event, MemorySegment userdata) {
+        int eventHandlerIndex = (int)userdata.address();
+
+        Event e = new Event(event);
+        UiObject obj = e.getObject();
+        EventHandler handler = Toolkit.getInstance().getEventHandler(eventHandlerIndex);
+        if(handler != null) {
+            handler.callback(e);
+        } // else: error?
     }
 }
index 15523e281ba89d4d6e166d6673ccfe401d45ff02..1e2b89898ade153cf282293a0b7da855f0775fa4 100644 (file)
@@ -4,6 +4,7 @@ import java.lang.foreign.*;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.ArrayList;
 import java.util.HashMap;
 
 public class Toolkit {
@@ -29,6 +30,8 @@ public class Toolkit {
     private SymbolLookup lib;
     private MethodHandle mainFunc;
 
+    private ArrayList<EventHandler> eventHandlers = new ArrayList<>();
+
     protected MemorySegment listFirst;
     protected MemorySegment listNext;
     protected MemorySegment listGet;
@@ -339,6 +342,15 @@ public class Toolkit {
         // TODO: remove this notice when subobjects are removed from toolkit
     }
 
+    public long addEventHandler(EventHandler handler) {
+        eventHandlers.add(handler);
+        return eventHandlers.size() - 1;
+    }
+
+    public EventHandler getEventHandler(int index) {
+        return eventHandlers.get(index);
+    }
+
     public Context getContext(long address) {
         return contexts.get(address);
     }
index 2a6e1c991a6f1039cc9a1814eb292dc43b7187a0..60bc75d44a4eddb381698e9c77a0f1fe0ab47082 100644 (file)
@@ -51,8 +51,13 @@ public class Main implements Application{
         Toolkit.init("testapp");
 
         AppMenu.menu("File", () -> {
-            AppMenu.menuItem("Open", null);
-            AppMenu.menuItem("Exit", null);
+            AppMenu.menuItem("Open", event -> {
+                System.out.println("Open");
+            });
+            AppMenu.menuItem("Exit", event -> {
+                System.out.println("Exit");
+                System.exit(0);
+            });
         });
 
         Toolkit.runApplication(new Main());