diff options
-rw-r--r-- | pugl/detail/mac.m | 20 | ||||
-rw-r--r-- | pugl/detail/win.c | 12 | ||||
-rw-r--r-- | pugl/detail/x11.c | 106 | ||||
-rw-r--r-- | pugl/detail/x11.h | 2 | ||||
-rw-r--r-- | pugl/pugl.h | 15 | ||||
-rw-r--r-- | test/pugl_cairo_test.c | 2 | ||||
-rw-r--r-- | test/pugl_test.c | 2 |
7 files changed, 107 insertions, 52 deletions
diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m index 74b207a..3fa700e 100644 --- a/pugl/detail/mac.m +++ b/pugl/detail/mac.m @@ -842,20 +842,26 @@ puglWaitForEvent(PuglView* view) return puglPollEvents(view->world, -1.0); } -PuglStatus -puglProcessEvents(PuglView* view) +PUGL_API PuglStatus +puglDispatchEvents(PuglWorld* world) { for (NSEvent* ev = NULL; - (ev = [view->impl->window nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:YES]);) { - [view->world->impl->app sendEvent: ev]; + (ev = [world->impl->app nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue:YES]);) { + [world->impl->app sendEvent: ev]; } return PUGL_SUCCESS; } +PuglStatus +puglProcessEvents(PuglView* view) +{ + return puglDispatchEvents(view->world); +} + PuglGlFunc puglGetProcAddress(const char *name) { diff --git a/pugl/detail/win.c b/pugl/detail/win.c index 9d0d0e5..6cd34e3 100644 --- a/pugl/detail/win.c +++ b/pugl/detail/win.c @@ -682,11 +682,11 @@ puglWaitForEvent(PuglView* PUGL_UNUSED(view)) return PUGL_SUCCESS; } -PuglStatus -puglProcessEvents(PuglView* view) +PUGL_API PuglStatus +puglDispatchEvents(PuglWorld* PUGL_UNUSED(world)) { MSG msg; - while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) { + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } @@ -694,6 +694,12 @@ puglProcessEvents(PuglView* view) return PUGL_SUCCESS; } +PuglStatus +puglProcessEvents(PuglView* view) +{ + return puglDispatchEvents(view->world); +} + LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c index 7ef3866..b564225 100644 --- a/pugl/detail/x11.c +++ b/pugl/detail/x11.c @@ -127,6 +127,18 @@ puglPollEvents(PuglWorld* world, const double timeout) return ret < 0 ? PUGL_ERR_UNKNOWN : ret == 0 ? PUGL_FAILURE : PUGL_SUCCESS; } +static PuglView* +puglFindView(PuglWorld* world, const Window window) +{ + for (size_t i = 0; i < world->numViews; ++i) { + if (world->views[i]->impl->win == window) { + return world->views[i]; + } + } + + return NULL; +} + int puglCreateWindow(PuglView* view, const char* title) { @@ -557,30 +569,32 @@ merge_expose_events(PuglEvent* dst, const PuglEvent* src) } } -PuglStatus -puglProcessEvents(PuglView* view) +PUGL_API PuglStatus +puglDispatchEvents(PuglWorld* world) { - /* Maintain a single expose/configure event to execute after all pending - events. This avoids redundant drawing/configuration which prevents a - series of window resizes in the same loop from being laggy. */ - PuglInternals* const impl = view->impl; - PuglEvent expose_event = { 0 }; - PuglEvent config_event = { 0 }; - XEvent xevent; - while (XPending(impl->display) > 0) { - XNextEvent(impl->display, &xevent); - if (xevent.type == KeyRelease) { - // Ignore key repeat if necessary - if (view->hints[PUGL_IGNORE_KEY_REPEAT] && - XEventsQueued(impl->display, QueuedAfterReading)) { - XEvent next; - XPeekEvent(impl->display, &next); - if (next.type == KeyPress && - next.xkey.time == xevent.xkey.time && - next.xkey.keycode == xevent.xkey.keycode) { - XNextEvent(impl->display, &xevent); - continue; - } + // Flush just once at the start to fill event queue + Display* display = world->impl->display; + XFlush(display); + + // Process all queued events (locally, without flushing or reading) + while (XEventsQueued(display, QueuedAlready) > 0) { + XEvent xevent; + XNextEvent(display, &xevent); + + PuglView* view = puglFindView(world, xevent.xany.window); + if (!view) { + continue; + } + + // Handle special events + PuglInternals* const impl = view->impl; + if (xevent.type == KeyRelease && view->hints[PUGL_IGNORE_KEY_REPEAT]) { + XEvent next; + if (XCheckTypedWindowEvent(display, impl->win, KeyPress, &next) && + next.type == KeyPress && + next.xkey.time == xevent.xkey.time && + next.xkey.keycode == xevent.xkey.keycode) { + continue; } } else if (xevent.type == FocusIn) { XSetICFocus(impl->xic); @@ -593,38 +607,52 @@ puglProcessEvents(PuglView* view) if (event.type == PUGL_EXPOSE) { // Expand expose event to be dispatched after loop - merge_expose_events(&expose_event, &event); + merge_expose_events(&view->impl->pendingExpose, &event); } else if (event.type == PUGL_CONFIGURE) { // Expand configure event to be dispatched after loop - config_event = event; + view->impl->pendingConfigure = event; } else { // Dispatch event to application immediately puglDispatchEvent(view, &event); } } - if (config_event.type || expose_event.type) { - const bool draw = expose_event.type && expose_event.expose.count == 0; - - puglEnterContext(view, draw); + // Flush pending configure and expose events for all views + for (size_t i = 0; i < world->numViews; ++i) { + PuglView* const view = world->views[i]; + PuglEvent* const configure = &view->impl->pendingConfigure; + PuglEvent* const expose = &view->impl->pendingExpose; + + if (configure->type || expose->type) { + const bool mustExpose = expose->type && expose->expose.count == 0; + puglEnterContext(view, mustExpose); + + if (configure->type) { + view->width = (int)configure->configure.width; + view->height = (int)configure->configure.height; + view->backend->resize(view, view->width, view->height); + view->eventFunc(view, &view->impl->pendingConfigure); + } - if (config_event.type) { - view->width = (int)config_event.configure.width; - view->height = (int)config_event.configure.height; - view->backend->resize(view, view->width, view->height); - view->eventFunc(view, (const PuglEvent*)&config_event); - } + if (mustExpose) { + view->eventFunc(view, &view->impl->pendingExpose); + } - if (draw) { - view->eventFunc(view, (const PuglEvent*)&expose_event); + puglLeaveContext(view, mustExpose); + configure->type = 0; + expose->type = 0; } - - puglLeaveContext(view, draw); } return PUGL_SUCCESS; } +PuglStatus +puglProcessEvents(PuglView* view) +{ + return puglDispatchEvents(view->world); +} + double puglGetTime(const PuglWorld* world) { diff --git a/pugl/detail/x11.h b/pugl/detail/x11.h index 34694fe..be5f3e0 100644 --- a/pugl/detail/x11.h +++ b/pugl/detail/x11.h @@ -45,4 +45,6 @@ struct PuglInternalsImpl { Window win; XIC xic; PuglSurface* surface; + PuglEvent pendingConfigure; + PuglEvent pendingExpose; }; diff --git a/pugl/pugl.h b/pugl/pugl.h index 923d361..3639a96 100644 --- a/pugl/pugl.h +++ b/pugl/pugl.h @@ -472,6 +472,17 @@ PUGL_API PuglStatus puglPollEvents(PuglWorld* world, double timeout); /** + Dispatch any pending events to views. + + This processes all pending events, dispatching them to the appropriate + views. View event handlers will be called in the scope of this call. This + function does not block, if no events are pending it will return + immediately. +*/ +PUGL_API PuglStatus +puglDispatchEvents(PuglWorld* world); + +/** @} @name Initialization Configuration functions which must be called before creating a window. @@ -756,8 +767,10 @@ puglWaitForEvent(PuglView* view); This handles input events as well as rendering, so it should be called regularly and rapidly enough to keep the UI responsive. This function does not block if no events are pending. + + @deprecated Use puglDispatchEvents(). */ -PUGL_API PuglStatus +PUGL_API PUGL_DEPRECATED_BY("puglDispatchEvents") PuglStatus puglProcessEvents(PuglView* view); /** diff --git a/test/pugl_cairo_test.c b/test/pugl_cairo_test.c index 6d85c54..3ac2054 100644 --- a/test/pugl_cairo_test.c +++ b/test/pugl_cairo_test.c @@ -230,7 +230,7 @@ main(int argc, char** argv) puglPollEvents(world, -1); } - puglProcessEvents(view); + puglDispatchEvents(world); if (continuous) { puglPrintFps(world, &fpsPrinter, &framesDrawn); diff --git a/test/pugl_test.c b/test/pugl_test.c index 66fd97d..d6207fe 100644 --- a/test/pugl_test.c +++ b/test/pugl_test.c @@ -215,7 +215,7 @@ main(int argc, char** argv) puglPollEvents(app.world, -1); } - puglProcessEvents(view); + puglDispatchEvents(app.world); if (!requestedAttention && thisTime > 5.0) { puglRequestAttention(view); |