aboutsummaryrefslogtreecommitdiffstats
path: root/pugl/detail
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2019-07-22 16:30:53 +0200
committerDavid Robillard <d@drobilla.net>2019-09-03 08:32:16 +0200
commite83c2b421d140244a6b9edb051b3e0d4aacda332 (patch)
tree398e49f43c96f4602496874fa7b3680236138720 /pugl/detail
parent5081d49f9f08596c07a8ed32430a4fa3e1baf352 (diff)
downloadpugl-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.c70
-rw-r--r--pugl/detail/implementation.h13
-rw-r--r--pugl/detail/mac.h5
-rw-r--r--pugl/detail/mac.m38
-rw-r--r--pugl/detail/types.h14
-rw-r--r--pugl/detail/win.c30
-rw-r--r--pugl/detail/win.h5
-rw-r--r--pugl/detail/x11.c32
-rw-r--r--pugl/detail/x11.h4
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;