diff options
author | David Robillard <d@drobilla.net> | 2019-07-22 16:30:53 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2019-09-03 08:32:16 +0200 |
commit | e83c2b421d140244a6b9edb051b3e0d4aacda332 (patch) | |
tree | 398e49f43c96f4602496874fa7b3680236138720 /pugl/detail | |
parent | 5081d49f9f08596c07a8ed32430a4fa3e1baf352 (diff) | |
download | pugl-e83c2b421d140244a6b9edb051b3e0d4aacda332.tar.gz pugl-e83c2b421d140244a6b9edb051b3e0d4aacda332.tar.bz2 pugl-e83c2b421d140244a6b9edb051b3e0d4aacda332.zip |
Add PuglWorld
The old API was broken for programs that manage multiple views, since it was
impossible to wait for events on any view. There are also several functions in
the API which are not actually associated with views at all, so those can now
be moved to the more appropriate PuglWorld to make this more clear.
The old puglInit() and puglDestroy() functions are preserved for compatibility,
but marked as deprecated.
Diffstat (limited to 'pugl/detail')
-rw-r--r-- | pugl/detail/implementation.c | 70 | ||||
-rw-r--r-- | pugl/detail/implementation.h | 13 | ||||
-rw-r--r-- | pugl/detail/mac.h | 5 | ||||
-rw-r--r-- | pugl/detail/mac.m | 38 | ||||
-rw-r--r-- | pugl/detail/types.h | 14 | ||||
-rw-r--r-- | pugl/detail/win.c | 30 | ||||
-rw-r--r-- | pugl/detail/win.h | 5 | ||||
-rw-r--r-- | pugl/detail/x11.c | 32 | ||||
-rw-r--r-- | pugl/detail/x11.h | 4 |
9 files changed, 176 insertions, 35 deletions
diff --git a/pugl/detail/implementation.c b/pugl/detail/implementation.c index 04b36d3..29daf15 100644 --- a/pugl/detail/implementation.c +++ b/pugl/detail/implementation.c @@ -46,27 +46,87 @@ puglSetDefaultHints(PuglHints hints) PuglView* puglInit(int* PUGL_UNUSED(pargc), char** PUGL_UNUSED(argv)) { - PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); - if (!view) { + return puglNewView(puglNewWorld()); +} + +void +puglDestroy(PuglView* const view) +{ + PuglWorld* const world = view->world; + + puglFreeView(view); + puglFreeWorld(world); +} + +PuglWorld* +puglNewWorld(void) +{ + PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld)); + if (!world || !(world->impl = puglInitWorldInternals())) { + free(world); return NULL; } - PuglInternals* impl = puglInitInternals(); - if (!impl) { + return world; +} + +void +puglFreeWorld(PuglWorld* const world) +{ + puglFreeWorldInternals(world); + free(world->views); + free(world); +} + +PuglView* +puglNewView(PuglWorld* const world) +{ + PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); + if (!view || !(view->impl = puglInitViewInternals())) { free(view); return NULL; } - view->impl = impl; + view->world = world; view->width = 640; view->height = 480; view->start_time = puglGetTime(view); puglSetDefaultHints(view->hints); + + // Add to world view list + ++world->numViews; + world->views = (PuglView**)realloc(world->views, + world->numViews * sizeof(PuglView*)); + world->views[world->numViews - 1] = view; + return view; } void +puglFreeView(PuglView* view) +{ + // Remove from world view list + PuglWorld* world = view->world; + for (size_t i = 0; i < world->numViews; ++i) { + if (world->views[i] == view) { + if (i == world->numViews - 1) { + world->views[i] = NULL; + } else { + memmove(world->views + i, world->views + i + 1, + sizeof(PuglView*) * (world->numViews - i - 1)); + world->views[world->numViews - 1] = NULL; + } + --world->numViews; + } + } + + puglFreeViewInternals(view); + free(view->windowClass); + free(view); +} + +void puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value) { if (hint < PUGL_NUM_WINDOW_HINTS) { diff --git a/pugl/detail/implementation.h b/pugl/detail/implementation.h index 50f54f5..d6288a3 100644 --- a/pugl/detail/implementation.h +++ b/pugl/detail/implementation.h @@ -30,8 +30,17 @@ extern "C" { #endif -/** Allocate and initialise internals (implemented once per platform) */ -PuglInternals* puglInitInternals(void); +/** Allocate and initialise world internals (implemented once per platform) */ +PuglWorldInternals* puglInitWorldInternals(void); + +/** Destroy and free world internals (implemented once per platform) */ +void puglFreeWorldInternals(PuglWorld* world); + +/** Allocate and initialise view internals (implemented once per platform) */ +PuglInternals* puglInitViewInternals(void); + +/** Destroy and free view internals (implemented once per platform) */ +void puglFreeViewInternals(PuglView* view); /** Return the Unicode code point for `buf` or the replacement character. */ uint32_t puglDecodeUTF8(const uint8_t* buf); diff --git a/pugl/detail/mac.h b/pugl/detail/mac.h index 8146373..f8cfbed 100644 --- a/pugl/detail/mac.h +++ b/pugl/detail/mac.h @@ -50,6 +50,11 @@ @end +struct PuglWorldInternalsImpl { + NSApplication* app; + NSAutoreleasePool* autoreleasePool; +}; + struct PuglInternalsImpl { NSApplication* app; PuglWrapperView* wrapperView; diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m index 385070d..23344ed 100644 --- a/pugl/detail/mac.m +++ b/pugl/detail/mac.m @@ -566,7 +566,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) - (void) urgentTick { - [NSApp requestUserAttention:NSInformationalRequest]; + [puglview->world->impl->app requestUserAttention:NSInformationalRequest]; } - (void) viewDidEndLiveResize @@ -636,8 +636,27 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) @end +PuglWorldInternals* +puglInitWorldInternals(void) +{ + PuglWorldInternals* impl = (PuglWorldInternals*)calloc( + 1, sizeof(PuglWorldInternals)); + + impl->app = [NSApplication sharedApplication]; + impl->autoreleasePool = [NSAutoreleasePool new]; + + return impl; +} + +void +puglFreeWorldInternals(PuglWorld* world) +{ + [world->impl->autoreleasePool drain]; + free(world->impl); +} + PuglInternals* -puglInitInternals(void) +puglInitViewInternals(void) { return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } @@ -660,9 +679,6 @@ puglCreateWindow(PuglView* view, const char* title) { PuglInternals* impl = view->impl; - [NSAutoreleasePool new]; - impl->app = [NSApplication sharedApplication]; - // Create wrapper view to handle input impl->wrapperView = [PuglWrapperView alloc]; impl->wrapperView->puglview = view; @@ -727,7 +743,7 @@ puglCreateWindow(PuglView* view, const char* title) } [window setContentView:impl->wrapperView]; - [impl->app activateIgnoringOtherApps:YES]; + [view->world->impl->app activateIgnoringOtherApps:YES]; [window makeFirstResponder:impl->wrapperView]; [window makeKeyAndOrderFront:window]; } @@ -752,7 +768,7 @@ puglHideWindow(PuglView* view) } void -puglDestroy(PuglView* view) +puglFreeViewInternals(PuglView* view) { view->backend->destroy(view); [view->impl->wrapperView removeFromSuperview]; @@ -764,9 +780,7 @@ puglDestroy(PuglView* view) if (view->impl->window) { [view->impl->window release]; } - free(view->windowClass); free(view->impl); - free(view); } void @@ -791,7 +805,7 @@ void puglRequestAttention(PuglView* view) { if (![view->impl->window isKeyWindow]) { - [NSApp requestUserAttention:NSInformationalRequest]; + [view->world->impl->app requestUserAttention:NSInformationalRequest]; view->impl->wrapperView->urgentTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:view->impl->wrapperView @@ -820,7 +834,7 @@ puglProcessEvents(PuglView* view) { if (view->impl->nextEvent) { // Process event that was dequeued earier by puglWaitForEvent - [view->impl->app sendEvent: view->impl->nextEvent]; + [view->world->impl->app sendEvent: view->impl->nextEvent]; view->impl->nextEvent = NULL; } @@ -830,7 +844,7 @@ puglProcessEvents(PuglView* view) untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]);) { - [view->impl->app sendEvent: ev]; + [view->world->impl->app sendEvent: ev]; } return PUGL_SUCCESS; diff --git a/pugl/detail/types.h b/pugl/detail/types.h index b538091..fdfb0f6 100644 --- a/pugl/detail/types.h +++ b/pugl/detail/types.h @@ -24,6 +24,7 @@ #include "pugl/pugl.h" #include <stdbool.h> +#include <stddef.h> #include <stdint.h> // Unused parameter macro to suppresses warnings and make it impossible to use @@ -35,7 +36,10 @@ # define PUGL_UNUSED(name) #endif -/** Platform-specific internals. */ +/** Platform-specific world internals. */ +typedef struct PuglWorldInternalsImpl PuglWorldInternals; + +/** Platform-specific view internals. */ typedef struct PuglInternalsImpl PuglInternals; /** View hints. */ @@ -43,6 +47,7 @@ typedef int PuglHints[PUGL_NUM_WINDOW_HINTS]; /** Cross-platform view definition. */ struct PuglViewImpl { + PuglWorld* world; const PuglBackend* backend; PuglInternals* impl; PuglHandle handle; @@ -63,6 +68,13 @@ struct PuglViewImpl { bool visible; }; +/** Cross-platform world definition. */ +struct PuglWorldImpl { + PuglWorldInternals* impl; + size_t numViews; + PuglView** views; +}; + /** Opaque surface used by graphics backend. */ typedef void PuglSurface; diff --git a/pugl/detail/win.c b/pugl/detail/win.c index a4597b5..804c883 100644 --- a/pugl/detail/win.c +++ b/pugl/detail/win.c @@ -88,10 +88,14 @@ puglRegisterWindowClass(const char* name) return RegisterClassEx(&wc); } -PuglInternals* -puglInitInternals(void) +PuglWorldInternals* +puglInitWorldInternals(void) { - PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); + PuglWorldInternals* impl = (PuglWorldInternals*)calloc( + 1, sizeof(PuglWorldInternals)); + if (!impl) { + return NULL; + } HMODULE user32 = LoadLibrary("user32.dll"); if (user32) { @@ -110,6 +114,12 @@ puglInitInternals(void) return impl; } +PuglInternals* +puglInitViewInternals(void) +{ + return (PuglInternals*)calloc(1, sizeof(PuglInternals)); +} + int puglCreateWindow(PuglView* view, const char* title) { @@ -171,19 +181,23 @@ puglHideWindow(PuglView* view) } void -puglDestroy(PuglView* view) +puglFreeViewInternals(PuglView* view) { if (view) { view->backend->destroy(view); ReleaseDC(view->impl->hwnd, view->impl->hdc); DestroyWindow(view->impl->hwnd); UnregisterClass(view->windowClass ? view->windowClass : DEFAULT_CLASSNAME, NULL); - free(view->windowClass); free(view->impl); - free(view); } } +void +puglFreeWorldInternals(PuglWorld* world) +{ + free(world->impl); +} + static PuglKey keySymToSpecial(WPARAM sym) { @@ -694,8 +708,8 @@ puglGetTime(PuglView* view) { LARGE_INTEGER count; QueryPerformanceCounter(&count); - const double now = (double)count.QuadPart / view->impl->timerFrequency; - return now - view->start_time; + return ((double)count.QuadPart / view->world->impl->timerFrequency - + view->start_time); } void diff --git a/pugl/detail/win.h b/pugl/detail/win.h index 88cb1a1..16d22c0 100644 --- a/pugl/detail/win.h +++ b/pugl/detail/win.h @@ -26,6 +26,10 @@ typedef PIXELFORMATDESCRIPTOR PuglWinPFD; +struct PuglWorldInternalsImpl { + double timerFrequency; +}; + struct PuglInternalsImpl { PuglWinPFD pfd; int pfId; @@ -33,7 +37,6 @@ struct PuglInternalsImpl { HDC hdc; PuglSurface* surface; DWORD refreshRate; - double timerFrequency; bool flashing; bool resizing; bool mouseTracked; diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c index cb9f0e2..1098f72 100644 --- a/pugl/detail/x11.c +++ b/pugl/detail/x11.c @@ -60,8 +60,24 @@ static const long eventMask = EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask); +PuglWorldInternals* +puglInitWorldInternals(void) +{ + Display* display = XOpenDisplay(NULL); + if (!display) { + return NULL; + } + + PuglWorldInternals* impl = (PuglWorldInternals*)calloc( + 1, sizeof(PuglWorldInternals)); + + impl->display = display; + + return impl; +} + PuglInternals* -puglInitInternals(void) +puglInitViewInternals(void) { return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } @@ -70,7 +86,7 @@ int puglCreateWindow(PuglView* view, const char* title) { PuglInternals* const impl = view->impl; - Display* const display = XOpenDisplay(0); + Display* const display = view->world->impl->display; impl->display = display; impl->screen = DefaultScreen(display); @@ -183,7 +199,7 @@ puglHideWindow(PuglView* view) } void -puglDestroy(PuglView* view) +puglFreeViewInternals(PuglView* view) { if (view) { if (view->impl->xic) { @@ -194,14 +210,18 @@ puglDestroy(PuglView* view) } view->backend->destroy(view); XDestroyWindow(view->impl->display, view->impl->win); - XCloseDisplay(view->impl->display); XFree(view->impl->vi); - free(view->windowClass); free(view->impl); - free(view); } } +void +puglFreeWorldInternals(PuglWorld* world) +{ + XCloseDisplay(world->impl->display); + free(world->impl); +} + static PuglKey keySymToSpecial(KeySym sym) { diff --git a/pugl/detail/x11.h b/pugl/detail/x11.h index 1ead119..6671a95 100644 --- a/pugl/detail/x11.h +++ b/pugl/detail/x11.h @@ -23,6 +23,10 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> +struct PuglWorldInternalsImpl { + Display* display; +}; + struct PuglInternalsImpl { Display* display; int screen; |