aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2025-01-23 17:00:37 -0500
committerDavid Robillard <d@drobilla.net>2025-01-23 18:02:52 -0500
commitef551ed4b85bc29b3eb48775faeadcf41596c40a (patch)
tree9ce41788cd4c06b9e9e3ce3f6fbfa01cd4931e8b
parentd7a93950b3af397580572adf2e366f3b162104a9 (diff)
downloadpugl-ef551ed4b85bc29b3eb48775faeadcf41596c40a.tar.gz
pugl-ef551ed4b85bc29b3eb48775faeadcf41596c40a.tar.bz2
pugl-ef551ed4b85bc29b3eb48775faeadcf41596c40a.zip
Replace puglPostRedisplayRect() with puglObscureRegion()
-rw-r--r--bindings/cpp/include/pugl/pugl.hpp9
-rw-r--r--doc/c/event-loop.rst2
-rw-r--r--examples/pugl_cairo_demo.c43
-rw-r--r--include/pugl/pugl.h42
-rw-r--r--meson.build2
-rw-r--r--src/mac.m30
-rw-r--r--src/win.c20
-rw-r--r--src/x11.c25
-rw-r--r--test/test_redisplay.c22
9 files changed, 129 insertions, 66 deletions
diff --git a/bindings/cpp/include/pugl/pugl.hpp b/bindings/cpp/include/pugl/pugl.hpp
index c74962b..bf87ed3 100644
--- a/bindings/cpp/include/pugl/pugl.hpp
+++ b/bindings/cpp/include/pugl/pugl.hpp
@@ -615,10 +615,13 @@ public:
return static_cast<Status>(puglObscureView(cobj()));
}
- /// @copydoc puglPostRedisplayRect
- Status postRedisplayRect(const Rect& rect) noexcept
+ /// "Obscure" a region so it will be exposed in the next render
+ Status obscure(const int x,
+ const int y,
+ const unsigned width,
+ const unsigned height)
{
- return static_cast<Status>(puglPostRedisplayRect(cobj(), rect));
+ return static_cast<Status>(puglObscureRegion(cobj(), x, y, width, height));
}
/**
diff --git a/doc/c/event-loop.rst b/doc/c/event-loop.rst
index 430566f..7bee397 100644
--- a/doc/c/event-loop.rst
+++ b/doc/c/event-loop.rst
@@ -23,7 +23,7 @@ while those that draw continuously may use a significant fraction of the frame p
Redrawing
*********
-Occasional redrawing can be requested by calling :func:`puglObscureView` or :func:`puglPostRedisplayRect`.
+Occasional redrawing can be requested by calling :func:`puglObscureView` or :func:`puglObscureRegion`.
After these are called,
a :struct:`PuglExposeEvent` will be dispatched on the next call to :func:`puglUpdate`.
diff --git a/examples/pugl_cairo_demo.c b/examples/pugl_cairo_demo.c
index 2859ff0..d973d69 100644
--- a/examples/pugl_cairo_demo.c
+++ b/examples/pugl_cairo_demo.c
@@ -114,13 +114,12 @@ postButtonRedisplay(PuglView* view)
const ViewScale scale = getScale(view);
for (const Button* b = buttons; b->label; ++b) {
- const double span = sqrt(b->w * b->w + b->h * b->h);
- const PuglRect rect = {(PuglCoord)((b->x - span) * scale.x),
- (PuglCoord)((b->y - span) * scale.y),
- (PuglSpan)ceil(span * 2.0 * scale.x),
- (PuglSpan)ceil(span * 2.0 * scale.y)};
-
- puglPostRedisplayRect(view, rect);
+ const double span = sqrt(b->w * b->w + b->h * b->h);
+ puglObscureRegion(view,
+ (int)((b->x - span) * scale.x),
+ (int)((b->y - span) * scale.y),
+ (unsigned)ceil(span * 2.0 * scale.x),
+ (unsigned)ceil(span * 2.0 * scale.y));
}
}
@@ -172,18 +171,17 @@ onClose(PuglView* view)
app->quit = 1;
}
-static PuglRect
-mouseCursorViewBounds(const PuglView* const view,
- const double mouseX,
- const double mouseY)
+static PuglStatus
+obscureMouseCursor(PuglView* const view,
+ const ViewScale scale,
+ const double mouseX,
+ const double mouseY)
{
- const ViewScale scale = getScale(view);
- const PuglRect rect = {(PuglCoord)floor(mouseX - (10.0 * scale.x)),
- (PuglCoord)floor(mouseY - (10.0 * scale.y)),
- (PuglSpan)ceil(20.0 * scale.x),
- (PuglSpan)ceil(20.0 * scale.y)};
-
- return rect;
+ return puglObscureRegion(view,
+ (int)floor(mouseX - (10.0 * scale.x)),
+ (int)floor(mouseY - (10.0 * scale.y)),
+ (unsigned)ceil(20.0 * scale.x),
+ (unsigned)ceil(20.0 * scale.y));
}
static PuglStatus
@@ -193,6 +191,7 @@ onEvent(PuglView* view, const PuglEvent* event)
printEvent(event, "Event: ", app->opts.verbose);
+ const ViewScale scale = getScale(view);
switch (event->type) {
case PUGL_KEY_PRESS:
if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) {
@@ -209,16 +208,12 @@ onEvent(PuglView* view, const PuglEvent* event)
break;
case PUGL_MOTION:
// Redisplay to clear the old cursor position
- puglPostRedisplayRect(
- view,
- mouseCursorViewBounds(view, app->lastDrawnMouseX, app->lastDrawnMouseY));
+ obscureMouseCursor(view, scale, app->lastDrawnMouseX, app->lastDrawnMouseY);
// Redisplay to show the new cursor position
app->currentMouseX = event->motion.x;
app->currentMouseY = event->motion.y;
- puglPostRedisplayRect(
- view,
- mouseCursorViewBounds(view, app->currentMouseX, app->currentMouseY));
+ obscureMouseCursor(view, scale, app->currentMouseX, app->currentMouseY);
app->lastDrawnMouseX = app->currentMouseX;
app->lastDrawnMouseY = app->currentMouseY;
diff --git a/include/pugl/pugl.h b/include/pugl/pugl.h
index 49e5fe5..d7366c6 100644
--- a/include/pugl/pugl.h
+++ b/include/pugl/pugl.h
@@ -298,7 +298,7 @@ typedef PuglAnyEvent PuglCloseEvent;
This event is sent to every view near the end of a main loop iteration when
any pending exposures are about to be redrawn. It is typically used to mark
- regions to expose with puglObscureView() or puglPostRedisplayRect(). For
+ regions to expose with puglObscureView() or puglObscureRegion(). For
example, to continuously animate, obscure the view when an update event is
received, and it will receive an expose event shortly afterwards.
*/
@@ -1425,14 +1425,29 @@ PuglStatus
puglObscureView(PuglView* view);
/**
- Request a redisplay of the given rectangle within the view.
+ "Obscure" a region so it will be exposed in the next render.
+
+ This will cause an expose event to be dispatched later. If called from
+ within the event handler, the expose should arrive at the end of the current
+ event loop iteration, though this is not strictly guaranteed on all
+ platforms. If called elsewhere, an expose will be enqueued to be processed
+ in the next event loop iteration.
+
+ The region is clamped to the size of the view if necessary.
- This has the same semantics as puglObscureView(), but allows giving a precise
- region for redrawing only a portion of the view.
+ @param view The view to expose later.
+ @param x The top-left X coordinate of the rectangle to obscure.
+ @param y The top-left Y coordinate of the rectangle to obscure.
+ @param width The width of the rectangle to obscure.
+ @param height The height coordinate of the rectangle to obscure.
*/
PUGL_API
PuglStatus
-puglPostRedisplayRect(PuglView* view, PuglRect rect);
+puglObscureRegion(PuglView* view,
+ int x,
+ int y,
+ unsigned width,
+ unsigned height);
/**
@}
@@ -1634,8 +1649,8 @@ puglStopTimer(PuglView* view, uintptr_t id);
Currently, only #PUGL_CLIENT events are supported on all platforms.
X11: A #PUGL_EXPOSE event can be sent, which is similar to calling
- puglPostRedisplayRect(), but will always send a message to the X server,
- even when called in an event handler.
+ puglObscureRegion(), but will always send a message to the X server, even
+ when called in an event handler.
@return #PUGL_UNSUPPORTED if sending events of this type is not supported,
#PUGL_UNKNOWN_ERROR if sending the event failed.
@@ -2210,6 +2225,19 @@ puglPostRedisplay(PuglView* view)
return puglObscureView(view);
}
+/**
+ Request a redisplay of the given rectangle within the view.
+
+ This has the same semantics as puglPostRedisplay(), but allows giving a
+ precise region for redrawing only a portion of the view.
+*/
+static inline PUGL_DEPRECATED_BY("puglObscureRegion")
+PuglStatus
+puglPostRedisplayRect(PuglView* view, PuglRect rect)
+{
+ return puglObscureRegion(view, rect.x, rect.y, rect.width, rect.height);
+}
+
#endif // PUGL_DISABLE_DEPRECATED
/**
diff --git a/meson.build b/meson.build
index ec58fb8..1c2d8ca 100644
--- a/meson.build
+++ b/meson.build
@@ -12,7 +12,7 @@ project(
],
license: 'ISC',
meson_version: '>= 0.54.0',
- version: '0.5.3',
+ version: '0.5.5',
)
pugl_src_root = meson.current_source_dir()
diff --git a/src/mac.m b/src/mac.m
index bf8e0f4..5f9d71e 100644
--- a/src/mac.m
+++ b/src/mac.m
@@ -7,6 +7,7 @@
#include "mac.h"
#include "internal.h"
+#include "macros.h"
#include "platform.h"
#include "pugl/pugl.h"
@@ -1651,15 +1652,30 @@ puglObscureView(PuglView* view)
}
PuglStatus
-puglPostRedisplayRect(PuglView* view, const PuglRect rect)
+puglObscureRegion(PuglView* view,
+ const int x,
+ const int y,
+ const unsigned width,
+ const unsigned height)
{
- const NSRect rectPx = {
- {(double)rect.x,
- (double)view->lastConfigure.height - (rect.y + rect.height)},
- {(double)rect.width, (double)rect.height},
- };
+ if (!puglIsValidPosition(x, y) || !puglIsValidSize(width, height)) {
+ return PUGL_BAD_PARAMETER;
+ }
+
+ const PuglSpan viewHeight = view->lastConfigure.height;
+
+ const int cx = MAX(0, x);
+ const int cy = MAX(0, viewHeight - y - (int)height);
+ const unsigned cw = MIN(view->lastConfigure.width, width);
+ const unsigned ch = MIN(view->lastConfigure.height, height);
- [view->impl->drawView setNeedsDisplayInRect:nsRectToPoints(view, rectPx)];
+ if (cw == view->lastConfigure.width && ch == view->lastConfigure.height) {
+ [view->impl->drawView setNeedsDisplay:YES];
+ } else {
+ const NSRect rectPx = NSMakeRect(cx, cy, cw, ch);
+
+ [view->impl->drawView setNeedsDisplayInRect:nsRectToPoints(view, rectPx)];
+ }
return PUGL_SUCCESS;
}
diff --git a/src/win.c b/src/win.c
index a0d0778..fe8d1b4 100644
--- a/src/win.c
+++ b/src/win.c
@@ -4,6 +4,7 @@
#include "win.h"
#include "internal.h"
+#include "macros.h"
#include "platform.h"
#include "pugl/pugl.h"
@@ -1216,13 +1217,22 @@ puglObscureView(PuglView* view)
}
PuglStatus
-puglPostRedisplayRect(PuglView* view, const PuglRect rect)
+puglObscureRegion(PuglView* const view,
+ const int x,
+ const int y,
+ const unsigned width,
+ const unsigned height)
{
- const RECT r = {(long)floor(rect.x),
- (long)floor(rect.y),
- (long)ceil(rect.x + rect.width),
- (long)ceil(rect.y + rect.height)};
+ if (!puglIsValidPosition(x, y) || !puglIsValidSize(width, height)) {
+ return PUGL_BAD_PARAMETER;
+ }
+
+ const int cx = MAX(0, x);
+ const int cy = MAX(0, y);
+ const unsigned cw = MIN(view->lastConfigure.width, width);
+ const unsigned ch = MIN(view->lastConfigure.height, height);
+ const RECT r = {cx, cy, cx + (long)cw, cy + (long)ch};
InvalidateRect(view->impl->hwnd, &r, false);
return PUGL_SUCCESS;
diff --git a/src/x11.c b/src/x11.c
index 235af39..f60528b 100644
--- a/src/x11.c
+++ b/src/x11.c
@@ -1879,18 +1879,27 @@ puglGetTime(const PuglWorld* const world)
PuglStatus
puglObscureView(PuglView* const view)
{
- PuglRect rect = puglGetFrame(view);
- rect.x = 0;
- rect.y = 0;
-
- return puglPostRedisplayRect(view, rect);
+ return puglObscureRegion(
+ view, 0, 0, view->lastConfigure.width, view->lastConfigure.height);
}
PuglStatus
-puglPostRedisplayRect(PuglView* const view, const PuglRect rect)
+puglObscureRegion(PuglView* const view,
+ const int x,
+ const int y,
+ const unsigned width,
+ const unsigned height)
{
- const PuglExposeEvent event = {
- PUGL_EXPOSE, 0, rect.x, rect.y, rect.width, rect.height};
+ if (!puglIsValidPosition(x, y) || !puglIsValidSize(width, height)) {
+ return PUGL_BAD_PARAMETER;
+ }
+
+ const PuglCoord cx = MAX((PuglCoord)0, (PuglCoord)x);
+ const PuglCoord cy = MAX((PuglCoord)0, (PuglCoord)y);
+ const PuglSpan cw = MIN(view->lastConfigure.width, (PuglSpan)width);
+ const PuglSpan ch = MIN(view->lastConfigure.height, (PuglSpan)height);
+
+ const PuglExposeEvent event = {PUGL_EXPOSE, 0, cx, cy, cw, ch};
if (view->world->impl->dispatchingEvents) {
// Currently dispatching events, add/expand expose for the loop end
diff --git a/test/test_redisplay.c b/test/test_redisplay.c
index f17e4c7..ae7267d 100644
--- a/test/test_redisplay.c
+++ b/test/test_redisplay.c
@@ -51,8 +51,11 @@ typedef struct {
State state;
} PuglTest;
-static const PuglRect redisplayRect = {2, 4, 8, 16};
-static const uintptr_t postRedisplayId = 42;
+static const PuglCoord obscureX = 2;
+static const PuglCoord obscureY = 4;
+static const PuglSpan obscureWidth = 8;
+static const PuglSpan obscureHeight = 16;
+static const uintptr_t obscureId = 42;
static PuglStatus
onEvent(PuglView* view, const PuglEvent* event)
@@ -67,7 +70,7 @@ onEvent(PuglView* view, const PuglEvent* event)
switch (event->type) {
case PUGL_UPDATE:
if (test->state == SHOULD_REDISPLAY) {
- puglPostRedisplayRect(view, redisplayRect);
+ puglObscureRegion(view, obscureX, obscureY, obscureWidth, obscureHeight);
test->state = POSTED_REDISPLAY;
}
break;
@@ -75,13 +78,12 @@ onEvent(PuglView* view, const PuglEvent* event)
case PUGL_EXPOSE:
if (test->state == START) {
test->state = EXPOSED;
- } else if (test->state == POSTED_REDISPLAY &&
- event->expose.x <= redisplayRect.x &&
- event->expose.y <= redisplayRect.y &&
+ } else if (test->state == POSTED_REDISPLAY && event->expose.x <= obscureX &&
+ event->expose.y <= obscureY &&
(event->expose.x + event->expose.width >=
- redisplayRect.x + redisplayRect.width) &&
+ obscureX + obscureWidth) &&
(event->expose.y + event->expose.height >=
- redisplayRect.y + redisplayRect.height)) {
+ obscureY + obscureHeight)) {
test->state = REDISPLAYED;
} else if (test->state == REDISPLAYED) {
test->state = REREDISPLAYED;
@@ -89,7 +91,7 @@ onEvent(PuglView* view, const PuglEvent* event)
break;
case PUGL_CLIENT:
- if (event->client.data1 == postRedisplayId) {
+ if (event->client.data1 == obscureId) {
test->state = SHOULD_REDISPLAY;
}
break;
@@ -128,7 +130,7 @@ main(int argc, char** argv)
// Send a custom event to trigger a redisplay in the event loop
PuglEvent client_event = {{PUGL_CLIENT, 0}};
- client_event.client.data1 = postRedisplayId;
+ client_event.client.data1 = obscureId;
client_event.client.data2 = 0;
assert(!puglSendEvent(test.view, &client_event));