implement window reference counting (WINUI3)

2 weeks ago

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 26 Feb 2025 17:39:03 +0100 (2 weeks ago)
changeset 477
be34594ee942
parent 476
31213068c2ba
child 478
6292f93c2213

implement window reference counting (WINUI3)

.hgignore file | annotate | diff | comparison | revisions
make/vs/testapp/main.c file | annotate | diff | comparison | revisions
ui/winui/toolkit.cpp file | annotate | diff | comparison | revisions
ui/winui/window.cpp file | annotate | diff | comparison | revisions
--- a/.hgignore	Wed Feb 26 17:06:56 2025 +0100
+++ b/.hgignore	Wed Feb 26 17:39:03 2025 +0100
@@ -5,4 +5,5 @@
 relre:^make/vs/packages/.*
 relre:^make/vs/.*vcxproj\.user
 relre:^make/xcode/toolkit/toolkit.xcodeproj/xcuserdata/.*
-relre:^make/xcode/toolkit/toolkit.xcodeproj/project.xcworkspace/xcuserdata/.*
\ No newline at end of file
+relre:^make/xcode/toolkit/toolkit.xcodeproj/project.xcworkspace/xcuserdata/.*
+relre:^ui/winui/Generated Files/.*
\ No newline at end of file
--- a/make/vs/testapp/main.c	Wed Feb 26 17:06:56 2025 +0100
+++ b/make/vs/testapp/main.c	Wed Feb 26 17:39:03 2025 +0100
@@ -131,15 +131,29 @@
     ui_show(dialog);
 }
 
+UiObject *new_window;
+
+static void action_unref_newwindow(UiEvent *event, void *userdata) {
+    ui_object_unref(event->obj);
+    new_window = NULL;
+}
+
 void action_toolbar_newwindow(UiEvent *event, void *userdata) {
+    if (new_window) {
+        ui_show(new_window);
+        return;
+    }
+
     UiObject *obj = ui_simple_window("New Window", NULL);
+    new_window = obj;
+    ui_object_ref(obj);
 
     ui_headerbar0(obj) {
         ui_headerbar_start(obj) {
             ui_button(obj, .label = "Open");
         }
         ui_headerbar_end(obj) {
-            ui_button(obj, .label = "Test");
+            ui_button(obj, .label = "Unref", .onclick = action_unref_newwindow);
         }
     }
 
--- a/ui/winui/toolkit.cpp	Wed Feb 26 17:06:56 2025 +0100
+++ b/ui/winui/toolkit.cpp	Wed Feb 26 17:39:03 2025 +0100
@@ -232,9 +232,13 @@
 
 void ui_show(UiObject* obj) {
 	if (obj->wobj) {
-		obj->wobj->window.Activate();
+		if (!obj->wobj->window.Visible()) {
+			obj->wobj->window.Activate();
+			obj->ref++;
+		}
 	} else if(obj->widget && obj->widget->Show) {
 		obj->widget->Show();
+		obj->ref++; // TODO: should we check if the widget is already visible?
 	}
 }
 
--- a/ui/winui/window.cpp	Wed Feb 26 17:06:56 2025 +0100
+++ b/ui/winui/window.cpp	Wed Feb 26 17:39:03 2025 +0100
@@ -63,6 +63,11 @@
 
 UiWindow::UiWindow(winrt::Microsoft::UI::Xaml::Window& win) : window(win) {}
 
+extern "C" static void ui_window_widget_destroy(UiObject *obj) {
+	obj->ref = 1;
+	obj->wobj->window.Close();
+}
+
 UiObject* ui_window(const char* title, void* window_data) {
 	UiObject* obj = ui_simple_window(title, window_data);
 
@@ -178,17 +183,14 @@
 	obj->wobj = new UiWindow(window);
 	ui_context_add_window_destructor(obj->ctx, obj->wobj);
 
-	window.Closed([obj](IInspectable const& sender, WindowEventArgs) {
-		if (obj->ctx->close_callback) {
-			UiEvent evt;
-			evt.obj = obj;
-			evt.document = obj->ctx->document;
-			evt.window = obj->window;
-			evt.eventdata = NULL;
-			evt.intval = 0;
-			obj->ctx->close_callback(&evt, obj->ctx->close_data);
+	window.Closed([obj](IInspectable const& sender, WindowEventArgs e) {
+		uic_context_prepare_close(obj->ctx);
+		obj->ref--;
+		if (obj->ref > 0) {
+			obj->wobj->window.AppWindow().Hide();
+			e.Handled(true);
 		} else {
-			ui_context_destroy(obj->ctx);
+			uic_object_destroy(obj);
 		}
 		});
 

mercurial