diff --git a/darwin/main.m b/darwin/main.m index 6d149fc3..52537882 100644 --- a/darwin/main.m +++ b/darwin/main.m @@ -242,3 +242,44 @@ void uiQueueMain(void (*f)(void *data), void *data) // the signature of f matches dispatch_function_t dispatch_async_f(dispatch_get_main_queue(), data, f); } + +@interface uiprivTimerDelegate : NSObject { + int (*f)(void *data); + void *data; +} +- (id)initWithCallback:(int (*)(void *))callback data:(void*)callbackData; +- (void)doTimer:(NSTimer *)timer; +@end + +@implementation uiprivTimerDelegate + +- (id)initWithCallback:(int (*)(void *))callback data:(void*)callbackData +{ + self = [super init]; + if (self) { + self->f = callback; + self->data = callbackData; + } + return self; +} + +- (void)doTimer:(NSTimer *)timer +{ + if (!self->f(self->data)) + [timer invalidate]; +} + +@end + +void uiTimer(int milliseconds, int (*f)(void *data), void *data) +{ + uiprivTimerDelegate *delegate; + + delegate = [[uiprivTimerDelegate alloc] initWithCallback:f data:data]; + [NSTimer scheduledTimerWithTimeInterval:milliseconds / 1000.0 + target:delegate + selector:@selector(doTimer:) + userInfo:nil + repeats:YES]; + [delegate release]; +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 61ed7b82..8d83566e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -42,9 +42,15 @@ _add_example(drawtext ${_EXAMPLE_RESOURCES_RC} ) +_add_example(timer + timer/main.c + ${_EXAMPLE_RESOURCES_RC} +) + add_custom_target(examples DEPENDS controlgallery histogram cpp-multithread - drawtext) + drawtext + timer) diff --git a/examples/timer/main.c b/examples/timer/main.c new file mode 100644 index 00000000..d1b80b97 --- /dev/null +++ b/examples/timer/main.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include "../../ui.h" + +uiMultilineEntry *e; + +int sayTime(void *data) +{ + time_t t; + char *s; + + t = time(NULL); + s = ctime(&t); + + uiMultilineEntryAppend(e, s); + return 1; +} + +int onClosing(uiWindow *w, void *data) +{ + uiQuit(); + return 1; +} + +void saySomething(uiButton *b, void *data) +{ + uiMultilineEntryAppend(e, "Saying something\n"); +} + +int main(void) +{ + uiInitOptions o; + uiWindow *w; + uiBox *b; + uiButton *btn; + + memset(&o, 0, sizeof (uiInitOptions)); + if (uiInit(&o) != NULL) + abort(); + + w = uiNewWindow("Hello", 320, 240, 0); + uiWindowSetMargined(w, 1); + + b = uiNewVerticalBox(); + uiBoxSetPadded(b, 1); + uiWindowSetChild(w, uiControl(b)); + + e = uiNewMultilineEntry(); + uiMultilineEntrySetReadOnly(e, 1); + + btn = uiNewButton("Say Something"); + uiButtonOnClicked(btn, saySomething, NULL); + uiBoxAppend(b, uiControl(btn), 0); + + uiBoxAppend(b, uiControl(e), 1); + + uiTimer(1000, sayTime, NULL); + + uiWindowOnClosing(w, onClosing, NULL); + uiControlShow(uiControl(w)); + uiMain(); + return 0; +} diff --git a/ui.h b/ui.h index e3f0c908..3eed0e39 100644 --- a/ui.h +++ b/ui.h @@ -62,6 +62,8 @@ _UI_EXTERN void uiQuit(void); _UI_EXTERN void uiQueueMain(void (*f)(void *data), void *data); +_UI_EXTERN void uiTimer(int milliseconds, int (*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 a0cd7835..338cf716 100644 --- a/unix/main.c +++ b/unix/main.c @@ -106,3 +106,30 @@ void uiQueueMain(void (*f)(void *data), void *data) q->data = data; gdk_threads_add_idle(doqueued, q); } + +struct timer { + int (*f)(void *); + void *data; +}; + +static gboolean dotimer(gpointer data) +{ + struct timer *t = (struct timer *) data; + + if((*(t->f))(t->data)) + return TRUE; + else { + uiFree(t); + return FALSE; + } +} + +void uiTimer(int milliseconds, int (*f)(void *data), void *data) +{ + struct timer *t; + + t = uiNew(struct timer); + t->f = f; + t->data = data; + g_timeout_add(milliseconds, dotimer, t); +} diff --git a/windows/main.cpp b/windows/main.cpp index eb6d8492..65e49dbb 100644 --- a/windows/main.cpp +++ b/windows/main.cpp @@ -128,3 +128,12 @@ void uiQueueMain(void (*f)(void *data), void *data) // LONGTERM this is likely not safe to call across threads (allocates memory) logLastError(L"error queueing function to run on main thread"); } + +void uiTimer(int milliseconds, int (*f)(void *data), void *data) +{ + UINT_PTR timer; + + timer = (UINT_PTR) new TimerHandler(f, data); + if (SetTimer(utilWindow, timer, milliseconds, NULL) == 0) + logLastError(L"SetTimer()"); +} diff --git a/windows/uipriv_windows.hpp b/windows/uipriv_windows.hpp index 7fb00efa..e77cf439 100644 --- a/windows/uipriv_windows.hpp +++ b/windows/uipriv_windows.hpp @@ -95,6 +95,22 @@ extern const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor); extern void uninitUtilWindow(void); // main.cpp +struct TimerHandler { +public: + TimerHandler() : TimerHandler(NULL, NULL) {} + TimerHandler(int(*f)(void *data), void *data) + { + this->f = f; + this->data = data; + } + int operator()() + { + return this->f(this->data); + } +private: + int(*f)(void *data); + void *data; +}; extern int registerMessageFilter(void); extern void unregisterMessageFilter(void); diff --git a/windows/utilwin.cpp b/windows/utilwin.cpp index 34b72ba8..fce3af09 100644 --- a/windows/utilwin.cpp +++ b/windows/utilwin.cpp @@ -18,6 +18,7 @@ static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, L { void (*qf)(void *); LRESULT lResult; + TimerHandler *timer; if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) return lResult; @@ -36,6 +37,14 @@ static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, L qf = (void (*)(void *)) wParam; (*qf)((void *) lParam); return 0; + case WM_TIMER: + timer = (TimerHandler *) wParam; + if (!(*timer)()) { + if (!KillTimer(utilWindow, (UINT_PTR) timer)) + logLastError(L"KillTimer()"); + delete timer; + } + return 0; } return DefWindowProcW(hwnd, uMsg, wParam, lParam); }