aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-10-19 12:15:55 +0200
committerDavid Robillard <d@drobilla.net>2020-10-19 12:47:39 +0200
commita87395423915f913b819291b3b4920501cccdf95 (patch)
treec748467f9923d3f120abb64cd8ce12f367abab19
parentf2e294f99b42becc35588673f45a2d536e1091fa (diff)
downloadpugl-a87395423915f913b819291b3b4920501cccdf95.tar.gz
pugl-a87395423915f913b819291b3b4920501cccdf95.tar.bz2
pugl-a87395423915f913b819291b3b4920501cccdf95.zip
Gracefully handle puglRealize() being called twice
-rw-r--r--pugl/detail/mac.m6
-rw-r--r--pugl/detail/win.c3
-rw-r--r--pugl/detail/x11.c6
-rw-r--r--test/test_realize.c100
-rw-r--r--wscript1
5 files changed, 114 insertions, 2 deletions
diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m
index 5f7e126..8faee86 100644
--- a/pugl/detail/mac.m
+++ b/pugl/detail/mac.m
@@ -868,7 +868,11 @@ puglConstraint(id item, NSLayoutAttribute attribute, float constant)
PuglStatus
puglRealize(PuglView* view)
{
- PuglInternals* impl = view->impl;
+ PuglInternals* impl = view->impl;
+ if (impl->wrapperView) {
+ return PUGL_FAILURE;
+ }
+
const NSScreen* const screen = [NSScreen mainScreen];
const double scaleFactor = [screen backingScaleFactor];
diff --git a/pugl/detail/win.c b/pugl/detail/win.c
index b29ccf4..b3ba00d 100644
--- a/pugl/detail/win.c
+++ b/pugl/detail/win.c
@@ -165,6 +165,9 @@ PuglStatus
puglRealize(PuglView* view)
{
PuglInternals* impl = view->impl;
+ if (impl->hwnd) {
+ return PUGL_FAILURE;
+ }
// Getting depth from the display mode seems tedious, just set usual values
if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) {
diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c
index f9a45e8..e6444c8 100644
--- a/pugl/detail/x11.c
+++ b/pugl/detail/x11.c
@@ -278,7 +278,11 @@ puglDefineCursorShape(PuglView* view, unsigned shape)
PuglStatus
puglRealize(PuglView* view)
{
- PuglInternals* const impl = view->impl;
+ PuglInternals* const impl = view->impl;
+ if (impl->win) {
+ return PUGL_FAILURE;
+ }
+
PuglWorld* const world = view->world;
PuglX11Atoms* const atoms = &view->world->impl->atoms;
Display* const display = world->impl->display;
diff --git a/test/test_realize.c b/test/test_realize.c
new file mode 100644
index 0000000..4a12d1d
--- /dev/null
+++ b/test/test_realize.c
@@ -0,0 +1,100 @@
+/*
+ Copyright 2020 David Robillard <d@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
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ Tests that realize sends a create event, and can safely be called twice.
+
+ Without handling this case, an application that accidentally calls realize
+ twice could end up in a very confusing situation where multiple windows have
+ been allocated (and ultimately leaked) for a view.
+*/
+
+#undef NDEBUG
+
+#include "test_utils.h"
+
+#include "pugl/pugl.h"
+#include "pugl/pugl_stub.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+typedef enum {
+ START,
+ CREATED,
+} State;
+
+typedef struct {
+ PuglWorld* world;
+ PuglView* view;
+ PuglTestOptions opts;
+ State state;
+} PuglTest;
+
+static PuglStatus
+onEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglTest* test = (PuglTest*)puglGetHandle(view);
+
+ if (test->opts.verbose) {
+ printEvent(event, "Event: ", true);
+ }
+
+ switch (event->type) {
+ case PUGL_CREATE:
+ assert(test->state == START);
+ test->state = CREATED;
+ break;
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+int
+main(int argc, char** argv)
+{
+ PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0),
+ NULL,
+ puglParseTestOptions(&argc, &argv),
+ START};
+
+ // Set up view
+ test.view = puglNewView(test.world);
+ puglSetClassName(test.world, "Pugl Test");
+ puglSetBackend(test.view, puglStubBackend());
+ puglSetHandle(test.view, &test);
+ puglSetEventFunc(test.view, onEvent);
+ puglSetDefaultSize(test.view, 512, 512);
+
+ // Create initially invisible window
+ assert(!puglRealize(test.view));
+ assert(!puglGetVisible(test.view));
+ while (test.state < CREATED) {
+ assert(!puglUpdate(test.world, -1.0));
+ }
+
+ // Check that calling realize() again is okay
+ assert(puglRealize(test.view) == PUGL_FAILURE);
+
+ // Tear down
+ puglFreeView(test.view);
+ puglFreeWorld(test.world);
+
+ return 0;
+}
diff --git a/wscript b/wscript
index 525c929..554a2e1 100644
--- a/wscript
+++ b/wscript
@@ -269,6 +269,7 @@ def _build_pc_file(bld, name, desc, target, libname, deps={}, requires=[]):
gl_tests = ['gl_hints']
basic_tests = [
+ 'realize',
'redisplay',
'show_hide',
'stub_hints',