diff options
author | David Robillard <d@drobilla.net> | 2020-03-15 18:30:24 +0100 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2020-03-15 20:53:37 +0100 |
commit | efc053fe5a38a4928fbfd3780f5665dd43bc7f95 (patch) | |
tree | c3e28366d5b57592e82c004ab59a3e364d4ef57f /pugl/detail | |
parent | 3b9e8287fd4c1096a2d6244aa07bc28cacb4da8d (diff) | |
download | pugl-efc053fe5a38a4928fbfd3780f5665dd43bc7f95.tar.gz pugl-efc053fe5a38a4928fbfd3780f5665dd43bc7f95.tar.bz2 pugl-efc053fe5a38a4928fbfd3780f5665dd43bc7f95.zip |
Unify event loop functions as puglUpdate()
The previous separation between polling and dispatching was a lie, especially
on MacOS where it is impossible to only poll for events without dispatching
anything. Providing such an API is misleading, and problematic in various
other ways.
So, merge them into a single puglUpdate() function which can do the right thing
on all platforms. This also adds the behaviour of actually processing all
events in the given time interval, which is almost always what clients actually
want to do when using a positive timeout (naively doing this before caused
terrible input lag).
Diffstat (limited to 'pugl/detail')
-rw-r--r-- | pugl/detail/implementation.c | 14 | ||||
-rw-r--r-- | pugl/detail/mac.m | 51 | ||||
-rw-r--r-- | pugl/detail/win.c | 39 | ||||
-rw-r--r-- | pugl/detail/x11.c | 54 |
4 files changed, 104 insertions, 54 deletions
diff --git a/pugl/detail/implementation.c b/pugl/detail/implementation.c index b2306c6..d7e7058 100644 --- a/pugl/detail/implementation.c +++ b/pugl/detail/implementation.c @@ -290,6 +290,18 @@ puglGetContext(PuglView* view) #ifndef PUGL_DISABLE_DEPRECATED PuglStatus +puglPollEvents(PuglWorld* world, double timeout) +{ + return puglUpdate(world, timeout); +} + +PuglStatus +puglDispatchEvents(PuglWorld* world) +{ + return puglUpdate(world, 0.0); +} + +PuglStatus puglEnterContext(PuglView* view, bool drawing) { const PuglEventExpose expose = { @@ -369,7 +381,7 @@ void puglDispatchSimpleEvent(PuglView* view, const PuglEventType type) { assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP || - type == PUGL_UNMAP || type == PUGL_CLOSE); + type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE); const PuglEvent event = {{type, 0}}; puglDispatchEvent(view, &event); diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m index ab59b99..22f8088 100644 --- a/pugl/detail/mac.m +++ b/pugl/detail/mac.m @@ -1,5 +1,5 @@ /* - Copyright 2012-2019 David Robillard <http://drobilla.net> + Copyright 2012-2020 David Robillard <http://drobilla.net> Copyright 2017 Hanspeter Portner <dev@open-music-kontrollers.ch> Permission to use, copy, modify, and/or distribute this software for any @@ -614,6 +614,12 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) [super viewWillStartLiveResize]; } +- (void) viewWillDraw +{ + puglDispatchSimpleEvent(puglview, PUGL_UPDATE); + [super viewWillDraw]; +} + - (void) resizeTick { puglPostRedisplay(puglview); @@ -915,27 +921,6 @@ puglRequestAttention(PuglView* view) return PUGL_SUCCESS; } -PuglStatus -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 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 puglSendEvent(PuglView* view, const PuglEvent* event) { if (event->type == PUGL_CLIENT) { @@ -990,28 +975,32 @@ dispatchClientEvent(PuglWorld* world, NSEvent* ev) } PuglStatus -puglDispatchEvents(PuglWorld* world) +puglUpdate(PuglWorld* world, const double timeout) { - const NSTimeInterval startTime = [[NSProcessInfo processInfo] systemUptime]; + NSDate* date = ((timeout < 0) + ? [NSDate distantFuture] + : [NSDate dateWithTimeIntervalSinceNow:timeout]); for (NSEvent* ev = NULL; (ev = [world->impl->app nextEventMatchingMask:NSAnyEventMask - untilDate:nil + untilDate:date inMode:NSDefaultRunLoopMode dequeue:YES]);) { - if ([ev timestamp] > startTime) { - // Event is later, put it back for the next iteration and return - [world->impl->app postEvent:ev atStart:true]; - break; - } else if ([ev type] == NSApplicationDefined && - [ev subtype] == PUGL_CLIENT) { + if ([ev type] == NSApplicationDefined && [ev subtype] == PUGL_CLIENT) { dispatchClientEvent(world, ev); } [world->impl->app sendEvent: ev]; } + for (size_t i = 0; i < world->numViews; ++i) { + PuglView* const view = world->views[i]; + + puglDispatchSimpleEvent(view, PUGL_UPDATE); + [view->impl->drawView displayIfNeeded]; + } + return PUGL_SUCCESS; } diff --git a/pugl/detail/win.c b/pugl/detail/win.c index bbaa872..22a0a25 100644 --- a/pugl/detail/win.c +++ b/pugl/detail/win.c @@ -1,5 +1,5 @@ /* - Copyright 2012-2019 David Robillard <http://drobilla.net> + Copyright 2012-2020 David Robillard <http://drobilla.net> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -145,8 +145,8 @@ puglInitViewInternals(void) return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } -PuglStatus -puglPollEvents(PuglWorld* world, const double timeout) +static PuglStatus +puglPollWinEvents(PuglWorld* world, const double timeout) { (void)world; @@ -792,8 +792,8 @@ puglDispatchViewEvents(PuglView* view) return PUGL_SUCCESS; } -PuglStatus -puglDispatchEvents(PuglWorld* world) +static PuglStatus +puglDispatchWinEvents(PuglWorld* world) { for (size_t i = 0; i < world->numViews; ++i) { PostMessage(world->views[i]->impl->hwnd, PUGL_LOCAL_MARK_MSG, 0, 0); @@ -803,18 +803,43 @@ puglDispatchEvents(PuglWorld* world) puglDispatchViewEvents(world->views[i]); } + return PUGL_SUCCESS; +} + +PuglStatus +puglUpdate(PuglWorld* world, double timeout) +{ + const double startTime = puglGetTime(world); + PuglStatus st = PUGL_SUCCESS; + + if (timeout < 0.0) { + st = puglPollWinEvents(world, timeout); + st = st ? st : puglDispatchWinEvents(world); + } else if (timeout == 0.0) { + st = puglDispatchWinEvents(world); + } else { + const double endTime = startTime + timeout - 0.001; + for (double t = startTime; t < endTime; t = puglGetTime(world)) { + if ((st = puglPollWinEvents(world, endTime - t)) || + (st = puglDispatchWinEvents(world))) { + break; + } + } + } + for (size_t i = 0; i < world->numViews; ++i) { + puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE); UpdateWindow(world->views[i]->impl->hwnd); } - return PUGL_SUCCESS; + return st; } #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglProcessEvents(PuglView* view) { - return puglDispatchEvents(view->world); + return puglUpdate(view->world, 0.0); } #endif diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c index 780213d..58451e9 100644 --- a/pugl/detail/x11.c +++ b/pugl/detail/x11.c @@ -117,8 +117,8 @@ puglInitViewInternals(void) return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } -PuglStatus -puglPollEvents(PuglWorld* world, const double timeout) +static PuglStatus +puglPollX11Socket(PuglWorld* world, const double timeout) { if (XPending(world->impl->display) > 0) { return PUGL_SUCCESS; @@ -140,8 +140,7 @@ puglPollEvents(PuglWorld* world, const double timeout) ret = select(nfds, &fds, NULL, NULL, &tv); } - return ret < 0 ? PUGL_UNKNOWN_ERROR - : ret == 0 ? PUGL_FAILURE : PUGL_SUCCESS; + return ret < 0 ? PUGL_UNKNOWN_ERROR : PUGL_SUCCESS; } static PuglView* @@ -750,6 +749,8 @@ flushExposures(PuglWorld* world) PuglEvent* const configure = &view->impl->pendingConfigure; PuglEvent* const expose = &view->impl->pendingExpose; + puglDispatchSimpleEvent(view, PUGL_UPDATE); + if (configure->type || expose->type) { view->backend->enter(view, expose->type ? &expose->expose : NULL); view->eventFunc(view, configure); @@ -762,8 +763,8 @@ flushExposures(PuglWorld* world) } } -PuglStatus -puglDispatchEvents(PuglWorld* world) +static PuglStatus +puglDispatchX11Events(PuglWorld* world) { const PuglX11Atoms* const atoms = &world->impl->atoms; @@ -771,8 +772,6 @@ puglDispatchEvents(PuglWorld* world) Display* display = world->impl->display; XFlush(display); - world->impl->dispatchingEvents = true; - // Process all queued events (without further flushing) while (XEventsQueued(display, QueuedAfterReading) > 0) { XEvent xevent; @@ -827,10 +826,6 @@ puglDispatchEvents(PuglWorld* world) } } - flushExposures(world); - - world->impl->dispatchingEvents = false; - return PUGL_SUCCESS; } @@ -838,10 +833,40 @@ puglDispatchEvents(PuglWorld* world) PuglStatus puglProcessEvents(PuglView* view) { - return puglDispatchEvents(view->world); + return puglUpdate(view->world, 0.0); } #endif +PuglStatus +puglUpdate(PuglWorld* world, double timeout) +{ + const double startTime = puglGetTime(world); + PuglStatus st = PUGL_SUCCESS; + + world->impl->dispatchingEvents = true; + + if (timeout < 0.0) { + st = puglPollX11Socket(world, timeout); + st = st ? st : puglDispatchX11Events(world); + } else if (timeout == 0.0) { + st = puglDispatchX11Events(world); + } else { + const double endTime = startTime + timeout - 0.001; + for (double t = startTime; t < endTime; t = puglGetTime(world)) { + if ((st = puglPollX11Socket(world, endTime - t)) || + (st = puglDispatchX11Events(world))) { + break; + } + } + } + + flushExposures(world); + + world->impl->dispatchingEvents = false; + + return st; +} + double puglGetTime(const PuglWorld* world) { @@ -988,8 +1013,7 @@ puglGetClipboard(PuglView* const view, // Run event loop until data is received while (!view->clipboard.data) { - puglPollEvents(view->world, -1); - puglDispatchEvents(view->world); + puglUpdate(view->world, -1.0); } } |