implement new menu itemlist binding (Motif)

7 days ago

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 06 Apr 2025 14:10:04 +0200 (7 days ago)
changeset 557
e6415fd4af4b
parent 556
1a95de56dadc
child 558
62aefa91ffc5

implement new menu itemlist binding (Motif)

ui/common/context.c file | annotate | diff | comparison | revisions
ui/common/context.h file | annotate | diff | comparison | revisions
ui/motif/menu.c file | annotate | diff | comparison | revisions
ui/motif/menu.h file | annotate | diff | comparison | revisions
--- a/ui/common/context.c	Sun Apr 06 13:54:28 2025 +0200
+++ b/ui/common/context.c	Sun Apr 06 14:10:04 2025 +0200
@@ -58,6 +58,7 @@
     memset(ctx, 0, sizeof(UiContext));
     ctx->mp = mp;
     ctx->allocator = mp->allocator;
+    ctx->destroy_handler = cxArrayListCreate(ctx->allocator, NULL, sizeof(UiDestroyHandler), 16);
     ctx->obj = toplevel;
     ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16);
     
@@ -82,6 +83,13 @@
     return ctx->parent ? uic_root_context(ctx->parent) : ctx;
 }
 
+void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data) {
+    UiDestroyHandler handler;
+    handler.destructor = func;
+    handler.data = data;
+    cxListAdd(ctx->destroy_handler, &handler);
+}
+
 void uic_context_prepare_close(UiContext *ctx) {
     cxListClear(ctx->groups);
     cxListClear(ctx->group_widgets);
@@ -469,6 +477,10 @@
 }
 
 UIEXPORT void ui_context_destroy(UiContext *ctx) {
+    CxIterator i = cxListIterator(ctx->destroy_handler);
+    cx_foreach(UiDestroyHandler *, h, i) {
+        h->destructor(h->data);
+    }
     cxMempoolFree(ctx->mp);
 }
 
--- a/ui/common/context.h	Sun Apr 06 13:54:28 2025 +0200
+++ b/ui/common/context.h	Sun Apr 06 14:10:04 2025 +0200
@@ -40,10 +40,11 @@
 extern "C" {
 #endif
 
-typedef struct UiVar         UiVar;
-typedef struct UiListPtr     UiListPtr;
-typedef struct UiListVar     UiListVar;
-typedef struct UiGroupWidget UiGroupWidget;
+typedef struct UiVar            UiVar;
+typedef struct UiListPtr        UiListPtr;
+typedef struct UiListVar        UiListVar;
+typedef struct UiGroupWidget    UiGroupWidget;
+typedef struct UiDestroyHandler UiDestroyHandler;
 
 typedef enum UiVarType {
     UI_VAR_SPECIAL = 0,
@@ -61,6 +62,7 @@
     UiObject      *obj;
     CxMempool *mp;
     const CxAllocator *allocator;
+    CxList *destroy_handler;
     
     void          *document;
     CxList        *documents;
@@ -106,11 +108,17 @@
     int           numgroups;
 };
 
+struct UiDestroyHandler {
+    cx_destructor_func destructor;
+    void *data;
+};
+
 
 void uic_init_global_context(void);
 
 UiContext* uic_context(UiObject *toplevel, CxMempool *mp);
 UiContext* uic_root_context(UiContext *ctx);
+void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data);
 void uic_context_set_document(UiContext *ctx, void *document); // deprecated
 void uic_context_detach_document(UiContext *ctx); // deprecated
 
--- a/ui/motif/menu.c	Sun Apr 06 13:54:28 2025 +0200
+++ b/ui/motif/menu.c	Sun Apr 06 14:10:04 2025 +0200
@@ -202,6 +202,20 @@
     ui_bind_radiobutton(obj, button, NULL, it->varname, it->callback, it->userdata, 0);
 }
 
+static void menuitem_list_remove_binding(void *obj) {
+    UiActiveMenuItemList *ls = obj;
+    UiList *list = ls->var->value;
+    CxList *bindings = list->obj;
+    if(bindings) {
+        (void)cxListFindRemove(bindings, obj);
+        if(cxListSize(bindings) == 0) {
+            cxListFree(bindings);
+            list->obj = NULL;
+            list->update = NULL;
+        }
+    }
+}
+
 void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) {
     UiMenuItemList *il = (UiMenuItemList*)item;
     const CxAllocator *a = obj->ctx->allocator;
@@ -218,17 +232,40 @@
     ls->userdata = il->userdata;
     ls->addseparator = il->addseparator;
     
-    ls->var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); //uic_widget_var(obj->ctx, obj->ctx, NULL, il->varname, UI_VAR_LIST);
-    UiList *list = ls->var->value;
-    
-    UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls);
-    list->observers = ui_obsvlist_add(list->observers, observer);
-    uic_list_register_observer_destructor(obj->ctx, list, observer);
-    
-    ui_update_menuitem_list(NULL, ls);
+    //ls->var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
+    ls->var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
+    if(ls->var) {
+        UiList *list = ls->var->value;
+        list->update = ui_menulist_update;
+        list->getselection = NULL;
+        list->setselection = NULL;
+        
+        // It is possible, that the UiVar is from a global shared context,
+        // used by multiple windows. To support this usecase, the list->obj
+        // binding object is a list of all connected UiActiveMenuItemList.
+        CxList *bindings = list->obj;
+        if(!bindings) {
+            bindings = cxLinkedListCreate(ls->var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS);
+            list->obj = bindings;
+        }
+        cxListAdd(bindings, ls);
+        
+        // The destruction of the toplevel obj must remove the menulist binding
+        uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls);
+        
+        ui_update_menuitem_list(ls);
+    }
 }
 
-void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) {
+void ui_menulist_update(UiList *list, int ignored) {
+    CxList *bindings = list->obj;
+    CxIterator i = cxListIterator(bindings);
+    cx_foreach(UiActiveMenuItemList *, ls, i) {
+        ui_update_menuitem_list(ls);
+    }
+}
+
+void ui_update_menuitem_list(UiActiveMenuItemList *list) {
     XmString s = NULL;
     Arg args[4];
     int n;
--- a/ui/motif/menu.h	Sun Apr 06 13:54:28 2025 +0200
+++ b/ui/motif/menu.h	Sun Apr 06 14:10:04 2025 +0200
@@ -64,7 +64,8 @@
 void add_checkitemnv_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj);
 void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj);
 
-void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list);
+void ui_menulist_update(UiList *list, int ignored);
+void ui_update_menuitem_list(UiActiveMenuItemList *list);
 
 #ifdef	__cplusplus
 }

mercurial