From 27ce10b5039e931eaad33e9499a630552d4e1f06 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 5 Jun 2022 20:24:51 -0400 Subject: Separate private and public function implementations --- src/common.c | 294 ++++++++++++++++++++++++++++++++ src/implementation.c | 473 --------------------------------------------------- src/implementation.h | 65 ------- src/internal.c | 191 +++++++++++++++++++++ src/internal.h | 65 +++++++ src/mac.m | 2 +- src/mac_cairo.m | 2 +- src/mac_gl.m | 2 +- src/mac_stub.m | 2 +- src/mac_vulkan.m | 2 +- src/win.c | 2 +- src/win.h | 2 +- src/x11.c | 2 +- 13 files changed, 558 insertions(+), 546 deletions(-) create mode 100644 src/common.c delete mode 100644 src/implementation.c delete mode 100644 src/implementation.h create mode 100644 src/internal.c create mode 100644 src/internal.h (limited to 'src') diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..313f0d0 --- /dev/null +++ b/src/common.c @@ -0,0 +1,294 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +#include "internal.h" + +#include "types.h" + +#include "pugl/pugl.h" + +#include +#include +#include + +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: return "Unsupported operation"; + case PUGL_NO_MEMORY: return "Failed to allocate memory"; + } + // clang-format on + + return "Unknown error"; +} + +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); + + 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 +puglSetClassName(PuglWorld* const world, const char* const name) +{ + puglSetString(&world->className, name); + return PUGL_SUCCESS; +} + +const char* +puglGetClassName(const PuglWorld* world) +{ + return world->className; +} + +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; +} + +PuglView* +puglNewView(PuglWorld* const world) +{ + PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); + if (!view || !(view->impl = puglInitViewInternals(world))) { + free(view); + return NULL; + } + + view->world = world; + view->sizeHints[PUGL_MIN_SIZE].width = 1; + view->sizeHints[PUGL_MIN_SIZE].height = 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) +{ + if (view->eventFunc && view->backend) { + puglDispatchSimpleEvent(view, PUGL_DESTROY); + } + + // Remove from world view list + PuglWorld* world = view->world; + for (size_t i = 0; i < world->numViews; ++i) { + 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); + puglFreeViewInternals(view); + free(view); +} + +PuglWorld* +puglGetWorld(PuglView* view) +{ + return view->world; +} + +void +puglSetHandle(PuglView* view, PuglHandle handle) +{ + view->handle = handle; +} + +PuglHandle +puglGetHandle(PuglView* view) +{ + return view->handle; +} + +PuglStatus +puglSetBackend(PuglView* view, const PuglBackend* backend) +{ + view->backend = backend; + return PUGL_SUCCESS; +} + +const PuglBackend* +puglGetBackend(const PuglView* view) +{ + return view->backend; +} + +PuglStatus +puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc) +{ + view->eventFunc = eventFunc; + return PUGL_SUCCESS; +} + +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; + } + } + + view->hints[hint] = value; + return PUGL_SUCCESS; +} + +int +puglGetViewHint(const PuglView* view, PuglViewHint hint) +{ + return view->hints[hint]; +} + +PuglRect +puglGetFrame(const PuglView* view) +{ + return view->frame; +} + +const char* +puglGetWindowTitle(const PuglView* const view) +{ + return view->title; +} + +PuglStatus +puglSetParentWindow(PuglView* view, PuglNativeView parent) +{ + view->parent = parent; + return PUGL_SUCCESS; +} + +PuglNativeView +puglGetParentWindow(const PuglView* const view) +{ + return view->parent; +} + +PuglNativeView +puglGetTransientParent(const PuglView* const view) +{ + return view->transientParent; +} + +bool +puglGetVisible(const PuglView* view) +{ + return view->visible; +} + +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 +puglShowWindow(PuglView* view) +{ + return puglShow(view); +} + +PuglStatus +puglHideWindow(PuglView* view) +{ + return puglHide(view); +} + +#endif diff --git a/src/implementation.c b/src/implementation.c deleted file mode 100644 index 84d9eea..0000000 --- a/src/implementation.c +++ /dev/null @@ -1,473 +0,0 @@ -// Copyright 2012-2022 David Robillard -// SPDX-License-Identifier: ISC - -#include "implementation.h" - -#include "types.h" - -#include "pugl/pugl.h" - -#include -#include -#include -#include - -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: return "Unsupported operation"; - case PUGL_NO_MEMORY: return "Failed to allocate memory"; - } - // 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); - } -} - -PuglStatus -puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len) -{ - if (data) { - void* const newData = realloc(dest->data, len + 1); - if (!newData) { - free(dest->data); - dest->len = 0; - return PUGL_NO_MEMORY; - } - - memcpy(newData, data, len); - ((char*)newData)[len] = 0; - - dest->len = len; - dest->data = newData; - } else { - dest->len = 0; - dest->data = NULL; - } - - return PUGL_SUCCESS; -} - -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); - - 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 -puglSetClassName(PuglWorld* const world, const char* const name) -{ - puglSetString(&world->className, name); - return PUGL_SUCCESS; -} - -const char* -puglGetClassName(const PuglWorld* world) -{ - return world->className; -} - -PuglView* -puglNewView(PuglWorld* const world) -{ - PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); - if (!view || !(view->impl = puglInitViewInternals(world))) { - free(view); - return NULL; - } - - view->world = world; - view->sizeHints[PUGL_MIN_SIZE].width = 1; - view->sizeHints[PUGL_MIN_SIZE].height = 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) -{ - if (view->eventFunc && view->backend) { - puglDispatchSimpleEvent(view, PUGL_DESTROY); - } - - // Remove from world view list - PuglWorld* world = view->world; - for (size_t i = 0; i < world->numViews; ++i) { - 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); - 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; - } - } - - view->hints[hint] = value; - return PUGL_SUCCESS; -} - -int -puglGetViewHint(const PuglView* view, PuglViewHint hint) -{ - return view->hints[hint]; -} - -const char* -puglGetWindowTitle(const PuglView* const view) -{ - return view->title; -} - -PuglStatus -puglSetParentWindow(PuglView* view, PuglNativeView parent) -{ - view->parent = parent; - return PUGL_SUCCESS; -} - -PuglNativeView -puglGetParentWindow(const PuglView* const view) -{ - return view->parent; -} - -PuglNativeView -puglGetTransientParent(const PuglView* const view) -{ - return view->transientParent; -} - -PuglStatus -puglSetBackend(PuglView* view, const PuglBackend* backend) -{ - view->backend = backend; - return PUGL_SUCCESS; -} - -const PuglBackend* -puglGetBackend(const PuglView* view) -{ - return view->backend; -} - -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 -puglShowWindow(PuglView* view) -{ - return puglShow(view); -} - -PuglStatus -puglHideWindow(PuglView* view) -{ - return puglHide(view); -} - -#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]; - } - - if (buf[0] < 0xC2) { - return 0xFFFD; - } - - if (buf[0] < 0xE0) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u; - } - - 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); - } - - 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 PuglConfigureEvent* configure) -{ - return !!memcmp(configure, &view->lastConfigure, sizeof(PuglConfigureEvent)); -} - -PuglStatus -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 || - type == PUGL_LOOP_ENTER || type == PUGL_LOOP_LEAVE); - - const PuglEvent event = {{type, 0}}; - return puglDispatchEvent(view, &event); -} - -PuglStatus -puglConfigure(PuglView* view, const PuglEvent* event) -{ - PuglStatus st = PUGL_SUCCESS; - - assert(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)) { - st = view->eventFunc(view, event); - view->lastConfigure = event->configure; - } - - return st; -} - -PuglStatus -puglExpose(PuglView* view, const PuglEvent* event) -{ - return (event->expose.width > 0.0 && event->expose.height > 0.0) - ? view->eventFunc(view, event) - : PUGL_SUCCESS; -} - -PuglStatus -puglDispatchEvent(PuglView* view, const PuglEvent* event) -{ - PuglStatus st0 = PUGL_SUCCESS; - PuglStatus st1 = PUGL_SUCCESS; - - switch (event->type) { - case PUGL_NOTHING: - break; - case PUGL_CREATE: - case PUGL_DESTROY: - if (!(st0 = view->backend->enter(view, NULL))) { - st0 = view->eventFunc(view, event); - st1 = view->backend->leave(view, NULL); - } - break; - case PUGL_CONFIGURE: - if (puglMustConfigure(view, &event->configure)) { - if (!(st0 = view->backend->enter(view, NULL))) { - st0 = puglConfigure(view, event); - st1 = view->backend->leave(view, NULL); - } - } - break; - case PUGL_MAP: - if (!view->visible) { - view->visible = true; - st0 = view->eventFunc(view, event); - } - break; - case PUGL_UNMAP: - if (view->visible) { - view->visible = false; - st0 = view->eventFunc(view, event); - } - break; - case PUGL_EXPOSE: - if (!(st0 = view->backend->enter(view, &event->expose))) { - st0 = puglExpose(view, event); - st1 = view->backend->leave(view, &event->expose); - } - break; - default: - st0 = view->eventFunc(view, event); - } - - return st0 ? st0 : st1; -} diff --git a/src/implementation.h b/src/implementation.h deleted file mode 100644 index 7c95fd2..0000000 --- a/src/implementation.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2012-2022 David Robillard -// SPDX-License-Identifier: ISC - -#ifndef PUGL_IMPLEMENTATION_H -#define PUGL_IMPLEMENTATION_H - -#include "attributes.h" -#include "types.h" - -#include "pugl/pugl.h" - -#include -#include - -PUGL_BEGIN_DECLS - -/// Set `blob` to `data` with length `len`, reallocating if necessary -PuglStatus -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(PuglWorld* world); - -/// 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` -PuglStatus -puglDispatchSimpleEvent(PuglView* view, PuglEventType type); - -/// Process configure event while already in the graphics context -PUGL_WARN_UNUSED_RESULT -PuglStatus -puglConfigure(PuglView* view, const PuglEvent* event); - -/// Process expose event while already in the graphics context -PUGL_WARN_UNUSED_RESULT -PuglStatus -puglExpose(PuglView* view, const PuglEvent* event); - -/// Dispatch `event` to `view`, entering graphics context if necessary -PuglStatus -puglDispatchEvent(PuglView* view, const PuglEvent* event); - -PUGL_END_DECLS - -#endif // PUGL_IMPLEMENTATION_H diff --git a/src/internal.c b/src/internal.c new file mode 100644 index 0000000..a3067f1 --- /dev/null +++ b/src/internal.c @@ -0,0 +1,191 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +#include "internal.h" + +#include "types.h" + +#include "pugl/pugl.h" + +#include +#include +#include +#include + +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); + } +} + +PuglStatus +puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len) +{ + if (data) { + void* const newData = realloc(dest->data, len + 1); + if (!newData) { + free(dest->data); + dest->len = 0; + return PUGL_NO_MEMORY; + } + + memcpy(newData, data, len); + ((char*)newData)[len] = 0; + + dest->len = len; + dest->data = newData; + } else { + dest->len = 0; + dest->data = NULL; + } + + 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]; + } + + if (buf[0] < 0xC2) { + return 0xFFFD; + } + + if (buf[0] < 0xE0) { + FAIL_IF((buf[1] & 0xC0u) != 0x80); + return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u; + } + + 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); + } + + 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 PuglConfigureEvent* configure) +{ + return !!memcmp(configure, &view->lastConfigure, sizeof(PuglConfigureEvent)); +} + +PuglStatus +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 || + type == PUGL_LOOP_ENTER || type == PUGL_LOOP_LEAVE); + + const PuglEvent event = {{type, 0}}; + return puglDispatchEvent(view, &event); +} + +PuglStatus +puglConfigure(PuglView* view, const PuglEvent* event) +{ + PuglStatus st = PUGL_SUCCESS; + + assert(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)) { + st = view->eventFunc(view, event); + view->lastConfigure = event->configure; + } + + return st; +} + +PuglStatus +puglExpose(PuglView* view, const PuglEvent* event) +{ + return (event->expose.width > 0.0 && event->expose.height > 0.0) + ? view->eventFunc(view, event) + : PUGL_SUCCESS; +} + +PuglStatus +puglDispatchEvent(PuglView* view, const PuglEvent* event) +{ + PuglStatus st0 = PUGL_SUCCESS; + PuglStatus st1 = PUGL_SUCCESS; + + switch (event->type) { + case PUGL_NOTHING: + break; + case PUGL_CREATE: + case PUGL_DESTROY: + if (!(st0 = view->backend->enter(view, NULL))) { + st0 = view->eventFunc(view, event); + st1 = view->backend->leave(view, NULL); + } + break; + case PUGL_CONFIGURE: + if (puglMustConfigure(view, &event->configure)) { + if (!(st0 = view->backend->enter(view, NULL))) { + st0 = puglConfigure(view, event); + st1 = view->backend->leave(view, NULL); + } + } + break; + case PUGL_MAP: + if (!view->visible) { + view->visible = true; + st0 = view->eventFunc(view, event); + } + break; + case PUGL_UNMAP: + if (view->visible) { + view->visible = false; + st0 = view->eventFunc(view, event); + } + break; + case PUGL_EXPOSE: + if (!(st0 = view->backend->enter(view, &event->expose))) { + st0 = puglExpose(view, event); + st1 = view->backend->leave(view, &event->expose); + } + break; + default: + st0 = view->eventFunc(view, event); + } + + return st0 ? st0 : st1; +} diff --git a/src/internal.h b/src/internal.h new file mode 100644 index 0000000..cfd65d2 --- /dev/null +++ b/src/internal.h @@ -0,0 +1,65 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +#ifndef PUGL_INTERNAL_H +#define PUGL_INTERNAL_H + +#include "attributes.h" +#include "types.h" + +#include "pugl/pugl.h" + +#include +#include + +PUGL_BEGIN_DECLS + +/// Set `blob` to `data` with length `len`, reallocating if necessary +PuglStatus +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(PuglWorld* world); + +/// 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` +PuglStatus +puglDispatchSimpleEvent(PuglView* view, PuglEventType type); + +/// Process configure event while already in the graphics context +PUGL_WARN_UNUSED_RESULT +PuglStatus +puglConfigure(PuglView* view, const PuglEvent* event); + +/// Process expose event while already in the graphics context +PUGL_WARN_UNUSED_RESULT +PuglStatus +puglExpose(PuglView* view, const PuglEvent* event); + +/// Dispatch `event` to `view`, entering graphics context if necessary +PuglStatus +puglDispatchEvent(PuglView* view, const PuglEvent* event); + +PUGL_END_DECLS + +#endif // PUGL_INTERNAL_H diff --git a/src/mac.m b/src/mac.m index 90e4505..b2b36a5 100644 --- a/src/mac.m +++ b/src/mac.m @@ -6,7 +6,7 @@ #include "mac.h" -#include "implementation.h" +#include "internal.h" #include "pugl/pugl.h" diff --git a/src/mac_cairo.m b/src/mac_cairo.m index e269955..66af5ba 100644 --- a/src/mac_cairo.m +++ b/src/mac_cairo.m @@ -1,7 +1,7 @@ // Copyright 2019-2022 David Robillard // SPDX-License-Identifier: ISC -#include "implementation.h" +#include "internal.h" #include "mac.h" #include "stub.h" diff --git a/src/mac_gl.m b/src/mac_gl.m index 25704c3..ddd9fde 100644 --- a/src/mac_gl.m +++ b/src/mac_gl.m @@ -1,7 +1,7 @@ // Copyright 2019-2022 David Robillard // SPDX-License-Identifier: ISC -#include "implementation.h" +#include "internal.h" #include "mac.h" #include "stub.h" diff --git a/src/mac_stub.m b/src/mac_stub.m index a0d0322..ceffa6e 100644 --- a/src/mac_stub.m +++ b/src/mac_stub.m @@ -1,7 +1,7 @@ // Copyright 2019-2022 David Robillard // SPDX-License-Identifier: ISC -#include "implementation.h" +#include "internal.h" #include "mac.h" #include "stub.h" diff --git a/src/mac_vulkan.m b/src/mac_vulkan.m index 619b75f..2362db1 100644 --- a/src/mac_vulkan.m +++ b/src/mac_vulkan.m @@ -3,7 +3,7 @@ #define VK_NO_PROTOTYPES 1 -#include "implementation.h" +#include "internal.h" #include "mac.h" #include "stub.h" #include "types.h" diff --git a/src/win.c b/src/win.c index 02d5bdb..bfa39c2 100644 --- a/src/win.c +++ b/src/win.c @@ -3,7 +3,7 @@ #include "win.h" -#include "implementation.h" +#include "internal.h" #include "pugl/pugl.h" diff --git a/src/win.h b/src/win.h index e733c10..4a89e11 100644 --- a/src/win.h +++ b/src/win.h @@ -4,7 +4,7 @@ #ifndef PUGL_SRC_WIN_H #define PUGL_SRC_WIN_H -#include "implementation.h" +#include "internal.h" #include "pugl/pugl.h" diff --git a/src/x11.c b/src/x11.c index deae154..934b4bb 100644 --- a/src/x11.c +++ b/src/x11.c @@ -6,7 +6,7 @@ #include "x11.h" #include "attributes.h" -#include "implementation.h" +#include "internal.h" #include "types.h" #include "pugl/pugl.h" -- cgit v1.2.1