aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/pugl/pugl.h14
-rw-r--r--meson.build4
-rw-r--r--src/common.c6
-rw-r--r--src/mac.m39
-rw-r--r--src/win.c26
-rw-r--r--src/x11.c66
-rw-r--r--test/test_show_hide.c43
7 files changed, 157 insertions, 41 deletions
diff --git a/include/pugl/pugl.h b/include/pugl/pugl.h
index 5a60e80..fda8af2 100644
--- a/include/pugl/pugl.h
+++ b/include/pugl/pugl.h
@@ -1163,9 +1163,7 @@ puglGetTransientParent(const PuglView* view);
Realize a view by creating a corresponding system view or window.
After this call, the (initially invisible) underlying system view exists and
- can be accessed with puglGetNativeView(). There is currently no
- corresponding unrealize function, the system view will be destroyed along
- with the view when puglFreeView() is called.
+ can be accessed with puglGetNativeView().
The view should be fully configured using the above functions before this is
called. This function may only be called once per view.
@@ -1175,6 +1173,16 @@ PuglStatus
puglRealize(PuglView* view);
/**
+ Unrealize a view by destroying the corresponding system view or window.
+
+ This is the inverse of puglRealize(). After this call, the view no longer
+ corresponds to a real system view, and can be realized again later.
+*/
+PUGL_API
+PuglStatus
+puglUnrealize(PuglView* view);
+
+/**
Show the view.
If the view has not yet been realized, the first call to this function will
diff --git a/meson.build b/meson.build
index d7b171c..4e04012 100644
--- a/meson.build
+++ b/meson.build
@@ -1,8 +1,8 @@
-# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# Copyright 2021-2023 David Robillard <d@drobilla.net>
# SPDX-License-Identifier: 0BSD OR ISC
project('pugl', ['c'],
- version: '0.4.0',
+ version: '0.5.0',
license: 'ISC',
meson_version: '>= 0.54.0',
default_options: [
diff --git a/src/common.c b/src/common.c
index 9ea3594..c3f0818 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1,4 +1,4 @@
-// Copyright 2012-2022 David Robillard <d@drobilla.net>
+// Copyright 2012-2023 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
// Common implementations of public API functions in the core library
@@ -136,10 +136,6 @@ puglNewView(PuglWorld* const world)
void
puglFreeView(PuglView* view)
{
- if (view->eventFunc && view->backend) {
- puglDispatchSimpleEvent(view, PUGL_DESTROY);
- }
-
// Remove from world view list
PuglWorld* world = view->world;
for (size_t i = 0; i < world->numViews; ++i) {
diff --git a/src/mac.m b/src/mac.m
index 0ba95ca..658c807 100644
--- a/src/mac.m
+++ b/src/mac.m
@@ -1,4 +1,4 @@
-// Copyright 2012-2022 David Robillard <d@drobilla.net>
+// Copyright 2012-2023 David Robillard <d@drobilla.net>
// Copyright 2017 Hanspeter Portner <dev@open-music-kontrollers.ch>
// SPDX-License-Identifier: ISC
@@ -1171,6 +1171,43 @@ puglRealize(PuglView* view)
}
PuglStatus
+puglUnrealize(PuglView* const view)
+{
+ PuglInternals* const impl = view->impl;
+ if (!impl || !impl->wrapperView) {
+ return PUGL_FAILURE;
+ }
+
+ puglDispatchSimpleEvent(view, PUGL_DESTROY);
+
+ if (view->backend) {
+ view->backend->destroy(view);
+ }
+
+ if (impl->wrapperView) {
+ [impl->wrapperView removeFromSuperview];
+ impl->wrapperView->puglview = NULL;
+ }
+
+ if (impl->window) {
+ [impl->window close];
+ }
+
+ if (impl->wrapperView) {
+ [impl->wrapperView release];
+ impl->wrapperView = NULL;
+ }
+
+ if (impl->window) {
+ [impl->window release];
+ impl->window = NULL;
+ }
+
+ memset(&view->lastConfigure, 0, sizeof(PuglConfigureEvent));
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
puglShow(PuglView* view)
{
if (!view->impl->wrapperView) {
diff --git a/src/win.c b/src/win.c
index e41222b..13ad090 100644
--- a/src/win.c
+++ b/src/win.c
@@ -1,4 +1,4 @@
-// Copyright 2012-2022 David Robillard <d@drobilla.net>
+// Copyright 2012-2023 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
#include "win.h"
@@ -275,6 +275,30 @@ puglRealize(PuglView* view)
}
PuglStatus
+puglUnrealize(PuglView* const view)
+{
+ PuglInternals* const impl = view->impl;
+ if (!impl || !impl->hwnd) {
+ return PUGL_FAILURE;
+ }
+
+ puglDispatchSimpleEvent(view, PUGL_DESTROY);
+
+ if (view->backend) {
+ view->backend->destroy(view);
+ }
+
+ ReleaseDC(view->impl->hwnd, view->impl->hdc);
+ view->impl->hdc = NULL;
+
+ DestroyWindow(view->impl->hwnd);
+ view->impl->hwnd = NULL;
+
+ memset(&view->lastConfigure, 0, sizeof(PuglConfigureEvent));
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
puglShow(PuglView* view)
{
PuglInternals* impl = view->impl;
diff --git a/src/x11.c b/src/x11.c
index 271a0fb..1dc4f9d 100644
--- a/src/x11.c
+++ b/src/x11.c
@@ -1,4 +1,4 @@
-// Copyright 2012-2022 David Robillard <d@drobilla.net>
+// Copyright 2012-2023 David Robillard <d@drobilla.net>
// Copyright 2013 Robin Gareus <robin@gareus.org>
// Copyright 2011-2012 Ben Loftis, Harrison Consoles
// SPDX-License-Identifier: ISC
@@ -344,6 +344,21 @@ defineCursorName(PuglView* const view, const char* const name)
}
#endif
+static void
+clearX11Clipboard(PuglX11Clipboard* const board)
+{
+ for (unsigned long i = 0; i < board->numFormats; ++i) {
+ free(board->formatStrings[i]);
+ board->formatStrings[i] = NULL;
+ }
+
+ board->source = None;
+ board->numFormats = 0;
+ board->acceptedFormatIndex = UINT32_MAX;
+ board->acceptedFormat = None;
+ board->data.len = 0;
+}
+
PuglStatus
puglRealize(PuglView* const view)
{
@@ -474,6 +489,40 @@ puglRealize(PuglView* const view)
}
PuglStatus
+puglUnrealize(PuglView* const view)
+{
+ PuglInternals* const impl = view->impl;
+ if (!impl || !impl->win) {
+ return PUGL_FAILURE;
+ }
+
+ puglDispatchSimpleEvent(view, PUGL_DESTROY);
+ clearX11Clipboard(&impl->clipboard);
+
+ if (impl->xic) {
+ XDestroyIC(impl->xic);
+ impl->xic = None;
+ }
+
+ if (view->backend) {
+ view->backend->destroy(view);
+ }
+
+ if (view->world->impl->display && impl->win) {
+ XDestroyWindow(view->world->impl->display, impl->win);
+ impl->win = None;
+ }
+
+ XFree(impl->vi);
+ impl->vi = NULL;
+
+ memset(&view->lastConfigure, 0, sizeof(PuglConfigureEvent));
+ memset(&view->impl->pendingConfigure, 0, sizeof(PuglEvent));
+ memset(&view->impl->pendingExpose, 0, sizeof(PuglEvent));
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
puglShow(PuglView* const view)
{
PuglStatus st = view->impl->win ? PUGL_SUCCESS : puglRealize(view);
@@ -493,21 +542,6 @@ puglHide(PuglView* const view)
return PUGL_SUCCESS;
}
-static void
-clearX11Clipboard(PuglX11Clipboard* const board)
-{
- for (unsigned long i = 0; i < board->numFormats; ++i) {
- free(board->formatStrings[i]);
- board->formatStrings[i] = NULL;
- }
-
- board->source = None;
- board->numFormats = 0;
- board->acceptedFormatIndex = UINT32_MAX;
- board->acceptedFormat = None;
- board->data.len = 0;
-}
-
void
puglFreeViewInternals(PuglView* const view)
{
diff --git a/test/test_show_hide.c b/test/test_show_hide.c
index 61f2bc6..1dc17a2 100644
--- a/test/test_show_hide.c
+++ b/test/test_show_hide.c
@@ -1,4 +1,4 @@
-// Copyright 2020 David Robillard <d@drobilla.net>
+// Copyright 2020-2023 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
/*
@@ -88,6 +88,24 @@ tick(PuglWorld* world)
#endif
}
+static void
+showHide(PuglTest* const test)
+{
+ // Show and hide window a couple of times
+ for (unsigned i = 0U; i < 2U; ++i) {
+ assert(!puglShow(test->view));
+ while (test->state != EXPOSED) {
+ tick(test->world);
+ }
+
+ assert(puglGetVisible(test->view));
+ assert(!puglHide(test->view));
+ while (test->state != UNMAPPED) {
+ tick(test->world);
+ }
+ }
+}
+
int
main(int argc, char** argv)
{
@@ -113,21 +131,20 @@ main(int argc, char** argv)
}
// Show and hide window a couple of times
- for (unsigned i = 0U; i < 2U; ++i) {
- assert(!puglShow(test.view));
- while (test.state != EXPOSED) {
- tick(test.world);
- }
+ showHide(&test);
- assert(puglGetVisible(test.view));
- assert(!puglHide(test.view));
- while (test.state != UNMAPPED) {
- tick(test.world);
- }
- }
+ // Unrealize view
+ assert(!puglGetVisible(test.view));
+ assert(!puglUnrealize(test.view));
+ assert(test.state == DESTROYED);
+
+ // Realize and show again
+ test.state = START;
+ assert(!puglRealize(test.view));
+ showHide(&test);
+ assert(!puglUnrealize(test.view));
// Tear down
- assert(!puglGetVisible(test.view));
puglFreeView(test.view);
assert(test.state == DESTROYED);
puglFreeWorld(test.world);