Skip to content

Add Timer API #277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 19, 2018
41 changes: 41 additions & 0 deletions darwin/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,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];
}
8 changes: 7 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
64 changes: 64 additions & 0 deletions examples/timer/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <string.h>
#include <stdlib.h>
#include <time.h>
#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;
}
2 changes: 2 additions & 0 deletions ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
27 changes: 27 additions & 0 deletions unix/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
9 changes: 9 additions & 0 deletions windows/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you can use a pointer to an arbitrary structure here?
From what I understood of the win32 docs, if you give it both an hWnd and a nIDEvent arguments, the function expect it to point to an existing timer id linked to that window.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timer IDs are pointer-sized, so we can get away with using the pointer to the timer metadata struct itself as an ID; should probably consider doing that instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I missed that comment... that's really an interesting design.

if (SetTimer(utilWindow, timer, milliseconds, NULL) == 0)
logLastError(L"SetTimer()");
}
16 changes: 16 additions & 0 deletions windows/uipriv_windows.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
9 changes: 9 additions & 0 deletions windows/utilwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down