From: Olaf Wintermann Date: Tue, 19 May 2026 16:41:29 +0000 (+0200) Subject: add UiObject onclose event handler X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=a24f3bcbce83c36dafe4b3d856be28e7386652d0;p=note.git add UiObject onclose event handler --- diff --git a/application/src/window.rs b/application/src/window.rs index 6fd2ab2..e3a8bf3 100644 --- a/application/src/window.rs +++ b/application/src/window.rs @@ -35,6 +35,7 @@ use crate::newnotebook::new_notebook_dialog; #[derive(UiModel)] pub struct MainWindow { + pub obj: Option>, pub backend: BackendHandle, #[bind] @@ -45,6 +46,7 @@ pub struct MainWindow { impl MainWindow { pub fn new(app: &App) -> MainWindow { MainWindow { + obj: None, backend: app.backend.clone(), notebooks: UiSourceList::default() } @@ -83,8 +85,9 @@ impl MainWindow { pub fn create_window(app: &App, ctx: &AppContext) -> UiObject { let windowdata: MainWindow = MainWindow::new(app); - let window = ctx.splitview_window("note", true, windowdata, |obj, data| { + let mut window = ctx.splitview_window("note", true, windowdata, |obj, data| { init_window_data(data, app); + data.obj = Some(obj.clone()); obj.sidebar_builder().create(|obj|{ obj.sourcelist(|b|{ @@ -127,6 +130,10 @@ pub fn create_window(app: &App, ctx: &AppContext) -> UiObject toolkit::UiObject { } } + pub fn onclose(&mut self, f: F) + where F: FnMut(&mut event::Event) + 'static { + let wrapper = Box::new(EventWrapper { callback: Box::new(f) }); + let ptr = self.ctx.reg_box(wrapper); + unsafe { + ui_object_set_onclose(self.ptr, Some(event::event_wrapper::), ptr.cast()); + } + } + pub fn set_size(&mut self, width: u32, height: u32) { unsafe { ui_window_size(self.ptr, width as c_int, height as c_int); @@ -487,6 +496,7 @@ extern "C" { pub fn ui_object_get_windowdata(obj: *const UiObject) -> *mut c_void; pub fn ui_object_set_windowdata(obj: *mut UiObject, data: *mut c_void); pub fn ui_object_get_context(obj: *const UiObject) -> *mut UiContext; + fn ui_object_set_onclose(obj: *const UiObject, onclose: UiCallback, data: *mut c_void); pub fn ui_reg_destructor(ctx: *mut UiContext, data: *mut c_void, destructor: UiDestructor); diff --git a/ui/common/context.c b/ui/common/context.c index 12130d0..19de77d 100644 --- a/ui/common/context.c +++ b/ui/common/context.c @@ -97,6 +97,15 @@ void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *d cxListAdd(ctx->destroy_handler, &handler); } +void uic_context_remove_destructor(UiContext *ctx, void *data) { + CxIterator i = cxListIterator(ctx->destroy_handler); + cx_foreach(UiDestroyHandler *, handler, i) { + if(handler->data == data) { + cxIteratorFlagRemoval(i); + } + } +} + void uic_context_prepare_close(UiContext *ctx) { cxListClear(ctx->states); cxListClear(ctx->state_widgets); @@ -733,6 +742,10 @@ void ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr) { uic_context_add_destructor(ctx, destr, data); } +void ui_remove_destructor(UiContext *ctx, void *data) { + uic_context_remove_destructor(ctx, data); +} + void ui_set_destructor(void *mem, ui_destructor_func destr) { cxMempoolSetDestructor(mem, (cx_destructor_func)destr); } diff --git a/ui/common/context.h b/ui/common/context.h index c846ba5..d692f16 100644 --- a/ui/common/context.h +++ b/ui/common/context.h @@ -134,6 +134,7 @@ 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_remove_destructor(UiContext *ctx, void *data); void uic_context_prepare_close(UiContext *ctx); void uic_context_destroy(UiContext *ctx, void *document); diff --git a/ui/common/object.c b/ui/common/object.c index 16f2ed9..8ea5b37 100644 --- a/ui/common/object.c +++ b/ui/common/object.c @@ -103,6 +103,7 @@ int ui_object_unref(UiObject *obj) { // it is possible to have 0 references, in case // a window was created but ui_show was never called if(obj->ref == 0 || --obj->ref == 0) { + uic_context_prepare_close(obj->ctx); if(obj->destroy) { obj->destroy(obj); } else { diff --git a/ui/common/wrapper.c b/ui/common/wrapper.c index 575dd29..8a89145 100644 --- a/ui/common/wrapper.c +++ b/ui/common/wrapper.c @@ -45,6 +45,11 @@ void ui_object_set_windowdata(UiObject *obj, void *windowdata) { obj->window = windowdata; } +void ui_object_set_onclose(UiObject *obj, ui_callback callback, void *userdata) { + obj->onclose = callback; + obj->onclosedata = userdata; +} + /* ---------------------------- UiList ---------------------------- */ diff --git a/ui/common/wrapper.h b/ui/common/wrapper.h index 37f2f38..1c94d53 100644 --- a/ui/common/wrapper.h +++ b/ui/common/wrapper.h @@ -39,6 +39,7 @@ extern "C" { UIEXPORT UiContext* ui_object_get_context(UiObject *obj); UIEXPORT void* ui_object_get_windowdata(UiObject *obj); UIEXPORT void ui_object_set_windowdata(UiObject *obj, void *windowdata); +UIEXPORT void ui_object_set_onclose(UiObject *obj, ui_callback callback, void *userdata); UIEXPORT void* ui_list_get_data(UiList *list); UIEXPORT void* ui_list_get_iter(UiList *list); diff --git a/ui/gtk/toolkit.c b/ui/gtk/toolkit.c index 9d6cf91..b1bb9d1 100644 --- a/ui/gtk/toolkit.c +++ b/ui/gtk/toolkit.c @@ -165,7 +165,6 @@ GtkApplication* ui_get_application() { void ui_show(UiObject *obj) { gboolean visible = FALSE; - uic_check_state_widgets(obj->ctx); if(obj->widget) { visible = gtk_widget_is_visible(obj->widget); #if GTK_MAJOR_VERSION >= 4 @@ -174,6 +173,7 @@ void ui_show(UiObject *obj) { gtk_widget_show_all(obj->widget); #endif } + uic_check_state_widgets(obj->ctx); if(!visible) { obj->ref++; @@ -181,18 +181,6 @@ void ui_show(UiObject *obj) { } void ui_close(UiObject *obj) { - uic_context_prepare_close(obj->ctx); // TODO: should this be moved to the close event handler? Yes! - /* - if(obj->widget) { -#if GTK_CHECK_VERSION(4, 0, 0) - gtk_window_close(GTK_WINDOW(obj->widget)); -#else - gtk_widget_destroy(obj->widget); -#endif - } else { - ui_window_close_request(obj); - } - */ ui_window_close_request(obj); } diff --git a/ui/gtk/window.c b/ui/gtk/window.c index 7952570..5b74b57 100644 --- a/ui/gtk/window.c +++ b/ui/gtk/window.c @@ -112,7 +112,12 @@ gboolean ui_window_close_request(UiObject *obj) { } } - obj->ref--; + if(obj->ref > 0) { + obj->ref--; + } else { + // warn about invalid reference counting + fprintf(stderr, "Error: UiObject %p ref == 0\n", obj); + } if(obj->ref > 0) { #if GTK_CHECK_VERSION(2, 18, 0) gtk_widget_set_visible(obj->widget, FALSE); @@ -121,29 +126,30 @@ gboolean ui_window_close_request(UiObject *obj) { #endif return TRUE; } else { - if(obj->ctx->close_callback) { - UiEvent ev; - ev.window = obj->window; - ev.document = obj->ctx->document; - ev.obj = obj; - ev.eventdata = NULL; - ev.eventdatatype = 0; - ev.intval = 0; - obj->ctx->close_callback(&ev, obj->ctx->close_data); - obj->ctx->close_callback = NULL; - } - uic_context_prepare_close(obj->ctx); return FALSE; } } +static void window_onclose_callback(UiObject *obj) { + if(obj->onclose) { + UiEvent event; + memset(&event, 0, sizeof(UiEvent)); + event.obj = obj; + event.window = obj->window; + event.document = obj->ctx->document; + obj->onclose(&event, obj->onclosedata); + } +} + #if GTK_MAJOR_VERSION >= 4 static gboolean close_request(GtkWindow* self, UiObject *obj) { + window_onclose_callback(obj); return ui_window_close_request(obj); } #else static gboolean close_request(GtkWidget* self, GdkEvent* event, UiObject *obj) { + window_onclose_callback(obj); return ui_window_close_request(obj); } #endif @@ -305,17 +311,23 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); } else if(!strcmp(show_title, "sidebar")) { adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE); + if(headerbar_sidebar) { + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE); + } } else if(!strcmp(show_title, "false")) { - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + if(headerbar_sidebar) { + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + } adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); } else { fprintf(stderr, "Unknown value '%s' for property ui.gtk.window.showtitle\n", show_title); - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + if(headerbar_sidebar) { + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + } } } else { adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); - if(sidebar) { + if(headerbar_sidebar) { adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE); } } diff --git a/ui/qt/window.cpp b/ui/qt/window.cpp index 6e4c1c8..1c69606 100644 --- a/ui/qt/window.cpp +++ b/ui/qt/window.cpp @@ -43,7 +43,6 @@ static UiObject* create_window(const char *title, bool simple, bool sidebar = false) { UiObject *obj = uic_object_new_toplevel(); - obj->next = NULL; QMainWindow *window = new QMainWindow(); window->setWindowTitle(title); diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index cd3fb44..7f7ede9 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -295,9 +295,10 @@ struct UiObject { UiContainer *container_end; /* - * next container object + * called when someone requests to close the window */ - UiObject *next; + void (*onclose)(UiEvent *event, void *userdata); + void *onclosedata; /* * obj destroy func