From 496f17c3804c79d304aa6095b92768593d1cc700 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 22 Jul 2019 16:53:36 +0200 Subject: Add puglPollEvents() This allows waiting for events for any view in the world. It also improves on puglWaitForEvent() by the addition of a time parameter that allows indefinite blocking, non-blocking polling, and blocking polling with a timeout. --- pugl/detail/mac.h | 1 - pugl/detail/mac.m | 34 ++++++++++++++++++++-------------- pugl/detail/win.c | 14 ++++++++++++++ pugl/detail/x11.c | 26 ++++++++++++++++++++++++++ pugl/pugl.h | 20 +++++++++++++++++++- test/pugl_cairo_test.c | 2 +- test/pugl_test.c | 2 +- 7 files changed, 81 insertions(+), 18 deletions(-) diff --git a/pugl/detail/mac.h b/pugl/detail/mac.h index f8cfbed..1bd2bbc 100644 --- a/pugl/detail/mac.h +++ b/pugl/detail/mac.h @@ -60,6 +60,5 @@ struct PuglInternalsImpl { PuglWrapperView* wrapperView; NSView* drawView; id window; - NSEvent* nextEvent; uint32_t mods; }; diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m index 527724d..74b207a 100644 --- a/pugl/detail/mac.m +++ b/pugl/detail/mac.m @@ -816,29 +816,35 @@ puglRequestAttention(PuglView* view) } PuglStatus -puglWaitForEvent(PuglView* view) +puglPollEvents(PuglWorld* world, const double timeout) { + NSDate* date = ((timeout < 0) ? [NSDate distantFuture] : + (timeout == 0) ? nil : + [NSDate dateWithTimeIntervalSinceNow:timeout]); + /* Note that dequeue:NO is broken (it blocks forever even when events are - pending), so we work around this by dequeueing the event here and - storing it in view->impl->nextEvent for later processing. */ - if (!view->impl->nextEvent) { - view->impl->nextEvent = - [view->impl->window nextEventMatchingMask:NSAnyEventMask]; - } + pending), so we work around this by dequeueing the event then posting it + back to the front of the queue. */ + NSEvent* event = [world->impl->app + nextEventMatchingMask:NSAnyEventMask + untilDate:date + inMode:NSDefaultRunLoopMode + dequeue:YES]; + + [world->impl->app postEvent:event atStart:true]; return PUGL_SUCCESS; } PuglStatus -puglProcessEvents(PuglView* view) +puglWaitForEvent(PuglView* view) { - if (view->impl->nextEvent) { - // Process event that was dequeued earier by puglWaitForEvent - [view->world->impl->app sendEvent: view->impl->nextEvent]; - view->impl->nextEvent = NULL; - } + return puglPollEvents(view->world, -1.0); +} - // Process all pending events +PuglStatus +puglProcessEvents(PuglView* view) +{ for (NSEvent* ev = NULL; (ev = [view->impl->window nextEventMatchingMask:NSAnyEventMask untilDate:nil diff --git a/pugl/detail/win.c b/pugl/detail/win.c index 6a0825a..9d0d0e5 100644 --- a/pugl/detail/win.c +++ b/pugl/detail/win.c @@ -120,6 +120,20 @@ puglInitViewInternals(void) return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } +PuglStatus +puglPollEvents(PuglWorld* world, const double timeout) +{ + (void)world; + + if (timeout < 0) { + WaitMessage(); + } else { + MsgWaitForMultipleObjects( + 0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS); + } + return PUGL_SUCCESS; +} + int puglCreateWindow(PuglView* view, const char* title) { diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c index d54f1bf..7ef3866 100644 --- a/pugl/detail/x11.c +++ b/pugl/detail/x11.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -102,6 +103,30 @@ puglInitViewInternals(void) return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } +PuglStatus +puglPollEvents(PuglWorld* world, const double timeout) +{ + XFlush(world->impl->display); + + const int fd = ConnectionNumber(world->impl->display); + const int nfds = fd + 1; + int ret = 0; + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd, &fds); + + if (timeout < 0.0) { + ret = select(nfds, &fds, NULL, NULL, NULL); + } else { + const long sec = (long)timeout; + const long msec = (long)((timeout - (double)sec) * 1e6); + struct timeval tv = {sec, msec}; + ret = select(nfds, &fds, NULL, NULL, &tv); + } + + return ret < 0 ? PUGL_ERR_UNKNOWN : ret == 0 ? PUGL_FAILURE : PUGL_SUCCESS; +} + int puglCreateWindow(PuglView* view, const char* title) { @@ -193,6 +218,7 @@ void puglShowWindow(PuglView* view) { XMapRaised(view->impl->display, view->impl->win); + puglPostRedisplay(view); view->visible = true; } diff --git a/pugl/pugl.h b/pugl/pugl.h index e7c7333..923d361 100644 --- a/pugl/pugl.h +++ b/pugl/pugl.h @@ -88,6 +88,8 @@ typedef void* PuglHandle; */ typedef enum { PUGL_SUCCESS, + PUGL_FAILURE, + PUGL_ERR_UNKNOWN, PUGL_ERR_CREATE_WINDOW, PUGL_ERR_SET_FORMAT, PUGL_ERR_CREATE_CONTEXT, @@ -455,6 +457,20 @@ puglFreeWorld(PuglWorld* world); PUGL_API double puglGetTime(const PuglWorld* world); +/** + Poll for events that are ready to be processed. + + This polls for events that are ready for any view in the application, + potentially blocking depending on `timeout`. + + @param world The world for all the views to poll. + @param timeout Maximum time to wait, in seconds. If zero, the call returns + immediately, if negative, the call blocks indefinitely. + @return PUGL_SUCCESS if events are read, PUGL_FAILURE if not, or an error. +*/ +PUGL_API PuglStatus +puglPollEvents(PuglWorld* world, double timeout); + /** @} @name Initialization @@ -728,8 +744,10 @@ puglRequestAttention(PuglView* view); necessary. This function will block indefinitely if no events are available, so is not appropriate for use in programs that need to perform regular updates (e.g. animation). + + @deprecated Use puglPollEvents(). */ -PUGL_API PuglStatus +PUGL_API PUGL_DEPRECATED_BY("puglPollEvents") PuglStatus puglWaitForEvent(PuglView* view); /** diff --git a/test/pugl_cairo_test.c b/test/pugl_cairo_test.c index 7779069..6d85c54 100644 --- a/test/pugl_cairo_test.c +++ b/test/pugl_cairo_test.c @@ -227,7 +227,7 @@ main(int argc, char** argv) if (continuous) { puglPostRedisplay(view); } else { - puglWaitForEvent(view); + puglPollEvents(world, -1); } puglProcessEvents(view); diff --git a/test/pugl_test.c b/test/pugl_test.c index c4df272..66fd97d 100644 --- a/test/pugl_test.c +++ b/test/pugl_test.c @@ -212,7 +212,7 @@ main(int argc, char** argv) if (app.continuous) { puglPostRedisplay(view); } else { - puglWaitForEvent(view); + puglPollEvents(app.world, -1); } puglProcessEvents(view); -- cgit v1.2.1