7 days ago
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 }