aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2019-07-22 16:53:02 +0200
committerDavid Robillard <d@drobilla.net>2019-09-03 08:32:16 +0200
commit93f4920cfc03d1a2a8c0df9c6d863cdf20c6ab32 (patch)
tree64ef7427a32b88183bae8720b07fc9258b769b3e
parent496f17c3804c79d304aa6095b92768593d1cc700 (diff)
Add puglDispatchEvents()
-rw-r--r--pugl/detail/mac.m20
-rw-r--r--pugl/detail/win.c12
-rw-r--r--pugl/detail/x11.c106
-rw-r--r--pugl/detail/x11.h2
-rw-r--r--pugl/pugl.h15
-rw-r--r--test/pugl_cairo_test.c2
-rw-r--r--test/pugl_test.c2
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);