implement ui_job() and add ui_call_mainthread (WinUI3) newapi

Sun, 28 Jan 2024 19:33:56 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 28 Jan 2024 19:33:56 +0100
branch
newapi
changeset 234
9036b346cd66
parent 233
84665f0a9ab2
child 235
9c79f00fbf36

implement ui_job() and add ui_call_mainthread (WinUI3)

make/vs/testapp/main.c file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
ui/winui/pch.h file | annotate | diff | comparison | revisions
ui/winui/toolkit.cpp file | annotate | diff | comparison | revisions
ui/winui/toolkit.h file | annotate | diff | comparison | revisions
--- a/make/vs/testapp/main.c	Sun Jan 28 17:10:30 2024 +0100
+++ b/make/vs/testapp/main.c	Sun Jan 28 19:33:56 2024 +0100
@@ -55,6 +55,21 @@
 
 UiList* menuList;
 
+void event_mt(UiEvent* event, void* data) {
+    char* mt_str = data;
+
+    printf("%s\n", mt_str);
+}
+
+int test_threadfunc(void *data) {
+    char* str = data;
+    
+    return 0;
+}
+
+void action_thread_test(UiEvent* event, void* data) {
+    ui_job(event->obj, test_threadfunc, "testdata", event_mt, "testdata2");
+}
 
 void action1(UiEvent* event, void* data) {
     char* action = data;
@@ -247,7 +262,7 @@
 
     ui_scrolledwindow0(obj) {
         ui_grid(obj, .margin = 10, .columnspacing = 5, .rowspacing = 20) {
-            ui_button(obj, .label = "Button1", .onclick = action1, .onclickdata = "action1");
+            ui_button(obj, .label = "Thread Test", .onclick = action_thread_test, .onclickdata = "action1");
             ui_button(obj, .label = "Button2", .icon = "Back", .onclick = action1, .onclickdata = "action2");
             ui_button(obj, .icon = "Forward", .onclick = action1, .onclickdata = "action3", .hexpand = true);
             ui_newline(obj);
--- a/ui/ui/toolkit.h	Sun Jan 28 17:10:30 2024 +0100
+++ b/ui/ui/toolkit.h	Sun Jan 28 19:33:56 2024 +0100
@@ -371,6 +371,7 @@
 UIEXPORT void ui_close(UiObject *obj);
 
 UIEXPORT void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd);
+UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td);
 
 UIEXPORT void* ui_document_new(size_t size);
 UIEXPORT void  ui_document_destroy(void *doc);
--- a/ui/winui/pch.h	Sun Jan 28 17:10:30 2024 +0100
+++ b/ui/winui/pch.h	Sun Jan 28 19:33:56 2024 +0100
@@ -33,6 +33,7 @@
 #include <winrt/Microsoft.UI.Input.h>
 #include <winrt/Windows.UI.Core.h>
 #include <winrt/Windows.ApplicationModel.h>
+#include <winrt\Microsoft.UI.Dispatching.h>
 
 
 #include <winrt/Windows.Storage.Streams.h>
--- a/ui/winui/toolkit.cpp	Sun Jan 28 17:10:30 2024 +0100
+++ b/ui/winui/toolkit.cpp	Sun Jan 28 19:33:56 2024 +0100
@@ -43,6 +43,8 @@
 
 #include "App.xaml.h"
 
+#include <thread>
+
 using namespace winrt;
 using namespace Microsoft::UI::Xaml;
 using namespace Microsoft::UI::Xaml::Controls;
@@ -50,6 +52,7 @@
 using namespace Microsoft::UI::Xaml::Markup;
 using namespace Windows::UI::Xaml::Interop;
 using namespace winrt::Windows::Foundation;
+using namespace Windows::UI::Core;
 
 static const char* application_name;
 
@@ -69,7 +72,11 @@
 
 static UiObject* active_window;
 
+static winrt::Microsoft::UI::Dispatching::DispatcherQueue uiDispatcherQueue = { nullptr };
+
 void ui_app_run_startup() {
+	uiDispatcherQueue = winrt::Microsoft::UI::Dispatching::DispatcherQueue::GetForCurrentThread();
+	
 	if (startup_func) {
 		startup_func(NULL, startup_data);
 	}
@@ -233,3 +240,58 @@
 
 }
 
+static void ui_job_finished(UiJob *job) {
+	UiEvent event;
+	event.obj = job->obj;
+	event.window = job->obj->window;
+	event.document = job->obj->ctx->document;
+	event.intval = 0;
+	event.eventdata = NULL;
+	job->finish_callback(&event, job->finish_data);
+}
+
+static void ui_job_thread(UiJob* job) {
+	if (!job->job_func(job->job_data)) {
+		bool isQueued = uiDispatcherQueue.TryEnqueue([job]()
+		{
+			UiEvent event;
+			event.obj = job->obj;
+			event.window = job->obj->window;
+			event.document = job->obj->ctx->document;
+			event.intval = 0;
+			event.eventdata = NULL;
+			job->finish_callback(&event, job->finish_data);
+			delete job;
+		});
+		if (!isQueued) {
+			// TODO: error or try again?
+			exit(-1);
+		}
+	}
+	else {
+		delete job;
+	}
+}
+
+UIEXPORT void ui_job(UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) {
+	UiJob* job = new UiJob;
+	job->obj = obj;
+	job->job_func = tf;
+	job->job_data = td;
+	job->finish_callback = f;
+	job->finish_data = fd;
+
+	std::thread jobThread(ui_job_thread, job);
+	jobThread.detach();
+}
+
+UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td) {
+	bool isQueued = uiDispatcherQueue.TryEnqueue([tf, td]()
+	{
+		(void)tf(td);
+	});
+	if (!isQueued) {
+		// TODO: error or try again?
+		exit(-1);
+	}
+}
--- a/ui/winui/toolkit.h	Sun Jan 28 17:10:30 2024 +0100
+++ b/ui/winui/toolkit.h	Sun Jan 28 19:33:56 2024 +0100
@@ -30,6 +30,14 @@
 
 #include "../ui/toolkit.h"
 
+typedef struct UiJob {
+    UiObject* obj;
+    ui_threadfunc job_func;
+    void* job_data;
+    ui_callback   finish_callback;
+    void* finish_data;
+} UiJob;
+
 typedef void(*ui_eventfunc)(void*, void*);
 
 void ui_app_run_startup();

mercurial