From f77955aefbb160afd616d9743ffce84c02a40f65 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Fri, 4 Dec 2015 23:42:03 -0500 Subject: [PATCH] Added uiQueueMain() (basically g_idle_add()) and implemented it on all platforms except Haiku. A test to come. After this we can start rewriting the Go package ui at long last. --- darwin/main.m | 10 ++++++++++ haiku/main.cpp | 5 +++++ ui.h | 3 +++ unix/main.c | 25 +++++++++++++++++++++++++ windows/main.c | 7 +++++++ windows/uipriv_windows.h | 1 + windows/utilwin.c | 5 +++++ 7 files changed, 56 insertions(+) diff --git a/darwin/main.m b/darwin/main.m index bb50d806..736eff12 100644 --- a/darwin/main.m +++ b/darwin/main.m @@ -105,8 +105,18 @@ void uiMain(void) [realNSApp() run]; } +// TODO make this delayed void uiQuit(void) { canQuit = YES; [realNSApp() terminate:realNSApp()]; } + +// thanks to mikeash in irc.freenode.net/#macdev for suggesting the use of Grand Central Dispatch for this +// TODO will dispatch_get_main_queue() break after _CFRunLoopSetCurrent()? +void uiQueueMain(void (*f)(void *data), void *data) +{ + // dispatch_get_main_queue() is a serial queue so it will not execute multiple uiQueueMain() functions concurrently + // the signature of f matches dispatch_function_t + dispatch_async_f(dispatch_get_main_queue(), data, f); +} diff --git a/haiku/main.cpp b/haiku/main.cpp index 9d2e4eb3..1c178bf1 100644 --- a/haiku/main.cpp +++ b/haiku/main.cpp @@ -44,3 +44,8 @@ void uiQuit(void) // TODO see window.cpp for why that alone won't work app->Quit(); } + +void uiQueueMain(void (*f)(void *data), void *data) +{ + // TODO +} diff --git a/ui.h b/ui.h index edd7045b..7e7ac403 100644 --- a/ui.h +++ b/ui.h @@ -29,6 +29,9 @@ _UI_EXTERN void uiFreeInitError(const char *err); _UI_EXTERN void uiMain(void); _UI_EXTERN void uiQuit(void); +// TODO write a test for this after adding multiline entries +_UI_EXTERN void uiQueueMain(void (*f)(void *data), void *data); + _UI_EXTERN void uiOnShouldQuit(int (*f)(void *data), void *data); _UI_EXTERN void uiFreeText(char *text); diff --git a/unix/main.c b/unix/main.c index 9c45bd88..673677f2 100644 --- a/unix/main.c +++ b/unix/main.c @@ -48,3 +48,28 @@ void uiQuit(void) { gdk_threads_add_idle(quit, NULL); } + +struct queued { + void (*f)(void *); + void *data; +}; + +static gboolean doqueued(gpointer data) +{ + struct queued *q = (struct queued *) data; + + (*(q->f))(q->data); + uiFree(q); + return FALSE; +} + +// TODO document that the effect of calling this function after uiQuit() is called (either directly or via a nonzero return to uiShouldQuit()) is undefined +void uiQueueMain(void (*f)(void *data), void *data) +{ + struct queued *q; + + q = uiNew(struct queued); + q->f = f; + q->data = data; + gdk_threads_add_idle(doqueued, q); +} diff --git a/windows/main.c b/windows/main.c index a36c22d0..62feb67b 100644 --- a/windows/main.c +++ b/windows/main.c @@ -41,3 +41,10 @@ void uiQuit(void) { PostQuitMessage(0); } + +void uiQueueMain(void (*f)(void *data), void *data) +{ + if (PostMessageW(utilWindow, msgQueued, (WPARAM) f, (LPARAM) data) == 0) + // TODO make sure this is safe to call across threads + logLastError("error queueing function to run on main thread in uiQueueMain()"); +} diff --git a/windows/uipriv_windows.h b/windows/uipriv_windows.h index 4c605b18..5af5e1ce 100644 --- a/windows/uipriv_windows.h +++ b/windows/uipriv_windows.h @@ -13,6 +13,7 @@ enum { msgNOTIFY, msgHSCROLL, msgConsoleEndSession, + msgQueued, }; // init.c diff --git a/windows/utilwin.c b/windows/utilwin.c index 7ef20df6..f8b702d8 100644 --- a/windows/utilwin.c +++ b/windows/utilwin.c @@ -18,6 +18,7 @@ HWND utilWindow; static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + void (*qf)(void *); LRESULT lResult; if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) @@ -41,6 +42,10 @@ static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, L case WM_WININICHANGE: issueWM_WININICHANGE(wParam, lParam); return 0; + case msgQueued: + qf = (void (*)(void *)) wParam; + (*qf)((void *) lParam); + return 0; } return DefWindowProcW(hwnd, uMsg, wParam, lParam); }