]> uap-core.de Git - rssreader.git/commitdiff
cache menuBuilder in sourceListGetValue
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 18 Oct 2025 08:49:17 +0000 (10:49 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 18 Oct 2025 08:49:17 +0000 (10:49 +0200)
ui-java/src/main/java/de/unixwork/ui/ListViewBuilder.java
ui-java/src/main/java/de/unixwork/ui/Menu.java
ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java
ui-java/src/main/java/de/unixwork/ui/SourceListBuilder.java
ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java
ui-java/src/main/java/de/unixwork/ui/Toolkit.java

index 9cc5289ff2e5e487083dab8e0251af8a9856c17b..8bdc17f84abbcd38f75fd7d7f6104a51db7f805e 100644 (file)
@@ -297,7 +297,7 @@ public class ListViewBuilder<T> extends AbstractWidgetBuilder {
         if(menuBuilder != null) {
             MenuFuncs ui = MenuFuncs.getInstance();
             try {
-                ui.menubuilder_free.invoke(menuBuilder);
+                ui.menubuilder_unref.invoke(menuBuilder);
             } catch (Throwable e) {
                 throw new RuntimeException(e);
             }
index 152eb0771f760503f9a32b7625dca851af57b76c..79f1a0f07fc7f419f656acc2d4b5a5edb55b2e0d 100644 (file)
@@ -9,6 +9,8 @@ public class Menu extends MenuElement {
     private LinkedList<MenuElement> items = new LinkedList<>();
     private String title;
 
+    private MemorySegment menuBuilder;
+
     public Menu() {
 
     }
@@ -62,5 +64,25 @@ public class Menu extends MenuElement {
             throw new RuntimeException(e);
         }
     }
+
+    protected MemorySegment createMenuBuilderCached() {
+        if(menuBuilder != null) {
+            return menuBuilder;
+        }
+        menuBuilder = createMenuBuilder();
+        return menuBuilder;
+    }
+
+    protected void cleanupMenuBuilder() {
+        if(menuBuilder != null) {
+            MenuFuncs ui = MenuFuncs.getInstance();
+            try {
+                ui.menubuilder_unref.invoke(menuBuilder);
+            } catch (Throwable e) {
+                throw new RuntimeException(e);
+            }
+            menuBuilder = null;
+        }
+    }
 }
 
index a4e1b955c0f80b5d9d863e27256c673ca7edac76..035fee536355fe653f866e4f3619f710caf6e4c1 100644 (file)
@@ -18,7 +18,8 @@ public class MenuFuncs {
     public MethodHandle menu_itemlist_create;
 
     public MethodHandle contextmenu_builder;
-    public MethodHandle menubuilder_free;
+    public MethodHandle menubuilder_ref;
+    public MethodHandle menubuilder_unref;
 
     public MethodHandle toolbar_item_create;
     public MethodHandle toolbar_toggleitem_create;
@@ -49,7 +50,8 @@ public class MenuFuncs {
         MemorySegment ui_menu_itemlist_create_addr = lib.find("ui_menu_itemlist_create").orElseThrow();
 
         MemorySegment ui_contextmenu_builder_addr = lib.find("ui_contextmenu_builder").orElseThrow();
-        MemorySegment ui_menubuilder_free_addr = lib.find("ui_menubuilder_free").orElseThrow();
+        MemorySegment ui_menubuilder_ref_addr = lib.find("ui_menubuilder_ref").orElseThrow();
+        MemorySegment ui_menubuilder_unref_addr = lib.find("ui_menubuilder_unref").orElseThrow();
 
         MemorySegment ui_toolbar_item_create_addr = lib.find("ui_toolbar_item_create").orElseThrow();
         MemorySegment ui_toolbar_toggleitem_create_addr = lib.find("ui_toolbar_toggleitem_create").orElseThrow();
@@ -68,7 +70,8 @@ public class MenuFuncs {
         menu_itemlist_create = linker.downcallHandle(ui_menu_itemlist_create_addr, sigv_m);
 
         contextmenu_builder = linker.downcallHandle(ui_contextmenu_builder_addr, sigv_mm);
-        menubuilder_free = linker.downcallHandle(ui_menubuilder_free_addr, sigv_m);
+        menubuilder_ref = linker.downcallHandle(ui_menubuilder_ref_addr, sigv_m);
+        menubuilder_unref = linker.downcallHandle(ui_menubuilder_unref_addr, sigv_m);
 
         toolbar_item_create = linker.downcallHandle(ui_toolbar_item_create_addr, sigv_mm);
         toolbar_toggleitem_create = linker.downcallHandle(ui_toolbar_toggleitem_create_addr, sigv_mm);
index 7728d0760e46990e8712539fe257750b07c32f9a..54d2e366ec1252667ee230c12945482c41b8f80c 100644 (file)
@@ -249,7 +249,7 @@ public class SourceListBuilder<T> extends AbstractWidgetBuilder {
         if(menuBuilder != null) {
             MenuFuncs ui = MenuFuncs.getInstance();
             try {
-                ui.menubuilder_free.invoke(menuBuilder);
+                ui.menubuilder_unref.invoke(menuBuilder);
             } catch (Throwable e) {
                 throw new RuntimeException(e);
             }
index bc4fe069fa9622f5951bad8c7fc486df701dbc1b..9ae86e5d453c05fb0c8d9405e0b8b18fee970a20 100644 (file)
@@ -316,7 +316,7 @@ public class TableViewBuilder<T> extends AbstractWidgetBuilder {
         if(menuBuilder != null) {
             MenuFuncs ui = MenuFuncs.getInstance();
             try {
-                ui.menubuilder_free.invoke(menuBuilder);
+                ui.menubuilder_unref.invoke(menuBuilder);
             } catch (Throwable e) {
                 throw new RuntimeException(e);
             }
index d9c5aadce313f68866ac9e308c3154e33fc17f8f..23742e4a6cfc97e47e75b2369e82989639e267db 100644 (file)
@@ -54,6 +54,8 @@ public class Toolkit {
 
     private HashMap<Integer, ThreadCallback> threadCallbacks = new HashMap<>();
 
+    private ArrayList<Menu> sourceListMenuBuilderCache = new ArrayList<>();
+
     private Toolkit(String appName) {
         // load shared library
         System.loadLibrary("uitk");
@@ -104,6 +106,7 @@ public class Toolkit {
         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*)
+        FunctionDescriptor sigv_m = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS);
         FunctionDescriptor sigv = FunctionDescriptor.ofVoid();
         FunctionDescriptor sigv_b = FunctionDescriptor.ofVoid(ValueLayout.JAVA_BOOLEAN);
 
@@ -116,6 +119,9 @@ public class Toolkit {
         app_save_settings = linker.downcallHandle(app_save_settings_addr, sigv);
         app_exit_on_shutdown = linker.downcallHandle(app_exit_on_shutdown_addr, sigv_b);
 
+        MemorySegment ui_sourcelist_set_update_callback_addr = lib.find("ui_sourcelist_set_update_callback").orElseThrow();
+        MethodHandle ui_sourcelist_set_update_callback = linker.downcallHandle(ui_sourcelist_set_update_callback_addr, sigv_m);
+
         // init java based UiList implementation
         try {
             MethodHandle listFirstMethod = MethodHandles.lookup().findStatic(
@@ -179,6 +185,10 @@ public class Toolkit {
                             int.class,
                             MemorySegment.class,
                             MemorySegment.class));
+            MethodHandle scListUpdated = MethodHandles.lookup().findStatic(
+                    Toolkit.class,
+                    "sourceListUpdated",
+                    MethodType.methodType(void.class));
             MethodHandle getStyleMethod = MethodHandles.lookup().findStatic(
                     Toolkit.class,
                     "getStyle",
@@ -220,10 +230,15 @@ public class Toolkit {
                             ValueLayout.ADDRESS,
                             ValueLayout.ADDRESS),
                     staticArena);
+
+            MemorySegment scListUpdatedPtr = linker.upcallStub(scListUpdated, FunctionDescriptor.ofVoid(), staticArena);
+            ui_sourcelist_set_update_callback.invoke(scListUpdatedPtr);
         } catch (NoSuchMethodException e) {
             throw new RuntimeException(e);
         } catch (IllegalAccessException e) {
             throw new RuntimeException(e);
+        } catch (Throwable e) {
+            throw new RuntimeException(e);
         }
 
         // threadfunc wrapper
@@ -571,7 +586,8 @@ public class Toolkit {
         long ctxPtr = userdata.getAtIndex(ValueLayout.JAVA_LONG, 0);
         long converterIndex = userdata.getAtIndex(ValueLayout.JAVA_LONG, 1);
 
-        Context ctx = Toolkit.getInstance().getContext(ctxPtr);
+        Toolkit tk = Toolkit.getInstance();
+        Context ctx = tk.getContext(ctxPtr);
         SubListValueConverter conv = ctx.getSubListValueConverter((int)converterIndex);
 
         UiList uilist = Toolkit.listPtrToObject(list);
@@ -598,6 +614,21 @@ public class Toolkit {
                 ui.sublist_item_set_button_label.invoke(out_item, cstr);
             }
             if(item.buttonMenu != null) {
+                MemorySegment menuBuilder = MemorySegment.NULL;
+                if(tk.sourceListMenuBuilderCache.size() <= 32) {
+                    // Cache up to 32 menubuilder objects
+                    // The cache is cleaned by the sourceListUpdated() method
+                    menuBuilder = item.buttonMenu.createMenuBuilderCached();
+                    if(!tk.sourceListMenuBuilderCache.contains(item.buttonMenu)) {
+                        tk.sourceListMenuBuilderCache.add(item.buttonMenu);
+                        // the menuBuilder is owned by the cache
+                        MenuFuncs.getInstance().menubuilder_ref.invoke(menuBuilder);
+                    }
+                } else {
+                    // the sourcelist takes ownership of the menubuilder
+                    menuBuilder = item.buttonMenu.createMenuBuilder();
+                }
+
                 ui.sublist_item_set_button_menu.invoke(out_item, item.buttonMenu.createMenuBuilder());
             }
             if(item.badge != null) {
@@ -609,6 +640,12 @@ public class Toolkit {
         }
     }
 
+    public static void sourceListUpdated() {
+        for(Menu menu : Toolkit.getInstance().sourceListMenuBuilderCache) {
+            menu.cleanupMenuBuilder();
+        }
+    }
+
     public static boolean getStyle(MemorySegment list, MemorySegment elm, int row, int col, MemorySegment userdata, MemorySegment stylePtr) {
         if(userdata == MemorySegment.NULL) {
             return false;