aboutsummaryrefslogtreecommitdiffstats
path: root/pugl
diff options
context:
space:
mode:
Diffstat (limited to 'pugl')
-rw-r--r--pugl/detail/implementation.c493
-rw-r--r--pugl/detail/implementation.h77
-rw-r--r--pugl/detail/mac.h55
-rw-r--r--pugl/detail/mac.m1459
-rw-r--r--pugl/detail/mac_cairo.m164
-rw-r--r--pugl/detail/mac_gl.m201
-rw-r--r--pugl/detail/mac_stub.m96
-rw-r--r--pugl/detail/stub.h75
-rw-r--r--pugl/detail/types.h118
-rw-r--r--pugl/detail/win.c1152
-rw-r--r--pugl/detail/win.h147
-rw-r--r--pugl/detail/win_cairo.c178
-rw-r--r--pugl/detail/win_gl.c325
-rw-r--r--pugl/detail/win_stub.c80
-rw-r--r--pugl/detail/x11.c1348
-rw-r--r--pugl/detail/x11.h76
-rw-r--r--pugl/detail/x11_cairo.c170
-rw-r--r--pugl/detail/x11_gl.c238
-rw-r--r--pugl/detail/x11_stub.c54
-rw-r--r--pugl/gl.h36
-rw-r--r--pugl/glu.h36
-rw-r--r--pugl/pugl.h1624
-rw-r--r--pugl/pugl.hpp726
-rw-r--r--pugl/pugl.ipp154
-rw-r--r--pugl/pugl_cairo.h50
-rw-r--r--pugl/pugl_cairo.hpp50
-rw-r--r--pugl/pugl_gl.h61
-rw-r--r--pugl/pugl_gl.hpp60
-rw-r--r--pugl/pugl_stub.h60
-rw-r--r--pugl/pugl_stub.hpp50
30 files changed, 0 insertions, 9413 deletions
diff --git a/pugl/detail/implementation.c b/pugl/detail/implementation.c
deleted file mode 100644
index 6a5f932..0000000
--- a/pugl/detail/implementation.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file implementation.c
- @brief Platform-independent implementation.
-*/
-
-#include "pugl/detail/implementation.h"
-#include "pugl/pugl.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static const char*
-puglLogLevelPrefix(const PuglLogLevel level)
-{
- switch (level) {
- case PUGL_LOG_LEVEL_ERR:
- return "error: ";
- case PUGL_LOG_LEVEL_WARNING:
- return "warning: ";
- case PUGL_LOG_LEVEL_INFO:
- case PUGL_LOG_LEVEL_DEBUG:
- return "";
- }
-
- return "";
-}
-
-static void
-puglDefaultLogFunc(PuglWorld* PUGL_UNUSED(world),
- PuglLogLevel level,
- const char* msg)
-{
- fprintf(stderr, "%s%s", puglLogLevelPrefix(level), msg);
-}
-
-const char*
-puglStrerror(const PuglStatus status)
-{
- // clang-format off
- switch (status) {
- case PUGL_SUCCESS: return "Success";
- case PUGL_FAILURE: return "Non-fatal failure";
- case PUGL_UNKNOWN_ERROR: return "Unknown system error";
- case PUGL_BAD_BACKEND: return "Invalid or missing backend";
- case PUGL_BAD_CONFIGURATION: return "Invalid view configuration";
- case PUGL_BAD_PARAMETER: return "Invalid parameter";
- case PUGL_BACKEND_FAILED: return "Backend initialisation failed";
- case PUGL_REGISTRATION_FAILED: return "Class registration failed";
- case PUGL_REALIZE_FAILED: return "View creation failed";
- case PUGL_SET_FORMAT_FAILED: return "Failed to set pixel format";
- case PUGL_CREATE_CONTEXT_FAILED: return "Failed to create drawing context";
- case PUGL_UNSUPPORTED_TYPE: return "Unsupported data type";
- }
- // clang-format on
-
- return "Unknown error";
-}
-
-void
-puglSetString(char** dest, const char* string)
-{
- if (*dest != string) {
- const size_t len = strlen(string);
-
- *dest = (char*)realloc(*dest, len + 1);
- strncpy(*dest, string, len + 1);
- }
-}
-
-void
-puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len)
-{
- if (data) {
- dest->len = len;
- dest->data = realloc(dest->data, len + 1);
- memcpy(dest->data, data, len);
- ((char*)dest->data)[len] = 0;
- } else {
- dest->len = 0;
- dest->data = NULL;
- }
-}
-
-static void
-puglSetDefaultHints(PuglHints hints)
-{
- hints[PUGL_USE_COMPAT_PROFILE] = PUGL_TRUE;
- hints[PUGL_CONTEXT_VERSION_MAJOR] = 2;
- hints[PUGL_CONTEXT_VERSION_MINOR] = 0;
- hints[PUGL_RED_BITS] = 8;
- hints[PUGL_GREEN_BITS] = 8;
- hints[PUGL_BLUE_BITS] = 8;
- hints[PUGL_ALPHA_BITS] = 8;
- hints[PUGL_DEPTH_BITS] = 0;
- hints[PUGL_STENCIL_BITS] = 0;
- hints[PUGL_SAMPLES] = 0;
- hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE;
- hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE;
- hints[PUGL_RESIZABLE] = PUGL_FALSE;
- hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE;
- hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE;
-}
-
-PuglWorld*
-puglNewWorld(PuglWorldType type, PuglWorldFlags flags)
-{
- PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld));
- if (!world || !(world->impl = puglInitWorldInternals(type, flags))) {
- free(world);
- return NULL;
- }
-
- world->startTime = puglGetTime(world);
- world->logFunc = puglDefaultLogFunc;
- world->logLevel = PUGL_LOG_LEVEL_INFO;
-
- puglSetString(&world->className, "Pugl");
-
- return world;
-}
-
-void
-puglFreeWorld(PuglWorld* const world)
-{
- puglFreeWorldInternals(world);
- free(world->className);
- free(world->views);
- free(world);
-}
-
-void
-puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle)
-{
- world->handle = handle;
-}
-
-PuglWorldHandle
-puglGetWorldHandle(PuglWorld* world)
-{
- return world->handle;
-}
-
-PuglStatus
-puglSetLogFunc(PuglWorld* world, PuglLogFunc logFunc)
-{
- world->logFunc = logFunc;
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetLogLevel(PuglWorld* world, PuglLogLevel level)
-{
- world->logLevel = level;
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetClassName(PuglWorld* const world, const char* const name)
-{
- puglSetString(&world->className, name);
- return PUGL_SUCCESS;
-}
-
-PuglView*
-puglNewView(PuglWorld* const world)
-{
- PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
- if (!view || !(view->impl = puglInitViewInternals())) {
- free(view);
- return NULL;
- }
-
- view->world = world;
- view->minWidth = 1;
- view->minHeight = 1;
-
- 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)
-{
- puglDispatchSimpleEvent(view, PUGL_DESTROY);
-
- // 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;
- }
- }
-
- free(view->title);
- free(view->clipboard.data);
- puglFreeViewInternals(view);
- free(view);
-}
-
-PuglWorld*
-puglGetWorld(PuglView* view)
-{
- return view->world;
-}
-
-PuglStatus
-puglSetViewHint(PuglView* view, PuglViewHint hint, int value)
-{
- if (value == PUGL_DONT_CARE) {
- switch (hint) {
- case PUGL_USE_COMPAT_PROFILE:
- case PUGL_USE_DEBUG_CONTEXT:
- case PUGL_CONTEXT_VERSION_MAJOR:
- case PUGL_CONTEXT_VERSION_MINOR:
- case PUGL_SWAP_INTERVAL:
- return PUGL_BAD_PARAMETER;
- default:
- break;
- }
- }
-
- if (hint < PUGL_NUM_VIEW_HINTS) {
- view->hints[hint] = value;
- return PUGL_SUCCESS;
- }
-
- return PUGL_BAD_PARAMETER;
-}
-
-int
-puglGetViewHint(const PuglView* view, PuglViewHint hint)
-{
- if (hint < PUGL_NUM_VIEW_HINTS) {
- return view->hints[hint];
- }
-
- return PUGL_DONT_CARE;
-}
-
-PuglStatus
-puglSetParentWindow(PuglView* view, PuglNativeView parent)
-{
- view->parent = parent;
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetBackend(PuglView* view, const PuglBackend* backend)
-{
- view->backend = backend;
- return PUGL_SUCCESS;
-}
-
-void
-puglSetHandle(PuglView* view, PuglHandle handle)
-{
- view->handle = handle;
-}
-
-PuglHandle
-puglGetHandle(PuglView* view)
-{
- return view->handle;
-}
-
-bool
-puglGetVisible(const PuglView* view)
-{
- return view->visible;
-}
-
-PuglRect
-puglGetFrame(const PuglView* view)
-{
- return view->frame;
-}
-
-void*
-puglGetContext(PuglView* view)
-{
- return view->backend->getContext(view);
-}
-
-#ifndef PUGL_DISABLE_DEPRECATED
-
-PuglStatus
-puglPollEvents(PuglWorld* world, double timeout)
-{
- return puglUpdate(world, timeout);
-}
-
-PuglStatus
-puglDispatchEvents(PuglWorld* world)
-{
- return puglUpdate(world, 0.0);
-}
-
-PuglStatus
-puglEnterContext(PuglView* view, bool drawing)
-{
- const PuglEventExpose expose = {
- PUGL_EXPOSE, 0, 0.0, 0.0, view->frame.width, view->frame.height};
-
- view->backend->enter(view, drawing ? &expose : NULL);
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglLeaveContext(PuglView* view, bool drawing)
-{
- const PuglEventExpose expose = {
- PUGL_EXPOSE, 0, 0.0, 0.0, view->frame.width, view->frame.height};
-
- view->backend->leave(view, drawing ? &expose : NULL);
-
- return PUGL_SUCCESS;
-}
-
-#endif
-
-PuglStatus
-puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc)
-{
- view->eventFunc = eventFunc;
- return PUGL_SUCCESS;
-}
-
-/// Return the code point for buf, or the replacement character on error
-uint32_t
-puglDecodeUTF8(const uint8_t* buf)
-{
-#define FAIL_IF(cond) do { if (cond) return 0xFFFD; } while (0)
-
- // http://en.wikipedia.org/wiki/UTF-8
-
- if (buf[0] < 0x80) {
- return buf[0];
- } else if (buf[0] < 0xC2) {
- return 0xFFFD;
- } else if (buf[0] < 0xE0) {
- FAIL_IF((buf[1] & 0xC0u) != 0x80);
- return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u;
- } else if (buf[0] < 0xF0) {
- FAIL_IF((buf[1] & 0xC0u) != 0x80);
- FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0);
- FAIL_IF((buf[2] & 0xC0u) != 0x80);
- return ((uint32_t)buf[0] << 12u) + //
- ((uint32_t)buf[1] << 6u) + //
- ((uint32_t)buf[2] - 0xE2080u);
- } else if (buf[0] < 0xF5) {
- FAIL_IF((buf[1] & 0xC0u) != 0x80);
- FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90);
- FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90);
- FAIL_IF((buf[2] & 0xC0u) != 0x80u);
- FAIL_IF((buf[3] & 0xC0u) != 0x80u);
- return (((uint32_t)buf[0] << 18u) + //
- ((uint32_t)buf[1] << 12u) + //
- ((uint32_t)buf[2] << 6u) + //
- ((uint32_t)buf[3] - 0x3C82080u));
- }
- return 0xFFFD;
-}
-
-static inline bool
-puglMustConfigure(PuglView* view, const PuglEventConfigure* configure)
-{
- return memcmp(configure, &view->lastConfigure, sizeof(PuglEventConfigure));
-}
-
-void
-puglDispatchSimpleEvent(PuglView* view, const PuglEventType type)
-{
- assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP ||
- type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE);
-
- const PuglEvent event = {{type, 0}};
- puglDispatchEvent(view, &event);
-}
-
-void
-puglDispatchEventInContext(PuglView* view, const PuglEvent* event)
-{
- if (event->type == PUGL_CONFIGURE) {
- view->frame.x = event->configure.x;
- view->frame.y = event->configure.y;
- view->frame.width = event->configure.width;
- view->frame.height = event->configure.height;
-
- if (puglMustConfigure(view, &event->configure)) {
- view->eventFunc(view, event);
- view->lastConfigure = event->configure;
- }
- } else {
- view->eventFunc(view, event);
- }
-}
-
-void
-puglDispatchEvent(PuglView* view, const PuglEvent* event)
-{
- switch (event->type) {
- case PUGL_NOTHING:
- break;
- case PUGL_CREATE:
- case PUGL_DESTROY:
- view->backend->enter(view, NULL);
- view->eventFunc(view, event);
- view->backend->leave(view, NULL);
- break;
- case PUGL_CONFIGURE:
- if (puglMustConfigure(view, &event->configure)) {
- view->backend->enter(view, NULL);
- puglDispatchEventInContext(view, event);
- view->backend->leave(view, NULL);
- }
- break;
- case PUGL_EXPOSE:
- view->backend->enter(view, &event->expose);
- view->eventFunc(view, event);
- view->backend->leave(view, &event->expose);
- break;
- default:
- view->eventFunc(view, event);
- }
-}
-
-const void*
-puglGetInternalClipboard(const PuglView* const view,
- const char** const type,
- size_t* const len)
-{
- if (len) {
- *len = view->clipboard.len;
- }
-
- if (type) {
- *type = "text/plain";
- }
-
- return view->clipboard.data;
-}
-
-PuglStatus
-puglSetInternalClipboard(PuglView* const view,
- const char* const type,
- const void* const data,
- const size_t len)
-{
- if (type && strcmp(type, "text/plain")) {
- return PUGL_UNSUPPORTED_TYPE;
- }
-
- puglSetBlob(&view->clipboard, data, len);
- return PUGL_SUCCESS;
-}
-
diff --git a/pugl/detail/implementation.h b/pugl/detail/implementation.h
deleted file mode 100644
index ff97fef..0000000
--- a/pugl/detail/implementation.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file implementation.h
- @brief Shared declarations for implementation.
-*/
-
-#ifndef PUGL_DETAIL_IMPLEMENTATION_H
-#define PUGL_DETAIL_IMPLEMENTATION_H
-
-#include "pugl/detail/types.h"
-#include "pugl/pugl.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-PUGL_BEGIN_DECLS
-
-/// Set `blob` to `data` with length `len`, reallocating if necessary
-void puglSetBlob(PuglBlob* dest, const void* data, size_t len);
-
-/// Reallocate and set `*dest` to `string`
-void puglSetString(char** dest, const char* string);
-
-/// Allocate and initialise world internals (implemented once per platform)
-PuglWorldInternals*
-puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags);
-
-/// 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);
-
-/// Dispatch an event with a simple `type` to `view`
-void puglDispatchSimpleEvent(PuglView* view, PuglEventType type);
-
-/// Dispatch `event` to `view` while already in the graphics context
-void puglDispatchEventInContext(PuglView* view, const PuglEvent* event);
-
-/// Dispatch `event` to `view`, entering graphics context if necessary
-void puglDispatchEvent(PuglView* view, const PuglEvent* event);
-
-/// Set internal (stored in view) clipboard contents
-const void*
-puglGetInternalClipboard(const PuglView* view, const char** type, size_t* len);
-
-/// Set internal (stored in view) clipboard contents
-PuglStatus
-puglSetInternalClipboard(PuglView* view,
- const char* type,
- const void* data,
- size_t len);
-
-PUGL_END_DECLS
-
-#endif // PUGL_DETAIL_IMPLEMENTATION_H
diff --git a/pugl/detail/mac.h b/pugl/detail/mac.h
deleted file mode 100644
index 7b64cfe..0000000
--- a/pugl/detail/mac.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- Copyright 2012-2020 David Robillard <d@drobilla.net>
- Copyright 2017 Hanspeter Portner <dev@open-music-kontrollers.ch>
-
- 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.
-*/
-
-/**
- @file mac.h
- @brief Shared definitions for MacOS implementation.
-*/
-
-#include "pugl/pugl.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include <stdint.h>
-
-@interface PuglWrapperView : NSView<NSTextInputClient>
-
-- (void) dispatchExpose:(NSRect)rect;
-- (void) setReshaped;
-
-@end
-
-@interface PuglWindow : NSWindow
-
-- (void) setPuglview:(PuglView*)view;
-
-@end
-
-struct PuglWorldInternalsImpl {
- NSApplication* app;
- NSAutoreleasePool* autoreleasePool;
-};
-
-struct PuglInternalsImpl {
- NSApplication* app;
- PuglWrapperView* wrapperView;
- NSView* drawView;
- NSCursor* cursor;
- PuglWindow* window;
- uint32_t mods;
- bool mouseTracked;
-};
diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m
deleted file mode 100644
index 354546a..0000000
--- a/pugl/detail/mac.m
+++ /dev/null
@@ -1,1459 +0,0 @@
-/*
- Copyright 2012-2020 David Robillard <d@drobilla.net>
- Copyright 2017 Hanspeter Portner <dev@open-music-kontrollers.ch>
-
- 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.
-*/
-
-/**
- @file mac.m
- @brief MacOS implementation.
-*/
-
-#define GL_SILENCE_DEPRECATION 1
-
-#include "pugl/detail/implementation.h"
-#include "pugl/detail/mac.h"
-#include "pugl/pugl.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include <mach/mach_time.h>
-
-#include <stdlib.h>
-
-#ifndef __MAC_10_10
-typedef NSUInteger NSEventModifierFlags;
-#endif
-
-#ifndef __MAC_10_12
-typedef NSUInteger NSWindowStyleMask;
-#endif
-
-static NSRect
-rectToScreen(NSScreen* screen, NSRect rect)
-{
- const double screenHeight = [screen frame].size.height;
-
- rect.origin.y = screenHeight - rect.origin.y - rect.size.height;
- return rect;
-}
-
-static NSScreen*
-viewScreen(PuglView* view)
-{
- return view->impl->window ? [view->impl->window screen] : [NSScreen mainScreen];
-}
-
-static NSRect
-nsRectToPoints(PuglView* view, const NSRect rect)
-{
- const double scaleFactor = [viewScreen(view) backingScaleFactor];
-
- return NSMakeRect(rect.origin.x / scaleFactor,
- rect.origin.y / scaleFactor,
- rect.size.width / scaleFactor,
- rect.size.height / scaleFactor);
-}
-
-static NSRect
-nsRectFromPoints(PuglView* view, const NSRect rect)
-{
- const double scaleFactor = [viewScreen(view) backingScaleFactor];
-
- return NSMakeRect(rect.origin.x * scaleFactor,
- rect.origin.y * scaleFactor,
- rect.size.width * scaleFactor,
- rect.size.height * scaleFactor);
-}
-
-static NSPoint
-nsPointFromPoints(PuglView* view, const NSPoint point)
-{
- const double scaleFactor = [viewScreen(view) backingScaleFactor];
-
- return NSMakePoint(point.x * scaleFactor, point.y * scaleFactor);
-}
-
-static NSRect
-rectToNsRect(const PuglRect rect)
-{
- return NSMakeRect(rect.x, rect.y, rect.width, rect.height);
-}
-
-static NSSize
-sizePoints(PuglView* view, const double width, const double height)
-{
- const double scaleFactor = [viewScreen(view) backingScaleFactor];
-
- return NSMakeSize(width / scaleFactor, height / scaleFactor);
-}
-
-static void
-updateViewRect(PuglView* view)
-{
- NSWindow* const window = view->impl->window;
- if (window) {
- const NSRect screenFramePt = [[NSScreen mainScreen] frame];
- const NSRect screenFramePx = nsRectFromPoints(view, screenFramePt);
- const NSRect framePt = [window frame];
- const NSRect contentPt = [window contentRectForFrameRect:framePt];
- const NSRect contentPx = nsRectFromPoints(view, contentPt);
- const double screenHeight = screenFramePx.size.height;
-
- view->frame.x = contentPx.origin.x;
- view->frame.y = screenHeight - contentPx.origin.y - contentPx.size.height;
- view->frame.width = contentPx.size.width;
- view->frame.height = contentPx.size.height;
- }
-}
-
-@implementation PuglWindow
-{
-@public
- PuglView* puglview;
-}
-
-- (id) initWithContentRect:(NSRect)contentRect
- styleMask:(NSWindowStyleMask)aStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)flag
-{
- (void)flag;
-
- NSWindow* result = [super initWithContentRect:contentRect
- styleMask:aStyle
- backing:bufferingType
- defer:NO];
-
- [result setAcceptsMouseMovedEvents:YES];
- return (PuglWindow*)result;
-}
-
-- (void)setPuglview:(PuglView*)view
-{
- puglview = view;
-
- [self
- setContentSize:sizePoints(view, view->frame.width, view->frame.height)];
-}
-
-- (BOOL) canBecomeKeyWindow
-{
- return YES;
-}
-
-- (BOOL) canBecomeMainWindow
-{
- return YES;
-}
-
-- (void) setIsVisible:(BOOL)flag
-{
- if (flag && !puglview->visible) {
- const PuglEventConfigure ev = {
- PUGL_CONFIGURE,
- 0,
- puglview->frame.x,
- puglview->frame.y,
- puglview->frame.width,
- puglview->frame.height,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
- puglDispatchSimpleEvent(puglview, PUGL_MAP);
- } else if (!flag && puglview->visible) {
- puglDispatchSimpleEvent(puglview, PUGL_UNMAP);
- }
-
- puglview->visible = flag;
-
- [super setIsVisible:flag];
-}
-
-@end
-
-@implementation PuglWrapperView
-{
-@public
- PuglView* puglview;
- NSTrackingArea* trackingArea;
- NSMutableAttributedString* markedText;
- NSTimer* timer;
- NSMutableDictionary* userTimers;
- bool reshaped;
-}
-
-- (void) dispatchExpose:(NSRect)rect
-{
- const double scaleFactor = [[NSScreen mainScreen] backingScaleFactor];
-
- if (reshaped) {
- updateViewRect(puglview);
-
- const PuglEventConfigure ev = {
- PUGL_CONFIGURE,
- 0,
- puglview->frame.x,
- puglview->frame.y,
- puglview->frame.width,
- puglview->frame.height,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
- reshaped = false;
- }
-
- if (![[puglview->impl->drawView window] isVisible]) {
- return;
- }
-
- const PuglEventExpose ev = {
- PUGL_EXPOSE,
- 0,
- rect.origin.x * scaleFactor,
- rect.origin.y * scaleFactor,
- rect.size.width * scaleFactor,
- rect.size.height * scaleFactor,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-}
-
-- (NSSize) intrinsicContentSize
-{
- if (puglview->defaultWidth || puglview->defaultHeight) {
- return sizePoints(puglview,
- puglview->defaultWidth,
- puglview->defaultHeight);
- }
-
- return NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric);
-}
-
-- (BOOL) isFlipped
-{
- return YES;
-}
-
-- (BOOL) acceptsFirstResponder
-{
- return YES;
-}
-
-- (void) setReshaped
-{
- reshaped = true;
-}
-
-static uint32_t
-getModifiers(const NSEvent* const ev)
-{
- const NSEventModifierFlags modifierFlags = [ev modifierFlags];
-
- return (((modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0) |
- ((modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0) |
- ((modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0) |
- ((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0));
-}
-
-static PuglKey
-keySymToSpecial(const NSEvent* const ev)
-{
- NSString* chars = [ev charactersIgnoringModifiers];
- if ([chars length] == 1) {
- switch ([chars characterAtIndex:0]) {
- case NSF1FunctionKey: return PUGL_KEY_F1;
- case NSF2FunctionKey: return PUGL_KEY_F2;
- case NSF3FunctionKey: return PUGL_KEY_F3;
- case NSF4FunctionKey: return PUGL_KEY_F4;
- case NSF5FunctionKey: return PUGL_KEY_F5;
- case NSF6FunctionKey: return PUGL_KEY_F6;
- case NSF7FunctionKey: return PUGL_KEY_F7;
- case NSF8FunctionKey: return PUGL_KEY_F8;
- case NSF9FunctionKey: return PUGL_KEY_F9;
- case NSF10FunctionKey: return PUGL_KEY_F10;
- case NSF11FunctionKey: return PUGL_KEY_F11;
- case NSF12FunctionKey: return PUGL_KEY_F12;
- case NSDeleteCharacter: return PUGL_KEY_BACKSPACE;
- case NSDeleteFunctionKey: return PUGL_KEY_DELETE;
- case NSLeftArrowFunctionKey: return PUGL_KEY_LEFT;
- case NSUpArrowFunctionKey: return PUGL_KEY_UP;
- case NSRightArrowFunctionKey: return PUGL_KEY_RIGHT;
- case NSDownArrowFunctionKey: return PUGL_KEY_DOWN;
- case NSPageUpFunctionKey: return PUGL_KEY_PAGE_UP;
- case NSPageDownFunctionKey: return PUGL_KEY_PAGE_DOWN;
- case NSHomeFunctionKey: return PUGL_KEY_HOME;
- case NSEndFunctionKey: return PUGL_KEY_END;
- case NSInsertFunctionKey: return PUGL_KEY_INSERT;
- case NSMenuFunctionKey: return PUGL_KEY_MENU;
- case NSScrollLockFunctionKey: return PUGL_KEY_SCROLL_LOCK;
- case NSClearLineFunctionKey: return PUGL_KEY_NUM_LOCK;
- case NSPrintScreenFunctionKey: return PUGL_KEY_PRINT_SCREEN;
- case NSPauseFunctionKey: return PUGL_KEY_PAUSE;
- }
- // SHIFT, CTRL, ALT, and SUPER are handled in [flagsChanged]
- }
- return (PuglKey)0;
-}
-
-- (void) updateTrackingAreas
-{
- if (trackingArea != nil) {
- [self removeTrackingArea:trackingArea];
- [trackingArea release];
- }
-
- const int opts = (NSTrackingMouseEnteredAndExited |
- NSTrackingMouseMoved |
- NSTrackingActiveAlways);
- trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
- options:opts
- owner:self
- userInfo:nil];
- [self addTrackingArea:trackingArea];
- [super updateTrackingAreas];
-}
-
-- (NSPoint) eventLocation:(NSEvent*)event
-{
- return nsPointFromPoints(puglview,
- [self convertPoint:[event locationInWindow]
- fromView:nil]);
-}
-
-static void
-handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
-{
- const NSPoint wloc = [view eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglEventCrossing ev = {
- type,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(event),
- PUGL_CROSSING_NORMAL,
- };
-
- puglDispatchEvent(view->puglview, (const PuglEvent*)&ev);
-}
-
-- (void) mouseEntered:(NSEvent*)event
-{
- handleCrossing(self, event, PUGL_POINTER_IN);
- [puglview->impl->cursor set];
- puglview->impl->mouseTracked = true;
-}
-
-- (void) mouseExited:(NSEvent*)event
-{
- [[NSCursor arrowCursor] set];
- handleCrossing(self, event, PUGL_POINTER_OUT);
- puglview->impl->mouseTracked = false;
-}
-
-- (void) cursorUpdate:(NSEvent*)event
-{
- (void)event;
- [puglview->impl->cursor set];
-}
-
-- (void) mouseMoved:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglEventMotion ev = {
- PUGL_MOTION,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(event),
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-}
-
-- (void) mouseDragged:(NSEvent*)event
-{
- [self mouseMoved: event];
-}
-
-- (void) rightMouseDragged:(NSEvent*)event
-{
- [self mouseMoved: event];
-}
-
-- (void) otherMouseDragged:(NSEvent*)event
-{
- [self mouseMoved: event];
-}
-
-- (void) mouseDown:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglEventButton ev = {
- PUGL_BUTTON_PRESS,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(event),
- (uint32_t)[event buttonNumber] + 1,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-}
-
-- (void) mouseUp:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglEventButton ev = {
- PUGL_BUTTON_RELEASE,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(event),
- (uint32_t)[event buttonNumber] + 1,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-}
-
-- (void) rightMouseDown:(NSEvent*)event
-{
- [self mouseDown: event];
-}
-
-- (void) rightMouseUp:(NSEvent*)event
-{
- [self mouseUp: event];
-}
-
-- (void) otherMouseDown:(NSEvent*)event
-{
- [self mouseDown: event];
-}
-
-- (void) otherMouseUp:(NSEvent*)event
-{
- [self mouseUp: event];
-}
-
-- (void) scrollWheel:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const double dx = [event scrollingDeltaX];
- const double dy = [event scrollingDeltaY];
- const PuglScrollDirection dir =
- ((dx == 0.0 && dy > 0.0)
- ? PUGL_SCROLL_UP
- : ((dx == 0.0 && dy < 0.0)
- ? PUGL_SCROLL_DOWN
- : ((dy == 0.0 && dx > 0.0)
- ? PUGL_SCROLL_RIGHT
- : ((dy == 0.0 && dx < 0.0) ? PUGL_SCROLL_LEFT
- : PUGL_SCROLL_SMOOTH))));
-
- const PuglEventScroll ev = {
- PUGL_SCROLL,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(event),
- [event hasPreciseScrollingDeltas] ? PUGL_SCROLL_SMOOTH : dir,
- dx,
- dy,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-}
-
-- (void) keyDown:(NSEvent*)event
-{
- if (puglview->hints[PUGL_IGNORE_KEY_REPEAT] && [event isARepeat]) {
- return;
- }
-
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglKey spec = keySymToSpecial(event);
- const NSString* chars = [event charactersIgnoringModifiers];
- const char* str = [[chars lowercaseString] UTF8String];
- const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str));
-
- const PuglEventKey ev = {
- PUGL_KEY_PRESS,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(event),
- [event keyCode],
- (code != 0xFFFD) ? code : 0,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-
- if (!spec) {
- [self interpretKeyEvents:@[event]];
- }
-}
-
-- (void)keyUp:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglKey spec = keySymToSpecial(event);
- const NSString* chars = [event charactersIgnoringModifiers];
- const char* str = [[chars lowercaseString] UTF8String];
- const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str));
-
- const PuglEventKey ev = {
- PUGL_KEY_RELEASE,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(event),
- [event keyCode],
- (code != 0xFFFD) ? code : 0,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-}
-
-- (BOOL) hasMarkedText
-{
- return [markedText length] > 0;
-}
-
-- (NSRange) markedRange
-{
- return (([markedText length] > 0)
- ? NSMakeRange(0, [markedText length] - 1)
- : NSMakeRange(NSNotFound, 0));
-}
-
-- (NSRange) selectedRange
-{
- return NSMakeRange(NSNotFound, 0);
-}
-
-- (void)setMarkedText:(id)string
- selectedRange:(NSRange)selected
- replacementRange:(NSRange)replacement
-{
- (void)selected;
- (void)replacement;
- [markedText release];
- markedText = (
- [(NSObject*)string isKindOfClass:[NSAttributedString class]]
- ? [[NSMutableAttributedString alloc] initWithAttributedString:string]
- : [[NSMutableAttributedString alloc] initWithString:string]);
-}
-
-- (void) unmarkText
-{
- [[markedText mutableString] setString:@""];
-}
-
-- (NSArray*) validAttributesForMarkedText
-{
- return @[];
-}
-
-- (NSAttributedString*)
- attributedSubstringForProposedRange:(NSRange)range
- actualRange:(NSRangePointer)actual
-{
- (void)range;
- (void)actual;
- return nil;
-}
-
-- (NSUInteger) characterIndexForPoint:(NSPoint)point
-{
- (void)point;
- return 0;
-}
-
-- (NSRect) firstRectForCharacterRange:(NSRange)range
- actualRange:(NSRangePointer)actual
-{
- (void)range;
- (void)actual;
-
- const NSRect frame = [self bounds];
- return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0);
-}
-
-- (void) doCommandBySelector:(SEL)selector
-{
- (void)selector;
-}
-
-- (void) insertText:(id)string
- replacementRange:(NSRange)replacement
-{
- (void)replacement;
-
- NSEvent* const event = [NSApp currentEvent];
- NSString* const characters =
- ([(NSObject*)string isKindOfClass:[NSAttributedString class]]
- ? [(NSAttributedString*)string string]
- : (NSString*)string);
-
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- for (size_t i = 0; i < [characters length]; ++i) {
- const uint32_t code = [characters characterAtIndex:i];
- char utf8[8] = {0};
- NSUInteger len = 0;
-
- [characters getBytes:utf8
- maxLength:sizeof(utf8)
- usedLength:&len
- encoding:NSUTF8StringEncoding
- options:0
- range:NSMakeRange(i, i + 1)
- remainingRange:nil];
-
- PuglEventText ev = {
- PUGL_TEXT,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(event),
- [event keyCode],
- code,
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- };
-
- memcpy(ev.string, utf8, len);
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
- }
-}
-
-- (void) flagsChanged:(NSEvent*)event
-{
- const uint32_t mods = getModifiers(event);
- PuglEventType type = PUGL_NOTHING;
- PuglKey special = (PuglKey)0;
-
- if ((mods & PUGL_MOD_SHIFT) != (puglview->impl->mods & PUGL_MOD_SHIFT)) {
- type = mods & PUGL_MOD_SHIFT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- special = PUGL_KEY_SHIFT;
- } else if ((mods & PUGL_MOD_CTRL) != (puglview->impl->mods & PUGL_MOD_CTRL)) {
- type = mods & PUGL_MOD_CTRL ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- special = PUGL_KEY_CTRL;
- } else if ((mods & PUGL_MOD_ALT) != (puglview->impl->mods & PUGL_MOD_ALT)) {
- type = mods & PUGL_MOD_ALT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- special = PUGL_KEY_ALT;
- } else if ((mods & PUGL_MOD_SUPER) != (puglview->impl->mods & PUGL_MOD_SUPER)) {
- type = mods & PUGL_MOD_SUPER ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- special = PUGL_KEY_SUPER;
- }
-
- if (special != 0) {
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- PuglEventKey ev = {
- type,
- 0,
- [event timestamp],
- wloc.x,
- wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- mods,
- [event keyCode],
- special
- };
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
- }
-
- puglview->impl->mods = mods;
-}
-
-- (BOOL) preservesContentInLiveResize
-{
- return NO;
-}
-
-- (void) viewWillStartLiveResize
-{
- timer = [NSTimer timerWithTimeInterval:(1 / 60.0)
- target:self
- selector:@selector(resizeTick)
- userInfo:nil
- repeats:YES];
- [[NSRunLoop currentRunLoop] addTimer:timer
- forMode:NSRunLoopCommonModes];
-
- [super viewWillStartLiveResize];
-}
-
-- (void) viewWillDraw
-{
- puglDispatchSimpleEvent(puglview, PUGL_UPDATE);
- [super viewWillDraw];
-}
-
-- (void) resizeTick
-{
- puglPostRedisplay(puglview);
-}
-
-- (void) timerTick:(NSTimer*)userTimer
-{
- const NSNumber* userInfo = userTimer.userInfo;
- const PuglEventTimer ev = {PUGL_TIMER, 0, userInfo.unsignedLongValue};
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-}
-
-- (void) viewDidEndLiveResize
-{
- [super viewDidEndLiveResize];
- [timer invalidate];
- timer = NULL;
-}
-
-@end
-
-@interface PuglWindowDelegate : NSObject<NSWindowDelegate>
-
-- (instancetype) initWithPuglWindow:(PuglWindow*)window;
-
-@end
-
-@implementation PuglWindowDelegate
-{
- PuglWindow* window;
-}
-
-- (instancetype) initWithPuglWindow:(PuglWindow*)puglWindow
-{
- if ((self = [super init])) {
- window = puglWindow;
- }
-
- return self;
-}
-
-- (BOOL) windowShouldClose:(id)sender
-{
- (void)sender;
-
- puglDispatchSimpleEvent(window->puglview, PUGL_CLOSE);
- return YES;
-}
-
-- (void) windowDidMove:(NSNotification*)notification
-{
- (void)notification;
-
- updateViewRect(window->puglview);
-}
-
-- (void) windowDidBecomeKey:(NSNotification*)notification
-{
- (void)notification;
-
- PuglEvent ev = {{PUGL_FOCUS_IN, 0}};
- ev.focus.mode = PUGL_CROSSING_NORMAL;
- puglDispatchEvent(window->puglview, &ev);
-}
-
-- (void) windowDidResignKey:(NSNotification*)notification
-{
- (void)notification;
-
- PuglEvent ev = {{PUGL_FOCUS_OUT, 0}};
- ev.focus.mode = PUGL_CROSSING_NORMAL;
- puglDispatchEvent(window->puglview, &ev);
-}
-
-@end
-
-PuglWorldInternals*
-puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags))
-{
- PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
- 1, sizeof(PuglWorldInternals));
-
- impl->app = [NSApplication sharedApplication];
-
- if (type == PUGL_PROGRAM) {
- impl->autoreleasePool = [NSAutoreleasePool new];
- }
-
- return impl;
-}
-
-void
-puglFreeWorldInternals(PuglWorld* world)
-{
- if (world->impl->autoreleasePool) {
- [world->impl->autoreleasePool drain];
- }
-
- free(world->impl);
-}
-
-void*
-puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world))
-{
- return NULL;
-}
-
-PuglInternals*
-puglInitViewInternals(void)
-{
- PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
-
- impl->cursor = [NSCursor arrowCursor];
-
- return impl;
-}
-
-static NSLayoutConstraint*
-puglConstraint(id item, NSLayoutAttribute attribute, float constant)
-{
- return [NSLayoutConstraint
- constraintWithItem: item
- attribute: attribute
- relatedBy: NSLayoutRelationGreaterThanOrEqual
- toItem: nil
- attribute: NSLayoutAttributeNotAnAttribute
- multiplier: 1.0
- constant: (CGFloat)constant];
-}
-
-PuglStatus
-puglRealize(PuglView* view)
-{
- PuglInternals* impl = view->impl;
- if (impl->wrapperView) {
- return PUGL_FAILURE;
- }
-
- const NSScreen* const screen = [NSScreen mainScreen];
- const double scaleFactor = [screen backingScaleFactor];
-
- // Getting depth from the display mode seems tedious, just set usual values
- if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_RED_BITS] = 8;
- }
- if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_BLUE_BITS] = 8;
- }
- if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_GREEN_BITS] = 8;
- }
- if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_ALPHA_BITS] = 8;
- }
-
- CGDirectDisplayID displayId = CGMainDisplayID();
- CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId);
-
- // Try to get refresh rate from mode (usually fails)
- view->hints[PUGL_REFRESH_RATE] = (int)CGDisplayModeGetRefreshRate(mode);
-
- CGDisplayModeRelease(mode);
- if (view->hints[PUGL_REFRESH_RATE] == 0) {
- // Get refresh rate from a display link
- // TODO: Keep and actually use the display link for something?
- CVDisplayLinkRef link;
- CVDisplayLinkCreateWithCGDisplay(displayId, &link);
-
- const CVTime p = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
- const double r = p.timeScale / (double)p.timeValue;
- view->hints[PUGL_REFRESH_RATE] = (int)lrint(r);
-
- CVDisplayLinkRelease(link);
- }
-
- if (view->frame.width == 0.0 && view->frame.height == 0.0) {
- if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) {
- return PUGL_BAD_CONFIGURATION;
- }
-
- const double screenWidthPx = [screen frame].size.width * scaleFactor;
- const double screenHeightPx = [screen frame].size.height * scaleFactor;
-
- view->frame.width = view->defaultWidth;
- view->frame.height = view->defaultHeight;
- view->frame.x = screenWidthPx / 2.0 - view->frame.width / 2.0;
- view->frame.y = screenHeightPx / 2.0 - view->frame.height / 2.0;
- }
-
- const NSRect framePx = rectToNsRect(view->frame);
- const NSRect framePt = NSMakeRect(framePx.origin.x / scaleFactor,
- framePx.origin.y / scaleFactor,
- framePx.size.width / scaleFactor,
- framePx.size.height / scaleFactor);
-
- // Create wrapper view to handle input
- impl->wrapperView = [PuglWrapperView alloc];
- impl->wrapperView->puglview = view;
- impl->wrapperView->userTimers = [[NSMutableDictionary alloc] init];
- impl->wrapperView->markedText = [[NSMutableAttributedString alloc] init];
- [impl->wrapperView setAutoresizesSubviews:YES];
- [impl->wrapperView initWithFrame:framePt];
- [impl->wrapperView addConstraint:
- puglConstraint(impl->wrapperView, NSLayoutAttributeWidth, view->minWidth)];
- [impl->wrapperView addConstraint:
- puglConstraint(impl->wrapperView, NSLayoutAttributeHeight, view->minHeight)];
-
- // Create draw view to be rendered to
- PuglStatus st = PUGL_SUCCESS;
- if ((st = view->backend->configure(view)) ||
- (st = view->backend->create(view))) {
- return st;
- }
-
- // Add draw view to wrapper view
- [impl->wrapperView addSubview:impl->drawView];
- [impl->wrapperView setHidden:NO];
- [impl->drawView setHidden:NO];
-
- if (view->parent) {
- NSView* pview = (NSView*)view->parent;
- [pview addSubview:impl->wrapperView];
- [impl->drawView setHidden:NO];
- [[impl->drawView window] makeFirstResponder:impl->wrapperView];
- } else {
- unsigned style = (NSClosableWindowMask |
- NSTitledWindowMask |
- NSMiniaturizableWindowMask );
- if (view->hints[PUGL_RESIZABLE]) {
- style |= NSResizableWindowMask;
- }
-
- PuglWindow* window = [[[PuglWindow alloc]
- initWithContentRect:rectToScreen([NSScreen mainScreen], framePt)
- styleMask:style
- backing:NSBackingStoreBuffered
- defer:NO
- ] retain];
- [window setPuglview:view];
-
- if (view->title) {
- NSString* titleString = [[NSString alloc]
- initWithBytes:view->title
- length:strlen(view->title)
- encoding:NSUTF8StringEncoding];
-
- [window setTitle:titleString];
- }
-
- if (view->minWidth || view->minHeight) {
- [window setContentMinSize:sizePoints(view,
- view->minWidth,
- view->minHeight)];
- }
- impl->window = window;
-
- ((NSWindow*)window).delegate = [[PuglWindowDelegate alloc]
- initWithPuglWindow:window];
-
- if (view->minAspectX && view->minAspectY) {
- [window setContentAspectRatio:sizePoints(view,
- view->minAspectX,
- view->minAspectY)];
- }
-
- puglSetFrame(view, view->frame);
-
- [window setContentView:impl->wrapperView];
- [view->world->impl->app activateIgnoringOtherApps:YES];
- [window makeFirstResponder:impl->wrapperView];
- [window makeKeyAndOrderFront:window];
- [impl->window setIsVisible:NO];
- }
-
- [impl->wrapperView updateTrackingAreas];
-
- puglDispatchSimpleEvent(view, PUGL_CREATE);
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglShowWindow(PuglView* view)
-{
- if (![view->impl->window isVisible]) {
- [view->impl->window setIsVisible:YES];
- [view->impl->drawView setNeedsDisplay: YES];
- updateViewRect(view);
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglHideWindow(PuglView* view)
-{
- [view->impl->window setIsVisible:NO];
- return PUGL_SUCCESS;
-}
-
-void
-puglFreeViewInternals(PuglView* view)
-{
- if (view) {
- if (view->backend) {
- view->backend->destroy(view);
- }
-
- if (view->impl) {
- [view->impl->wrapperView removeFromSuperview];
- view->impl->wrapperView->puglview = NULL;
- if (view->impl->window) {
- [view->impl->window close];
- }
- [view->impl->wrapperView release];
- if (view->impl->window) {
- [view->impl->window release];
- }
- free(view->impl);
- }
- }
-}
-
-PuglStatus
-puglGrabFocus(PuglView* view)
-{
- NSWindow* window = [view->impl->wrapperView window];
-
- [window makeKeyWindow];
- [window makeFirstResponder:view->impl->wrapperView];
- return PUGL_SUCCESS;
-}
-
-bool
-puglHasFocus(const PuglView* view)
-{
- PuglInternals* const impl = view->impl;
-
- return ([[impl->wrapperView window] isKeyWindow] &&
- [[impl->wrapperView window] firstResponder] == impl->wrapperView);
-}
-
-PuglStatus
-puglRequestAttention(PuglView* view)
-{
- if (![view->impl->window isKeyWindow]) {
- [view->world->impl->app requestUserAttention:NSInformationalRequest];
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglStartTimer(PuglView* view, uintptr_t id, double timeout)
-{
- puglStopTimer(view, id);
-
- NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id];
-
- NSTimer* timer = [NSTimer timerWithTimeInterval:timeout
- target:view->impl->wrapperView
- selector:@selector(timerTick:)
- userInfo:idNumber
- repeats:YES];
-
- [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
-
- view->impl->wrapperView->userTimers[idNumber] = timer;
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglStopTimer(PuglView* view, uintptr_t id)
-{
- NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id];
- NSTimer* timer = view->impl->wrapperView->userTimers[idNumber];
-
- if (timer) {
- [view->impl->wrapperView->userTimers removeObjectForKey:timer];
- [timer invalidate];
- return PUGL_SUCCESS;
- }
-
- return PUGL_UNKNOWN_ERROR;
-}
-
-PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event)
-{
- if (event->type == PUGL_CLIENT) {
- PuglWrapperView* wrapper = view->impl->wrapperView;
- const NSWindow* window = [wrapper window];
- const NSRect rect = [wrapper frame];
- const NSPoint center = {NSMidX(rect), NSMidY(rect)};
-
- NSEvent* nsevent = [NSEvent
- otherEventWithType:NSApplicationDefined
- location:center
- modifierFlags:0
- timestamp:[[NSProcessInfo processInfo] systemUptime]
- windowNumber:window.windowNumber
- context:nil
- subtype:PUGL_CLIENT
- data1:(NSInteger)event->client.data1
- data2:(NSInteger)event->client.data2];
-
- [view->world->impl->app postEvent:nsevent atStart:false];
- return PUGL_SUCCESS;
- }
-
- return PUGL_UNSUPPORTED_TYPE;
-}
-
-#ifndef PUGL_DISABLE_DEPRECATED
-PuglStatus
-puglWaitForEvent(PuglView* view)
-{
- return puglPollEvents(view->world, -1.0);
-}
-#endif
-
-static void
-dispatchClientEvent(PuglWorld* world, NSEvent* ev)
-{
- NSWindow* win = [ev window];
- NSPoint loc = [ev locationInWindow];
- for (size_t i = 0; i < world->numViews; ++i) {
- PuglView* view = world->views[i];
- PuglWrapperView* wrapper = view->impl->wrapperView;
- if ([wrapper window] == win && NSPointInRect(loc, [wrapper frame])) {
- const PuglEventClient event = {PUGL_CLIENT,
- 0,
- (uintptr_t)[ev data1],
- (uintptr_t)[ev data2]};
-
- puglDispatchEvent(view, (const PuglEvent*)&event);
- }
- }
-}
-
-PuglStatus
-puglUpdate(PuglWorld* world, const double timeout)
-{
- NSDate* date = ((timeout < 0)
- ? [NSDate distantFuture]
- : [NSDate dateWithTimeIntervalSinceNow:timeout]);
-
- for (NSEvent* ev = NULL;
- (ev = [world->impl->app nextEventMatchingMask:NSAnyEventMask
- untilDate:date
- inMode:NSDefaultRunLoopMode
- dequeue:YES]);) {
-
- if ([ev type] == NSApplicationDefined && [ev subtype] == PUGL_CLIENT) {
- dispatchClientEvent(world, ev);
- }
-
- [world->impl->app sendEvent: ev];
-
- if (timeout < 0) {
- // Now that we've waited and got an event, set the date to now to
- // avoid looping forever
- date = [NSDate date];
- }
- }
-
- for (size_t i = 0; i < world->numViews; ++i) {
- PuglView* const view = world->views[i];
-
- if ([[view->impl->drawView window] isVisible]) {
- puglDispatchSimpleEvent(view, PUGL_UPDATE);
- }
-
- [view->impl->drawView displayIfNeeded];
- }
-
- return PUGL_SUCCESS;
-}
-
-#ifndef PUGL_DISABLE_DEPRECATED
-PuglStatus
-puglProcessEvents(PuglView* view)
-{
- return puglDispatchEvents(view->world);
-}
-#endif
-
-double
-puglGetTime(const PuglWorld* world)
-{
- return (mach_absolute_time() / 1e9) - world->startTime;
-}
-
-PuglStatus
-puglPostRedisplay(PuglView* view)
-{
- [view->impl->drawView setNeedsDisplay: YES];
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglPostRedisplayRect(PuglView* view, const PuglRect rect)
-{
- const NSRect rectPx = rectToNsRect(rect);
-
- [view->impl->drawView setNeedsDisplayInRect:nsRectToPoints(view, rectPx)];
-
- return PUGL_SUCCESS;
-}
-
-PuglNativeView
-puglGetNativeWindow(PuglView* view)
-{
- return (PuglNativeView)view->impl->wrapperView;
-}
-
-PuglStatus
-puglSetWindowTitle(PuglView* view, const char* title)
-{
- puglSetString(&view->title, title);
-
- if (view->impl->window) {
- NSString* titleString = [[NSString alloc]
- initWithBytes:title
- length:strlen(title)
- encoding:NSUTF8StringEncoding];
-
- [view->impl->window setTitle:titleString];
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetFrame(PuglView* view, const PuglRect frame)
-{
- PuglInternals* const impl = view->impl;
-
- // Update view frame to exactly the requested frame in Pugl coordinates
- view->frame = frame;
-
- const NSRect framePx = rectToNsRect(frame);
- const NSRect framePt = nsRectToPoints(view, framePx);
- if (impl->window) {
- // Resize window to fit new content rect
- const NSRect screenPt = rectToScreen(viewScreen(view), framePt);
- const NSRect winFrame = [impl->window frameRectForContentRect:screenPt];
-
- [impl->window setFrame:winFrame display:NO];
- }
-
- // Resize views
- const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height);
- const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx];
-
- [impl->wrapperView setFrame:(impl->window ? sizePt : framePt)];
- [impl->drawView setFrame:sizePt];
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetDefaultSize(PuglView* const view, const int width, const int height)
-{
- view->defaultWidth = width;
- view->defaultHeight = height;
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetMinSize(PuglView* const view, const int width, const int height)
-{
- view->minWidth = width;
- view->minHeight = height;
-
- if (view->impl->window && (view->minWidth || view->minHeight)) {
- [view->impl->window setContentMinSize:sizePoints(view,
- view->minWidth,
- view->minHeight)];
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetMaxSize(PuglView* const view, const int width, const int height)
-{
- view->maxWidth = width;
- view->maxHeight = height;
-
- if (view->impl->window && (view->maxWidth || view->maxHeight)) {
- [view->impl->window setContentMaxSize:sizePoints(view,
- view->maxWidth,
- view->maxHeight)];
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetAspectRatio(PuglView* const view,
- const int minX,
- const int minY,
- const int maxX,
- const int maxY)
-{
- view->minAspectX = minX;
- view->minAspectY = minY;
- view->maxAspectX = maxX;
- view->maxAspectY = maxY;
-
- if (view->impl->window && view->minAspectX && view->minAspectY) {
- [view->impl->window setContentAspectRatio:sizePoints(view,
- view->minAspectX,
- view->minAspectY)];
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetTransientFor(PuglView* view, PuglNativeView parent)
-{
- view->transientParent = parent;
-
- if (view->impl->window) {
- NSWindow* parentWindow = [(NSView*)parent window];
- if (parentWindow) {
- [parentWindow addChildWindow:view->impl->window
- ordered:NSWindowAbove];
- return PUGL_SUCCESS;
- }
- }
-
- return PUGL_FAILURE;
-}
-
-const void*
-puglGetClipboard(PuglView* const view,
- const char** const type,
- size_t* const len)
-{
- NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard];
-
- if ([[pasteboard types] containsObject:NSStringPboardType]) {
- const NSString* str = [pasteboard stringForType:NSStringPboardType];
- const char* utf8 = [str UTF8String];
-
- puglSetBlob(&view->clipboard, utf8, strlen(utf8) + 1);
- }
-
- return puglGetInternalClipboard(view, type, len);
-}
-
-static NSCursor*
-puglGetNsCursor(const PuglCursor cursor)
-{
- switch (cursor) {
- case PUGL_CURSOR_ARROW:
- return [NSCursor arrowCursor];
- case PUGL_CURSOR_CARET:
- return [NSCursor IBeamCursor];
- case PUGL_CURSOR_CROSSHAIR:
- return [NSCursor crosshairCursor];
- case PUGL_CURSOR_HAND:
- return [NSCursor pointingHandCursor];
- case PUGL_CURSOR_NO:
- return [NSCursor operationNotAllowedCursor];
- case PUGL_CURSOR_LEFT_RIGHT:
- return [NSCursor resizeLeftRightCursor];
- case PUGL_CURSOR_UP_DOWN:
- return [NSCursor resizeUpDownCursor];
- }
-
- return NULL;
-}
-
-PuglStatus
-puglSetCursor(PuglView* view, PuglCursor cursor)
-{
- PuglInternals* const impl = view->impl;
- NSCursor* const cur = puglGetNsCursor(cursor);
- if (!cur) {
- return PUGL_FAILURE;
- }
-
- impl->cursor = cur;
-
- if (impl->mouseTracked) {
- [cur set];
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetClipboard(PuglView* const view,
- const char* const type,
- const void* const data,
- const size_t len)
-{
- NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard];
- const char* const str = (const char*)data;
-
- PuglStatus st = puglSetInternalClipboard(view, type, data, len);
- if (st) {
- return st;
- }
-
- NSString* nsString = [NSString stringWithUTF8String:str];
- if (nsString) {
- [pasteboard
- declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil]
- owner:nil];
-
- [pasteboard setString:nsString forType:NSStringPboardType];
-
- return PUGL_SUCCESS;
- }
-
- return PUGL_UNKNOWN_ERROR;
-}
diff --git a/pugl/detail/mac_cairo.m b/pugl/detail/mac_cairo.m
deleted file mode 100644
index 18209d9..0000000
--- a/pugl/detail/mac_cairo.m
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- Copyright 2019-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.
-*/
-
-/**
- @file mac_cairo.m
- @brief Cairo graphics backend for MacOS.
-*/
-
-#include "pugl/detail/implementation.h"
-#include "pugl/detail/mac.h"
-#include "pugl/detail/stub.h"
-#include "pugl/pugl_cairo.h"
-
-#include <cairo-quartz.h>
-
-#import <Cocoa/Cocoa.h>
-
-#include <assert.h>
-
-@interface PuglCairoView : NSView
-@end
-
-@implementation PuglCairoView
-{
-@public
- PuglView* puglview;
- cairo_surface_t* surface;
- cairo_t* cr;
-}
-
-- (id) initWithFrame:(NSRect)frame
-{
- self = [super initWithFrame:frame];
-
- return self;
-}
-
-- (void) resizeWithOldSuperviewSize:(NSSize)oldSize
-{
- PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
-
- [super resizeWithOldSuperviewSize:oldSize];
- [wrapper setReshaped];
-}
-
-- (void) drawRect:(NSRect)rect
-{
- PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
- [wrapper dispatchExpose:rect];
-}
-
-@end
-
-static PuglStatus
-puglMacCairoCreate(PuglView* view)
-{
- PuglInternals* impl = view->impl;
- PuglCairoView* drawView = [PuglCairoView alloc];
-
- drawView->puglview = view;
- [drawView initWithFrame:[impl->wrapperView bounds]];
- if (view->hints[PUGL_RESIZABLE]) {
- [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- } else {
- [drawView setAutoresizingMask:NSViewNotSizable];
- }
-
- impl->drawView = drawView;
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglMacCairoDestroy(PuglView* view)
-{
- PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;
-
- [drawView removeFromSuperview];
- [drawView release];
-
- view->impl->drawView = nil;
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglMacCairoEnter(PuglView* view, const PuglEventExpose* expose)
-{
- PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;
- if (!expose) {
- return PUGL_SUCCESS;
- }
-
- assert(!drawView->surface);
- assert(!drawView->cr);
-
- const double scale = 1.0 / [[NSScreen mainScreen] backingScaleFactor];
- CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
- const CGSize sizePx = {view->frame.width, view->frame.height};
- const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx);
-
- // Convert coordinates to standard Cairo space
- CGContextTranslateCTM(context, 0.0, -sizePt.height);
- CGContextScaleCTM(context, scale, -scale);
-
- drawView->surface = cairo_quartz_surface_create_for_cg_context(
- context, (unsigned)sizePx.width, (unsigned)sizePx.height);
-
- drawView->cr = cairo_create(drawView->surface);
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglMacCairoLeave(PuglView* view, const PuglEventExpose* expose)
-{
- PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;
- if (!expose) {
- return PUGL_SUCCESS;
- }
-
- assert(drawView->surface);
- assert(drawView->cr);
-
- CGContextRef context = cairo_quartz_surface_get_cg_context(drawView->surface);
-
- cairo_destroy(drawView->cr);
- cairo_surface_destroy(drawView->surface);
- drawView->cr = NULL;
- drawView->surface = NULL;
-
- CGContextFlush(context);
-
- return PUGL_SUCCESS;
-}
-
-static void*
-puglMacCairoGetContext(PuglView* view)
-{
- return ((PuglCairoView*)view->impl->drawView)->cr;
-}
-
-const PuglBackend* puglCairoBackend(void)
-{
- static const PuglBackend backend = {puglStubConfigure,
- puglMacCairoCreate,
- puglMacCairoDestroy,
- puglMacCairoEnter,
- puglMacCairoLeave,
- puglMacCairoGetContext};
-
- return &backend;
-}
diff --git a/pugl/detail/mac_gl.m b/pugl/detail/mac_gl.m
deleted file mode 100644
index 4d4f324..0000000
--- a/pugl/detail/mac_gl.m
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- Copyright 2019-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.
-*/
-
-/**
- @file mac_gl.m
- @brief OpenGL graphics backend for MacOS.
-*/
-
-#include "pugl/detail/implementation.h"
-#include "pugl/detail/mac.h"
-#include "pugl/detail/stub.h"
-#include "pugl/pugl_gl.h"
-
-#ifndef __MAC_10_10
-# define NSOpenGLProfileVersion4_1Core NSOpenGLProfileVersion3_2Core
-#endif
-
-@interface PuglOpenGLView : NSOpenGLView
-@end
-
-@implementation PuglOpenGLView
-{
-@public
- PuglView* puglview;
-}
-
-- (id) initWithFrame:(NSRect)frame
-{
- const bool compat = puglview->hints[PUGL_USE_COMPAT_PROFILE];
- const unsigned samples = (unsigned)puglview->hints[PUGL_SAMPLES];
- const int major = puglview->hints[PUGL_CONTEXT_VERSION_MAJOR];
- const unsigned profile = ((compat || major < 3)
- ? NSOpenGLProfileVersionLegacy
- : (major >= 4
- ? NSOpenGLProfileVersion4_1Core
- : NSOpenGLProfileVersion3_2Core));
-
- // Set attributes to default if they are unset
- // (There is no GLX_DONT_CARE equivalent on MacOS)
- if (puglview->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) {
- puglview->hints[PUGL_DEPTH_BITS] = 0;
- }
- if (puglview->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) {
- puglview->hints[PUGL_STENCIL_BITS] = 0;
- }
- if (puglview->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) {
- puglview->hints[PUGL_SAMPLES] = 1;
- }
- if (puglview->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) {
- puglview->hints[PUGL_DOUBLE_BUFFER] = 1;
- }
- if (puglview->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) {
- puglview->hints[PUGL_SWAP_INTERVAL] = 1;
- }
-
- const unsigned colorSize = (unsigned)(puglview->hints[PUGL_RED_BITS] +
- puglview->hints[PUGL_BLUE_BITS] +
- puglview->hints[PUGL_GREEN_BITS] +
- puglview->hints[PUGL_ALPHA_BITS]);
-
- NSOpenGLPixelFormatAttribute pixelAttribs[17] = {
- NSOpenGLPFADoubleBuffer,
- NSOpenGLPFAAccelerated,
- NSOpenGLPFAOpenGLProfile, profile,
- NSOpenGLPFAColorSize, colorSize,
- NSOpenGLPFADepthSize, (unsigned)puglview->hints[PUGL_DEPTH_BITS],
- NSOpenGLPFAStencilSize, (unsigned)puglview->hints[PUGL_STENCIL_BITS],
- NSOpenGLPFAMultisample, samples ? 1 : 0,
- NSOpenGLPFASampleBuffers, samples ? 1 : 0,
- NSOpenGLPFASamples, samples,
- 0};
-
- NSOpenGLPixelFormat* pixelFormat = [
- [NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs];
-
- if (pixelFormat) {
- self = [super initWithFrame:frame pixelFormat:pixelFormat];
- [pixelFormat release];
- } else {
- self = [super initWithFrame:frame];
- }
-
- [self setWantsBestResolutionOpenGLSurface:YES];
-
- if (self) {
- [[self openGLContext] makeCurrentContext];
- [self reshape];
- }
- return self;
-}
-
-- (void) reshape
-{
- PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
-
- [super reshape];
- [wrapper setReshaped];
-}
-
-- (void) drawRect:(NSRect)rect
-{
- PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
- [wrapper dispatchExpose:rect];
-}
-
-@end
-
-static PuglStatus
-puglMacGlCreate(PuglView* view)
-{
- PuglInternals* impl = view->impl;
- PuglOpenGLView* drawView = [PuglOpenGLView alloc];
-
- drawView->puglview = view;
- [drawView initWithFrame:[impl->wrapperView bounds]];
- if (view->hints[PUGL_RESIZABLE]) {
- [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- } else {
- [drawView setAutoresizingMask:NSViewNotSizable];
- }
-
- impl->drawView = drawView;
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglMacGlDestroy(PuglView* view)
-{
- PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;
-
- [drawView removeFromSuperview];
- [drawView release];
-
- view->impl->drawView = nil;
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglMacGlEnter(PuglView* view, const PuglEventExpose* PUGL_UNUSED(expose))
-{
- PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;
-
- [[drawView openGLContext] makeCurrentContext];
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglMacGlLeave(PuglView* view, const PuglEventExpose* expose)
-{
- PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;
-
- if (expose) {
- [[drawView openGLContext] flushBuffer];
- }
-
- [NSOpenGLContext clearCurrentContext];
-
- return PUGL_SUCCESS;
-}
-
-PuglGlFunc
-puglGetProcAddress(const char *name)
-{
- CFBundleRef framework =
- CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
-
- CFStringRef symbol = CFStringCreateWithCString(
- kCFAllocatorDefault, name, kCFStringEncodingASCII);
-
- PuglGlFunc func = (PuglGlFunc)CFBundleGetFunctionPointerForName(
- framework, symbol);
-
- CFRelease(symbol);
-
- return func;
-}
-
-const PuglBackend* puglGlBackend(void)
-{
- static const PuglBackend backend = {puglStubConfigure,
- puglMacGlCreate,
- puglMacGlDestroy,
- puglMacGlEnter,
- puglMacGlLeave,
- puglStubGetContext};
-
- return &backend;
-}
diff --git a/pugl/detail/mac_stub.m b/pugl/detail/mac_stub.m
deleted file mode 100644
index 8271735..0000000
--- a/pugl/detail/mac_stub.m
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- Copyright 2019-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.
-*/
-
-/**
- @file mac_stub.m
- @brief Stub graphics backend for MacOS.
-*/
-
-#include "pugl/detail/implementation.h"
-#include "pugl/detail/mac.h"
-#include "pugl/detail/stub.h"
-#include "pugl/pugl_stub.h"
-
-#import <Cocoa/Cocoa.h>
-
-@interface PuglStubView : NSView
-@end
-
-@implementation PuglStubView
-{
-@public
- PuglView* puglview;
-}
-
-- (void) resizeWithOldSuperviewSize:(NSSize)oldSize
-{
- PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
-
- [super resizeWithOldSuperviewSize:oldSize];
- [wrapper setReshaped];
-}
-
-- (void) drawRect:(NSRect)rect
-{
- PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
-
- [wrapper dispatchExpose:rect];
-}
-
-@end
-
-static PuglStatus
-puglMacStubCreate(PuglView* view)
-{
- PuglInternals* impl = view->impl;
- PuglStubView* drawView = [PuglStubView alloc];
-
- drawView->puglview = view;
- [drawView initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)];
- if (view->hints[PUGL_RESIZABLE]) {
- [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- } else {
- [drawView setAutoresizingMask:NSViewNotSizable];
- }
-
- impl->drawView = drawView;
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglMacStubDestroy(PuglView* view)
-{
- PuglStubView* const drawView = (PuglStubView*)view->impl->drawView;
-
- [drawView removeFromSuperview];
- [drawView release];
-
- view->impl->drawView = nil;
- return PUGL_SUCCESS;
-}
-
-const PuglBackend*
-puglStubBackend(void)
-{
- static const PuglBackend backend = {puglStubConfigure,
- puglMacStubCreate,
- puglMacStubDestroy,
- puglStubEnter,
- puglStubLeave,
- puglStubGetContext};
-
- return &backend;
-}
diff --git a/pugl/detail/stub.h b/pugl/detail/stub.h
deleted file mode 100644
index acd3181..0000000
--- a/pugl/detail/stub.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file stub.h
- @brief Definition of generic stub backend functions.
-*/
-
-#ifndef PUGL_DETAIL_STUB_H
-#define PUGL_DETAIL_STUB_H
-
-#include "pugl/pugl.h"
-
-PUGL_BEGIN_DECLS
-
-static inline PuglStatus
-puglStubConfigure(PuglView* view)
-{
- (void)view;
- return PUGL_SUCCESS;
-}
-
-static inline PuglStatus
-puglStubCreate(PuglView* view)
-{
- (void)view;
- return PUGL_SUCCESS;
-}
-
-static inline PuglStatus
-puglStubDestroy(PuglView* view)
-{
- (void)view;
- return PUGL_SUCCESS;
-}
-
-static inline PuglStatus
-puglStubEnter(PuglView* view, const PuglEventExpose* expose)
-{
- (void)view;
- (void)expose;
- return PUGL_SUCCESS;
-}
-
-static inline PuglStatus
-puglStubLeave(PuglView* view, const PuglEventExpose* expose)
-{
- (void)view;
- (void)expose;
- return PUGL_SUCCESS;
-}
-
-static inline void*
-puglStubGetContext(PuglView* view)
-{
- (void)view;
- return NULL;
-}
-
-PUGL_END_DECLS
-
-#endif // PUGL_DETAIL_STUB_H
diff --git a/pugl/detail/types.h b/pugl/detail/types.h
deleted file mode 100644
index edd2bd0..0000000
--- a/pugl/detail/types.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file types.h
- @brief Shared internal type definitions.
-*/
-
-#ifndef PUGL_DETAIL_TYPES_H
-#define PUGL_DETAIL_TYPES_H
-
-#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
-#if defined(__cplusplus)
-# define PUGL_UNUSED(name)
-#elif defined(__GNUC__)
-# define PUGL_UNUSED(name) name##_unused __attribute__((__unused__))
-#else
-# define PUGL_UNUSED(name) name
-#endif
-
-/// Platform-specific world internals
-typedef struct PuglWorldInternalsImpl PuglWorldInternals;
-
-/// Platform-specific view internals
-typedef struct PuglInternalsImpl PuglInternals;
-
-/// View hints
-typedef int PuglHints[PUGL_NUM_VIEW_HINTS];
-
-/// Blob of arbitrary data
-typedef struct {
- void* data; ///< Dynamically allocated data
- size_t len; ///< Length of data in bytes
-} PuglBlob;
-
-/// Cross-platform view definition
-struct PuglViewImpl {
- PuglWorld* world;
- const PuglBackend* backend;
- PuglInternals* impl;
- PuglHandle handle;
- PuglEventFunc eventFunc;
- char* title;
- PuglBlob clipboard;
- PuglNativeView parent;
- uintptr_t transientParent;
- PuglRect frame;
- PuglEventConfigure lastConfigure;
- PuglHints hints;
- int defaultWidth;
- int defaultHeight;
- int minWidth;
- int minHeight;
- int maxWidth;
- int maxHeight;
- int minAspectX;
- int minAspectY;
- int maxAspectX;
- int maxAspectY;
- bool visible;
-};
-
-/// Cross-platform world definition
-struct PuglWorldImpl {
- PuglWorldInternals* impl;
- PuglWorldHandle handle;
- PuglLogFunc logFunc;
- char* className;
- double startTime;
- size_t numViews;
- PuglView** views;
- PuglLogLevel logLevel;
-};
-
-/// Opaque surface used by graphics backend
-typedef void PuglSurface;
-
-/// Graphics backend interface
-struct PuglBackendImpl {
- /// Get visual information from display and setup view as necessary
- PuglStatus (*configure)(PuglView*);
-
- /// Create surface and drawing context
- PuglStatus (*create)(PuglView*);
-
- /// Destroy surface and drawing context
- PuglStatus (*destroy)(PuglView*);
-
- /// Enter drawing context, for drawing if expose is non-null
- PuglStatus (*enter)(PuglView*, const PuglEventExpose*);
-
- /// Leave drawing context, after drawing if expose is non-null
- PuglStatus (*leave)(PuglView*, const PuglEventExpose*);
-
- /// Return the puglGetContext() handle for the application, if any
- void* (*getContext)(PuglView*);
-};
-
-#endif // PUGL_DETAIL_TYPES_H
diff --git a/pugl/detail/win.c b/pugl/detail/win.c
deleted file mode 100644
index 078b0a0..0000000
--- a/pugl/detail/win.c
+++ /dev/null
@@ -1,1152 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file win.c
- @brief Windows implementation.
-*/
-
-#include "pugl/detail/win.h"
-
-#include "pugl/detail/implementation.h"
-#include "pugl/detail/stub.h"
-#include "pugl/pugl.h"
-#include "pugl/pugl_stub.h"
-
-#include <windows.h>
-#include <windowsx.h>
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wctype.h>
-
-#ifndef WM_MOUSEWHEEL
-# define WM_MOUSEWHEEL 0x020A
-#endif
-#ifndef WM_MOUSEHWHEEL
-# define WM_MOUSEHWHEEL 0x020E
-#endif
-#ifndef WHEEL_DELTA
-# define WHEEL_DELTA 120
-#endif
-#ifndef GWLP_USERDATA
-# define GWLP_USERDATA (-21)
-#endif
-
-#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50)
-#define PUGL_LOCAL_MARK_MSG (WM_USER + 51)
-#define PUGL_LOCAL_CLIENT_MSG (WM_USER + 52)
-#define PUGL_RESIZE_TIMER_ID 9461
-#define PUGL_USER_TIMER_MIN 9470
-
-typedef BOOL (WINAPI *PFN_SetProcessDPIAware)(void);
-
-LRESULT CALLBACK
-wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
-
-static wchar_t*
-puglUtf8ToWideChar(const char* const utf8)
-{
- const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
- if (len > 0) {
- wchar_t* result = (wchar_t*)calloc((size_t)len, sizeof(wchar_t));
- MultiByteToWideChar(CP_UTF8, 0, utf8, -1, result, len);
- return result;
- }
-
- return NULL;
-}
-
-static char*
-puglWideCharToUtf8(const wchar_t* const wstr, size_t* len)
-{
- int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
- if (n > 0) {
- char* result = (char*)calloc((size_t)n, sizeof(char));
- WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, n, NULL, NULL);
- *len = (size_t)n;
- return result;
- }
-
- return NULL;
-}
-
-static bool
-puglRegisterWindowClass(const char* name)
-{
- WNDCLASSEX wc = { 0 };
- if (GetClassInfoEx(GetModuleHandle(NULL), name, &wc)) {
- return true; // Already registered
- }
-
- wc.cbSize = sizeof(wc);
- wc.style = CS_OWNDC;
- wc.lpfnWndProc = wndProc;
- wc.hInstance = GetModuleHandle(NULL);
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
- wc.lpszClassName = name;
-
- return RegisterClassEx(&wc);
-}
-
-PuglWorldInternals*
-puglInitWorldInternals(PuglWorldType PUGL_UNUSED(type),
- PuglWorldFlags PUGL_UNUSED(flags))
-{
- PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
- 1, sizeof(PuglWorldInternals));
- if (!impl) {
- return NULL;
- }
-
- HMODULE user32 = LoadLibrary("user32.dll");
- if (user32) {
- PFN_SetProcessDPIAware SetProcessDPIAware =
- (PFN_SetProcessDPIAware)GetProcAddress(
- user32, "SetProcessDPIAware");
- if (SetProcessDPIAware) {
- SetProcessDPIAware();
- }
-
- FreeLibrary(user32);
- }
-
- LARGE_INTEGER frequency;
- QueryPerformanceFrequency(&frequency);
- impl->timerFrequency = (double)frequency.QuadPart;
-
- return impl;
-}
-
-void*
-puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world))
-{
- return GetModuleHandle(NULL);
-}
-
-PuglInternals*
-puglInitViewInternals(void)
-{
- return (PuglInternals*)calloc(1, sizeof(PuglInternals));
-}
-
-static PuglStatus
-puglPollWinEvents(PuglWorld* world, const double timeout)
-{
- (void)world;
-
- if (timeout < 0) {
- WaitMessage();
- } else {
- MsgWaitForMultipleObjects(
- 0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS);
- }
- return PUGL_SUCCESS;
-}
-
-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) {
- view->hints[PUGL_RED_BITS] = 8;
- }
- if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_BLUE_BITS] = 8;
- }
- if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_GREEN_BITS] = 8;
- }
- if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_ALPHA_BITS] = 8;
- }
-
- // Get refresh rate for resize draw timer
- DEVMODEA devMode = {0};
- EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode);
- view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency;
-
- // Register window class if necessary
- if (!puglRegisterWindowClass(view->world->className)) {
- return PUGL_REGISTRATION_FAILED;
- }
-
- if (!view->backend || !view->backend->configure) {
- return PUGL_BAD_BACKEND;
- }
-
- PuglStatus st;
- if ((st = view->backend->configure(view))) {
- return st;
- } else if ((st = view->backend->create(view))) {
- return st;
- }
-
- if (view->title) {
- puglSetWindowTitle(view, view->title);
- }
-
- view->impl->cursor = LoadCursor(NULL, IDC_ARROW);
-
- puglSetFrame(view, view->frame);
- SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view);
-
- puglDispatchSimpleEvent(view, PUGL_CREATE);
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglShowWindow(PuglView* view)
-{
- PuglInternals* impl = view->impl;
-
- ShowWindow(impl->hwnd, SW_SHOWNORMAL);
- SetFocus(impl->hwnd);
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglHideWindow(PuglView* view)
-{
- PuglInternals* impl = view->impl;
-
- ShowWindow(impl->hwnd, SW_HIDE);
- return PUGL_SUCCESS;
-}
-
-void
-puglFreeViewInternals(PuglView* view)
-{
- if (view) {
- if (view->backend) {
- view->backend->destroy(view);
- }
-
- ReleaseDC(view->impl->hwnd, view->impl->hdc);
- DestroyWindow(view->impl->hwnd);
- free(view->impl);
- }
-}
-
-void
-puglFreeWorldInternals(PuglWorld* world)
-{
- UnregisterClass(world->className, NULL);
- free(world->impl);
-}
-
-static PuglKey
-keySymToSpecial(WPARAM sym)
-{
- // clang-format off
- switch (sym) {
- case VK_F1: return PUGL_KEY_F1;
- case VK_F2: return PUGL_KEY_F2;
- case VK_F3: return PUGL_KEY_F3;
- case VK_F4: return PUGL_KEY_F4;
- case VK_F5: return PUGL_KEY_F5;
- case VK_F6: return PUGL_KEY_F6;
- case VK_F7: return PUGL_KEY_F7;
- case VK_F8: return PUGL_KEY_F8;
- case VK_F9: return PUGL_KEY_F9;
- case VK_F10: return PUGL_KEY_F10;
- case VK_F11: return PUGL_KEY_F11;
- case VK_F12: return PUGL_KEY_F12;
- case VK_BACK: return PUGL_KEY_BACKSPACE;
- case VK_DELETE: return PUGL_KEY_DELETE;
- case VK_LEFT: return PUGL_KEY_LEFT;
- case VK_UP: return PUGL_KEY_UP;
- case VK_RIGHT: return PUGL_KEY_RIGHT;
- case VK_DOWN: return PUGL_KEY_DOWN;
- case VK_PRIOR: return PUGL_KEY_PAGE_UP;
- case VK_NEXT: return PUGL_KEY_PAGE_DOWN;
- case VK_HOME: return PUGL_KEY_HOME;
- case VK_END: return PUGL_KEY_END;
- case VK_INSERT: return PUGL_KEY_INSERT;
- case VK_SHIFT:
- case VK_LSHIFT: return PUGL_KEY_SHIFT_L;
- case VK_RSHIFT: return PUGL_KEY_SHIFT_R;
- case VK_CONTROL:
- case VK_LCONTROL: return PUGL_KEY_CTRL_L;
- case VK_RCONTROL: return PUGL_KEY_CTRL_R;
- case VK_MENU:
- case VK_LMENU: return PUGL_KEY_ALT_L;
- case VK_RMENU: return PUGL_KEY_ALT_R;
- case VK_LWIN: return PUGL_KEY_SUPER_L;
- case VK_RWIN: return PUGL_KEY_SUPER_R;
- case VK_CAPITAL: return PUGL_KEY_CAPS_LOCK;
- case VK_SCROLL: return PUGL_KEY_SCROLL_LOCK;
- case VK_NUMLOCK: return PUGL_KEY_NUM_LOCK;
- case VK_SNAPSHOT: return PUGL_KEY_PRINT_SCREEN;
- case VK_PAUSE: return PUGL_KEY_PAUSE;
- }
- // clang-format on
-
- return (PuglKey)0;
-}
-
-static uint32_t
-getModifiers(void)
-{
- // clang-format off
- return (((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0u) |
- ((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0u) |
- ((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0u) |
- ((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0u) |
- ((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0u));
- // clang-format on
-}
-
-static void
-initMouseEvent(PuglEvent* event,
- PuglView* view,
- int button,
- bool press,
- LPARAM lParam)
-{
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- ClientToScreen(view->impl->hwnd, &pt);
-
- if (press) {
- SetCapture(view->impl->hwnd);
- } else {
- ReleaseCapture();
- }
-
- event->button.time = GetMessageTime() / 1e3;
- event->button.type = press ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE;
- event->button.x = GET_X_LPARAM(lParam);
- event->button.y = GET_Y_LPARAM(lParam);
- event->button.xRoot = pt.x;
- event->button.yRoot = pt.y;
- event->button.state = getModifiers();
- event->button.button = (uint32_t)button;
-}
-
-static void
-initScrollEvent(PuglEvent* event, PuglView* view, LPARAM lParam)
-{
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- ScreenToClient(view->impl->hwnd, &pt);
-
- event->scroll.time = GetMessageTime() / 1e3;
- event->scroll.type = PUGL_SCROLL;
- event->scroll.x = pt.x;
- event->scroll.y = pt.y;
- event->scroll.xRoot = GET_X_LPARAM(lParam);
- event->scroll.yRoot = GET_Y_LPARAM(lParam);
- event->scroll.state = getModifiers();
- event->scroll.dx = 0;
- event->scroll.dy = 0;
-}
-
-/// Return the code point for buf, or the replacement character on error
-static uint32_t
-puglDecodeUTF16(const wchar_t* buf, const int len)
-{
- const uint32_t c0 = buf[0];
- const uint32_t c1 = buf[0];
- if (c0 >= 0xD800 && c0 < 0xDC00) {
- if (len < 2) {
- return 0xFFFD; // Surrogate, but length is only 1
- } else if (c1 >= 0xDC00 && c1 <= 0xDFFF) {
- return ((c0 & 0x03FF) << 10) + (c1 & 0x03FF) + 0x10000;
- }
-
- return 0xFFFD; // Unpaired surrogates
- }
-
- return c0;
-}
-
-static void
-initKeyEvent(PuglEventKey* event,
- PuglView* view,
- bool press,
- WPARAM wParam,
- LPARAM lParam)
-{
- POINT rpos = { 0, 0 };
- GetCursorPos(&rpos);
-
- POINT cpos = { rpos.x, rpos.y };
- ScreenToClient(view->impl->hwnd, &rpos);
-
- const unsigned scode = (uint32_t)((lParam & 0xFF0000) >> 16);
- const unsigned vkey = ((wParam == VK_SHIFT)
- ? MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX)
- : (unsigned)wParam);
-
- const unsigned vcode = MapVirtualKey(vkey, MAPVK_VK_TO_VSC);
- const unsigned kchar = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR);
- const bool dead = kchar >> (sizeof(UINT) * 8 - 1) & 1;
- const bool ext = lParam & 0x01000000;
-
- event->type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- event->time = GetMessageTime() / 1e3;
- event->state = getModifiers();
- event->xRoot = rpos.x;
- event->yRoot = rpos.y;
- event->x = cpos.x;
- event->y = cpos.y;
- event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16);
- event->key = 0;
-
- const PuglKey special = keySymToSpecial(vkey);
- if (special) {
- if (ext && (special == PUGL_KEY_CTRL || special == PUGL_KEY_ALT)) {
- event->key = special + 1u; // Right hand key
- } else {
- event->key = special;
- }
- } else if (!dead) {
- // Translate unshifted key
- BYTE keyboardState[256] = {0};
- wchar_t buf[5] = {0};
-
- event->key = puglDecodeUTF16(
- buf, ToUnicode(vkey, vcode, keyboardState, buf, 4, 1 << 2));
- }
-}
-
-static void
-initCharEvent(PuglEvent* event, PuglView* view, WPARAM wParam, LPARAM lParam)
-{
- const wchar_t utf16[2] = { wParam & 0xFFFF, (wParam >> 16) & 0xFFFF };
-
- initKeyEvent(&event->key, view, true, wParam, lParam);
- event->type = PUGL_TEXT;
- event->text.character = puglDecodeUTF16(utf16, 2);
-
- if (!WideCharToMultiByte(
- CP_UTF8, 0, utf16, 2, event->text.string, 8, NULL, NULL)) {
- memset(event->text.string, 0, 8);
- }
-}
-
-static bool
-ignoreKeyEvent(PuglView* view, LPARAM lParam)
-{
- return view->hints[PUGL_IGNORE_KEY_REPEAT] && (lParam & (1 << 30));
-}
-
-static RECT
-handleConfigure(PuglView* view, PuglEvent* event)
-{
- RECT rect;
- GetClientRect(view->impl->hwnd, &rect);
- MapWindowPoints(view->impl->hwnd,
- view->parent ? (HWND)view->parent : HWND_DESKTOP,
- (LPPOINT)&rect,
- 2);
-
- const LONG width = rect.right - rect.left;
- const LONG height = rect.bottom - rect.top;
-
- view->frame.x = rect.left;
- view->frame.y = rect.top;
-
- event->configure.type = PUGL_CONFIGURE;
- event->configure.x = view->frame.x;
- event->configure.y = view->frame.y;
- event->configure.width = width;
- event->configure.height = height;
-
- if (view->frame.width != width || view->frame.height != height) {
- view->frame.width = width;
- view->frame.height = height;
- }
-
- return rect;
-}
-
-static void
-handleCrossing(PuglView* view, const PuglEventType type, POINT pos)
-{
- POINT root_pos = pos;
- ClientToScreen(view->impl->hwnd, &root_pos);
-
- const PuglEventCrossing ev = {
- type,
- 0,
- GetMessageTime() / 1e3,
- (double)pos.x,
- (double)pos.y,
- (double)root_pos.x,
- (double)root_pos.y,
- getModifiers(),
- PUGL_CROSSING_NORMAL,
- };
-
- puglDispatchEvent(view, (const PuglEvent*)&ev);
-}
-
-static void
-constrainAspect(const PuglView* const view,
- RECT* const size,
- const WPARAM wParam)
-{
- const float minA = (float)view->minAspectX / (float)view->minAspectY;
- const float maxA = (float)view->maxAspectX / (float)view->maxAspectY;
- const int w = size->right - size->left;
- const int h = size->bottom - size->top;
- const float a = (float)w / (float)h;
-
- switch (wParam) {
- case WMSZ_TOP:
- size->top = (a < minA ? (LONG)(size->bottom - w * minA) :
- a > maxA ? (LONG)(size->bottom - w * maxA) :
- size->top);
- break;
- case WMSZ_TOPRIGHT:
- case WMSZ_RIGHT:
- case WMSZ_BOTTOMRIGHT:
- size->right = (a < minA ? (LONG)(size->left + h * minA) :
- a > maxA ? (LONG)(size->left + h * maxA) :
- size->right);
- break;
- case WMSZ_BOTTOM:
- size->bottom = (a < minA ? (LONG)(size->top + w * minA) :
- a > maxA ? (LONG)(size->top + w * maxA) :
- size->bottom);
- break;
- case WMSZ_BOTTOMLEFT:
- case WMSZ_LEFT:
- case WMSZ_TOPLEFT:
- size->left = (a < minA ? (LONG)(size->right - h * minA) :
- a > maxA ? (LONG)(size->right - h * maxA) :
- size->left);
- break;
- }
-}
-
-static LRESULT
-handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
-{
- PuglEvent event;
- void* dummy_ptr = NULL;
- RECT rect;
- MINMAXINFO* mmi;
- POINT pt;
-
- memset(&event, 0, sizeof(event));
-
- event.any.type = PUGL_NOTHING;
- if (InSendMessageEx(dummy_ptr)) {
- event.any.flags |= PUGL_IS_SEND_EVENT;
- }
-
- switch (message) {
- case WM_SETCURSOR:
- if (LOWORD(lParam) == HTCLIENT) {
- SetCursor(view->impl->cursor);
- } else {
- return DefWindowProc(view->impl->hwnd, message, wParam, lParam);
- }
- break;
- case WM_SHOWWINDOW:
- if (wParam) {
- handleConfigure(view, &event);
- puglDispatchEvent(view, &event);
- event.type = PUGL_NOTHING;
-
- RedrawWindow(view->impl->hwnd, NULL, NULL,
- RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT);
- }
-
- if ((bool)wParam != view->visible) {
- view->visible = wParam;
- event.any.type = wParam ? PUGL_MAP : PUGL_UNMAP;
- }
- break;
- case WM_SIZE:
- handleConfigure(view, &event);
- InvalidateRect(view->impl->hwnd, NULL, false);
- break;
- case WM_SIZING:
- if (view->minAspectX) {
- constrainAspect(view, (RECT*)lParam, wParam);
- return TRUE;
- }
- break;
- case WM_ENTERSIZEMOVE:
- case WM_ENTERMENULOOP:
- view->impl->resizing = true;
- SetTimer(view->impl->hwnd,
- PUGL_RESIZE_TIMER_ID,
- 1000 / (UINT)view->hints[PUGL_REFRESH_RATE],
- NULL);
- break;
- case WM_TIMER:
- if (wParam == PUGL_RESIZE_TIMER_ID) {
- RedrawWindow(view->impl->hwnd, NULL, NULL,
- RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT);
- } else if (wParam >= PUGL_USER_TIMER_MIN) {
- PuglEvent ev = {{PUGL_TIMER, 0}};
- ev.timer.id = wParam - PUGL_USER_TIMER_MIN;
- puglDispatchEvent(view, &ev);
- }
- break;
- case WM_EXITSIZEMOVE:
- case WM_EXITMENULOOP:
- KillTimer(view->impl->hwnd, PUGL_RESIZE_TIMER_ID);
- view->impl->resizing = false;
- puglPostRedisplay(view);
- break;
- case WM_GETMINMAXINFO:
- mmi = (MINMAXINFO*)lParam;
- mmi->ptMinTrackSize.x = view->minWidth;
- mmi->ptMinTrackSize.y = view->minHeight;
- if (view->maxWidth > 0 && view->maxHeight > 0) {
- mmi->ptMaxTrackSize.x = view->maxWidth;
- mmi->ptMaxTrackSize.y = view->maxHeight;
- }
- break;
- case WM_PAINT:
- GetUpdateRect(view->impl->hwnd, &rect, false);
- event.expose.type = PUGL_EXPOSE;
- event.expose.x = rect.left;
- event.expose.y = rect.top;
- event.expose.width = rect.right - rect.left;
- event.expose.height = rect.bottom - rect.top;
- break;
- case WM_ERASEBKGND:
- return true;
- case WM_MOUSEMOVE:
- pt.x = GET_X_LPARAM(lParam);
- pt.y = GET_Y_LPARAM(lParam);
-
- if (!view->impl->mouseTracked) {
- TRACKMOUSEEVENT tme = {0};
-
- tme.cbSize = sizeof(tme);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = view->impl->hwnd;
- TrackMouseEvent(&tme);
-
- handleCrossing(view, PUGL_POINTER_IN, pt);
- view->impl->mouseTracked = true;
- }
-
- ClientToScreen(view->impl->hwnd, &pt);
- event.motion.type = PUGL_MOTION;
- event.motion.time = GetMessageTime() / 1e3;
- event.motion.x = GET_X_LPARAM(lParam);
- event.motion.y = GET_Y_LPARAM(lParam);
- event.motion.xRoot = pt.x;
- event.motion.yRoot = pt.y;
- event.motion.state = getModifiers();
- break;
- case WM_MOUSELEAVE:
- GetCursorPos(&pt);
- ScreenToClient(view->impl->hwnd, &pt);
- handleCrossing(view, PUGL_POINTER_OUT, pt);
- view->impl->mouseTracked = false;
- break;
- case WM_LBUTTONDOWN:
- initMouseEvent(&event, view, 1, true, lParam);
- break;
- case WM_MBUTTONDOWN:
- initMouseEvent(&event, view, 2, true, lParam);
- break;
- case WM_RBUTTONDOWN:
- initMouseEvent(&event, view, 3, true, lParam);
- break;
- case WM_LBUTTONUP:
- initMouseEvent(&event, view, 1, false, lParam);
- break;
- case WM_MBUTTONUP:
- initMouseEvent(&event, view, 2, false, lParam);
- break;
- case WM_RBUTTONUP:
- initMouseEvent(&event, view, 3, false, lParam);
- break;
- case WM_MOUSEWHEEL:
- initScrollEvent(&event, view, lParam);
- event.scroll.dy = GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
- event.scroll.direction = (event.scroll.dy > 0
- ? PUGL_SCROLL_UP
- : PUGL_SCROLL_DOWN);
- break;
- case WM_MOUSEHWHEEL:
- initScrollEvent(&event, view, lParam);
- event.scroll.dx = GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
- event.scroll.direction = (event.scroll.dx > 0
- ? PUGL_SCROLL_RIGHT
- : PUGL_SCROLL_LEFT);
- break;
- case WM_KEYDOWN:
- if (!ignoreKeyEvent(view, lParam)) {
- initKeyEvent(&event.key, view, true, wParam, lParam);
- }
- break;
- case WM_KEYUP:
- initKeyEvent(&event.key, view, false, wParam, lParam);
- break;
- case WM_CHAR:
- initCharEvent(&event, view, wParam, lParam);
- break;
- case WM_SETFOCUS:
- event.type = PUGL_FOCUS_IN;
- break;
- case WM_KILLFOCUS:
- event.type = PUGL_FOCUS_OUT;
- break;
- case WM_SYSKEYDOWN:
- initKeyEvent(&event.key, view, true, wParam, lParam);
- break;
- case WM_SYSKEYUP:
- initKeyEvent(&event.key, view, false, wParam, lParam);
- break;
- case WM_SYSCHAR:
- return TRUE;
- case PUGL_LOCAL_CLIENT_MSG:
- event.client.type = PUGL_CLIENT;
- event.client.data1 = (uintptr_t)wParam;
- event.client.data2 = (uintptr_t)lParam;
- break;
- case WM_QUIT:
- case PUGL_LOCAL_CLOSE_MSG:
- event.any.type = PUGL_CLOSE;
- break;
- default:
- return DefWindowProc(view->impl->hwnd, message, wParam, lParam);
- }
-
- puglDispatchEvent(view, &event);
-
- return 0;
-}
-
-PuglStatus
-puglGrabFocus(PuglView* view)
-{
- SetFocus(view->impl->hwnd);
- return PUGL_SUCCESS;
-}
-
-bool
-puglHasFocus(const PuglView* view)
-{
- return GetFocus() == view->impl->hwnd;
-}
-
-PuglStatus
-puglRequestAttention(PuglView* view)
-{
- FLASHWINFO info = {sizeof(FLASHWINFO),
- view->impl->hwnd,
- FLASHW_ALL|FLASHW_TIMERNOFG,
- 1,
- 0};
-
- FlashWindowEx(&info);
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglStartTimer(PuglView* view, uintptr_t id, double timeout)
-{
- const UINT msec = (UINT)floor(timeout * 1000.0);
-
- return (SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL)
- ? PUGL_SUCCESS
- : PUGL_UNKNOWN_ERROR);
-}
-
-PuglStatus
-puglStopTimer(PuglView* view, uintptr_t id)
-{
- return (KillTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id)
- ? PUGL_SUCCESS
- : PUGL_UNKNOWN_ERROR);
-}
-
-PuglStatus
-puglSendEvent(PuglView* view, const PuglEvent* event)
-{
- if (event->type == PUGL_CLIENT) {
- PostMessage(view->impl->hwnd,
- PUGL_LOCAL_CLIENT_MSG,
- (WPARAM)event->client.data1,
- (LPARAM)event->client.data2);
-
- return PUGL_SUCCESS;
- }
-
- return PUGL_UNSUPPORTED_TYPE;
-}
-
-#ifndef PUGL_DISABLE_DEPRECATED
-PuglStatus
-puglWaitForEvent(PuglView* PUGL_UNUSED(view))
-{
- WaitMessage();
- return PUGL_SUCCESS;
-}
-#endif
-
-static PuglStatus
-puglDispatchViewEvents(PuglView* view)
-{
- /* Windows has no facility to process only currently queued messages, which
- causes the event loop to run forever in cases like mouse movement where
- the queue is constantly being filled with new messages. To work around
- this, we post a message to ourselves before starting, record its time
- when it is received, then break the loop on the first message that was
- created afterwards. */
-
- long markTime = 0;
- MSG msg;
- while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
- if (msg.message == PUGL_LOCAL_MARK_MSG) {
- markTime = GetMessageTime();
- } else {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- if (markTime != 0 && GetMessageTime() > markTime) {
- break;
- }
- }
- }
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglDispatchWinEvents(PuglWorld* world)
-{
- for (size_t i = 0; i < world->numViews; ++i) {
- PostMessage(world->views[i]->impl->hwnd, PUGL_LOCAL_MARK_MSG, 0, 0);
- }
-
- for (size_t i = 0; i < world->numViews; ++i) {
- puglDispatchViewEvents(world->views[i]);
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglUpdate(PuglWorld* world, double timeout)
-{
- const double startTime = puglGetTime(world);
- PuglStatus st = PUGL_SUCCESS;
-
- if (timeout < 0.0) {
- st = puglPollWinEvents(world, timeout);
- st = st ? st : puglDispatchWinEvents(world);
- } else if (timeout == 0.0) {
- st = puglDispatchWinEvents(world);
- } else {
- const double endTime = startTime + timeout - 0.001;
- for (double t = startTime; t < endTime; t = puglGetTime(world)) {
- if ((st = puglPollWinEvents(world, endTime - t)) ||
- (st = puglDispatchWinEvents(world))) {
- break;
- }
- }
- }
-
- for (size_t i = 0; i < world->numViews; ++i) {
- if (world->views[i]->visible) {
- puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE);
- }
-
- UpdateWindow(world->views[i]->impl->hwnd);
- }
-
- return st;
-}
-
-#ifndef PUGL_DISABLE_DEPRECATED
-PuglStatus
-puglProcessEvents(PuglView* view)
-{
- return puglUpdate(view->world, 0.0);
-}
-#endif
-
-LRESULT CALLBACK
-wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
-
- switch (message) {
- case WM_CREATE:
- PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
- return 0;
- case WM_CLOSE:
- PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam);
- return 0;
- case WM_DESTROY:
- return 0;
- default:
- if (view && hwnd == view->impl->hwnd) {
- return handleMessage(view, message, wParam, lParam);
- } else {
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- }
-}
-
-double
-puglGetTime(const PuglWorld* world)
-{
- LARGE_INTEGER count;
- QueryPerformanceCounter(&count);
- return ((double)count.QuadPart / world->impl->timerFrequency -
- world->startTime);
-}
-
-PuglStatus
-puglPostRedisplay(PuglView* view)
-{
- InvalidateRect(view->impl->hwnd, NULL, false);
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglPostRedisplayRect(PuglView* view, const PuglRect rect)
-{
- const RECT r = {(long)floor(rect.x),
- (long)floor(rect.y),
- (long)ceil(rect.x + rect.width),
- (long)ceil(rect.y + rect.height)};
-
- InvalidateRect(view->impl->hwnd, &r, false);
-
- return PUGL_SUCCESS;
-}
-
-PuglNativeView
-puglGetNativeWindow(PuglView* view)
-{
- return (PuglNativeView)view->impl->hwnd;
-}
-
-PuglStatus
-puglSetWindowTitle(PuglView* view, const char* title)
-{
- puglSetString(&view->title, title);
-
- if (view->impl->hwnd) {
- wchar_t* wtitle = puglUtf8ToWideChar(title);
- if (wtitle) {
- SetWindowTextW(view->impl->hwnd, wtitle);
- free(wtitle);
- }
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetFrame(PuglView* view, const PuglRect frame)
-{
- view->frame = frame;
-
- if (view->impl->hwnd) {
- RECT rect = { (long)frame.x,
- (long)frame.y,
- (long)frame.x + (long)frame.width,
- (long)frame.y + (long)frame.height };
-
- AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view),
- FALSE,
- puglWinGetWindowExFlags(view));
-
- if (!SetWindowPos(view->impl->hwnd,
- HWND_TOP,
- rect.left,
- rect.top,
- rect.right - rect.left,
- rect.bottom - rect.top,
- SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER)) {
- return PUGL_UNKNOWN_ERROR;
- }
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetDefaultSize(PuglView* const view, const int width, const int height)
-{
- view->defaultWidth = width;
- view->defaultHeight = height;
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetMinSize(PuglView* const view, const int width, const int height)
-{
- view->minWidth = width;
- view->minHeight = height;
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetMaxSize(PuglView* const view, const int width, const int height)
-{
- view->maxWidth = width;
- view->maxHeight = height;
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetAspectRatio(PuglView* const view,
- const int minX,
- const int minY,
- const int maxX,
- const int maxY)
-{
- view->minAspectX = minX;
- view->minAspectY = minY;
- view->maxAspectX = maxX;
- view->maxAspectY = maxY;
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetTransientFor(PuglView* view, PuglNativeView parent)
-{
- if (view->parent) {
- return PUGL_FAILURE;
- }
-
- view->transientParent = parent;
-
- if (view->impl->hwnd) {
- SetWindowLongPtr(view->impl->hwnd, GWLP_HWNDPARENT, (LONG_PTR)parent);
- return GetLastError() == NO_ERROR ? PUGL_SUCCESS : PUGL_FAILURE;
- }
-
- return PUGL_SUCCESS;
-}
-
-const void*
-puglGetClipboard(PuglView* const view,
- const char** const type,
- size_t* const len)
-{
- PuglInternals* const impl = view->impl;
-
- if (!IsClipboardFormatAvailable(CF_UNICODETEXT) ||
- !OpenClipboard(impl->hwnd)) {
- return NULL;
- }
-
- HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
- wchar_t* wstr = mem ? (wchar_t*)GlobalLock(mem) : NULL;
- if (!wstr) {
- CloseClipboard();
- return NULL;
- }
-
- free(view->clipboard.data);
- view->clipboard.data = puglWideCharToUtf8(wstr, &view->clipboard.len);
- GlobalUnlock(mem);
- CloseClipboard();
-
- return puglGetInternalClipboard(view, type, len);
-}
-
-PuglStatus
-puglSetClipboard(PuglView* const view,
- const char* const type,
- const void* const data,
- const size_t len)
-{
- PuglInternals* const impl = view->impl;
-
- PuglStatus st = puglSetInternalClipboard(view, type, data, len);
- if (st) {
- return st;
- } else if (!OpenClipboard(impl->hwnd)) {
- return PUGL_UNKNOWN_ERROR;
- }
-
- // Measure string and allocate global memory for clipboard
- const char* str = (const char*)data;
- const int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
- HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wlen + 1) * sizeof(wchar_t));
- if (!mem) {
- CloseClipboard();
- return PUGL_UNKNOWN_ERROR;
- }
-
- // Lock global memory
- wchar_t* wstr = (wchar_t*)GlobalLock(mem);
- if (!wstr) {
- GlobalFree(mem);
- CloseClipboard();
- return PUGL_UNKNOWN_ERROR;
- }
-
- // Convert string into global memory and set it as clipboard data
- MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, wlen);
- wstr[wlen] = 0;
- GlobalUnlock(mem);
- SetClipboardData(CF_UNICODETEXT, mem);
- CloseClipboard();
- return PUGL_SUCCESS;
-}
-
-static const char* const cursor_ids[] = {
- IDC_ARROW, // ARROW
- IDC_IBEAM, // CARET
- IDC_CROSS, // CROSSHAIR
- IDC_HAND, // HAND
- IDC_NO, // NO
- IDC_SIZEWE, // LEFT_RIGHT
- IDC_SIZENS, // UP_DOWN
-};
-
-PuglStatus
-puglSetCursor(PuglView* view, PuglCursor cursor)
-{
- PuglInternals* const impl = view->impl;
- const unsigned index = (unsigned)cursor;
- const unsigned count = sizeof(cursor_ids) / sizeof(cursor_ids[0]);
-
- if (index >= count) {
- return PUGL_BAD_PARAMETER;
- }
-
- const HCURSOR cur = LoadCursor(NULL, cursor_ids[index]);
- if (!cur) {
- return PUGL_FAILURE;
- }
-
- impl->cursor = cur;
- if (impl->mouseTracked) {
- SetCursor(cur);
- }
-
- return PUGL_SUCCESS;
-}
diff --git a/pugl/detail/win.h b/pugl/detail/win.h
deleted file mode 100644
index b0d92e0..0000000
--- a/pugl/detail/win.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file win.h
- @brief Shared definitions for Windows implementation.
-*/
-
-#include "pugl/detail/implementation.h"
-
-#include <windows.h>
-
-#include <stdbool.h>
-
-typedef PIXELFORMATDESCRIPTOR PuglWinPFD;
-
-struct PuglWorldInternalsImpl {
- double timerFrequency;
-};
-
-struct PuglInternalsImpl {
- PuglWinPFD pfd;
- int pfId;
- HWND hwnd;
- HCURSOR cursor;
- HDC hdc;
- PuglSurface* surface;
- bool flashing;
- bool resizing;
- bool mouseTracked;
-};
-
-static inline PuglWinPFD
-puglWinGetPixelFormatDescriptor(const PuglHints hints)
-{
- const int rgbBits = (hints[PUGL_RED_BITS] + //
- hints[PUGL_GREEN_BITS] + //
- hints[PUGL_BLUE_BITS]);
-
- const DWORD dwFlags = hints[PUGL_DOUBLE_BUFFER] ? PFD_DOUBLEBUFFER : 0u;
-
- PuglWinPFD pfd;
- ZeroMemory(&pfd, sizeof(pfd));
- pfd.nSize = sizeof(pfd);
- pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | dwFlags;
- pfd.iPixelType = PFD_TYPE_RGBA;
- pfd.cColorBits = (BYTE)rgbBits;
- pfd.cRedBits = (BYTE)hints[PUGL_RED_BITS];
- pfd.cGreenBits = (BYTE)hints[PUGL_GREEN_BITS];
- pfd.cBlueBits = (BYTE)hints[PUGL_BLUE_BITS];
- pfd.cAlphaBits = (BYTE)hints[PUGL_ALPHA_BITS];
- pfd.cDepthBits = (BYTE)hints[PUGL_DEPTH_BITS];
- pfd.cStencilBits = (BYTE)hints[PUGL_STENCIL_BITS];
- pfd.iLayerType = PFD_MAIN_PLANE;
- return pfd;
-}
-
-static inline unsigned
-puglWinGetWindowFlags(const PuglView* const view)
-{
- const bool resizable = view->hints[PUGL_RESIZABLE];
- const unsigned sizeFlags = resizable ? (WS_SIZEBOX | WS_MAXIMIZEBOX) : 0u;
-
- return (WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
- (view->parent
- ? WS_CHILD
- : (WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | sizeFlags)));
-}
-
-static inline unsigned
-puglWinGetWindowExFlags(const PuglView* const view)
-{
- return WS_EX_NOINHERITLAYOUT | (view->parent ? 0u : WS_EX_APPWINDOW);
-}
-
-static inline PuglStatus
-puglWinCreateWindow(PuglView* const view,
- const char* const title,
- HWND* const hwnd,
- HDC* const hdc)
-{
- const char* className = (const char*)view->world->className;
- const unsigned winFlags = puglWinGetWindowFlags(view);
- const unsigned winExFlags = puglWinGetWindowExFlags(view);
-
- if (view->frame.width == 0.0 && view->frame.height == 0.0) {
- if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) {
- return PUGL_BAD_CONFIGURATION;
- }
-
- RECT desktopRect;
- GetClientRect(GetDesktopWindow(), &desktopRect);
-
- const int screenWidth = desktopRect.right - desktopRect.left;
- const int screenHeight = desktopRect.bottom - desktopRect.top;
-
- view->frame.width = view->defaultWidth;
- view->frame.height = view->defaultHeight;
- view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0;
- view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0;
- }
-
- // The meaning of "parent" depends on the window type (WS_CHILD)
- PuglNativeView parent = view->parent ? view->parent : view->transientParent;
-
- // Calculate total window size to accommodate requested view size
- RECT wr = { (long)view->frame.x, (long)view->frame.y,
- (long)view->frame.width, (long)view->frame.height };
- AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags);
-
- // Create window and get drawing context
- if (!(*hwnd = CreateWindowEx(winExFlags, className, title, winFlags,
- CW_USEDEFAULT, CW_USEDEFAULT,
- wr.right-wr.left, wr.bottom-wr.top,
- (HWND)parent, NULL, NULL, NULL))) {
- return PUGL_REALIZE_FAILED;
- } else if (!(*hdc = GetDC(*hwnd))) {
- DestroyWindow(*hwnd);
- *hwnd = NULL;
- return PUGL_REALIZE_FAILED;
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglWinStubConfigure(PuglView* view);
-
-PuglStatus
-puglWinStubEnter(PuglView* view, const PuglEventExpose* expose);
-
-PuglStatus
-puglWinStubLeave(PuglView* view, const PuglEventExpose* expose);
diff --git a/pugl/detail/win_cairo.c b/pugl/detail/win_cairo.c
deleted file mode 100644
index 1b9afb9..0000000
--- a/pugl/detail/win_cairo.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file win_cairo.c
- @brief Cairo graphics backend for Windows.
-*/
-
-#include "pugl/detail/stub.h"
-#include "pugl/detail/types.h"
-#include "pugl/detail/win.h"
-#include "pugl/pugl_cairo.h"
-
-#include <cairo-win32.h>
-#include <cairo.h>
-
-#include <stdlib.h>
-
-typedef struct {
- cairo_surface_t* surface;
- cairo_t* cr;
- HDC drawDc;
- HBITMAP drawBitmap;
-} PuglWinCairoSurface;
-
-static PuglStatus
-puglWinCairoCreateDrawContext(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
-
- surface->drawDc = CreateCompatibleDC(impl->hdc);
- surface->drawBitmap = CreateCompatibleBitmap(
- impl->hdc, (int)view->frame.width, (int)view->frame.height);
-
- DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap));
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglWinCairoDestroyDrawContext(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
-
- DeleteDC(surface->drawDc);
- DeleteObject(surface->drawBitmap);
-
- surface->drawDc = NULL;
- surface->drawBitmap = NULL;
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglWinCairoConfigure(PuglView* view)
-{
- const PuglStatus st = puglWinStubConfigure(view);
-
- if (!st) {
- view->impl->surface = (PuglWinCairoSurface*)calloc(
- 1, sizeof(PuglWinCairoSurface));
- }
-
- return st;
-}
-
-static void
-puglWinCairoClose(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
-
- cairo_surface_destroy(surface->surface);
-
- surface->surface = NULL;
-}
-
-static PuglStatus
-puglWinCairoOpen(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
-
- cairo_status_t st = CAIRO_STATUS_SUCCESS;
- if (!(surface->surface = cairo_win32_surface_create(surface->drawDc)) ||
- (st = cairo_surface_status(surface->surface)) ||
- !(surface->cr = cairo_create(surface->surface)) ||
- (st = cairo_status(surface->cr))) {
- return PUGL_CREATE_CONTEXT_FAILED;
- }
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglWinCairoDestroy(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
-
- puglWinCairoClose(view);
- puglWinCairoDestroyDrawContext(view);
- free(surface);
- impl->surface = NULL;
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglWinCairoEnter(PuglView* view, const PuglEventExpose* expose)
-{
- PuglStatus st = PUGL_SUCCESS;
-
- if (expose &&
- !(st = puglWinCairoCreateDrawContext(view)) &&
- !(st = puglWinCairoOpen(view))) {
- PAINTSTRUCT ps;
- BeginPaint(view->impl->hwnd, &ps);
- }
-
- return st;
-}
-
-static PuglStatus
-puglWinCairoLeave(PuglView* view, const PuglEventExpose* expose)
-{
- PuglInternals* const impl = view->impl;
- PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
-
- if (expose) {
- cairo_surface_flush(surface->surface);
- BitBlt(impl->hdc,
- 0, 0, (int)view->frame.width, (int)view->frame.height,
- surface->drawDc, 0, 0, SRCCOPY);
-
- puglWinCairoClose(view);
- puglWinCairoDestroyDrawContext(view);
-
- PAINTSTRUCT ps;
- EndPaint(view->impl->hwnd, &ps);
- }
-
- return PUGL_SUCCESS;
-}
-
-static void*
-puglWinCairoGetContext(PuglView* view)
-{
- return ((PuglWinCairoSurface*)view->impl->surface)->cr;
-}
-
-const PuglBackend*
-puglCairoBackend()
-{
- static const PuglBackend backend = {puglWinCairoConfigure,
- puglStubCreate,
- puglWinCairoDestroy,
- puglWinCairoEnter,
- puglWinCairoLeave,
- puglWinCairoGetContext};
-
- return &backend;
-}
diff --git a/pugl/detail/win_gl.c b/pugl/detail/win_gl.c
deleted file mode 100644
index 096c715..0000000
--- a/pugl/detail/win_gl.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file win_gl.c
- @brief OpenGL graphics backend for Windows.
-*/
-
-#include "pugl/detail/stub.h"
-#include "pugl/detail/types.h"
-#include "pugl/detail/win.h"
-#include "pugl/pugl_gl.h"
-
-#include <windows.h>
-
-#include <GL/gl.h>
-
-#include <stdbool.h>
-#include <stdlib.h>
-
-#define WGL_DRAW_TO_WINDOW_ARB 0x2001
-#define WGL_ACCELERATION_ARB 0x2003
-#define WGL_SUPPORT_OPENGL_ARB 0x2010
-#define WGL_DOUBLE_BUFFER_ARB 0x2011
-#define WGL_PIXEL_TYPE_ARB 0x2013
-#define WGL_RED_BITS_ARB 0x2015
-#define WGL_GREEN_BITS_ARB 0x2017
-#define WGL_BLUE_BITS_ARB 0x2019
-#define WGL_ALPHA_BITS_ARB 0x201b
-#define WGL_DEPTH_BITS_ARB 0x2022
-#define WGL_STENCIL_BITS_ARB 0x2023
-#define WGL_FULL_ACCELERATION_ARB 0x2027
-#define WGL_TYPE_RGBA_ARB 0x202b
-#define WGL_SAMPLE_BUFFERS_ARB 0x2041
-#define WGL_SAMPLES_ARB 0x2042
-
-#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
-#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
-#define WGL_CONTEXT_FLAGS_ARB 0x2094
-#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
-
-#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
-#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
-#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
-
-typedef HGLRC (*WglCreateContextAttribs)(HDC, HGLRC, const int*);
-typedef BOOL (*WglSwapInterval)(int);
-typedef BOOL (*WglChoosePixelFormat)(
- HDC, const int*, const FLOAT*, UINT, int*, UINT*);
-
-typedef struct {
- WglChoosePixelFormat wglChoosePixelFormat;
- WglCreateContextAttribs wglCreateContextAttribs;
- WglSwapInterval wglSwapInterval;
-} PuglWinGlProcs;
-
-typedef struct {
- PuglWinGlProcs procs;
- HGLRC hglrc;
-} PuglWinGlSurface;
-
-// Struct to manage the fake window used during configuration
-typedef struct {
- HWND hwnd;
- HDC hdc;
-} PuglFakeWindow;
-
-static PuglStatus
-puglWinError(PuglFakeWindow* fakeWin, const PuglStatus status)
-{
- if (fakeWin->hwnd) {
- ReleaseDC(fakeWin->hwnd, fakeWin->hdc);
- DestroyWindow(fakeWin->hwnd);
- }
-
- return status;
-}
-
-static PuglWinGlProcs puglWinGlGetProcs(void)
-{
- const PuglWinGlProcs procs = {
- (WglChoosePixelFormat)(
- wglGetProcAddress("wglChoosePixelFormatARB")),
- (WglCreateContextAttribs)(
- wglGetProcAddress("wglCreateContextAttribsARB")),
- (WglSwapInterval)(
- wglGetProcAddress("wglSwapIntervalEXT"))
- };
-
- return procs;
-}
-
-static PuglStatus
-puglWinGlConfigure(PuglView* view)
-{
- PuglInternals* impl = view->impl;
-
- // Set attributes to default if they are unset
- // (There is no GLX_DONT_CARE equivalent on Windows)
- if (view->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_DEPTH_BITS] = 0;
- }
- if (view->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_STENCIL_BITS] = 0;
- }
- if (view->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) {
- view->hints[PUGL_SAMPLES] = 1;
- }
- if (view->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) {
- view->hints[PUGL_DOUBLE_BUFFER] = 1;
- }
- if (view->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) {
- view->hints[PUGL_SWAP_INTERVAL] = 1;
- }
-
- // clang-format off
- const int pixelAttrs[] = {
- WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
- WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
- WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
- WGL_DOUBLE_BUFFER_ARB, view->hints[PUGL_DOUBLE_BUFFER],
- WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
- WGL_SAMPLE_BUFFERS_ARB, view->hints[PUGL_SAMPLES] ? 1 : 0,
- WGL_SAMPLES_ARB, view->hints[PUGL_SAMPLES],
- WGL_RED_BITS_ARB, view->hints[PUGL_RED_BITS],
- WGL_GREEN_BITS_ARB, view->hints[PUGL_GREEN_BITS],
- WGL_BLUE_BITS_ARB, view->hints[PUGL_BLUE_BITS],
- WGL_ALPHA_BITS_ARB, view->hints[PUGL_ALPHA_BITS],
- WGL_DEPTH_BITS_ARB, view->hints[PUGL_DEPTH_BITS],
- WGL_STENCIL_BITS_ARB, view->hints[PUGL_STENCIL_BITS],
- 0,
- };
- // clang-format on
-
- PuglWinGlSurface* const surface =
- (PuglWinGlSurface*)calloc(1, sizeof(PuglWinGlSurface));
- impl->surface = surface;
-
- // Create fake window for getting at GL context
- PuglStatus st = PUGL_SUCCESS;
- PuglFakeWindow fakeWin = {0, 0};
- static const char* title = "Pugl Configuration";
- if ((st = puglWinCreateWindow(view, title, &fakeWin.hwnd, &fakeWin.hdc))) {
- return puglWinError(&fakeWin, st);
- }
-
- // Set pixel format for fake window
- const PuglWinPFD fakePfd = puglWinGetPixelFormatDescriptor(view->hints);
- const int fakePfId = ChoosePixelFormat(fakeWin.hdc, &fakePfd);
- if (!fakePfId) {
- return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED);
- } else if (!SetPixelFormat(fakeWin.hdc, fakePfId, &fakePfd)) {
- return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED);
- }
-
- // Create fake GL context to get at the functions we need
- HGLRC fakeRc = wglCreateContext(fakeWin.hdc);
- if (!fakeRc) {
- return puglWinError(&fakeWin, PUGL_CREATE_CONTEXT_FAILED);
- }
-
- // Enter fake context and get extension functions
- wglMakeCurrent(fakeWin.hdc, fakeRc);
- surface->procs = puglWinGlGetProcs();
-
- if (surface->procs.wglChoosePixelFormat) {
- // Choose pixel format based on attributes
- UINT numFormats = 0;
- if (!surface->procs.wglChoosePixelFormat(
- fakeWin.hdc, pixelAttrs, NULL, 1u, &impl->pfId, &numFormats)) {
- return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED);
- }
-
- DescribePixelFormat(
- impl->hdc, impl->pfId, sizeof(impl->pfd), &impl->pfd);
- } else {
- // Modern extensions not available, use basic pixel format
- impl->pfd = fakePfd;
- impl->pfId = fakePfId;
- }
-
- // Dispose of fake window and context
- wglMakeCurrent(NULL, NULL);
- wglDeleteContext(fakeRc);
- ReleaseDC(fakeWin.hwnd, fakeWin.hdc);
- DestroyWindow(fakeWin.hwnd);
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglWinGlCreate(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglWinGlSurface* const surface = (PuglWinGlSurface*)impl->surface;
- PuglStatus st = PUGL_SUCCESS;
-
- const int contextAttribs[] = {
- WGL_CONTEXT_MAJOR_VERSION_ARB,
- view->hints[PUGL_CONTEXT_VERSION_MAJOR],
-
- WGL_CONTEXT_MINOR_VERSION_ARB,
- view->hints[PUGL_CONTEXT_VERSION_MINOR],
-
- WGL_CONTEXT_FLAGS_ARB,
- (view->hints[PUGL_USE_DEBUG_CONTEXT] ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
-
- WGL_CONTEXT_PROFILE_MASK_ARB,
- (view->hints[PUGL_USE_COMPAT_PROFILE]
- ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB
- : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB),
-
- 0};
-
- // Create real window with desired pixel format
- if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) {
- return st;
- } else if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) {
- ReleaseDC(impl->hwnd, impl->hdc);
- DestroyWindow(impl->hwnd);
- impl->hwnd = NULL;
- impl->hdc = NULL;
- return PUGL_SET_FORMAT_FAILED;
- }
-
- // Create GL context
- if (surface->procs.wglCreateContextAttribs &&
- !(surface->hglrc = surface->procs.wglCreateContextAttribs(
- impl->hdc, 0, contextAttribs))) {
- return PUGL_CREATE_CONTEXT_FAILED;
- } else if (!(surface->hglrc = wglCreateContext(impl->hdc))) {
- return PUGL_CREATE_CONTEXT_FAILED;
- }
-
- // Enter context and set swap interval
- wglMakeCurrent(impl->hdc, surface->hglrc);
- const int swapInterval = view->hints[PUGL_SWAP_INTERVAL];
- if (surface->procs.wglSwapInterval && swapInterval != PUGL_DONT_CARE) {
- surface->procs.wglSwapInterval(swapInterval);
- }
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglWinGlDestroy(PuglView* view)
-{
- PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface;
- if (surface) {
- wglMakeCurrent(NULL, NULL);
- wglDeleteContext(surface->hglrc);
- free(surface);
- view->impl->surface = NULL;
- }
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglWinGlEnter(PuglView* view, const PuglEventExpose* expose)
-{
- PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface;
-
- wglMakeCurrent(view->impl->hdc, surface->hglrc);
-
- if (expose) {
- PAINTSTRUCT ps;
- BeginPaint(view->impl->hwnd, &ps);
- }
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglWinGlLeave(PuglView* view, const PuglEventExpose* expose)
-{
- if (expose) {
- PAINTSTRUCT ps;
- EndPaint(view->impl->hwnd, &ps);
- SwapBuffers(view->impl->hdc);
- }
-
- wglMakeCurrent(NULL, NULL);
- return PUGL_SUCCESS;
-}
-
-PuglGlFunc
-puglGetProcAddress(const char* name)
-{
- const PuglGlFunc func = (PuglGlFunc)wglGetProcAddress(name);
-
- /* Windows has the annoying property that wglGetProcAddress returns NULL
- for functions from OpenGL 1.1, so we fall back to pulling them directly
- from opengl32.dll */
-
- return func
- ? func
- : (PuglGlFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), name);
-}
-
-const PuglBackend*
-puglGlBackend(void)
-{
- static const PuglBackend backend = {puglWinGlConfigure,
- puglWinGlCreate,
- puglWinGlDestroy,
- puglWinGlEnter,
- puglWinGlLeave,
- puglStubGetContext};
-
- return &backend;
-}
diff --git a/pugl/detail/win_stub.c b/pugl/detail/win_stub.c
deleted file mode 100644
index ab9e6aa..0000000
--- a/pugl/detail/win_stub.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-#include "pugl/pugl_stub.h"
-
-#include "pugl/detail/stub.h"
-#include "pugl/detail/types.h"
-#include "pugl/detail/win.h"
-
-PuglStatus
-puglWinStubConfigure(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglStatus st = PUGL_SUCCESS;
-
- if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) {
- return st;
- }
-
- impl->pfd = puglWinGetPixelFormatDescriptor(view->hints);
- impl->pfId = ChoosePixelFormat(impl->hdc, &impl->pfd);
-
- if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) {
- ReleaseDC(impl->hwnd, impl->hdc);
- DestroyWindow(impl->hwnd);
- impl->hwnd = NULL;
- impl->hdc = NULL;
- return PUGL_SET_FORMAT_FAILED;
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglWinStubEnter(PuglView* view, const PuglEventExpose* expose)
-{
- if (expose) {
- PAINTSTRUCT ps;
- BeginPaint(view->impl->hwnd, &ps);
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglWinStubLeave(PuglView* view, const PuglEventExpose* expose)
-{
- if (expose) {
- PAINTSTRUCT ps;
- EndPaint(view->impl->hwnd, &ps);
- }
-
- return PUGL_SUCCESS;
-}
-
-const PuglBackend*
-puglStubBackend(void)
-{
- static const PuglBackend backend = {puglWinStubConfigure,
- puglStubCreate,
- puglStubDestroy,
- puglWinStubEnter,
- puglWinStubLeave,
- puglStubGetContext};
-
- return &backend;
-}
diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c
deleted file mode 100644
index fd76606..0000000
--- a/pugl/detail/x11.c
+++ /dev/null
@@ -1,1348 +0,0 @@
-/*
- Copyright 2012-2020 David Robillard <d@drobilla.net>
- Copyright 2013 Robin Gareus <robin@gareus.org>
- Copyright 2011-2012 Ben Loftis, Harrison Consoles
-
- 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.
-*/
-
-/**
- @file x11.c
- @brief X11 implementation.
-*/
-
-#define _POSIX_C_SOURCE 199309L
-
-#include "pugl/detail/x11.h"
-
-#include "pugl/detail/implementation.h"
-#include "pugl/detail/types.h"
-#include "pugl/pugl.h"
-
-#include <X11/X.h>
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/keysym.h>
-
-#ifdef HAVE_XRANDR
-# include <X11/extensions/Xrandr.h>
-#endif
-
-#ifdef HAVE_XSYNC
-# include <X11/extensions/sync.h>
-# include <X11/extensions/syncconst.h>
-#endif
-
-#ifdef HAVE_XCURSOR
-# include <X11/Xcursor/Xcursor.h>
-# include <X11/cursorfont.h>
-#endif
-
-#include <sys/select.h>
-#include <sys/time.h>
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifndef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef MAX
-# define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-enum WmClientStateMessageAction {
- WM_STATE_REMOVE,
- WM_STATE_ADD,
- WM_STATE_TOGGLE
-};
-
-static const long eventMask =
- (ExposureMask | StructureNotifyMask |
- VisibilityChangeMask | FocusChangeMask |
- EnterWindowMask | LeaveWindowMask | PointerMotionMask |
- ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask);
-
-static bool
-puglInitXSync(PuglWorldInternals* impl)
-{
-#ifdef HAVE_XSYNC
- int syncMajor = 0;
- int syncMinor = 0;
- int errorBase = 0;
- XSyncSystemCounter* counters = NULL;
- int numCounters = 0;
-
- if (XSyncQueryExtension(impl->display, &impl->syncEventBase, &errorBase) &&
- XSyncInitialize(impl->display, &syncMajor, &syncMinor) &&
- (counters = XSyncListSystemCounters(impl->display, &numCounters))) {
-
- for (int n = 0; n < numCounters; ++n) {
- if (!strcmp(counters[n].name, "SERVERTIME")) {
- impl->serverTimeCounter = counters[n].counter;
- impl->syncSupported = true;
- break;
- }
- }
-
- XSyncFreeSystemCounterList(counters);
- }
-#else
- (void)impl;
-#endif
-
- return false;
-}
-
-PuglWorldInternals*
-puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags)
-{
- if (type == PUGL_PROGRAM && (flags & PUGL_WORLD_THREADS)) {
- XInitThreads();
- }
-
- Display* display = XOpenDisplay(NULL);
- if (!display) {
- return NULL;
- }
-
- PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
- 1, sizeof(PuglWorldInternals));
-
- impl->display = display;
-
- // Intern the various atoms we will need
- impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0);
- impl->atoms.UTF8_STRING = XInternAtom(display, "UTF8_STRING", 0);
- impl->atoms.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0);
- impl->atoms.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", 0);
- impl->atoms.PUGL_CLIENT_MSG = XInternAtom(display, "_PUGL_CLIENT_MSG", 0);
- impl->atoms.NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", 0);
- impl->atoms.NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", 0);
- impl->atoms.NET_WM_STATE_DEMANDS_ATTENTION =
- XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", 0);
-
- // Open input method
- XSetLocaleModifiers("");
- if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) {
- XSetLocaleModifiers("@im=");
- impl->xim = XOpenIM(display, NULL, NULL, NULL);
- }
-
- puglInitXSync(impl);
- XFlush(display);
-
- return impl;
-}
-
-void*
-puglGetNativeWorld(PuglWorld* world)
-{
- return world->impl->display;
-}
-
-PuglInternals*
-puglInitViewInternals(void)
-{
- PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
-
-#ifdef HAVE_XCURSOR
- impl->cursorShape = XC_arrow;
-#endif
-
- return impl;
-}
-
-static PuglStatus
-puglPollX11Socket(PuglWorld* world, const double timeout)
-{
- if (XPending(world->impl->display) > 0) {
- return PUGL_SUCCESS;
- }
-
- const int fd = ConnectionNumber(world->impl->display);
- const int nfds = fd + 1;
- int ret = 0;
- fd_set fds;
- FD_ZERO(&fds); // NOLINT
- FD_SET(fd, &fds);
-
- if (timeout < 0.0) {
- ret = select(nfds, &fds, NULL, NULL, NULL);
- } else {
- const long sec = (long)timeout;
- const long usec = (long)((timeout - (double)sec) * 1e6);
- struct timeval tv = {sec, usec};
- ret = select(nfds, &fds, NULL, NULL, &tv);
- }
-
- return ret < 0 ? PUGL_UNKNOWN_ERROR : PUGL_SUCCESS;
-}
-
-static PuglView*
-puglFindView(PuglWorld* world, const Window window)
-{
- for (size_t i = 0; i < world->numViews; ++i) {
- if (world->views[i]->impl->win == window) {
- return world->views[i];
- }
- }
-
- return NULL;
-}
-
-static PuglStatus
-updateSizeHints(const PuglView* view)
-{
- if (!view->impl->win) {
- return PUGL_SUCCESS;
- }
-
- Display* display = view->world->impl->display;
- XSizeHints sizeHints = {0};
-
- if (!view->hints[PUGL_RESIZABLE]) {
- sizeHints.flags = PBaseSize | PMinSize | PMaxSize;
- sizeHints.base_width = (int)view->frame.width;
- sizeHints.base_height = (int)view->frame.height;
- sizeHints.min_width = (int)view->frame.width;
- sizeHints.min_height = (int)view->frame.height;
- sizeHints.max_width = (int)view->frame.width;
- sizeHints.max_height = (int)view->frame.height;
- } else {
- if (view->defaultWidth || view->defaultHeight) {
- sizeHints.flags = PBaseSize;
- sizeHints.base_width = view->defaultWidth;
- sizeHints.base_height = view->defaultHeight;
- }
- if (view->minWidth || view->minHeight) {
- sizeHints.flags = PMinSize;
- sizeHints.min_width = view->minWidth;
- sizeHints.min_height = view->minHeight;
- }
- if (view->maxWidth || view->maxHeight) {
- sizeHints.flags = PMaxSize;
- sizeHints.max_width = view->maxWidth;
- sizeHints.max_height = view->maxHeight;
- }
- if (view->minAspectX) {
- sizeHints.flags |= PAspect;
- sizeHints.min_aspect.x = view->minAspectX;
- sizeHints.min_aspect.y = view->minAspectY;
- sizeHints.max_aspect.x = view->maxAspectX;
- sizeHints.max_aspect.y = view->maxAspectY;
- }
- }
-
- XSetNormalHints(display, view->impl->win, &sizeHints);
- return PUGL_SUCCESS;
-}
-
-#ifdef HAVE_XCURSOR
-static PuglStatus
-puglDefineCursorShape(PuglView* view, unsigned shape)
-{
- PuglInternals* const impl = view->impl;
- PuglWorld* const world = view->world;
- Display* const display = world->impl->display;
- const Cursor cur = XcursorShapeLoadCursor(display, shape);
-
- if (cur) {
- XDefineCursor(display, impl->win, cur);
- XFreeCursor(display, cur);
- return PUGL_SUCCESS;
- }
-
- return PUGL_FAILURE;
-}
-#endif
-
-PuglStatus
-puglRealize(PuglView* view)
-{
- 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;
-
- impl->display = display;
- impl->screen = DefaultScreen(display);
-
- if (!view->backend || !view->backend->configure) {
- return PUGL_BAD_BACKEND;
- } else if (view->frame.width == 0.0 && view->frame.height == 0.0) {
- if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) {
- return PUGL_BAD_CONFIGURATION;
- }
-
- const int screenWidth = DisplayWidth(display, impl->screen);
- const int screenHeight = DisplayHeight(display, impl->screen);
-
- view->frame.width = view->defaultWidth;
- view->frame.height = view->defaultHeight;
- view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0;
- view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0;
- }
-
- PuglStatus st = view->backend->configure(view);
- if (st || !impl->vi) {
- view->backend->destroy(view);
- return st ? st : PUGL_BACKEND_FAILED;
- }
-
- Window xParent = view->parent ? (Window)view->parent
- : RootWindow(display, impl->screen);
-
- Colormap cmap = XCreateColormap(
- display, xParent, impl->vi->visual, AllocNone);
-
- XSetWindowAttributes attr = {0};
- attr.colormap = cmap;
- attr.event_mask = eventMask;
-
- const Window win = impl->win = XCreateWindow(
- display, xParent,
- (int)view->frame.x, (int)view->frame.y,
- (unsigned)view->frame.width, (unsigned)view->frame.height,
- 0, impl->vi->depth, InputOutput,
- impl->vi->visual, CWColormap | CWEventMask, &attr);
-
- if ((st = view->backend->create(view))) {
- return st;
- }
-
-#ifdef HAVE_XRANDR
- // Set refresh rate hint to the real refresh rate
- XRRScreenConfiguration* conf = XRRGetScreenInfo(display, xParent);
- short current_rate = XRRConfigCurrentRate(conf);
-
- view->hints[PUGL_REFRESH_RATE] = current_rate;
- XRRFreeScreenConfigInfo(conf);
-#endif
-
- updateSizeHints(view);
-
- XClassHint classHint = { world->className, world->className };
- XSetClassHint(display, win, &classHint);
-
- if (view->title) {
- puglSetWindowTitle(view, view->title);
- }
-
- if (!view->parent) {
- XSetWMProtocols(display, win, &atoms->WM_DELETE_WINDOW, 1);
- }
-
- if (view->transientParent) {
- XSetTransientForHint(display, win, (Window)(view->transientParent));
- }
-
- // Create input context
- const XIMStyle im_style = XIMPreeditNothing | XIMStatusNothing;
- if (!(impl->xic = XCreateIC(world->impl->xim,
- XNInputStyle, im_style,
- XNClientWindow, win,
- XNFocusWindow, win,
- NULL))) {
- view->world->logFunc(view->world,
- PUGL_LOG_LEVEL_WARNING,
- "XCreateID failed\n");
- }
-
-#ifdef HAVE_XCURSOR
- puglDefineCursorShape(view, impl->cursorShape);
-#endif
-
- puglDispatchSimpleEvent(view, PUGL_CREATE);
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglShowWindow(PuglView* view)
-{
- PuglStatus st = PUGL_SUCCESS;
-
- if (!view->impl->win) {
- if ((st = puglRealize(view))) {
- return st;
- }
- }
-
- XMapRaised(view->impl->display, view->impl->win);
- puglPostRedisplay(view);
-
- return st;
-}
-
-PuglStatus
-puglHideWindow(PuglView* view)
-{
- XUnmapWindow(view->impl->display, view->impl->win);
- return PUGL_SUCCESS;
-}
-
-void
-puglFreeViewInternals(PuglView* view)
-{
- if (view && view->impl) {
- if (view->impl->xic) {
- XDestroyIC(view->impl->xic);
- }
- if (view->backend) {
- view->backend->destroy(view);
- }
- if (view->impl->display) {
- XDestroyWindow(view->impl->display, view->impl->win);
- }
- XFree(view->impl->vi);
- free(view->impl);
- }
-}
-
-void
-puglFreeWorldInternals(PuglWorld* world)
-{
- if (world->impl->xim) {
- XCloseIM(world->impl->xim);
- }
- XCloseDisplay(world->impl->display);
- free(world->impl->timers);
- free(world->impl);
-}
-
-static PuglKey
-keySymToSpecial(KeySym sym)
-{
- switch (sym) {
- case XK_F1: return PUGL_KEY_F1;
- case XK_F2: return PUGL_KEY_F2;
- case XK_F3: return PUGL_KEY_F3;
- case XK_F4: return PUGL_KEY_F4;
- case XK_F5: return PUGL_KEY_F5;
- case XK_F6: return PUGL_KEY_F6;
- case XK_F7: return PUGL_KEY_F7;
- case XK_F8: return PUGL_KEY_F8;
- case XK_F9: return PUGL_KEY_F9;
- case XK_F10: return PUGL_KEY_F10;
- case XK_F11: return PUGL_KEY_F11;
- case XK_F12: return PUGL_KEY_F12;
- case XK_Left: return PUGL_KEY_LEFT;
- case XK_Up: return PUGL_KEY_UP;
- case XK_Right: return PUGL_KEY_RIGHT;
- case XK_Down: return PUGL_KEY_DOWN;
- case XK_Page_Up: return PUGL_KEY_PAGE_UP;
- case XK_Page_Down: return PUGL_KEY_PAGE_DOWN;
- case XK_Home: return PUGL_KEY_HOME;
- case XK_End: return PUGL_KEY_END;
- case XK_Insert: return PUGL_KEY_INSERT;
- case XK_Shift_L: return PUGL_KEY_SHIFT_L;
- case XK_Shift_R: return PUGL_KEY_SHIFT_R;
- case XK_Control_L: return PUGL_KEY_CTRL_L;
- case XK_Control_R: return PUGL_KEY_CTRL_R;
- case XK_Alt_L: return PUGL_KEY_ALT_L;
- case XK_ISO_Level3_Shift:
- case XK_Alt_R: return PUGL_KEY_ALT_R;
- case XK_Super_L: return PUGL_KEY_SUPER_L;
- case XK_Super_R: return PUGL_KEY_SUPER_R;
- case XK_Menu: return PUGL_KEY_MENU;
- case XK_Caps_Lock: return PUGL_KEY_CAPS_LOCK;
- case XK_Scroll_Lock: return PUGL_KEY_SCROLL_LOCK;
- case XK_Num_Lock: return PUGL_KEY_NUM_LOCK;
- case XK_Print: return PUGL_KEY_PRINT_SCREEN;
- case XK_Pause: return PUGL_KEY_PAUSE;
- default: break;
- }
- return (PuglKey)0;
-}
-
-static int
-lookupString(XIC xic, XEvent* xevent, char* str, KeySym* sym)
-{
- Status status = 0;
-
-#ifdef X_HAVE_UTF8_STRING
- const int n = Xutf8LookupString(xic, &xevent->xkey, str, 7, sym, &status);
-#else
- const int n = XmbLookupString(xic, &xevent->xkey, str, 7, sym, &status);
-#endif
-
- return status == XBufferOverflow ? 0 : n;
-}
-
-static void
-translateKey(PuglView* view, XEvent* xevent, PuglEvent* event)
-{
- const unsigned state = xevent->xkey.state;
- const bool filter = XFilterEvent(xevent, None);
-
- event->key.keycode = xevent->xkey.keycode;
- xevent->xkey.state = 0;
-
- // Lookup unshifted key
- char ustr[8] = {0};
- KeySym sym = 0;
- const int ufound = XLookupString(&xevent->xkey, ustr, 8, &sym, NULL);
- const PuglKey special = keySymToSpecial(sym);
-
- event->key.key = ((special || ufound <= 0)
- ? special
- : puglDecodeUTF8((const uint8_t*)ustr));
-
- if (xevent->type == KeyPress && !filter && !special) {
- // Lookup shifted key for possible text event
- xevent->xkey.state = state;
-
- char sstr[8] = {0};
- const int sfound = lookupString(view->impl->xic, xevent, sstr, &sym);
- if (sfound > 0) {
- // Dispatch key event now
- puglDispatchEvent(view, event);
-
- // "Return" a text event in its place
- event->text.type = PUGL_TEXT;
- event->text.character = puglDecodeUTF8((const uint8_t*)sstr);
- memcpy(event->text.string, sstr, sizeof(sstr));
- }
- }
-}
-
-static uint32_t
-translateModifiers(const unsigned xstate)
-{
- return (((xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0u) |
- ((xstate & ControlMask) ? PUGL_MOD_CTRL : 0u) |
- ((xstate & Mod1Mask) ? PUGL_MOD_ALT : 0u) |
- ((xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0u));
-}
-
-static PuglEvent
-translateEvent(PuglView* view, XEvent xevent)
-{
- const PuglX11Atoms* atoms = &view->world->impl->atoms;
-
- PuglEvent event = {{PUGL_NOTHING, 0}};
- event.any.flags = xevent.xany.send_event ? PUGL_IS_SEND_EVENT : 0;
-
- switch (xevent.type) {
- case ClientMessage:
- if (xevent.xclient.message_type == atoms->WM_PROTOCOLS) {
- const Atom protocol = (Atom)xevent.xclient.data.l[0];
- if (protocol == atoms->WM_DELETE_WINDOW) {
- event.type = PUGL_CLOSE;
- }
- } else if (xevent.xclient.message_type == atoms->PUGL_CLIENT_MSG) {
- event.type = PUGL_CLIENT;
- event.client.data1 = (uintptr_t)xevent.xclient.data.l[0];
- event.client.data2 = (uintptr_t)xevent.xclient.data.l[1];
- }
- break;
- case VisibilityNotify:
- view->visible = xevent.xvisibility.state != VisibilityFullyObscured;
- break;
- case MapNotify:
- event.type = PUGL_MAP;
- break;
- case UnmapNotify:
- event.type = PUGL_UNMAP;
- view->visible = false;
- break;
- case ConfigureNotify:
- event.type = PUGL_CONFIGURE;
- event.configure.x = xevent.xconfigure.x;
- event.configure.y = xevent.xconfigure.y;
- event.configure.width = xevent.xconfigure.width;
- event.configure.height = xevent.xconfigure.height;
- break;
- case Expose:
- event.type = PUGL_EXPOSE;
- event.expose.x = xevent.xexpose.x;
- event.expose.y = xevent.xexpose.y;
- event.expose.width = xevent.xexpose.width;
- event.expose.height = xevent.xexpose.height;
- break;
- case MotionNotify:
- event.type = PUGL_MOTION;
- event.motion.time = (double)xevent.xmotion.time / 1e3;
- event.motion.x = xevent.xmotion.x;
- event.motion.y = xevent.xmotion.y;
- event.motion.xRoot = xevent.xmotion.x_root;
- event.motion.yRoot = xevent.xmotion.y_root;
- event.motion.state = translateModifiers(xevent.xmotion.state);
- if (xevent.xmotion.is_hint == NotifyHint) {
- event.motion.flags |= PUGL_IS_HINT;
- }
- break;
- case ButtonPress:
- if (xevent.xbutton.button >= 4 && xevent.xbutton.button <= 7) {
- event.type = PUGL_SCROLL;
- event.scroll.time = (double)xevent.xbutton.time / 1e3;
- event.scroll.x = xevent.xbutton.x;
- event.scroll.y = xevent.xbutton.y;
- event.scroll.xRoot = xevent.xbutton.x_root;
- event.scroll.yRoot = xevent.xbutton.y_root;
- event.scroll.state = translateModifiers(xevent.xbutton.state);
- event.scroll.dx = 0.0;
- event.scroll.dy = 0.0;
- switch (xevent.xbutton.button) {
- case 4:
- event.scroll.dy = 1.0;
- event.scroll.direction = PUGL_SCROLL_UP;
- break;
- case 5:
- event.scroll.dy = -1.0;
- event.scroll.direction = PUGL_SCROLL_DOWN;
- break;
- case 6:
- event.scroll.dx = -1.0;
- event.scroll.direction = PUGL_SCROLL_LEFT;
- break;
- case 7:
- event.scroll.dx = 1.0;
- event.scroll.direction = PUGL_SCROLL_RIGHT;
- break;
- }
- // fallthru
- }
- // fallthru
- case ButtonRelease:
- if (xevent.xbutton.button < 4 || xevent.xbutton.button > 7) {
- event.button.type = ((xevent.type == ButtonPress)
- ? PUGL_BUTTON_PRESS
- : PUGL_BUTTON_RELEASE);
- event.button.time = (double)xevent.xbutton.time / 1e3;
- event.button.x = xevent.xbutton.x;
- event.button.y = xevent.xbutton.y;
- event.button.xRoot = xevent.xbutton.x_root;
- event.button.yRoot = xevent.xbutton.y_root;
- event.button.state = translateModifiers(xevent.xbutton.state);
- event.button.button = xevent.xbutton.button;
- }
- break;
- case KeyPress:
- case KeyRelease:
- event.type = ((xevent.type == KeyPress)
- ? PUGL_KEY_PRESS
- : PUGL_KEY_RELEASE);
- event.key.time = (double)xevent.xkey.time / 1e3;
- event.key.x = xevent.xkey.x;
- event.key.y = xevent.xkey.y;
- event.key.xRoot = xevent.xkey.x_root;
- event.key.yRoot = xevent.xkey.y_root;
- event.key.state = translateModifiers(xevent.xkey.state);
- translateKey(view, &xevent, &event);
- break;
- case EnterNotify:
- case LeaveNotify:
- event.type = ((xevent.type == EnterNotify)
- ? PUGL_POINTER_IN
- : PUGL_POINTER_OUT);
- event.crossing.time = (double)xevent.xcrossing.time / 1e3;
- event.crossing.x = xevent.xcrossing.x;
- event.crossing.y = xevent.xcrossing.y;
- event.crossing.xRoot = xevent.xcrossing.x_root;
- event.crossing.yRoot = xevent.xcrossing.y_root;
- event.crossing.state = translateModifiers(xevent.xcrossing.state);
- event.crossing.mode = PUGL_CROSSING_NORMAL;
- if (xevent.xcrossing.mode == NotifyGrab) {
- event.crossing.mode = PUGL_CROSSING_GRAB;
- } else if (xevent.xcrossing.mode == NotifyUngrab) {
- event.crossing.mode = PUGL_CROSSING_UNGRAB;
- }
- break;
-
- case FocusIn:
- case FocusOut:
- event.type = (xevent.type == FocusIn) ? PUGL_FOCUS_IN : PUGL_FOCUS_OUT;
- event.focus.mode = PUGL_CROSSING_NORMAL;
- if (xevent.xfocus.mode == NotifyGrab) {
- event.focus.mode = PUGL_CROSSING_GRAB;
- } else if (xevent.xfocus.mode == NotifyUngrab) {
- event.focus.mode = PUGL_CROSSING_UNGRAB;
- }
- break;
-
- default:
- break;
- }
-
- return event;
-}
-
-PuglStatus
-puglGrabFocus(PuglView* view)
-{
- XSetInputFocus(
- view->impl->display, view->impl->win, RevertToNone, CurrentTime);
- return PUGL_SUCCESS;
-}
-
-bool
-puglHasFocus(const PuglView* view)
-{
- int revertTo = 0;
- Window focusedWindow = 0;
- XGetInputFocus(view->impl->display, &focusedWindow, &revertTo);
- return focusedWindow == view->impl->win;
-}
-
-PuglStatus
-puglRequestAttention(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- const PuglX11Atoms* const atoms = &view->world->impl->atoms;
- XEvent event = {0};
-
- event.type = ClientMessage;
- event.xclient.window = impl->win;
- event.xclient.format = 32;
- event.xclient.message_type = atoms->NET_WM_STATE;
- event.xclient.data.l[0] = WM_STATE_ADD;
- event.xclient.data.l[1] = (long)atoms->NET_WM_STATE_DEMANDS_ATTENTION;
- event.xclient.data.l[2] = 0;
- event.xclient.data.l[3] = 1;
- event.xclient.data.l[4] = 0;
-
- const Window root = RootWindow(impl->display, impl->screen);
- XSendEvent(impl->display,
- root,
- False,
- SubstructureNotifyMask | SubstructureRedirectMask,
- &event);
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglStartTimer(PuglView* view, uintptr_t id, double timeout)
-{
-#ifdef HAVE_XSYNC
- if (view->world->impl->syncSupported) {
- XSyncValue value;
- XSyncIntToValue(&value, (int)floor(timeout * 1000.0));
-
- PuglWorldInternals* w = view->world->impl;
- Display* const display = w->display;
- const XSyncCounter counter = w->serverTimeCounter;
- const XSyncTestType type = XSyncPositiveTransition;
- const XSyncTrigger trigger = {counter, XSyncRelative, value, type};
- XSyncAlarmAttributes attr = {trigger, value, True, XSyncAlarmActive};
- const XSyncAlarm alarm = XSyncCreateAlarm(display, 0x17, &attr);
- const PuglTimer timer = {alarm, view, id};
-
- if (alarm != None) {
- for (size_t i = 0; i < w->numTimers; ++i) {
- if (w->timers[i].view == view && w->timers[i].id == id) {
- // Replace existing timer
- XSyncDestroyAlarm(w->display, w->timers[i].alarm);
- w->timers[i] = timer;
- return PUGL_SUCCESS;
- }
- }
-
- // Add new timer
- const size_t size = ++w->numTimers * sizeof(timer);
- w->timers = (PuglTimer*)realloc(w->timers, size);
- w->timers[w->numTimers - 1] = timer;
- return PUGL_SUCCESS;
- }
- }
-#else
- (void)view;
- (void)id;
- (void)timeout;
-#endif
-
- return PUGL_FAILURE;
-}
-
-PuglStatus
-puglStopTimer(PuglView* view, uintptr_t id)
-{
-#ifdef HAVE_XSYNC
- PuglWorldInternals* w = view->world->impl;
-
- for (size_t i = 0; i < w->numTimers; ++i) {
- if (w->timers[i].view == view && w->timers[i].id == id) {
- XSyncDestroyAlarm(w->display, w->timers[i].alarm);
-
- if (i == w->numTimers - 1) {
- memset(&w->timers[i], 0, sizeof(PuglTimer));
- } else {
- memmove(w->timers + i,
- w->timers + i + 1,
- sizeof(PuglTimer) * (w->numTimers - i - 1));
-
- memset(&w->timers[i], 0, sizeof(PuglTimer));
- }
-
- --w->numTimers;
- return PUGL_SUCCESS;
- }
- }
-#else
- (void)view;
- (void)id;
-#endif
-
- return PUGL_FAILURE;
-}
-
-static XEvent
-puglEventToX(PuglView* view, const PuglEvent* event)
-{
- XEvent xev = {0};
- xev.xany.send_event = True;
-
- switch (event->type) {
- case PUGL_EXPOSE: {
- const double x = floor(event->expose.x);
- const double y = floor(event->expose.y);
- const double w = ceil(event->expose.x + event->expose.width) - x;
- const double h = ceil(event->expose.y + event->expose.height) - y;
-
- xev.xexpose.type = Expose;
- xev.xexpose.serial = 0;
- xev.xexpose.display = view->impl->display;
- xev.xexpose.window = view->impl->win;
- xev.xexpose.x = (int)x;
- xev.xexpose.y = (int)y;
- xev.xexpose.width = (int)w;
- xev.xexpose.height = (int)h;
- break;
- }
-
- case PUGL_CLIENT:
- xev.xclient.type = ClientMessage;
- xev.xclient.serial = 0;
- xev.xclient.send_event = True;
- xev.xclient.display = view->impl->display;
- xev.xclient.window = view->impl->win;
- xev.xclient.message_type = view->world->impl->atoms.PUGL_CLIENT_MSG;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = (long)event->client.data1;
- xev.xclient.data.l[1] = (long)event->client.data2;
- break;
-
- default:
- break;
- }
-
- return xev;
-}
-
-PuglStatus
-puglSendEvent(PuglView* view, const PuglEvent* event)
-{
- XEvent xev = puglEventToX(view, event);
-
- if (xev.type) {
- if (XSendEvent(view->impl->display, view->impl->win, False, 0, &xev)) {
- return PUGL_SUCCESS;
- } else {
- return PUGL_UNKNOWN_ERROR;
- }
- }
-
- return PUGL_UNSUPPORTED_TYPE;
-}
-
-#ifndef PUGL_DISABLE_DEPRECATED
-PuglStatus
-puglWaitForEvent(PuglView* view)
-{
- XEvent xevent;
- XPeekEvent(view->impl->display, &xevent);
- return PUGL_SUCCESS;
-}
-#endif
-
-static void
-mergeExposeEvents(PuglEvent* dst, const PuglEvent* src)
-{
- if (!dst->type) {
- *dst = *src;
- } else {
- const double max_x = MAX(dst->expose.x + dst->expose.width,
- src->expose.x + src->expose.width);
- const double max_y = MAX(dst->expose.y + dst->expose.height,
- src->expose.y + src->expose.height);
-
- dst->expose.x = MIN(dst->expose.x, src->expose.x);
- dst->expose.y = MIN(dst->expose.y, src->expose.y);
- dst->expose.width = max_x - dst->expose.x;
- dst->expose.height = max_y - dst->expose.y;
- }
-}
-
-static void
-handleSelectionNotify(const PuglWorld* world, PuglView* view)
-{
- uint8_t* str = NULL;
- Atom type = 0;
- int fmt = 0;
- unsigned long len = 0;
- unsigned long left = 0;
-
- XGetWindowProperty(world->impl->display,
- view->impl->win,
- XA_PRIMARY,
- 0,
- 0x1FFFFFFF,
- False,
- AnyPropertyType,
- &type,
- &fmt,
- &len,
- &left,
- &str);
-
- if (str && fmt == 8 && type == world->impl->atoms.UTF8_STRING &&
- left == 0) {
- puglSetBlob(&view->clipboard, str, len);
- }
-
- XFree(str);
-}
-
-static void
-handleSelectionRequest(const PuglWorld* world,
- PuglView* view,
- const XSelectionRequestEvent* request)
-{
- XSelectionEvent note = {SelectionNotify,
- request->serial,
- False,
- world->impl->display,
- request->requestor,
- request->selection,
- request->target,
- None,
- request->time};
-
- const char* type = NULL;
- size_t len = 0;
- const void* data = puglGetInternalClipboard(view, &type, &len);
- if (data && request->selection == world->impl->atoms.CLIPBOARD &&
- request->target == world->impl->atoms.UTF8_STRING) {
- note.property = request->property;
- XChangeProperty(world->impl->display,
- note.requestor,
- note.property,
- note.target,
- 8,
- PropModeReplace,
- (const uint8_t*)data,
- (int)len);
- } else {
- note.property = None;
- }
-
- XSendEvent(world->impl->display, note.requestor, True, 0, (XEvent*)&note);
-}
-
-/// Flush pending configure and expose events for all views
-static void
-flushExposures(PuglWorld* world)
-{
- for (size_t i = 0; i < world->numViews; ++i) {
- PuglView* const view = world->views[i];
-
- if (view->visible) {
- puglDispatchSimpleEvent(view, PUGL_UPDATE);
- }
-
- const PuglEvent configure = view->impl->pendingConfigure;
- const PuglEvent expose = view->impl->pendingExpose;
-
- view->impl->pendingConfigure.type = PUGL_NOTHING;
- view->impl->pendingExpose.type = PUGL_NOTHING;
-
- if (configure.type || expose.type) {
- view->backend->enter(view, expose.type ? &expose.expose : NULL);
- puglDispatchEventInContext(view, &configure);
- puglDispatchEventInContext(view, &expose);
- view->backend->leave(view, expose.type ? &expose.expose : NULL);
- }
- }
-}
-
-static bool
-handleTimerEvent(PuglWorld* world, XEvent xevent)
-{
-#ifdef HAVE_XSYNC
- if (xevent.type == world->impl->syncEventBase + XSyncAlarmNotify) {
- XSyncAlarmNotifyEvent* notify = ((XSyncAlarmNotifyEvent*)&xevent);
-
- for (size_t i = 0; i < world->impl->numTimers; ++i) {
- if (world->impl->timers[i].alarm == notify->alarm) {
- PuglEvent event = {{PUGL_TIMER, 0}};
- event.timer.id = world->impl->timers[i].id;
- puglDispatchEvent(world->impl->timers[i].view,
- (const PuglEvent*)&event);
- }
- }
-
- return true;
- }
-#else
- (void)world;
- (void)xevent;
-#endif
-
- return false;
-}
-
-static PuglStatus
-puglDispatchX11Events(PuglWorld* world)
-{
- const PuglX11Atoms* const atoms = &world->impl->atoms;
-
- // Flush output to the server once at the start
- Display* display = world->impl->display;
- XFlush(display);
-
- // Process all queued events (without further flushing)
- while (XEventsQueued(display, QueuedAfterReading) > 0) {
- XEvent xevent;
- XNextEvent(display, &xevent);
-
- if (handleTimerEvent(world, xevent)) {
- continue;
- }
-
- PuglView* view = puglFindView(world, xevent.xany.window);
- if (!view) {
- continue;
- }
-
- // Handle special events
- PuglInternals* const impl = view->impl;
- if (xevent.type == KeyRelease && view->hints[PUGL_IGNORE_KEY_REPEAT]) {
- XEvent next;
- if (XCheckTypedWindowEvent(display, impl->win, KeyPress, &next) &&
- next.type == KeyPress &&
- next.xkey.time == xevent.xkey.time &&
- next.xkey.keycode == xevent.xkey.keycode) {
- continue;
- }
- } else if (xevent.type == FocusIn) {
- XSetICFocus(impl->xic);
- } else if (xevent.type == FocusOut) {
- XUnsetICFocus(impl->xic);
- } else if (xevent.type == SelectionClear) {
- puglSetBlob(&view->clipboard, NULL, 0);
- } else if (xevent.type == SelectionNotify &&
- xevent.xselection.selection == atoms->CLIPBOARD &&
- xevent.xselection.target == atoms->UTF8_STRING &&
- xevent.xselection.property == XA_PRIMARY) {
- handleSelectionNotify(world, view);
- } else if (xevent.type == SelectionRequest) {
- handleSelectionRequest(world, view, &xevent.xselectionrequest);
- }
-
- // Translate X11 event to Pugl event
- const PuglEvent event = translateEvent(view, xevent);
-
- if (event.type == PUGL_EXPOSE) {
- // Expand expose event to be dispatched after loop
- mergeExposeEvents(&view->impl->pendingExpose, &event);
- } else if (event.type == PUGL_CONFIGURE) {
- // Expand configure event to be dispatched after loop
- view->impl->pendingConfigure = event;
- view->frame.x = event.configure.x;
- view->frame.y = event.configure.y;
- view->frame.width = event.configure.width;
- view->frame.height = event.configure.height;
- } else if (event.type == PUGL_MAP && view->parent) {
- XWindowAttributes attrs;
- XGetWindowAttributes(view->impl->display, view->impl->win, &attrs);
-
- const PuglEventConfigure configure = {
- PUGL_CONFIGURE, 0, attrs.x, attrs.y, attrs.width, attrs.height};
-
- puglDispatchEvent(view, (const PuglEvent*)&configure);
- puglDispatchEvent(view, &event);
- } else {
- // Dispatch event to application immediately
- puglDispatchEvent(view, &event);
- }
- }
-
- return PUGL_SUCCESS;
-}
-
-#ifndef PUGL_DISABLE_DEPRECATED
-PuglStatus
-puglProcessEvents(PuglView* view)
-{
- return puglUpdate(view->world, 0.0);
-}
-#endif
-
-PuglStatus
-puglUpdate(PuglWorld* world, double timeout)
-{
- const double startTime = puglGetTime(world);
- PuglStatus st = PUGL_SUCCESS;
-
- world->impl->dispatchingEvents = true;
-
- if (timeout < 0.0) {
- st = puglPollX11Socket(world, timeout);
- st = st ? st : puglDispatchX11Events(world);
- } else if (timeout <= 0.001) {
- st = puglDispatchX11Events(world);
- } else {
- const double endTime = startTime + timeout - 0.001;
- for (double t = startTime; t < endTime; t = puglGetTime(world)) {
- if ((st = puglPollX11Socket(world, endTime - t)) ||
- (st = puglDispatchX11Events(world))) {
- break;
- }
- }
- }
-
- flushExposures(world);
-
- world->impl->dispatchingEvents = false;
-
- return st;
-}
-
-double
-puglGetTime(const PuglWorld* world)
-{
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return ((double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0) -
- world->startTime;
-}
-
-PuglStatus
-puglPostRedisplay(PuglView* view)
-{
- const PuglRect rect = { 0, 0, view->frame.width, view->frame.height };
-
- return puglPostRedisplayRect(view, rect);
-}
-
-PuglStatus
-puglPostRedisplayRect(PuglView* view, PuglRect rect)
-{
- const PuglEventExpose event = {
- PUGL_EXPOSE, 0, rect.x, rect.y, rect.width, rect.height
- };
-
- if (view->world->impl->dispatchingEvents) {
- // Currently dispatching events, add/expand expose for the loop end
- mergeExposeEvents(&view->impl->pendingExpose, (const PuglEvent*)&event);
- } else if (view->visible) {
- // Not dispatching events, send an X expose so we wake up next time
- return puglSendEvent(view, (const PuglEvent*)&event);
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglNativeView
-puglGetNativeWindow(PuglView* view)
-{
- return (PuglNativeView)view->impl->win;
-}
-
-PuglStatus
-puglSetWindowTitle(PuglView* view, const char* title)
-{
- Display* display = view->world->impl->display;
- const PuglX11Atoms* const atoms = &view->world->impl->atoms;
-
- puglSetString(&view->title, title);
-
- if (view->impl->win) {
- XStoreName(display, view->impl->win, title);
- XChangeProperty(display, view->impl->win, atoms->NET_WM_NAME,
- atoms->UTF8_STRING, 8, PropModeReplace,
- (const uint8_t*)title, (int)strlen(title));
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetFrame(PuglView* view, const PuglRect frame)
-{
- if (view->impl->win) {
- if (!XMoveResizeWindow(view->world->impl->display,
- view->impl->win,
- (int)frame.x,
- (int)frame.y,
- (unsigned)frame.width,
- (unsigned)frame.height)) {
- return PUGL_UNKNOWN_ERROR;
- }
- }
-
- view->frame = frame;
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglSetDefaultSize(PuglView* const view, const int width, const int height)
-{
- view->defaultWidth = width;
- view->defaultHeight = height;
- return updateSizeHints(view);
-}
-
-PuglStatus
-puglSetMinSize(PuglView* const view, const int width, const int height)
-{
- view->minWidth = width;
- view->minHeight = height;
- return updateSizeHints(view);
-}
-
-PuglStatus
-puglSetMaxSize(PuglView* const view, const int width, const int height)
-{
- view->minWidth = width;
- view->minHeight = height;
- return updateSizeHints(view);
-}
-
-PuglStatus
-puglSetAspectRatio(PuglView* const view,
- const int minX,
- const int minY,
- const int maxX,
- const int maxY)
-{
- view->minAspectX = minX;
- view->minAspectY = minY;
- view->maxAspectX = maxX;
- view->maxAspectY = maxY;
-
- return updateSizeHints(view);
-}
-
-PuglStatus
-puglSetTransientFor(PuglView* view, PuglNativeView parent)
-{
- Display* display = view->world->impl->display;
-
- view->transientParent = parent;
-
- if (view->impl->win) {
- XSetTransientForHint(display, view->impl->win,
- (Window)view->transientParent);
- }
-
- return PUGL_SUCCESS;
-}
-
-const void*
-puglGetClipboard(PuglView* const view,
- const char** const type,
- size_t* const len)
-{
- PuglInternals* const impl = view->impl;
- const PuglX11Atoms* const atoms = &view->world->impl->atoms;
-
- const Window owner = XGetSelectionOwner(impl->display, atoms->CLIPBOARD);
- if (owner != None && owner != impl->win) {
- // Clear internal selection
- puglSetBlob(&view->clipboard, NULL, 0);
-
- // Request selection from the owner
- XConvertSelection(impl->display,
- atoms->CLIPBOARD,
- atoms->UTF8_STRING,
- XA_PRIMARY,
- impl->win,
- CurrentTime);
-
- // Run event loop until data is received
- while (!view->clipboard.data) {
- puglUpdate(view->world, -1.0);
- }
- }
-
- return puglGetInternalClipboard(view, type, len);
-}
-
-PuglStatus
-puglSetClipboard(PuglView* const view,
- const char* const type,
- const void* const data,
- const size_t len)
-{
- PuglInternals* const impl = view->impl;
- const PuglX11Atoms* const atoms = &view->world->impl->atoms;
-
- PuglStatus st = puglSetInternalClipboard(view, type, data, len);
- if (st) {
- return st;
- }
-
- XSetSelectionOwner(impl->display, atoms->CLIPBOARD, impl->win, CurrentTime);
- return PUGL_SUCCESS;
-}
-
-#ifdef HAVE_XCURSOR
-static const unsigned cursor_nums[] = {
- XC_arrow, // ARROW
- XC_xterm, // CARET
- XC_crosshair, // CROSSHAIR
- XC_hand2, // HAND
- XC_pirate, // NO
- XC_sb_h_double_arrow, // LEFT_RIGHT
- XC_sb_v_double_arrow, // UP_DOWN
-};
-#endif
-
-PuglStatus
-puglSetCursor(PuglView* view, PuglCursor cursor)
-{
-#ifdef HAVE_XCURSOR
- PuglInternals* const impl = view->impl;
- const unsigned index = (unsigned)cursor;
- const unsigned count = sizeof(cursor_nums) / sizeof(cursor_nums[0]);
- if (index >= count) {
- return PUGL_BAD_PARAMETER;
- }
-
- const unsigned shape = cursor_nums[index];
- if (!impl->win || impl->cursorShape == shape) {
- return PUGL_SUCCESS;
- }
-
- impl->cursorShape = cursor_nums[index];
-
- return puglDefineCursorShape(view, impl->cursorShape);
-#else
- (void)view;
- (void)cursor;
- return PUGL_FAILURE;
-#endif
-}
diff --git a/pugl/detail/x11.h b/pugl/detail/x11.h
deleted file mode 100644
index b5ca75c..0000000
--- a/pugl/detail/x11.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file x11.h
- @brief Shared definitions for X11 implementation.
-*/
-
-#include "pugl/detail/types.h"
-#include "pugl/pugl.h"
-
-#include <X11/X.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-typedef struct {
- Atom CLIPBOARD;
- Atom UTF8_STRING;
- Atom WM_PROTOCOLS;
- Atom WM_DELETE_WINDOW;
- Atom PUGL_CLIENT_MSG;
- Atom NET_WM_NAME;
- Atom NET_WM_STATE;
- Atom NET_WM_STATE_DEMANDS_ATTENTION;
-} PuglX11Atoms;
-
-typedef struct {
- XID alarm;
- PuglView* view;
- uintptr_t id;
-} PuglTimer;
-
-struct PuglWorldInternalsImpl {
- Display* display;
- PuglX11Atoms atoms;
- XIM xim;
- PuglTimer* timers;
- size_t numTimers;
- XID serverTimeCounter;
- int syncEventBase;
- bool syncSupported;
- bool dispatchingEvents;
-};
-
-struct PuglInternalsImpl {
- Display* display;
- XVisualInfo* vi;
- Window win;
- XIC xic;
- PuglSurface* surface;
- PuglEvent pendingConfigure;
- PuglEvent pendingExpose;
- int screen;
-#ifdef HAVE_XCURSOR
- unsigned cursorShape;
-#endif
-};
-
-PuglStatus puglX11StubConfigure(PuglView* view);
diff --git a/pugl/detail/x11_cairo.c b/pugl/detail/x11_cairo.c
deleted file mode 100644
index 0112c4e..0000000
--- a/pugl/detail/x11_cairo.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file x11_cairo.c
- @brief Cairo graphics backend for X11.
-*/
-
-#include "pugl/detail/types.h"
-#include "pugl/detail/x11.h"
-#include "pugl/pugl.h"
-#include "pugl/pugl_cairo.h"
-
-#include <X11/Xutil.h>
-#include <cairo-xlib.h>
-#include <cairo.h>
-
-#include <stdlib.h>
-
-typedef struct {
- cairo_surface_t* back;
- cairo_surface_t* front;
- cairo_t* cr;
-} PuglX11CairoSurface;
-
-static void
-puglX11CairoClose(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
-
- cairo_surface_destroy(surface->front);
- cairo_surface_destroy(surface->back);
- surface->front = surface->back = NULL;
-}
-
-static PuglStatus
-puglX11CairoOpen(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
-
- surface->back = cairo_xlib_surface_create(impl->display,
- impl->win,
- impl->vi->visual,
- (int)view->frame.width,
- (int)view->frame.height);
-
- surface->front = cairo_surface_create_similar(
- surface->back,
- cairo_surface_get_content(surface->back),
- (int)view->frame.width,
- (int)view->frame.height);
-
- if (cairo_surface_status(surface->back) ||
- cairo_surface_status(surface->front)) {
- puglX11CairoClose(view);
- return PUGL_CREATE_CONTEXT_FAILED;
- }
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglX11CairoCreate(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
-
- impl->surface = (cairo_surface_t*)calloc(1, sizeof(PuglX11CairoSurface));
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglX11CairoDestroy(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
-
- puglX11CairoClose(view);
- free(surface);
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglX11CairoEnter(PuglView* view, const PuglEventExpose* expose)
-{
- PuglInternals* const impl = view->impl;
- PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
- PuglStatus st = PUGL_SUCCESS;
-
- if (expose && !(st = puglX11CairoOpen(view))) {
- surface->cr = cairo_create(surface->front);
-
- if (cairo_status(surface->cr)) {
- st = PUGL_CREATE_CONTEXT_FAILED;
- }
- }
-
- return st;
-}
-
-static PuglStatus
-puglX11CairoLeave(PuglView* view, const PuglEventExpose* expose)
-{
- PuglInternals* const impl = view->impl;
- PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
-
- if (expose) {
- // Destroy front context and create a new one for drawing to the back
- cairo_destroy(surface->cr);
- surface->cr = cairo_create(surface->back);
-
- // Clip to expose region
- cairo_rectangle(surface->cr,
- expose->x,
- expose->y,
- expose->width,
- expose->height);
- cairo_clip(surface->cr);
-
- // Paint front onto back
- cairo_set_source_surface(surface->cr, surface->front, 0, 0);
- cairo_paint(surface->cr);
-
- // Flush to X and close everything
- cairo_destroy(surface->cr);
- cairo_surface_flush(surface->back);
- puglX11CairoClose(view);
- surface->cr = NULL;
- }
-
- return PUGL_SUCCESS;
-}
-
-static void*
-puglX11CairoGetContext(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
-
- return surface->cr;
-}
-
-const PuglBackend*
-puglCairoBackend(void)
-{
- static const PuglBackend backend = {puglX11StubConfigure,
- puglX11CairoCreate,
- puglX11CairoDestroy,
- puglX11CairoEnter,
- puglX11CairoLeave,
- puglX11CairoGetContext};
-
- return &backend;
-}
diff --git a/pugl/detail/x11_gl.c b/pugl/detail/x11_gl.c
deleted file mode 100644
index b756355..0000000
--- a/pugl/detail/x11_gl.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file x11_gl.c
- @brief OpenGL graphics backend for X11.
-*/
-
-#include "pugl/detail/stub.h"
-#include "pugl/detail/types.h"
-#include "pugl/detail/x11.h"
-#include "pugl/pugl.h"
-#include "pugl/pugl_gl.h"
-
-#include <GL/glx.h>
-#include <X11/X.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-typedef struct {
- GLXFBConfig fb_config;
- GLXContext ctx;
-} PuglX11GlSurface;
-
-static int
-puglX11GlHintValue(const int value)
-{
- return value == PUGL_DONT_CARE ? (int)GLX_DONT_CARE : value;
-}
-
-static int
-puglX11GlGetAttrib(Display* const display,
- GLXFBConfig fb_config,
- const int attrib)
-{
- int value = 0;
- glXGetFBConfigAttrib(display, fb_config, attrib, &value);
- return value;
-}
-
-static PuglStatus
-puglX11GlConfigure(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- const int screen = impl->screen;
- Display* const display = impl->display;
-
- PuglX11GlSurface* const surface =
- (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface));
- impl->surface = surface;
-
- const int attrs[] = {
- GLX_X_RENDERABLE, True,
- GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
- GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
- GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_SAMPLES, puglX11GlHintValue(view->hints[PUGL_SAMPLES]),
- GLX_RED_SIZE, puglX11GlHintValue(view->hints[PUGL_RED_BITS]),
- GLX_GREEN_SIZE, puglX11GlHintValue(view->hints[PUGL_GREEN_BITS]),
- GLX_BLUE_SIZE, puglX11GlHintValue(view->hints[PUGL_BLUE_BITS]),
- GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints[PUGL_ALPHA_BITS]),
- GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints[PUGL_DEPTH_BITS]),
- GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints[PUGL_STENCIL_BITS]),
- GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints[PUGL_DOUBLE_BUFFER]),
- None
- };
-
- int n_fbc = 0;
- GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc);
- if (n_fbc <= 0) {
- return PUGL_CREATE_CONTEXT_FAILED;
- }
-
- surface->fb_config = fbc[0];
- impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]);
-
- view->hints[PUGL_RED_BITS] = puglX11GlGetAttrib(
- display, fbc[0], GLX_RED_SIZE);
- view->hints[PUGL_GREEN_BITS] = puglX11GlGetAttrib(
- display, fbc[0], GLX_GREEN_SIZE);
- view->hints[PUGL_BLUE_BITS] = puglX11GlGetAttrib(
- display, fbc[0], GLX_BLUE_SIZE);
- view->hints[PUGL_ALPHA_BITS] = puglX11GlGetAttrib(
- display, fbc[0], GLX_ALPHA_SIZE);
- view->hints[PUGL_DEPTH_BITS] = puglX11GlGetAttrib(
- display, fbc[0], GLX_DEPTH_SIZE);
- view->hints[PUGL_STENCIL_BITS] = puglX11GlGetAttrib(
- display, fbc[0], GLX_STENCIL_SIZE);
- view->hints[PUGL_SAMPLES] = puglX11GlGetAttrib(
- display, fbc[0], GLX_SAMPLES);
- view->hints[PUGL_DOUBLE_BUFFER] = puglX11GlGetAttrib(
- display, fbc[0], GLX_DOUBLEBUFFER);
-
- char msg[256];
-
- snprintf(
- msg,
- sizeof(msg),
- "Using visual 0x%lX: R=%d G=%d B=%d A=%d D=%d DOUBLE=%d SAMPLES=%d\n",
- impl->vi->visualid,
- puglX11GlGetAttrib(display, fbc[0], GLX_RED_SIZE),
- puglX11GlGetAttrib(display, fbc[0], GLX_GREEN_SIZE),
- puglX11GlGetAttrib(display, fbc[0], GLX_BLUE_SIZE),
- puglX11GlGetAttrib(display, fbc[0], GLX_ALPHA_SIZE),
- puglX11GlGetAttrib(display, fbc[0], GLX_DEPTH_SIZE),
- puglX11GlGetAttrib(display, fbc[0], GLX_DOUBLEBUFFER),
- puglX11GlGetAttrib(display, fbc[0], GLX_SAMPLES));
-
- view->world->logFunc(view->world, PUGL_LOG_LEVEL_INFO, msg);
-
- XFree(fbc);
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglX11GlEnter(PuglView* view, const PuglEventExpose* PUGL_UNUSED(expose))
-{
- PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
- glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx);
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglX11GlLeave(PuglView* view, const PuglEventExpose* expose)
-{
- if (expose && view->hints[PUGL_DOUBLE_BUFFER]) {
- glXSwapBuffers(view->impl->display, view->impl->win);
- }
-
- glXMakeCurrent(view->impl->display, None, NULL);
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglX11GlCreate(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface;
- Display* const display = impl->display;
- GLXFBConfig fb_config = surface->fb_config;
-
- const int ctx_attrs[] = {
- GLX_CONTEXT_MAJOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MAJOR],
- GLX_CONTEXT_MINOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MINOR],
- GLX_CONTEXT_FLAGS_ARB, (view->hints[PUGL_USE_DEBUG_CONTEXT]
- ? GLX_CONTEXT_DEBUG_BIT_ARB
- : 0),
- GLX_CONTEXT_PROFILE_MASK_ARB, (view->hints[PUGL_USE_COMPAT_PROFILE]
- ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
- : GLX_CONTEXT_CORE_PROFILE_BIT_ARB),
- 0};
-
- PFNGLXCREATECONTEXTATTRIBSARBPROC create_context =
- (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress(
- (const uint8_t*)"glXCreateContextAttribsARB");
-
- PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
- (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress(
- (const uint8_t*)"glXSwapIntervalEXT");
-
- surface->ctx = create_context(display, fb_config, 0, True, ctx_attrs);
- if (!surface->ctx) {
- surface->ctx =
- glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True);
- }
-
- if (!surface->ctx) {
- return PUGL_CREATE_CONTEXT_FAILED;
- }
-
- const int swapInterval = view->hints[PUGL_SWAP_INTERVAL];
- if (glXSwapIntervalEXT && swapInterval != PUGL_DONT_CARE) {
- puglX11GlEnter(view, NULL);
- glXSwapIntervalEXT(display, impl->win, swapInterval);
- puglX11GlLeave(view, NULL);
- }
-
- glXGetConfig(impl->display,
- impl->vi,
- GLX_DOUBLEBUFFER,
- &view->hints[PUGL_DOUBLE_BUFFER]);
-
- glXQueryDrawable(display,
- impl->win,
- GLX_SWAP_INTERVAL_EXT,
- (unsigned int*)&view->hints[PUGL_SWAP_INTERVAL]);
-
- return PUGL_SUCCESS;
-}
-
-static PuglStatus
-puglX11GlDestroy(PuglView* view)
-{
- PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
- if (surface) {
- glXDestroyContext(view->impl->display, surface->ctx);
- free(surface);
- view->impl->surface = NULL;
- }
- return PUGL_SUCCESS;
-}
-
-PuglGlFunc
-puglGetProcAddress(const char* name)
-{
- return glXGetProcAddress((const uint8_t*)name);
-}
-
-const PuglBackend* puglGlBackend(void)
-{
- static const PuglBackend backend = {puglX11GlConfigure,
- puglX11GlCreate,
- puglX11GlDestroy,
- puglX11GlEnter,
- puglX11GlLeave,
- puglStubGetContext};
-
- return &backend;
-}
diff --git a/pugl/detail/x11_stub.c b/pugl/detail/x11_stub.c
deleted file mode 100644
index 8efd68f..0000000
--- a/pugl/detail/x11_stub.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-#include "pugl/pugl_stub.h"
-
-#include "pugl/detail/stub.h"
-#include "pugl/detail/types.h"
-#include "pugl/detail/x11.h"
-
-PuglStatus
-puglX11StubConfigure(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- XVisualInfo pat = {0};
- int n = 0;
-
- pat.screen = impl->screen;
- impl->vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n);
-
- view->hints[PUGL_RED_BITS] = impl->vi->bits_per_rgb;
- view->hints[PUGL_GREEN_BITS] = impl->vi->bits_per_rgb;
- view->hints[PUGL_BLUE_BITS] = impl->vi->bits_per_rgb;
- view->hints[PUGL_ALPHA_BITS] = 0;
-
- return PUGL_SUCCESS;
-}
-
-const PuglBackend*
-puglStubBackend(void)
-{
- static const PuglBackend backend = {
- puglX11StubConfigure,
- puglStubCreate,
- puglStubDestroy,
- puglStubEnter,
- puglStubLeave,
- puglStubGetContext,
- };
-
- return &backend;
-}
diff --git a/pugl/gl.h b/pugl/gl.h
deleted file mode 100644
index 9f7a741..0000000
--- a/pugl/gl.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file gl.h
- @brief Portable header wrapper for gl.h.
-
- Unfortunately, GL includes vary across platforms so this header allows for
- pure portable programs.
-*/
-
-// IWYU pragma: begin_exports
-
-#ifdef __APPLE__
-# include "OpenGL/gl.h"
-#else
-# ifdef _WIN32
-# include <windows.h> /* Broken Windows GL headers require this */
-# endif
-# include "GL/gl.h"
-#endif
-
-// IWYU pragma: end_exports
diff --git a/pugl/glu.h b/pugl/glu.h
deleted file mode 100644
index 423a917..0000000
--- a/pugl/glu.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file glu.h
- @brief Portable header wrapper for glu.h.
-
- Unfortunately, GL includes vary across platforms so this header allows for
- pure portable programs.
-*/
-
-// IWYU pragma: begin_exports
-
-#ifdef __APPLE__
-# include "OpenGL/glu.h"
-#else
-# ifdef _WIN32
-# include <windows.h> /* Broken Windows GL headers require this */
-# endif
-# include "GL/glu.h"
-#endif
-
-// IWYU pragma: end_exports
diff --git a/pugl/pugl.h b/pugl/pugl.h
deleted file mode 100644
index ad24c0d..0000000
--- a/pugl/pugl.h
+++ /dev/null
@@ -1,1624 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file pugl.h
- @brief Pugl API.
-*/
-
-#ifndef PUGL_PUGL_H
-#define PUGL_PUGL_H
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef PUGL_SHARED
-# ifdef _WIN32
-# define PUGL_LIB_IMPORT __declspec(dllimport)
-# define PUGL_LIB_EXPORT __declspec(dllexport)
-# else
-# define PUGL_LIB_IMPORT __attribute__((visibility("default")))
-# define PUGL_LIB_EXPORT __attribute__((visibility("default")))
-# endif
-# ifdef PUGL_INTERNAL
-# define PUGL_API PUGL_LIB_EXPORT
-# else
-# define PUGL_API PUGL_LIB_IMPORT
-# endif
-#else
-# define PUGL_API
-#endif
-
-#ifndef PUGL_DISABLE_DEPRECATED
-# if defined(__clang__)
-# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("", rep)))
-# elif defined(__GNUC__)
-# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("Use " rep)))
-# else
-# define PUGL_DEPRECATED_BY(rep)
-# endif
-#endif
-
-#if defined(__GNUC__)
-# define PUGL_CONST_FUNC __attribute__((const))
-#else
-# define PUGL_CONST_FUNC
-#endif
-
-#ifdef __cplusplus
-# define PUGL_BEGIN_DECLS extern "C" {
-# define PUGL_END_DECLS }
-#else
-# define PUGL_BEGIN_DECLS
-# define PUGL_END_DECLS
-#endif
-
-PUGL_BEGIN_DECLS
-
-/**
- @defgroup pugl Pugl
- A minimal portable API for embeddable GUIs.
- @{
-
- @defgroup pugl_c C API
- Public C API.
- @{
-*/
-
-/**
- A rectangle.
-
- This is used to describe things like view position and size. Pugl generally
- uses coordinates where the top left corner is 0,0.
-*/
-typedef struct {
- double x;
- double y;
- double width;
- double height;
-} PuglRect;
-
-/**
- @defgroup events Events
-
- Event definitions.
-
- All updates to the view happen via events, which are dispatched to the
- view's event function by Pugl. Most events map directly to one from the
- underlying window system, but some are constructed by Pugl itself so there
- is not necessarily a direct correspondence.
-
- @{
-*/
-
-/**
- Keyboard modifier flags.
-*/
-typedef enum {
- PUGL_MOD_SHIFT = 1u << 0u, ///< Shift key
- PUGL_MOD_CTRL = 1u << 1u, ///< Control key
- PUGL_MOD_ALT = 1u << 2u, ///< Alt/Option key
- PUGL_MOD_SUPER = 1u << 3u ///< Mod4/Command/Windows key
-} PuglMod;
-
-/**
- Bitwise OR of #PuglMod values.
-*/
-typedef uint32_t PuglMods;
-
-/**
- Keyboard key codepoints.
-
- All keys are identified by a Unicode code point in PuglEventKey::key. This
- enumeration defines constants for special keys that do not have a standard
- code point, and some convenience constants for control characters. Note
- that all keys are handled in the same way, this enumeration is just for
- convenience when writing hard-coded key bindings.
-
- Keys that do not have a standard code point use values in the Private Use
- Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). Applications
- must take care to not interpret these values beyond key detection, the
- mapping used here is arbitrary and specific to Pugl.
-*/
-typedef enum {
- // ASCII control codes
- PUGL_KEY_BACKSPACE = 0x08,
- PUGL_KEY_ESCAPE = 0x1B,
- PUGL_KEY_DELETE = 0x7F,
-
- // Unicode Private Use Area
- PUGL_KEY_F1 = 0xE000,
- PUGL_KEY_F2,
- PUGL_KEY_F3,
- PUGL_KEY_F4,
- PUGL_KEY_F5,
- PUGL_KEY_F6,
- PUGL_KEY_F7,
- PUGL_KEY_F8,
- PUGL_KEY_F9,
- PUGL_KEY_F10,
- PUGL_KEY_F11,
- PUGL_KEY_F12,
- PUGL_KEY_LEFT,
- PUGL_KEY_UP,
- PUGL_KEY_RIGHT,
- PUGL_KEY_DOWN,
- PUGL_KEY_PAGE_UP,
- PUGL_KEY_PAGE_DOWN,
- PUGL_KEY_HOME,
- PUGL_KEY_END,
- PUGL_KEY_INSERT,
- PUGL_KEY_SHIFT,
- PUGL_KEY_SHIFT_L = PUGL_KEY_SHIFT,
- PUGL_KEY_SHIFT_R,
- PUGL_KEY_CTRL,
- PUGL_KEY_CTRL_L = PUGL_KEY_CTRL,
- PUGL_KEY_CTRL_R,
- PUGL_KEY_ALT,
- PUGL_KEY_ALT_L = PUGL_KEY_ALT,
- PUGL_KEY_ALT_R,
- PUGL_KEY_SUPER,
- PUGL_KEY_SUPER_L = PUGL_KEY_SUPER,
- PUGL_KEY_SUPER_R,
- PUGL_KEY_MENU,
- PUGL_KEY_CAPS_LOCK,
- PUGL_KEY_SCROLL_LOCK,
- PUGL_KEY_NUM_LOCK,
- PUGL_KEY_PRINT_SCREEN,
- PUGL_KEY_PAUSE
-} PuglKey;
-
-/**
- The type of a PuglEvent.
-*/
-typedef enum {
- PUGL_NOTHING, ///< No event
- PUGL_CREATE, ///< View created, a #PuglEventCreate
- PUGL_DESTROY, ///< View destroyed, a #PuglEventDestroy
- PUGL_CONFIGURE, ///< View moved/resized, a #PuglEventConfigure
- PUGL_MAP, ///< View made visible, a #PuglEventMap
- PUGL_UNMAP, ///< View made invisible, a #PuglEventUnmap
- PUGL_UPDATE, ///< View ready to draw, a #PuglEventUpdate
- PUGL_EXPOSE, ///< View must be drawn, a #PuglEventExpose
- PUGL_CLOSE, ///< View will be closed, a #PuglEventClose
- PUGL_FOCUS_IN, ///< Keyboard focus entered view, a #PuglEventFocus
- PUGL_FOCUS_OUT, ///< Keyboard focus left view, a #PuglEventFocus
- PUGL_KEY_PRESS, ///< Key pressed, a #PuglEventKey
- PUGL_KEY_RELEASE, ///< Key released, a #PuglEventKey
- PUGL_TEXT, ///< Character entered, a #PuglEventText
- PUGL_POINTER_IN, ///< Pointer entered view, a #PuglEventCrossing
- PUGL_POINTER_OUT, ///< Pointer left view, a #PuglEventCrossing
- PUGL_BUTTON_PRESS, ///< Mouse button pressed, a #PuglEventButton
- PUGL_BUTTON_RELEASE, ///< Mouse button released, a #PuglEventButton
- PUGL_MOTION, ///< Pointer moved, a #PuglEventMotion
- PUGL_SCROLL, ///< Scrolled, a #PuglEventScroll
- PUGL_CLIENT, ///< Custom client message, a #PuglEventClient
- PUGL_TIMER, ///< Timer triggered, a #PuglEventTimer
-
-#ifndef PUGL_DISABLE_DEPRECATED
- PUGL_ENTER_NOTIFY PUGL_DEPRECATED_BY("PUGL_POINTER_IN") = PUGL_POINTER_IN,
- PUGL_LEAVE_NOTIFY PUGL_DEPRECATED_BY("PUGL_POINTER_OUT") = PUGL_POINTER_OUT,
- PUGL_MOTION_NOTIFY PUGL_DEPRECATED_BY("PUGL_MOTION") = PUGL_MOTION,
-#endif
-
-} PuglEventType;
-
-/**
- Common flags for all event types.
-*/
-typedef enum {
- PUGL_IS_SEND_EVENT = 1, ///< Event is synthetic
- PUGL_IS_HINT = 2 ///< Event is a hint (not direct user input)
-} PuglEventFlag;
-
-/**
- Bitwise OR of #PuglEventFlag values.
-*/
-typedef uint32_t PuglEventFlags;
-
-/**
- Reason for a PuglEventCrossing.
-*/
-typedef enum {
- PUGL_CROSSING_NORMAL, ///< Crossing due to pointer motion
- PUGL_CROSSING_GRAB, ///< Crossing due to a grab
- PUGL_CROSSING_UNGRAB ///< Crossing due to a grab release
-} PuglCrossingMode;
-
-/**
- Scroll direction.
-
- Describes the direction of a #PuglEventScroll along with whether the scroll
- is a "smooth" scroll. The discrete directions are for devices like mouse
- wheels with constrained axes, while a smooth scroll is for those with
- arbitrary scroll direction freedom, like some touchpads.
-*/
-typedef enum {
- PUGL_SCROLL_UP, ///< Scroll up
- PUGL_SCROLL_DOWN, ///< Scroll down
- PUGL_SCROLL_LEFT, ///< Scroll left
- PUGL_SCROLL_RIGHT, ///< Scroll right
- PUGL_SCROLL_SMOOTH ///< Smooth scroll in any direction
-} PuglScrollDirection;
-
-/**
- Common header for all event structs.
-*/
-typedef struct {
- PuglEventType type; ///< Event type
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
-} PuglEventAny;
-
-/**
- View create event.
-
- This event is sent when a view is realized before it is first displayed,
- with the graphics context entered. This is typically used for setting up
- the graphics system, for example by loading OpenGL extensions.
-
- This event type has no extra fields.
-*/
-typedef PuglEventAny PuglEventCreate;
-
-/**
- View destroy event.
-
- This event is the counterpart to #PuglEventCreate, and it is sent when the
- view is being destroyed. This is typically used for tearing down the
- graphics system, or otherwise freeing any resources allocated when the
- create event was handled.
-
- This is the last event sent to any view, and immediately after it is
- processed, the view is destroyed and may no longer be used.
-
- This event type has no extra fields.
-*/
-typedef PuglEventAny PuglEventDestroy;
-
-/**
- View resize or move event.
-
- A configure event is sent whenever the view is resized or moved. When a
- configure event is received, the graphics context is active but not set up
- for drawing. For example, it is valid to adjust the OpenGL viewport or
- otherwise configure the context, but not to draw anything.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_CONFIGURE
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- double x; ///< New parent-relative X coordinate
- double y; ///< New parent-relative Y coordinate
- double width; ///< New width
- double height; ///< New height
-} PuglEventConfigure;
-
-/**
- View show event.
-
- This event is sent when a view is mapped to the screen and made visible.
-
- This event type has no extra fields.
-*/
-typedef PuglEventAny PuglEventMap;
-
-/**
- View hide event.
-
- This event is sent when a view is unmapped from the screen and made
- invisible.
-
- This event type has no extra fields.
-*/
-typedef PuglEventAny PuglEventUnmap;
-
-/**
- View update event.
-
- This event is sent to every view near the end of a main loop iteration when
- any pending exposures are about to be redrawn. It is typically used to mark
- regions to expose with puglPostRedisplay() or puglPostRedisplayRect(). For
- example, to continuously animate, a view calls puglPostRedisplay() when an
- update event is received, and it will then shortly receive an expose event.
-*/
-typedef PuglEventAny PuglEventUpdate;
-
-/**
- Expose event for when a region must be redrawn.
-
- When an expose event is received, the graphics context is active, and the
- view must draw the entire specified region. The contents of the region are
- undefined, there is no preservation of anything drawn previously.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_EXPOSE
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- double x; ///< View-relative X coordinate
- double y; ///< View-relative Y coordinate
- double width; ///< Width of exposed region
- double height; ///< Height of exposed region
-} PuglEventExpose;
-
-/**
- View close event.
-
- This event is sent when the view is to be closed, for example when the user
- clicks the close button.
-
- This event type has no extra fields.
-*/
-typedef PuglEventAny PuglEventClose;
-
-/**
- Keyboard focus event.
-
- This event is sent whenever the view gains or loses the keyboard focus. The
- view with the keyboard focus will receive any key press or release events.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_FOCUS_IN or #PUGL_FOCUS_OUT
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- PuglCrossingMode mode; ///< Reason for focus change
-} PuglEventFocus;
-
-/**
- Key press or release event.
-
- This event represents low-level key presses and releases. This can be used
- for "direct" keyboard handing like key bindings, but must not be interpreted
- as text input.
-
- Keys are represented portably as Unicode code points, using the "natural"
- code point for the key where possible (see #PuglKey for details). The `key`
- field is the code for the pressed key, without any modifiers applied. For
- example, a press or release of the 'A' key will have `key` 97 ('a')
- regardless of whether shift or control are being held.
-
- Alternatively, the raw `keycode` can be used to work directly with physical
- keys, but note that this value is not portable and differs between platforms
- and hardware.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_KEY_PRESS or #PUGL_KEY_RELEASE
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- double time; ///< Time in seconds
- double x; ///< View-relative X coordinate
- double y; ///< View-relative Y coordinate
- double xRoot; ///< Root-relative X coordinate
- double yRoot; ///< Root-relative Y coordinate
- PuglMods state; ///< Bitwise OR of #PuglMod flags
- uint32_t keycode; ///< Raw key code
- uint32_t key; ///< Unshifted Unicode character code, or 0
-} PuglEventKey;
-
-/**
- Character input event.
-
- This event represents text input, usually as the result of a key press. The
- text is given both as a Unicode character code and a UTF-8 string.
-
- Note that this event is generated by the platform's input system, so there
- is not necessarily a direct correspondence between text events and physical
- key presses. For example, with some input methods a sequence of several key
- presses will generate a single character.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_TEXT
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- double time; ///< Time in seconds
- double x; ///< View-relative X coordinate
- double y; ///< View-relative Y coordinate
- double xRoot; ///< Root-relative X coordinate
- double yRoot; ///< Root-relative Y coordinate
- PuglMods state; ///< Bitwise OR of #PuglMod flags
- uint32_t keycode; ///< Raw key code
- uint32_t character; ///< Unicode character code
- char string[8]; ///< UTF-8 string
-} PuglEventText;
-
-/**
- Pointer enter or leave event.
-
- This event is sent when the pointer enters or leaves the view. This can
- happen for several reasons (not just the user dragging the pointer over the
- window edge), as described by the `mode` field.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_POINTER_IN or #PUGL_POINTER_OUT
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- double time; ///< Time in seconds
- double x; ///< View-relative X coordinate
- double y; ///< View-relative Y coordinate
- double xRoot; ///< Root-relative X coordinate
- double yRoot; ///< Root-relative Y coordinate
- PuglMods state; ///< Bitwise OR of #PuglMod flags
- PuglCrossingMode mode; ///< Reason for crossing
-} PuglEventCrossing;
-
-/**
- Button press or release event.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_BUTTON_PRESS or #PUGL_BUTTON_RELEASE
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- double time; ///< Time in seconds
- double x; ///< View-relative X coordinate
- double y; ///< View-relative Y coordinate
- double xRoot; ///< Root-relative X coordinate
- double yRoot; ///< Root-relative Y coordinate
- PuglMods state; ///< Bitwise OR of #PuglMod flags
- uint32_t button; ///< Button number starting from 1
-} PuglEventButton;
-
-/**
- Pointer motion event.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_MOTION
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- double time; ///< Time in seconds
- double x; ///< View-relative X coordinate
- double y; ///< View-relative Y coordinate
- double xRoot; ///< Root-relative X coordinate
- double yRoot; ///< Root-relative Y coordinate
- PuglMods state; ///< Bitwise OR of #PuglMod flags
-} PuglEventMotion;
-
-/**
- Scroll event.
-
- The scroll distance is expressed in "lines", an arbitrary unit that
- corresponds to a single tick of a detented mouse wheel. For example, `dy` =
- 1.0 scrolls 1 line up. Some systems and devices support finer resolution
- and/or higher values for fast scrolls, so programs should handle any value
- gracefully.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_SCROLL
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- double time; ///< Time in seconds
- double x; ///< View-relative X coordinate
- double y; ///< View-relative Y coordinate
- double xRoot; ///< Root-relative X coordinate
- double yRoot; ///< Root-relative Y coordinate
- PuglMods state; ///< Bitwise OR of #PuglMod flags
- PuglScrollDirection direction; ///< Scroll direction
- double dx; ///< Scroll X distance in lines
- double dy; ///< Scroll Y distance in lines
-} PuglEventScroll;
-
-/**
- Custom client message event.
-
- This can be used to send a custom message to a view, which is delivered via
- the window system and processed in the event loop as usual. Among other
- things, this makes it possible to wake up the event loop for any reason.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_CLIENT
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- uintptr_t data1; ///< Client-specific data
- uintptr_t data2; ///< Client-specific data
-} PuglEventClient;
-
-/**
- Timer event.
-
- This event is sent at the regular interval specified in the call to
- puglStartTimer() that activated it.
-
- The `id` is the application-specific ID given to puglStartTimer() which
- distinguishes this timer from others. It should always be checked in the
- event handler, even in applications that register only one timer.
-*/
-typedef struct {
- PuglEventType type; ///< #PUGL_TIMER
- PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
- uintptr_t id; ///< Timer ID
-} PuglEventTimer;
-
-/**
- View event.
-
- This is a union of all event types. The type must be checked to determine
- which fields are safe to access. A pointer to PuglEvent can either be cast
- to the appropriate type, or the union members used.
-
- The graphics system may only be accessed when handling certain events. The
- graphics context is active for #PUGL_CREATE, #PUGL_DESTROY, #PUGL_CONFIGURE,
- and #PUGL_EXPOSE, but only enabled for drawing for #PUGL_EXPOSE.
-*/
-typedef union {
- PuglEventAny any; ///< Valid for all event types
- PuglEventType type; ///< Event type
- PuglEventButton button; ///< #PUGL_BUTTON_PRESS, #PUGL_BUTTON_RELEASE
- PuglEventConfigure configure; ///< #PUGL_CONFIGURE
- PuglEventExpose expose; ///< #PUGL_EXPOSE
- PuglEventKey key; ///< #PUGL_KEY_PRESS, #PUGL_KEY_RELEASE
- PuglEventText text; ///< #PUGL_TEXT
- PuglEventCrossing crossing; ///< #PUGL_POINTER_IN, #PUGL_POINTER_OUT
- PuglEventMotion motion; ///< #PUGL_MOTION
- PuglEventScroll scroll; ///< #PUGL_SCROLL
- PuglEventFocus focus; ///< #PUGL_FOCUS_IN, #PUGL_FOCUS_OUT
- PuglEventClient client; ///< #PUGL_CLIENT
- PuglEventTimer timer; ///< #PUGL_TIMER
-} PuglEvent;
-
-/**
- @}
- @defgroup status Status
-
- Status codes and error handling.
-
- @{
-*/
-
-/**
- Return status code.
-*/
-typedef enum {
- PUGL_SUCCESS, ///< Success
- PUGL_FAILURE, ///< Non-fatal failure
- PUGL_UNKNOWN_ERROR, ///< Unknown system error
- PUGL_BAD_BACKEND, ///< Invalid or missing backend
- PUGL_BAD_CONFIGURATION, ///< Invalid view configuration
- PUGL_BAD_PARAMETER, ///< Invalid parameter
- PUGL_BACKEND_FAILED, ///< Backend initialisation failed
- PUGL_REGISTRATION_FAILED, ///< Class registration failed
- PUGL_REALIZE_FAILED, ///< System view realization failed
- PUGL_SET_FORMAT_FAILED, ///< Failed to set pixel format
- PUGL_CREATE_CONTEXT_FAILED, ///< Failed to create drawing context
- PUGL_UNSUPPORTED_TYPE, ///< Unsupported data type
-} PuglStatus;
-
-/**
- Return a string describing a status code.
-*/
-PUGL_API PUGL_CONST_FUNC
-const char*
-puglStrerror(PuglStatus status);
-
-/**
- @}
- @defgroup world World
-
- The top-level context of a Pugl application or plugin.
-
- The world contains all library-wide state. There is no static data in Pugl,
- so it is safe to use multiple worlds in a single process. This is to
- facilitate plugins or other situations where it is not possible to share a
- world, but a single world should be shared for all views where possible.
-
- @{
-*/
-
-/**
- The "world" of application state.
-
- The world represents everything that is not associated with a particular
- view. Several worlds can be created in a single process, but code using
- different worlds must be isolated so they are never mixed. Views are
- strongly associated with the world they were created in.
-*/
-typedef struct PuglWorldImpl PuglWorld;
-
-/**
- Handle for the world's opaque user data.
-*/
-typedef void* PuglWorldHandle;
-
-/**
- The type of a World.
-*/
-typedef enum {
- PUGL_PROGRAM, ///< Top-level application
- PUGL_MODULE ///< Plugin or module within a larger application
-} PuglWorldType;
-
-/**
- World flags.
-*/
-typedef enum {
- /**
- Set up support for threads if necessary.
-
- - X11: Calls XInitThreads() which is required for some drivers.
- */
- PUGL_WORLD_THREADS = 1u << 0u
-} PuglWorldFlag;
-
-/**
- Bitwise OR of #PuglWorldFlag values.
-*/
-typedef uint32_t PuglWorldFlags;
-
-/**
- A log message level, compatible with syslog.
-*/
-typedef enum {
- PUGL_LOG_LEVEL_ERR = 3, ///< Error
- PUGL_LOG_LEVEL_WARNING = 4, ///< Warning
- PUGL_LOG_LEVEL_INFO = 6, ///< Informational message
- PUGL_LOG_LEVEL_DEBUG = 7 ///< Debug message
-} PuglLogLevel;
-
-/**
- A function called to report log messages.
-
- @param world The world that produced this log message.
- @param level Log level.
- @param msg Message string.
-*/
-typedef void (*PuglLogFunc)(PuglWorld* world,
- PuglLogLevel level,
- const char* msg);
-
-/**
- Create a new world.
-
- @param type The type, which dictates what this world is responsible for.
- @param flags Flags to control world features.
- @return A new world, which must be later freed with puglFreeWorld().
-*/
-PUGL_API PuglWorld*
-puglNewWorld(PuglWorldType type, PuglWorldFlags flags);
-
-/**
- Free a world allocated with puglNewWorld().
-*/
-PUGL_API void
-puglFreeWorld(PuglWorld* world);
-
-/**
- Set the user data for the world.
-
- This is usually a pointer to a struct that contains all the state which must
- be accessed by several views.
-
- The handle is opaque to Pugl and is not interpreted in any way.
-*/
-PUGL_API void
-puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle);
-
-/**
- Get the user data for the world.
-*/
-PUGL_API PuglWorldHandle
-puglGetWorldHandle(PuglWorld* world);
-
-/**
- Return a pointer to the native handle of the world.
-
- @return
- - X11: A pointer to the `Display`.
- - MacOS: `NULL`.
- - Windows: The `HMODULE` of the calling process.
-*/
-PUGL_API void*
-puglGetNativeWorld(PuglWorld* world);
-
-/**
- Set the function to call to log a message.
-
- This will be called to report any log messages generated internally by Pugl
- which are enabled according to the log level.
-*/
-PUGL_API PuglStatus
-puglSetLogFunc(PuglWorld* world, PuglLogFunc logFunc);
-
-/**
- Set the level of log messages to emit.
-
- Any log messages with a level less than or equal to `level` will be emitted.
-*/
-PUGL_API PuglStatus
-puglSetLogLevel(PuglWorld* world, PuglLogLevel level);
-
-/**
- Set the class name of the application.
-
- This is a stable identifier for the application, used as the window
- class/instance name on X11 and Windows. It is not displayed to the user,
- but can be used in scripts and by window managers, so it should be the same
- for every instance of the application, but different from other
- applications.
-*/
-PUGL_API PuglStatus
-puglSetClassName(PuglWorld* world, const char* name);
-
-/**
- Return the time in seconds.
-
- This is a monotonically increasing clock with high resolution. The returned
- time is only useful to compare against other times returned by this
- function, its absolute value has no meaning.
-*/
-PUGL_API double
-puglGetTime(const PuglWorld* world);
-
-/**
- Update by processing events from the window system.
-
- This function is a single iteration of the main loop, and should be called
- repeatedly to update all views.
-
- If `timeout` is zero, then this function will not block. Plugins should
- always use a timeout of zero to avoid blocking the host.
-
- If a positive `timeout` is given, then events will be processed for that
- amount of time, starting from when this function was called.
-
- If a negative `timeout` is given, this function will block indefinitely
- until an event occurs.
-
- For continuously animating programs, a timeout that is a reasonable fraction
- of the ideal frame period should be used, to minimise input latency by
- ensuring that as many input events are consumed as possible before drawing.
-
- @return
- - #PUGL_SUCCESS if events are read
- - #PUGL_FAILURE if not, or an error.
-*/
-PUGL_API PuglStatus
-puglUpdate(PuglWorld* world, double timeout);
-
-/**
- @}
-
- @defgroup view View
-
- A drawable region that receives events.
-
- A view can be thought of as a window, but does not necessarily correspond to
- a top-level window in a desktop environment. For example, a view can be
- embedded in some other window, or represent an embedded system where there
- is no concept of multiple windows at all.
-
- @{
-*/
-
-/**
- A drawable region that receives events.
-*/
-typedef struct PuglViewImpl PuglView;
-
-/**
- A graphics backend.
-
- The backend dictates how graphics are set up for a view, and how drawing is
- performed. A backend must be set by calling puglSetBackend() before
- realising a view.
-
- If you are using a local copy of Pugl, it is possible to implement a custom
- backend. See the definition of `PuglBackendImpl` in the source code for
- details.
-*/
-typedef struct PuglBackendImpl PuglBackend;
-
-/**
- A native view handle.
-
- X11: This is a `Window`.
-
- MacOS: This is a pointer to an `NSView*`.
-
- Windows: This is a `HWND`.
-*/
-typedef uintptr_t PuglNativeView;
-
-/**
- Handle for a view's opaque user data.
-*/
-typedef void* PuglHandle;
-
-/**
- A hint for configuring a view.
-*/
-typedef enum {
- PUGL_USE_COMPAT_PROFILE, ///< Use compatible (not core) OpenGL profile
- PUGL_USE_DEBUG_CONTEXT, ///< True to use a debug OpenGL context
- PUGL_CONTEXT_VERSION_MAJOR, ///< OpenGL context major version
- PUGL_CONTEXT_VERSION_MINOR, ///< OpenGL context minor version
- PUGL_RED_BITS, ///< Number of bits for red channel
- PUGL_GREEN_BITS, ///< Number of bits for green channel
- PUGL_BLUE_BITS, ///< Number of bits for blue channel
- PUGL_ALPHA_BITS, ///< Number of bits for alpha channel
- PUGL_DEPTH_BITS, ///< Number of bits for depth buffer
- PUGL_STENCIL_BITS, ///< Number of bits for stencil buffer
- PUGL_SAMPLES, ///< Number of samples per pixel (AA)
- PUGL_DOUBLE_BUFFER, ///< True if double buffering should be used
- PUGL_SWAP_INTERVAL, ///< Number of frames between buffer swaps
- PUGL_RESIZABLE, ///< True if view should be resizable
- PUGL_IGNORE_KEY_REPEAT, ///< True if key repeat events are ignored
- PUGL_REFRESH_RATE, ///< Refresh rate in Hz
-
- PUGL_NUM_VIEW_HINTS
-} PuglViewHint;
-
-/**
- A special view hint value.
-*/
-typedef enum {
- PUGL_DONT_CARE = -1, ///< Use best available value
- PUGL_FALSE = 0, ///< Explicitly false
- PUGL_TRUE = 1 ///< Explicitly true
-} PuglViewHintValue;
-
-/**
- A function called when an event occurs.
-*/
-typedef PuglStatus (*PuglEventFunc)(PuglView* view, const PuglEvent* event);
-
-/**
- @name Setup
- Functions for creating and destroying a view.
- @{
-*/
-
-/**
- Create a new view.
-
- A newly created view does not correspond to a real system view or window.
- It must first be configured, then the system view can be created with
- puglRealize().
-*/
-PUGL_API PuglView*
-puglNewView(PuglWorld* world);
-
-/**
- Free a view created with puglNewView().
-*/
-PUGL_API void
-puglFreeView(PuglView* view);
-
-/**
- Return the world that `view` is a part of.
-*/
-PUGL_API PuglWorld*
-puglGetWorld(PuglView* view);
-
-/**
- Set the user data for a view.
-
- This is usually a pointer to a struct that contains all the state which must
- be accessed by a view. Everything needed to process events should be stored
- here, not in static variables.
-
- The handle is opaque to Pugl and is not interpreted in any way.
-*/
-PUGL_API void
-puglSetHandle(PuglView* view, PuglHandle handle);
-
-/**
- Get the user data for a view.
-*/
-PUGL_API PuglHandle
-puglGetHandle(PuglView* view);
-
-/**
- Set the graphics backend to use for a view.
-
- This must be called once to set the graphics backend before calling
- puglRealize().
-
- Pugl includes the following backends:
-
- - puglGlBackend(), declared in pugl_gl.h
- - puglCairoBackend(), declared in pugl_cairo.h
-
- Note that backends are modular and not compiled into the main Pugl library
- to avoid unnecessary dependencies. To use a particular backend,
- applications must link against the appropriate backend library, or be sure
- to compile in the appropriate code if using a local copy of Pugl.
-*/
-PUGL_API PuglStatus
-puglSetBackend(PuglView* view, const PuglBackend* backend);
-
-/**
- Set the function to call when an event occurs.
-*/
-PUGL_API PuglStatus
-puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc);
-
-/**
- Set a hint to configure view properties.
-
- This only has an effect when called before puglRealize().
-*/
-PUGL_API PuglStatus
-puglSetViewHint(PuglView* view, PuglViewHint hint, int value);
-
-/**
- Get the value for a view hint.
-
- If the view has been realized, this can be used to get the actual value of a
- hint which was initially set to PUGL_DONT_CARE, or has been adjusted from
- the suggested value.
-*/
-PUGL_API int
-puglGetViewHint(const PuglView* view, PuglViewHint hint);
-
-/**
- @}
- @anchor frame
- @name Frame
- Functions for working with the position and size of a view.
- @{
-*/
-
-/**
- Get the current position and size of the view.
-
- The position is in screen coordinates with an upper left origin.
-*/
-PUGL_API PuglRect
-puglGetFrame(const PuglView* view);
-
-/**
- Set the current position and size of the view.
-
- The position is in screen coordinates with an upper left origin.
-
- @return #PUGL_UNKNOWN_ERROR on failure, in which case the view frame is
- unchanged.
-*/
-PUGL_API PuglStatus
-puglSetFrame(PuglView* view, PuglRect frame);
-
-/**
- Set the default size of the view.
-
- This should be called before puglResize() to set the default size of the
- view, which will be the initial size of the window if this is a top level
- view.
-
- @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is
- not yet realized.
-*/
-PUGL_API PuglStatus
-puglSetDefaultSize(PuglView* view, int width, int height);
-
-/**
- Set the minimum size of the view.
-
- If an initial minimum size is known, this should be called before
- puglRealize() to avoid stutter, though it can be called afterwards as well.
-
- @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is
- not yet realized.
-*/
-PUGL_API PuglStatus
-puglSetMinSize(PuglView* view, int width, int height);
-
-/**
- Set the maximum size of the view.
-
- If an initial maximum size is known, this should be called before
- puglRealize() to avoid stutter, though it can be called afterwards as well.
-
- @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is
- not yet realized.
-*/
-PUGL_API PuglStatus
-puglSetMaxSize(PuglView* view, int width, int height);
-
-/**
- Set the view aspect ratio range.
-
- The x and y values here represent a ratio of width to height. To set a
- fixed aspect ratio, set the minimum and maximum values to the same ratio.
-
- Note that setting different minimum and maximum constraints does not
- currenty work on MacOS (the minimum is used), so only setting a fixed aspect
- ratio works properly across all platforms.
-
- If an initial aspect ratio is known, this should be called before
- puglRealize() to avoid stutter, though it can be called afterwards as well.
-
- @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is
- not yet realized.
-*/
-PUGL_API PuglStatus
-puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY);
-
-/**
- @}
- @name Windows
- Functions for working with system views and the window hierarchy.
- @{
-*/
-
-/**
- Set the title of the window.
-
- This only makes sense for non-embedded views that will have a corresponding
- top-level window, and sets the title, typically displayed in the title bar
- or in window switchers.
-*/
-PUGL_API PuglStatus
-puglSetWindowTitle(PuglView* view, const char* title);
-
-/**
- Set the parent window for embedding a view in an existing window.
-
- This must be called before puglRealize(), reparenting is not supported.
-*/
-PUGL_API PuglStatus
-puglSetParentWindow(PuglView* view, PuglNativeView parent);
-
-/**
- Set the transient parent of the window.
-
- Set this for transient children like dialogs, to have them properly
- associated with their parent window. This should be called before
- puglRealize().
-
- A view can either have a parent (for embedding) or a transient parent (for
- top-level windows like dialogs), but not both.
-*/
-PUGL_API PuglStatus
-puglSetTransientFor(PuglView* view, PuglNativeView parent);
-
-/**
- Realise 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 puglGetNativeWindow(). There is currently no
- corresponding unrealize function, the system view will be destroyed along
- with the view when puglFreeView() is called.
-
- The view should be fully configured using the above functions before this is
- called. This function may only be called once per view.
-*/
-PUGL_API PuglStatus
-puglRealize(PuglView* view);
-
-/**
- Show the view.
-
- If the view has not yet been realized, the first call to this function will
- do so automatically.
-
- If the view is currently hidden, it will be shown and possibly raised to the
- top depending on the platform.
-*/
-PUGL_API PuglStatus
-puglShowWindow(PuglView* view);
-
-/**
- Hide the current window.
-*/
-PUGL_API PuglStatus
-puglHideWindow(PuglView* view);
-
-/**
- Return true iff the view is currently visible.
-*/
-PUGL_API bool
-puglGetVisible(const PuglView* view);
-
-/**
- Return the native window handle.
-*/
-PUGL_API PuglNativeView
-puglGetNativeWindow(PuglView* view);
-
-/**
- @}
- @name Graphics
- Functions for working with the graphics context and scheduling redisplays.
- @{
-*/
-
-/**
- Get the graphics context.
-
- This is a backend-specific context used for drawing if the backend graphics
- API requires one. It is only available during an expose.
-
- @return
- - Cairo: A pointer to a
- [`cairo_t`](http://www.cairographics.org/manual/cairo-cairo-t.html).
- - OpenGL: `NULL`.
- - Stub: `NULL`.
-*/
-PUGL_API void*
-puglGetContext(PuglView* view);
-
-/**
- Request a redisplay for the entire view.
-
- This will cause an expose event to be dispatched later. If called from
- within the event handler, the expose should arrive at the end of the current
- event loop iteration, though this is not strictly guaranteed on all
- platforms. If called elsewhere, an expose will be enqueued to be processed
- in the next event loop iteration.
-*/
-PUGL_API PuglStatus
-puglPostRedisplay(PuglView* view);
-
-/**
- Request a redisplay of the given rectangle within the view.
-
- This has the same semantics as puglPostRedisplay(), but allows giving a
- precise region for redrawing only a portion of the view.
-*/
-PUGL_API PuglStatus
-puglPostRedisplayRect(PuglView* view, PuglRect rect);
-
-/**
- @}
- @anchor interaction
- @name Interaction
- Functions for interacting with the user and window system.
- @{
-*/
-
-/**
- A mouse cursor type.
-
- This is a portable subset of mouse cursors that exist on X11, MacOS, and
- Windows.
-*/
-typedef enum {
- PUGL_CURSOR_ARROW, ///< Default pointing arrow
- PUGL_CURSOR_CARET, ///< Caret (I-Beam) for text entry
- PUGL_CURSOR_CROSSHAIR, ///< Cross-hair
- PUGL_CURSOR_HAND, ///< Hand with a pointing finger
- PUGL_CURSOR_NO, ///< Operation not allowed
- PUGL_CURSOR_LEFT_RIGHT, ///< Left/right arrow for horizontal resize
- PUGL_CURSOR_UP_DOWN, ///< Up/down arrow for vertical resize
-} PuglCursor;
-
-/**
- Grab the keyboard input focus.
-*/
-PUGL_API PuglStatus
-puglGrabFocus(PuglView* view);
-
-/**
- Return whether `view` has the keyboard input focus.
-*/
-PUGL_API bool
-puglHasFocus(const PuglView* view);
-
-/**
- Set the clipboard contents.
-
- This sets the system clipboard contents, which can be retrieved with
- puglGetClipboard() or pasted into other applications.
-
- @param view The view.
- @param type The MIME type of the data, "text/plain" is assumed if `NULL`.
- @param data The data to copy to the clipboard.
- @param len The length of data in bytes (including terminator if necessary).
-*/
-PUGL_API PuglStatus
-puglSetClipboard(PuglView* view,
- const char* type,
- const void* data,
- size_t len);
-
-/**
- Get the clipboard contents.
-
- This gets the system clipboard contents, which may have been set with
- puglSetClipboard() or copied from another application.
-
- @param view The view.
- @param[out] type Set to the MIME type of the data.
- @param[out] len Set to the length of the data in bytes.
- @return The clipboard contents, or `NULL`.
-*/
-PUGL_API const void*
-puglGetClipboard(PuglView* view, const char** type, size_t* len);
-
-/**
- Set the mouse cursor.
-
- This changes the system cursor that is displayed when the pointer is inside
- the view. May fail if setting the cursor is not supported on this system,
- for example if compiled on X11 without Xcursor support.
-
- @return
- - #PUGL_BAD_PARAMETER if the given cursor is invalid.
- - #PUGL_FAILURE if the cursor isknown but loading it from the system fails.
-*/
-PUGL_API PuglStatus
-puglSetCursor(PuglView* view, PuglCursor cursor);
-
-/**
- Request user attention.
-
- This hints to the system that the window or application requires attention
- from the user. The exact effect depends on the platform, but is usually
- something like a flashing task bar entry or bouncing application icon.
-*/
-PUGL_API PuglStatus
-puglRequestAttention(PuglView* view);
-
-/**
- Activate a repeating timer event.
-
- This starts a timer which will send a #PuglEventTimer to `view` every
- `timeout` seconds. This can be used to perform some action in a view at a
- regular interval with relatively low frequency. Note that the frequency of
- timer events may be limited by how often puglUpdate() is called.
-
- If the given timer already exists, it is replaced.
-
- @param view The view to begin seding #PUGL_TIMER events to.
-
- @param id The identifier for this timer. This is an application-specific ID
- that should be a low number, typically the value of a constant or `enum`
- that starts from 0. There is a platform-specific limit to the number of
- supported timers, and overhead associated with each, so applications should
- create only a few timers and perform several tasks in one if necessary.
-
- @param timeout The period, in seconds, of this timer. This is not
- guaranteed to have a resolution better than 10ms (the maximum timer
- resolution on Windows) and may be rounded up if it is too short. On X11 and
- MacOS, a resolution of about 1ms can usually be relied on.
-
- @return
- - #PUGL_FAILURE if timers are not supported by this system or build.
- - #PUGL_UNKNOWN_ERROR if setting the timer failed.
-*/
-PUGL_API PuglStatus
-puglStartTimer(PuglView* view, uintptr_t id, double timeout);
-
-/**
- Stop an active timer.
-
- @param view The view that the timer is set for.
- @param id The ID previously passed to puglStartTimer().
-
- @return
- - #PUGL_FAILURE if timers are not supported by this system or build.
- - #PUGL_UNKNOWN_ERROR if stopping the timer failed.
-*/
-PUGL_API PuglStatus
-puglStopTimer(PuglView* view, uintptr_t id);
-
-/**
- Send an event to a view via the window system.
-
- If supported, the event will be delivered to the view via the event loop
- like other events. Note that this function only works for certain event
- types.
-
- Currently, only #PUGL_CLIENT events are supported on all platforms.
-
- X11: A #PUGL_EXPOSE event can be sent, which is similar to calling
- puglPostRedisplayRect(), but will always send a message to the X server,
- even when called in an event handler.
-
- @return
- - #PUGL_UNSUPPORTED_TYPE if sending events of this type is not supported.
- - #PUGL_UNKNOWN_ERROR if sending the event failed.
-*/
-PUGL_API PuglStatus
-puglSendEvent(PuglView* view, const PuglEvent* event);
-
-/**
- @}
-*/
-
-#ifndef PUGL_DISABLE_DEPRECATED
-
-/**
- @}
- @name Deprecated API
- @{
-*/
-
-/**
- A native window handle.
-
- X11: This is a `Window`.
-
- MacOS: This is a pointer to an `NSView*`.
-
- Windows: This is a `HWND`.
-*/
-typedef uintptr_t PuglNativeWindow;
-
-/**
- Create a Pugl application and view.
-
- To create a window, call the various puglInit* functions as necessary, then
- call puglRealize().
-
- @deprecated Use puglNewApp() and puglNewView().
-
- @param pargc Pointer to argument count (currently unused).
- @param argv Arguments (currently unused).
- @return A newly created view.
-*/
-static inline PUGL_DEPRECATED_BY("puglNewView") PuglView*
-puglInit(const int* pargc, char** argv)
-{
- (void)pargc;
- (void)argv;
-
- return puglNewView(puglNewWorld(PUGL_MODULE, 0));
-}
-
-/**
- Destroy an app and view created with `puglInit()`.
-
- @deprecated Use puglFreeApp() and puglFreeView().
-*/
-static inline PUGL_DEPRECATED_BY("puglFreeView") void
-puglDestroy(PuglView* view)
-{
- PuglWorld* const world = puglGetWorld(view);
-
- puglFreeView(view);
- puglFreeWorld(world);
-}
-
-/**
- Set the window class name before creating a window.
-*/
-static inline PUGL_DEPRECATED_BY("puglSetClassName") void
-puglInitWindowClass(PuglView* view, const char* name)
-{
- puglSetClassName(puglGetWorld(view), name);
-}
-
-/**
- Set the window size before creating a window.
-
- @deprecated Use puglSetFrame().
-*/
-static inline PUGL_DEPRECATED_BY("puglSetFrame") void
-puglInitWindowSize(PuglView* view, int width, int height)
-{
- PuglRect frame = puglGetFrame(view);
-
- frame.width = width;
- frame.height = height;
-
- puglSetFrame(view, frame);
-}
-
-/**
- Set the minimum window size before creating a window.
-*/
-static inline PUGL_DEPRECATED_BY("puglSetMinSize") void
-puglInitWindowMinSize(PuglView* view, int width, int height)
-{
- puglSetMinSize(view, width, height);
-}
-
-/**
- Set the window aspect ratio range before creating a window.
-
- The x and y values here represent a ratio of width to height. To set a
- fixed aspect ratio, set the minimum and maximum values to the same ratio.
-
- Note that setting different minimum and maximum constraints does not
- currenty work on MacOS (the minimum is used), so only setting a fixed aspect
- ratio works properly across all platforms.
-*/
-static inline PUGL_DEPRECATED_BY("puglSetAspectRatio") void
-puglInitWindowAspectRatio(PuglView* view,
- int minX,
- int minY,
- int maxX,
- int maxY)
-{
- puglSetAspectRatio(view, minX, minY, maxX, maxY);
-}
-
-/**
- Set transient parent before creating a window.
-
- On X11, parent must be a Window.
- On OSX, parent must be an NSView*.
-*/
-static inline PUGL_DEPRECATED_BY("puglSetTransientFor") void
-puglInitTransientFor(PuglView* view, uintptr_t parent)
-{
- puglSetTransientFor(view, (PuglNativeWindow)parent);
-}
-
-/**
- Enable or disable resizing before creating a window.
-
- @deprecated Use puglSetViewHint() with #PUGL_RESIZABLE.
-*/
-static inline PUGL_DEPRECATED_BY("puglSetViewHint") void
-puglInitResizable(PuglView* view, bool resizable)
-{
- puglSetViewHint(view, PUGL_RESIZABLE, resizable);
-}
-
-/**
- Get the current size of the view.
-
- @deprecated Use puglGetFrame().
-
-*/
-static inline PUGL_DEPRECATED_BY("puglGetFrame") void
-puglGetSize(PuglView* view, int* width, int* height)
-{
- const PuglRect frame = puglGetFrame(view);
-
- *width = (int)frame.width;
- *height = (int)frame.height;
-}
-
-/**
- Ignore synthetic repeated key events.
-
- @deprecated Use puglSetViewHint() with #PUGL_IGNORE_KEY_REPEAT.
-*/
-static inline PUGL_DEPRECATED_BY("puglSetViewHint") void
-puglIgnoreKeyRepeat(PuglView* view, bool ignore)
-{
- puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, ignore);
-}
-
-/**
- Set a hint before creating a window.
-
- @deprecated Use puglSetWindowHint().
-*/
-static inline PUGL_DEPRECATED_BY("puglSetViewHint") void
-puglInitWindowHint(PuglView* view, PuglViewHint hint, int value)
-{
- puglSetViewHint(view, hint, value);
-}
-
-/**
- Set the parent window before creating a window (for embedding).
-
- @deprecated Use puglSetWindowParent().
-*/
-static inline PUGL_DEPRECATED_BY("puglSetParentWindow") void
-puglInitWindowParent(PuglView* view, PuglNativeWindow parent)
-{
- puglSetParentWindow(view, parent);
-}
-
-/**
- Set the graphics backend to use.
-
- @deprecated Use puglSetBackend().
-*/
-static inline PUGL_DEPRECATED_BY("puglSetBackend") int
-puglInitBackend(PuglView* view, const PuglBackend* backend)
-{
- return (int)puglSetBackend(view, backend);
-}
-
-/**
- Realise a view by creating a corresponding system view or window.
-
- The view should be fully configured using the above functions before this is
- called. This function may only be called once per view.
-
- @deprecated Use puglRealize(), or just show the view.
-*/
-static inline PUGL_DEPRECATED_BY("puglRealize") PuglStatus
-puglCreateWindow(PuglView* view, const char* title)
-{
- puglSetWindowTitle(view, title);
- return puglRealize(view);
-}
-
-/**
- Block and wait for an event to be ready.
-
- This can be used in a loop to only process events via puglProcessEvents when
- necessary. This function will block indefinitely if no events are
- available, so is not appropriate for use in programs that need to perform
- regular updates (e.g. animation).
-
- @deprecated Use puglPollEvents().
-*/
-PUGL_API PUGL_DEPRECATED_BY("puglPollEvents") PuglStatus
-puglWaitForEvent(PuglView* view);
-
-/**
- Process all pending window events.
-
- This handles input events as well as rendering, so it should be called
- regularly and rapidly enough to keep the UI responsive. This function does
- not block if no events are pending.
-
- @deprecated Use puglDispatchEvents().
-*/
-PUGL_API PUGL_DEPRECATED_BY("puglDispatchEvents") PuglStatus
-puglProcessEvents(PuglView* view);
-
-/**
- Poll for events that are ready to be processed.
-
- This polls for events that are ready for any view in the world, potentially
- blocking depending on `timeout`.
-
- @param world The world to poll for events.
-
- @param timeout Maximum time to wait, in seconds. If zero, the call returns
- immediately, if negative, the call blocks indefinitely.
-
- @return #PUGL_SUCCESS if events are read, #PUGL_FAILURE if not, or an error.
-
- @deprecated Use puglUpdate().
-*/
-PUGL_API PUGL_DEPRECATED_BY("puglUpdate") PuglStatus
-puglPollEvents(PuglWorld* world, double timeout);
-
-/**
- Dispatch any pending events to views.
-
- This processes all pending events, dispatching them to the appropriate
- views. View event handlers will be called in the scope of this call. This
- function does not block, if no events are pending then it will return
- immediately.
-
- @deprecated Use puglUpdate().
-*/
-PUGL_API PUGL_DEPRECATED_BY("puglUpdate") PuglStatus
-puglDispatchEvents(PuglWorld* world);
-
-/**
- Enter the graphics context.
-
- Note that, unlike some similar libraries, Pugl automatically enters and
- leaves the graphics context when required and application should not
- normally do this. Drawing in Pugl is only allowed during the processing of
- an expose event.
-
- However, this can be used to enter the graphics context elsewhere, for
- example to call any GL functions during setup.
-
- @param view The view being entered.
- @param drawing If true, prepare for drawing.
-
- @deprecated Set up graphics when a #PUGL_CREATE event is received.
-*/
-PUGL_API PUGL_DEPRECATED_BY("PUGL_CREATE") PuglStatus
-puglEnterContext(PuglView* view, bool drawing);
-
-/**
- Leave the graphics context.
-
- This must be called after puglEnterContext() with a matching `drawing`
- parameter.
-
- @param view The view being left.
- @param drawing If true, finish drawing, for example by swapping buffers.
-
- @deprecated Shut down graphics when a #PUGL_DESTROY event is received.
-*/
-PUGL_API PUGL_DEPRECATED_BY("PUGL_DESTROY") PuglStatus
-puglLeaveContext(PuglView* view, bool drawing);
-
-#endif /* PUGL_DISABLE_DEPRECATED */
-
-/**
- @}
- @}
- @}
-*/
-
-PUGL_END_DECLS
-
-#endif /* PUGL_PUGL_H */
diff --git a/pugl/pugl.hpp b/pugl/pugl.hpp
deleted file mode 100644
index 9709e51..0000000
--- a/pugl/pugl.hpp
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file pugl.hpp
- @brief Pugl C++ API wrapper.
-*/
-
-#ifndef PUGL_PUGL_HPP
-#define PUGL_PUGL_HPP
-
-#include "pugl/pugl.h"
-
-#include <cassert>
-#include <chrono>
-#include <functional>
-#include <memory>
-#include <stdexcept>
-#include <type_traits>
-
-/**
- @defgroup pugl_cxx C++ API
- C++ API wrapper.
-
- @ingroup pugl
- @{
-*/
-
-/**
- Pugl C++ API namespace.
-*/
-namespace pugl {
-
-namespace detail {
-
-/// Free function for a C object
-template<typename T>
-using FreeFunc = void (*)(T*);
-
-/// Simple overhead-free deleter for a C object
-template<typename T, FreeFunc<T> Free>
-struct Deleter {
- void operator()(T* ptr) { Free(ptr); }
-};
-
-/// Generic C++ wrapper for a C object
-template<class T, FreeFunc<T> Free>
-class Wrapper
-{
-public:
- Wrapper(const Wrapper&) = delete;
- Wrapper& operator=(const Wrapper&) = delete;
-
- Wrapper(Wrapper&&) = default;
- Wrapper& operator=(Wrapper&&) = default;
-
- T* cobj() { return _ptr.get(); }
- const T* cobj() const { return _ptr.get(); }
-
-protected:
- explicit Wrapper(T* ptr)
- : _ptr(ptr, Deleter<T, Free>{})
- {}
-
-private:
- std::unique_ptr<T, Deleter<T, Free>> _ptr;
-};
-
-} // namespace detail
-
-using Rect = PuglRect; ///< @copydoc PuglRect
-
-/**
- @defgroup eventsxx Events
- @ingroup pugl_cxx
- @copydoc events
- @{
-*/
-
-/**
- A strongly-typed analogue of PuglEvent.
-
- This is bit-for-bit identical to the corresponding PuglEvent, so events are
- simply cast to this type to avoid any copying overhead.
-
- @tparam t The `type` field of the corresponding PuglEvent.
-
- @tparam Base The specific struct type of the corresponding PuglEvent.
-*/
-template<PuglEventType t, class Base>
-struct Event final : Base {
- using BaseEvent = Base;
-
- static constexpr const PuglEventType type = t;
-};
-
-using Mod = PuglMod; ///< @copydoc PuglMod
-using Mods = PuglMods; ///< @copydoc PuglMods
-using Key = PuglKey; ///< @copydoc PuglKey
-using EventType = PuglEventType; ///< @copydoc PuglEventType
-using EventFlag = PuglEventFlag; ///< @copydoc PuglEventFlag
-using EventFlags = PuglEventFlags; ///< @copydoc PuglEventFlags
-using CrossingMode = PuglCrossingMode; ///< @copydoc PuglCrossingMode
-
-/// @copydoc PuglEventCreate
-using CreateEvent = Event<PUGL_CREATE, PuglEventCreate>;
-
-/// @copydoc PuglEventDestroy
-using DestroyEvent = Event<PUGL_DESTROY, PuglEventDestroy>;
-
-/// @copydoc PuglEventConfigure
-using ConfigureEvent = Event<PUGL_CONFIGURE, PuglEventConfigure>;
-
-/// @copydoc PuglEventMap
-using MapEvent = Event<PUGL_MAP, PuglEventMap>;
-
-/// @copydoc PuglEventUnmap
-using UnmapEvent = Event<PUGL_UNMAP, PuglEventUnmap>;
-
-/// @copydoc PuglEventUpdate
-using UpdateEvent = Event<PUGL_UPDATE, PuglEventUpdate>;
-
-/// @copydoc PuglEventExpose
-using ExposeEvent = Event<PUGL_EXPOSE, PuglEventExpose>;
-
-/// @copydoc PuglEventClose
-using CloseEvent = Event<PUGL_CLOSE, PuglEventClose>;
-
-/// @copydoc PuglEventFocus
-using FocusInEvent = Event<PUGL_FOCUS_IN, PuglEventFocus>;
-
-/// @copydoc PuglEventFocus
-using FocusOutEvent = Event<PUGL_FOCUS_OUT, PuglEventFocus>;
-
-/// @copydoc PuglEventKey
-using KeyPressEvent = Event<PUGL_KEY_PRESS, PuglEventKey>;
-
-/// @copydoc PuglEventKey
-using KeyReleaseEvent = Event<PUGL_KEY_RELEASE, PuglEventKey>;
-
-/// @copydoc PuglEventText
-using TextEvent = Event<PUGL_TEXT, PuglEventText>;
-
-/// @copydoc PuglEventCrossing
-using PointerInEvent = Event<PUGL_POINTER_IN, PuglEventCrossing>;
-
-/// @copydoc PuglEventCrossing
-using PointerOutEvent = Event<PUGL_POINTER_OUT, PuglEventCrossing>;
-
-/// @copydoc PuglEventButton
-using ButtonPressEvent = Event<PUGL_BUTTON_PRESS, PuglEventButton>;
-
-/// @copydoc PuglEventButton
-using ButtonReleaseEvent = Event<PUGL_BUTTON_RELEASE, PuglEventButton>;
-
-/// @copydoc PuglEventMotion
-using MotionEvent = Event<PUGL_MOTION, PuglEventMotion>;
-
-/// @copydoc PuglEventScroll
-using ScrollEvent = Event<PUGL_SCROLL, PuglEventScroll>;
-
-/// @copydoc PuglEventClient
-using ClientEvent = Event<PUGL_CLIENT, PuglEventClient>;
-
-/// @copydoc PuglEventTimer
-using TimerEvent = Event<PUGL_TIMER, PuglEventTimer>;
-
-/**
- @}
- @defgroup statusxx Status
- @ingroup pugl_cxx
- @copydoc status
- @{
-*/
-
-/// @copydoc PuglStatus
-enum class Status {
- success, ///< @copydoc PUGL_SUCCESS
- failure, ///< @copydoc PUGL_FAILURE
- unknownError, ///< @copydoc PUGL_UNKNOWN_ERROR
- badBackend, ///< @copydoc PUGL_BAD_BACKEND
- badConfiguration, ///< @copydoc PUGL_BAD_CONFIGURATION
- badParameter, ///< @copydoc PUGL_BAD_PARAMETER
- backendFailed, ///< @copydoc PUGL_BACKEND_FAILED
- registrationFailed, ///< @copydoc PUGL_REGISTRATION_FAILED
- realizeFailed, ///< @copydoc PUGL_REALIZE_FAILED
- setFormatFailed, ///< @copydoc PUGL_SET_FORMAT_FAILED
- createContextFailed, ///< @copydoc PUGL_CREATE_CONTEXT_FAILED
- unsupportedType, ///< @copydoc PUGL_UNSUPPORTED_TYPE
-};
-
-static_assert(Status(PUGL_UNSUPPORTED_TYPE) == Status::unsupportedType, "");
-
-/// @copydoc puglStrerror
-static inline const char*
-strerror(const pugl::Status status)
-{
- return puglStrerror(static_cast<PuglStatus>(status));
-}
-
-/**
- @}
- @defgroup worldxx World
- @ingroup pugl_cxx
- @copydoc world
- @{
-*/
-
-class World;
-
-/// @copydoc PuglWorldType
-enum class WorldType {
- program, ///< @copydoc PUGL_PROGRAM
- module, ///< @copydoc PUGL_MODULE
-};
-
-static_assert(WorldType(PUGL_MODULE) == WorldType::module, "");
-
-/// @copydoc PuglWorldFlag
-enum class WorldFlag {
- threads = PUGL_WORLD_THREADS, ///< @copydoc PUGL_WORLD_THREADS
-};
-
-static_assert(WorldFlag(PUGL_WORLD_THREADS) == WorldFlag::threads, "");
-
-using WorldFlags = PuglWorldFlags; ///< @copydoc PuglWorldFlags
-
-/// @copydoc PuglLogLevel
-enum class LogLevel {
- err = PUGL_LOG_LEVEL_ERR, ///< @copydoc PUGL_LOG_LEVEL_ERR
- warning = PUGL_LOG_LEVEL_WARNING, ///< @copydoc PUGL_LOG_LEVEL_WARNING
- info = PUGL_LOG_LEVEL_INFO, ///< @copydoc PUGL_LOG_LEVEL_INFO
- debug = PUGL_LOG_LEVEL_DEBUG, ///< @copydoc PUGL_LOG_LEVEL_DEBUG
-};
-
-static_assert(LogLevel(PUGL_LOG_LEVEL_DEBUG) == LogLevel::debug, "");
-
-/// @copydoc PuglLogFunc
-using LogFunc =
- std::function<void(World& world, LogLevel level, const char* msg)>;
-
-/**
- A `std::chrono` compatible clock that uses Pugl time.
-*/
-class Clock
-{
-public:
- using rep = double; ///< Time representation
- using duration = std::chrono::duration<double>; ///< Duration in seconds
- using time_point = std::chrono::time_point<Clock>; ///< A Pugl time point
-
- static constexpr bool is_steady = true; ///< Steady clock flag, always true
-
- /// Construct a clock that uses time from puglGetTime()
- explicit Clock(World& world)
- : _world{world}
- {}
-
- Clock(const Clock&) = delete;
- Clock& operator=(const Clock&) = delete;
-
- Clock(Clock&&) = delete;
- Clock& operator=(Clock&&) = delete;
-
- /// Return the current time
- time_point now() const;
-
-private:
- const pugl::World& _world;
-};
-
-/// @copydoc PuglWorld
-class World : public detail::Wrapper<PuglWorld, puglFreeWorld>
-{
-public:
- World(const World&) = delete;
- World& operator=(const World&) = delete;
-
- World(World&&) = delete;
- World& operator=(World&&) = delete;
-
- explicit World(WorldType type, WorldFlags flags)
- : Wrapper{puglNewWorld(static_cast<PuglWorldType>(type), flags)}
- , _clock(*this)
- {
- if (!cobj()) {
- throw std::runtime_error("Failed to create pugl::World");
- }
- }
-
- explicit World(WorldType type)
- : World{type, {}}
- {
- if (!cobj()) {
- throw std::runtime_error("Failed to create pugl::World");
- }
- }
-
- /// @copydoc puglGetNativeWorld
- void* nativeWorld() { return puglGetNativeWorld(cobj()); }
-
- // TODO: setLogFunc
-
- Status setLogLevel(const LogLevel level)
- {
- return static_cast<Status>(
- puglSetLogLevel(cobj(), static_cast<PuglLogLevel>(level)));
- }
-
- /// @copydoc puglSetClassName
- Status setClassName(const char* const name)
- {
- return static_cast<Status>(puglSetClassName(cobj(), name));
- }
-
- /// @copydoc puglGetTime
- double time() const { return puglGetTime(cobj()); }
-
- /// @copydoc puglUpdate
- Status update(const double timeout)
- {
- return static_cast<Status>(puglUpdate(cobj(), timeout));
- }
-
- /// Return a clock that uses Pugl time
- const Clock& clock() { return _clock; }
-
-private:
- Clock _clock;
-};
-
-inline Clock::time_point
-Clock::now() const
-{
- return time_point{duration{_world.time()}};
-}
-
-/**
- @}
- @defgroup viewxx View
- @ingroup pugl_cxx
- @copydoc view
- @{
-*/
-
-using Backend = PuglBackend; ///< @copydoc PuglBackend
-using NativeView = PuglNativeView; ///< @copydoc PuglNativeView
-
-/// @copydoc PuglViewHint
-enum class ViewHint {
- useCompatProfile, ///< @copydoc PUGL_USE_COMPAT_PROFILE
- useDebugContext, ///< @copydoc PUGL_USE_DEBUG_CONTEXT
- contextVersionMajor, ///< @copydoc PUGL_CONTEXT_VERSION_MAJOR
- contextVersionMinor, ///< @copydoc PUGL_CONTEXT_VERSION_MINOR
- redBits, ///< @copydoc PUGL_RED_BITS
- greenBits, ///< @copydoc PUGL_GREEN_BITS
- blueBits, ///< @copydoc PUGL_BLUE_BITS
- alphaBits, ///< @copydoc PUGL_ALPHA_BITS
- depthBits, ///< @copydoc PUGL_DEPTH_BITS
- stencilBits, ///< @copydoc PUGL_STENCIL_BITS
- samples, ///< @copydoc PUGL_SAMPLES
- doubleBuffer, ///< @copydoc PUGL_DOUBLE_BUFFER
- swapInterval, ///< @copydoc PUGL_SWAP_INTERVAL
- resizable, ///< @copydoc PUGL_RESIZABLE
- ignoreKeyRepeat, ///< @copydoc PUGL_IGNORE_KEY_REPEAT
- refreshRate, ///< @copydoc PUGL_REFRESH_RATE
-};
-
-static_assert(ViewHint(PUGL_REFRESH_RATE) == ViewHint::refreshRate, "");
-
-using ViewHintValue = PuglViewHintValue; ///< @copydoc PuglViewHintValue
-
-/// @copydoc PuglCursor
-enum class Cursor {
- arrow, ///< @copydoc PUGL_CURSOR_ARROW
- caret, ///< @copydoc PUGL_CURSOR_CARET
- crosshair, ///< @copydoc PUGL_CURSOR_CROSSHAIR
- hand, ///< @copydoc PUGL_CURSOR_HAND
- no, ///< @copydoc PUGL_CURSOR_NO
- leftRight, ///< @copydoc PUGL_CURSOR_LEFT_RIGHT
- upDown, ///< @copydoc PUGL_CURSOR_UP_DOWN
-};
-
-static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, "");
-
-/// @copydoc PuglView
-class View : protected detail::Wrapper<PuglView, puglFreeView>
-{
-public:
- /**
- @name Setup
- Methods for creating and destroying a view.
- @{
- */
-
- explicit View(World& world)
- : Wrapper{puglNewView(world.cobj())}
- , _world(world)
- {
- if (!cobj()) {
- throw std::runtime_error("Failed to create pugl::View");
- }
-
- puglSetHandle(cobj(), this);
- puglSetEventFunc(cobj(), dispatchEvent);
- }
-
- virtual ~View() = default;
-
- View(const View&) = delete;
- View& operator=(const View&) = delete;
-
- View(View&&) = delete;
- View&& operator=(View&&) = delete;
-
- const pugl::World& world() const { return _world; }
- pugl::World& world() { return _world; }
-
- /// @copydoc puglSetViewHint
- Status setHint(ViewHint hint, int value)
- {
- return static_cast<Status>(
- puglSetViewHint(cobj(), static_cast<PuglViewHint>(hint), value));
- }
-
- /// @copydoc puglGetViewHint
- int getHint(ViewHint hint)
- {
- return puglGetViewHint(cobj(), static_cast<PuglViewHint>(hint));
- }
-
- /**
- @}
- @name Frame
- Methods for working with the position and size of a view.
- @{
- */
-
- /// @copydoc puglGetFrame
- Rect frame() const { return puglGetFrame(cobj()); }
-
- /// @copydoc puglSetFrame
- Status setFrame(Rect frame)
- {
- return static_cast<Status>(puglSetFrame(cobj(), frame));
- }
-
- /// @copydoc puglSetDefaultSize
- Status setDefaultSize(int width, int height)
- {
- return static_cast<Status>(puglSetDefaultSize(cobj(), width, height));
- }
-
- /// @copydoc puglSetMinSize
- Status setMinSize(int width, int height)
- {
- return static_cast<Status>(puglSetMinSize(cobj(), width, height));
- }
-
- /// @copydoc puglSetMaxSize
- Status setMaxSize(int width, int height)
- {
- return static_cast<Status>(puglSetMaxSize(cobj(), width, height));
- }
-
- /// @copydoc puglSetAspectRatio
- Status setAspectRatio(int minX, int minY, int maxX, int maxY)
- {
- return static_cast<Status>(
- puglSetAspectRatio(cobj(), minX, minY, maxX, maxY));
- }
-
- /**
- @}
- @name Windows
- Methods for working with top-level windows.
- @{
- */
-
- /// @copydoc puglSetWindowTitle
- Status setWindowTitle(const char* title)
- {
- return static_cast<Status>(puglSetWindowTitle(cobj(), title));
- }
-
- /// @copydoc puglSetParentWindow
- Status setParentWindow(NativeView parent)
- {
- return static_cast<Status>(puglSetParentWindow(cobj(), parent));
- }
-
- /// @copydoc puglSetTransientFor
- Status setTransientFor(NativeView parent)
- {
- return static_cast<Status>(puglSetTransientFor(cobj(), parent));
- }
-
- /// @copydoc puglRealize
- Status realize() { return static_cast<Status>(puglRealize(cobj())); }
-
- /// @copydoc puglShowWindow
- Status showWindow() { return static_cast<Status>(puglShowWindow(cobj())); }
-
- /// @copydoc puglHideWindow
- Status hideWindow() { return static_cast<Status>(puglHideWindow(cobj())); }
-
- /// @copydoc puglGetVisible
- bool visible() const { return puglGetVisible(cobj()); }
-
- /// @copydoc puglGetNativeWindow
- NativeView nativeWindow() { return puglGetNativeWindow(cobj()); }
-
- /**
- @}
- @name Graphics
- Methods for working with the graphics context and scheduling
- redisplays.
- @{
- */
-
- /// @copydoc puglGetContext
- void* context() { return puglGetContext(cobj()); }
-
- /// @copydoc puglPostRedisplay
- Status postRedisplay()
- {
- return static_cast<Status>(puglPostRedisplay(cobj()));
- }
-
- /// @copydoc puglPostRedisplayRect
- Status postRedisplayRect(const Rect rect)
- {
- return static_cast<Status>(puglPostRedisplayRect(cobj(), rect));
- }
-
- /**
- @}
- @name Interaction
- Methods for interacting with the user and window system.
- @{
- */
-
- /// @copydoc puglGrabFocus
- Status grabFocus() { return static_cast<Status>(puglGrabFocus(cobj())); }
-
- /// @copydoc puglHasFocus
- bool hasFocus() const { return puglHasFocus(cobj()); }
-
- /// @copydoc puglSetBackend
- Status setBackend(const PuglBackend* backend)
- {
- return static_cast<Status>(puglSetBackend(cobj(), backend));
- }
-
- /// @copydoc puglSetCursor
- Status setCursor(const Cursor cursor)
- {
- return static_cast<Status>(
- puglSetCursor(cobj(), static_cast<PuglCursor>(cursor)));
- }
-
- /// @copydoc puglRequestAttention
- Status requestAttention()
- {
- return static_cast<Status>(puglRequestAttention(cobj()));
- }
-
- /**
- @}
- @name Event Handlers
- Methods called when events are dispatched to the view.
- @{
- */
-
- virtual Status onCreate(const CreateEvent&) PUGL_CONST_FUNC;
- virtual Status onDestroy(const DestroyEvent&) PUGL_CONST_FUNC;
- virtual Status onConfigure(const ConfigureEvent&) PUGL_CONST_FUNC;
- virtual Status onMap(const MapEvent&) PUGL_CONST_FUNC;
- virtual Status onUnmap(const UnmapEvent&) PUGL_CONST_FUNC;
- virtual Status onUpdate(const UpdateEvent&) PUGL_CONST_FUNC;
- virtual Status onExpose(const ExposeEvent&) PUGL_CONST_FUNC;
- virtual Status onClose(const CloseEvent&) PUGL_CONST_FUNC;
- virtual Status onFocusIn(const FocusInEvent&) PUGL_CONST_FUNC;
- virtual Status onFocusOut(const FocusOutEvent&) PUGL_CONST_FUNC;
- virtual Status onKeyPress(const KeyPressEvent&) PUGL_CONST_FUNC;
- virtual Status onKeyRelease(const KeyReleaseEvent&) PUGL_CONST_FUNC;
- virtual Status onText(const TextEvent&) PUGL_CONST_FUNC;
- virtual Status onPointerIn(const PointerInEvent&) PUGL_CONST_FUNC;
- virtual Status onPointerOut(const PointerOutEvent&) PUGL_CONST_FUNC;
- virtual Status onButtonPress(const ButtonPressEvent&) PUGL_CONST_FUNC;
- virtual Status onButtonRelease(const ButtonReleaseEvent&) PUGL_CONST_FUNC;
- virtual Status onMotion(const MotionEvent&) PUGL_CONST_FUNC;
- virtual Status onScroll(const ScrollEvent&) PUGL_CONST_FUNC;
- virtual Status onClient(const ClientEvent&) PUGL_CONST_FUNC;
- virtual Status onTimer(const TimerEvent&) PUGL_CONST_FUNC;
-
- /**
- @}
- */
-
- PuglView* cobj() { return Wrapper::cobj(); }
- const PuglView* cobj() const { return Wrapper::cobj(); }
-
-private:
- template<class Typed, class Base>
- static const Typed& typedEventRef(const Base& base)
- {
- const auto& event = static_cast<const Typed&>(base);
- static_assert(sizeof(event) == sizeof(typename Typed::BaseEvent), "");
- static_assert(std::is_standard_layout<Typed>::value, "");
- assert(event.type == Typed::type);
- return event;
- }
-
- static PuglStatus
- dispatchEvent(PuglView* view, const PuglEvent* event) noexcept
- {
- try {
- View* self = static_cast<View*>(puglGetHandle(view));
-
- return self->dispatch(event);
- } catch (...) {
- return PUGL_UNKNOWN_ERROR;
- }
- }
-
- PuglStatus dispatch(const PuglEvent* event)
- {
- switch (event->type) {
- case PUGL_NOTHING:
- return PUGL_SUCCESS;
- case PUGL_CREATE:
- return static_cast<PuglStatus>(
- onCreate(typedEventRef<CreateEvent>(event->any)));
- case PUGL_DESTROY:
- return static_cast<PuglStatus>(
- onDestroy(typedEventRef<DestroyEvent>(event->any)));
- case PUGL_CONFIGURE:
- return static_cast<PuglStatus>(
- onConfigure(typedEventRef<ConfigureEvent>(event->configure)));
- case PUGL_MAP:
- return static_cast<PuglStatus>(
- onMap(typedEventRef<MapEvent>(event->any)));
- case PUGL_UNMAP:
- return static_cast<PuglStatus>(
- onUnmap(typedEventRef<UnmapEvent>(event->any)));
- case PUGL_UPDATE:
- return static_cast<PuglStatus>(
- onUpdate(typedEventRef<UpdateEvent>(event->any)));
- case PUGL_EXPOSE:
- return static_cast<PuglStatus>(
- onExpose(typedEventRef<ExposeEvent>(event->expose)));
- case PUGL_CLOSE:
- return static_cast<PuglStatus>(
- onClose(typedEventRef<CloseEvent>(event->any)));
- case PUGL_FOCUS_IN:
- return static_cast<PuglStatus>(
- onFocusIn(typedEventRef<FocusInEvent>(event->focus)));
- case PUGL_FOCUS_OUT:
- return static_cast<PuglStatus>(
- onFocusOut(typedEventRef<FocusOutEvent>(event->focus)));
- case PUGL_KEY_PRESS:
- return static_cast<PuglStatus>(
- onKeyPress(typedEventRef<KeyPressEvent>(event->key)));
- case PUGL_KEY_RELEASE:
- return static_cast<PuglStatus>(
- onKeyRelease(typedEventRef<KeyReleaseEvent>(event->key)));
- case PUGL_TEXT:
- return static_cast<PuglStatus>(
- onText(typedEventRef<TextEvent>(event->text)));
- case PUGL_POINTER_IN:
- return static_cast<PuglStatus>(
- onPointerIn(typedEventRef<PointerInEvent>(event->crossing)));
- case PUGL_POINTER_OUT:
- return static_cast<PuglStatus>(
- onPointerOut(typedEventRef<PointerOutEvent>(event->crossing)));
- case PUGL_BUTTON_PRESS:
- return static_cast<PuglStatus>(
- onButtonPress(typedEventRef<ButtonPressEvent>(event->button)));
- case PUGL_BUTTON_RELEASE:
- return static_cast<PuglStatus>(onButtonRelease(
- typedEventRef<ButtonReleaseEvent>(event->button)));
- case PUGL_MOTION:
- return static_cast<PuglStatus>(
- onMotion(typedEventRef<MotionEvent>(event->motion)));
- case PUGL_SCROLL:
- return static_cast<PuglStatus>(
- onScroll(typedEventRef<ScrollEvent>(event->scroll)));
- case PUGL_CLIENT:
- return static_cast<PuglStatus>(
- onClient(typedEventRef<ClientEvent>(event->client)));
- case PUGL_TIMER:
- return static_cast<PuglStatus>(
- onTimer(typedEventRef<TimerEvent>(event->timer)));
- }
-
- return PUGL_FAILURE;
- }
-
- World& _world;
-};
-
-/**
- @}
-*/
-
-} // namespace pugl
-
-/**
- @}
-*/
-
-#endif /* PUGL_PUGL_HPP */
diff --git a/pugl/pugl.ipp b/pugl/pugl.ipp
deleted file mode 100644
index 0ed8c4d..0000000
--- a/pugl/pugl.ipp
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file pugl.ipp
- @brief Pugl C++ API wrapper implementation.
-
- This file must be included exactly once in the application.
-*/
-
-#include "pugl/pugl.hpp"
-
-namespace pugl {
-
-Status
-View::onCreate(const CreateEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onDestroy(const DestroyEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onConfigure(const ConfigureEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onMap(const MapEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onUnmap(const UnmapEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onUpdate(const UpdateEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onExpose(const ExposeEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onClose(const CloseEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onFocusIn(const FocusInEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onFocusOut(const FocusOutEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onKeyPress(const KeyPressEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onKeyRelease(const KeyReleaseEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onText(const TextEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onPointerIn(const PointerInEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onPointerOut(const PointerOutEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onButtonPress(const ButtonPressEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onButtonRelease(const ButtonReleaseEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onMotion(const MotionEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onScroll(const ScrollEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onClient(const ClientEvent&)
-{
- return pugl::Status::success;
-}
-
-Status
-View::onTimer(const TimerEvent&)
-{
- return pugl::Status::success;
-}
-
-} // namespace pugl
diff --git a/pugl/pugl_cairo.h b/pugl/pugl_cairo.h
deleted file mode 100644
index 4b3b621..0000000
--- a/pugl/pugl_cairo.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file pugl_cairo.h
- @brief Declaration of Cairo backend accessor.
-*/
-
-#ifndef PUGL_PUGL_CAIRO_H
-#define PUGL_PUGL_CAIRO_H
-
-#include "pugl/pugl.h"
-
-PUGL_BEGIN_DECLS
-
-/**
- @defgroup cairo Cairo
- Cairo graphics support.
- @ingroup pugl_c
- @{
-*/
-
-/**
- Cairo graphics backend accessor.
-
- Pass the return value to puglInitBackend() to draw to a view with Cairo.
-*/
-PUGL_API PUGL_CONST_FUNC const PuglBackend*
-puglCairoBackend(void);
-
-/**
- @}
-*/
-
-PUGL_END_DECLS
-
-#endif // PUGL_PUGL_CAIRO_H
diff --git a/pugl/pugl_cairo.hpp b/pugl/pugl_cairo.hpp
deleted file mode 100644
index 5b17ab7..0000000
--- a/pugl/pugl_cairo.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file pugl_cairo.hpp
- @brief Declaration of Cairo backend accessor for C++.
-*/
-
-#ifndef PUGL_PUGL_CAIRO_HPP
-#define PUGL_PUGL_CAIRO_HPP
-
-#include "pugl/pugl.h"
-#include "pugl/pugl_cairo.h"
-
-namespace pugl {
-
-/**
- @defgroup cairoxx Cairo
- Cairo graphics support.
- @ingroup pugl_cxx
- @{
-*/
-
-/// @copydoc puglCairoBackend
-static inline const PuglBackend*
-cairoBackend()
-{
- return puglCairoBackend();
-}
-
-/**
- @}
-*/
-
-} // namespace pugl
-
-#endif // PUGL_PUGL_CAIRO_HPP
diff --git a/pugl/pugl_gl.h b/pugl/pugl_gl.h
deleted file mode 100644
index 471c5ac..0000000
--- a/pugl/pugl_gl.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file pugl_gl.h
- @brief OpenGL-specific API.
-*/
-
-#ifndef PUGL_PUGL_GL_H
-#define PUGL_PUGL_GL_H
-
-#include "pugl/pugl.h"
-
-PUGL_BEGIN_DECLS
-
-/**
- @defgroup gl OpenGL
- OpenGL graphics support.
- @ingroup pugl_c
- @{
-*/
-
-/**
- OpenGL extension function.
-*/
-typedef void (*PuglGlFunc)(void);
-
-/**
- Return the address of an OpenGL extension function.
-*/
-PUGL_API PuglGlFunc
-puglGetProcAddress(const char* name);
-
-/**
- OpenGL graphics backend.
-
- Pass the return value to puglSetBackend() to draw to a view with OpenGL.
-*/
-PUGL_API PUGL_CONST_FUNC const PuglBackend*
-puglGlBackend(void);
-
-PUGL_END_DECLS
-
-/**
- @}
-*/
-
-#endif // PUGL_PUGL_GL_H
diff --git a/pugl/pugl_gl.hpp b/pugl/pugl_gl.hpp
deleted file mode 100644
index 4bc5bbd..0000000
--- a/pugl/pugl_gl.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file pugl_gl.hpp
- @brief OpenGL-specific C++ API.
-*/
-
-#ifndef PUGL_PUGL_GL_HPP
-#define PUGL_PUGL_GL_HPP
-
-#include "pugl/pugl.h"
-#include "pugl/pugl_gl.h"
-
-namespace pugl {
-
-/**
- @defgroup glxx OpenGL
- OpenGL graphics support.
- @ingroup pugl_cxx
- @{
-*/
-
-/// @copydoc PuglGlFunc
-using GlFunc = PuglGlFunc;
-
-/// @copydoc puglGetProcAddress
-static inline GlFunc
-getProcAddress(const char* name)
-{
- return puglGetProcAddress(name);
-}
-
-/// @copydoc puglGlBackend
-static inline const PuglBackend*
-glBackend()
-{
- return puglGlBackend();
-}
-
-/**
- @}
-*/
-
-} // namespace pugl
-
-#endif // PUGL_PUGL_GL_HPP
diff --git a/pugl/pugl_stub.h b/pugl/pugl_stub.h
deleted file mode 100644
index f50418e..0000000
--- a/pugl/pugl_stub.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- Copyright 2019-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.
-*/
-
-/**
- @file pugl_stub.h
- @brief Stub backend functions and accessor declaration.
-*/
-
-#ifndef PUGL_PUGL_STUB_H
-#define PUGL_PUGL_STUB_H
-
-#include "pugl/pugl.h"
-
-PUGL_BEGIN_DECLS
-
-/**
- @defgroup stub Stub
-
- Stub graphics backend.
-
- The stub backend functions do nothing and always
- return success. These do not make for a usable backend on their own since
- the platform implementation would fail to create a window, but are useful
- for other backends to reuse since not all need non-trivial implementations
- of every backend function.
-
- @ingroup pugl_c
- @{
-*/
-
-/**
- Stub graphics backend.
-
- This backend just creates a simple native window without setting up any
- portable graphics API.
-*/
-PUGL_API PUGL_CONST_FUNC
-const PuglBackend*
-puglStubBackend(void);
-
-/**
- @}
-*/
-
-PUGL_END_DECLS
-
-#endif // PUGL_PUGL_STUB_H
diff --git a/pugl/pugl_stub.hpp b/pugl/pugl_stub.hpp
deleted file mode 100644
index c5f3901..0000000
--- a/pugl/pugl_stub.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- Copyright 2012-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.
-*/
-
-/**
- @file pugl_stub.hpp
- @brief Declaration of Stub backend accessor for C++.
-*/
-
-#ifndef PUGL_PUGL_STUB_HPP
-#define PUGL_PUGL_STUB_HPP
-
-#include "pugl/pugl.h"
-#include "pugl/pugl_stub.h"
-
-namespace pugl {
-
-/**
- @defgroup stubxx Stub
- Stub graphics support.
- @ingroup pugl_cxx
- @{
-*/
-
-/// @copydoc puglStubBackend
-static inline const PuglBackend*
-stubBackend()
-{
- return puglStubBackend();
-}
-
-/**
- @}
-*/
-
-} // namespace pugl
-
-#endif // PUGL_PUGL_STUB_HPP