From: Olaf Wintermann Date: Sat, 18 Oct 2025 08:49:17 +0000 (+0200) Subject: cache menuBuilder in sourceListGetValue X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=a24ac2311c2beffb06f0f6329afb6e23ee95a00a;p=rssreader.git cache menuBuilder in sourceListGetValue --- diff --git a/ui-java/src/main/java/de/unixwork/ui/ListViewBuilder.java b/ui-java/src/main/java/de/unixwork/ui/ListViewBuilder.java index 9cc5289..8bdc17f 100644 --- a/ui-java/src/main/java/de/unixwork/ui/ListViewBuilder.java +++ b/ui-java/src/main/java/de/unixwork/ui/ListViewBuilder.java @@ -297,7 +297,7 @@ public class ListViewBuilder 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); } diff --git a/ui-java/src/main/java/de/unixwork/ui/Menu.java b/ui-java/src/main/java/de/unixwork/ui/Menu.java index 152eb07..79f1a0f 100644 --- a/ui-java/src/main/java/de/unixwork/ui/Menu.java +++ b/ui-java/src/main/java/de/unixwork/ui/Menu.java @@ -9,6 +9,8 @@ public class Menu extends MenuElement { private LinkedList 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; + } + } } diff --git a/ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java b/ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java index a4e1b95..035fee5 100644 --- a/ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java +++ b/ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java @@ -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); diff --git a/ui-java/src/main/java/de/unixwork/ui/SourceListBuilder.java b/ui-java/src/main/java/de/unixwork/ui/SourceListBuilder.java index 7728d07..54d2e36 100644 --- a/ui-java/src/main/java/de/unixwork/ui/SourceListBuilder.java +++ b/ui-java/src/main/java/de/unixwork/ui/SourceListBuilder.java @@ -249,7 +249,7 @@ public class SourceListBuilder 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); } diff --git a/ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java b/ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java index bc4fe06..9ae86e5 100644 --- a/ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java +++ b/ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java @@ -316,7 +316,7 @@ public class TableViewBuilder 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); } diff --git a/ui-java/src/main/java/de/unixwork/ui/Toolkit.java b/ui-java/src/main/java/de/unixwork/ui/Toolkit.java index d9c5aad..23742e4 100644 --- a/ui-java/src/main/java/de/unixwork/ui/Toolkit.java +++ b/ui-java/src/main/java/de/unixwork/ui/Toolkit.java @@ -54,6 +54,8 @@ public class Toolkit { private HashMap threadCallbacks = new HashMap<>(); + private ArrayList 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;