diff options
-rw-r--r-- | include/pugl/pugl.h | 14 | ||||
-rw-r--r-- | meson.build | 4 | ||||
-rw-r--r-- | src/common.c | 6 | ||||
-rw-r--r-- | src/mac.m | 39 | ||||
-rw-r--r-- | src/win.c | 26 | ||||
-rw-r--r-- | src/x11.c | 66 | ||||
-rw-r--r-- | test/test_show_hide.c | 43 |
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) { @@ -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) { @@ -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; @@ -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); |