diff options
Diffstat (limited to 'pugl/detail/implementation.c')
-rw-r--r-- | pugl/detail/implementation.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/pugl/detail/implementation.c b/pugl/detail/implementation.c new file mode 100644 index 0000000..5cd7ce5 --- /dev/null +++ b/pugl/detail/implementation.c @@ -0,0 +1,275 @@ +/* + Copyright 2012-2019 David Robillard <http://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 Platform-independent implementation. +*/ + +#include "pugl/detail/implementation.h" +#include "pugl/pugl.h" + +#include <stdlib.h> +#include <string.h> + +static PuglHints +puglDefaultHints(void) +{ + static const PuglHints hints = { + 2, 0, 4, 4, 4, 4, 24, 8, 0, true, true, false + }; + return hints; +} + +PuglView* +puglInit(int* PUGL_UNUSED(pargc), char** PUGL_UNUSED(argv)) +{ + PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); + if (!view) { + return NULL; + } + + PuglInternals* impl = puglInitInternals(); + if (!impl) { + return NULL; + } + + view->hints = puglDefaultHints(); + view->impl = impl; + view->width = 640; + view->height = 480; + view->start_time = puglGetTime(view); + + return view; +} + +void +puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value) +{ + switch (hint) { + case PUGL_USE_COMPAT_PROFILE: + view->hints.use_compat_profile = value; + break; + case PUGL_CONTEXT_VERSION_MAJOR: + view->hints.context_version_major = value; + break; + case PUGL_CONTEXT_VERSION_MINOR: + view->hints.context_version_minor = value; + break; + case PUGL_RED_BITS: + view->hints.red_bits = value; + break; + case PUGL_GREEN_BITS: + view->hints.green_bits = value; + break; + case PUGL_BLUE_BITS: + view->hints.blue_bits = value; + break; + case PUGL_ALPHA_BITS: + view->hints.alpha_bits = value; + break; + case PUGL_DEPTH_BITS: + view->hints.depth_bits = value; + break; + case PUGL_STENCIL_BITS: + view->hints.stencil_bits = value; + break; + case PUGL_SAMPLES: + view->hints.samples = value; + break; + case PUGL_DOUBLE_BUFFER: + view->hints.double_buffer = value; + break; + case PUGL_RESIZABLE: + view->hints.resizable = value; + break; + } +} + +void +puglInitWindowSize(PuglView* view, int width, int height) +{ + view->width = width; + view->height = height; +} + +void +puglInitWindowMinSize(PuglView* view, int width, int height) +{ + view->min_width = width; + view->min_height = height; +} + +void +puglInitWindowAspectRatio(PuglView* view, + int min_x, + int min_y, + int max_x, + int max_y) +{ + view->min_aspect_x = min_x; + view->min_aspect_y = min_y; + view->max_aspect_x = max_x; + view->max_aspect_y = max_y; +} + +void +puglInitWindowClass(PuglView* view, const char* name) +{ + const size_t len = strlen(name); + + free(view->windowClass); + view->windowClass = (char*)calloc(1, len + 1); + memcpy(view->windowClass, name, len); +} + +void +puglInitWindowParent(PuglView* view, PuglNativeWindow parent) +{ + view->parent = parent; +} + +void +puglInitResizable(PuglView* view, bool resizable) +{ + view->hints.resizable = resizable; +} + +void +puglInitTransientFor(PuglView* view, uintptr_t parent) +{ + view->transient_parent = parent; +} + +int +puglInitBackend(PuglView* view, const PuglBackend* backend) +{ + view->backend = backend; + return 0; +} + +void +puglSetHandle(PuglView* view, PuglHandle handle) +{ + view->handle = handle; +} + +PuglHandle +puglGetHandle(PuglView* view) +{ + return view->handle; +} + +bool +puglGetVisible(PuglView* view) +{ + return view->visible; +} + +void +puglGetSize(PuglView* view, int* width, int* height) +{ + *width = view->width; + *height = view->height; +} + +void* +puglGetContext(PuglView* view) +{ + return view->backend->getContext(view); +} + +void +puglEnterContext(PuglView* view, bool drawing) +{ + view->backend->enter(view, drawing); +} + +void +puglLeaveContext(PuglView* view, bool drawing) +{ + view->backend->leave(view, drawing); +} + +void +puglIgnoreKeyRepeat(PuglView* view, bool ignore) +{ + view->ignoreKeyRepeat = ignore; +} + +void +puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc) +{ + view->eventFunc = eventFunc; +} + +/** 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] & 0xC0) != 0x80); + return (buf[0] << 6) + buf[1] - 0x3080u; + } else if (buf[0] < 0xF0) { + FAIL_IF((buf[1] & 0xC0) != 0x80); + FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); + FAIL_IF((buf[2] & 0xC0) != 0x80); + return (buf[0] << 12) + (buf[1] << 6) + buf[2] - 0xE2080u; + } else if (buf[0] < 0xF5) { + FAIL_IF((buf[1] & 0xC0) != 0x80); + FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); + FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); + FAIL_IF((buf[2] & 0xC0) != 0x80); + FAIL_IF((buf[3] & 0xC0) != 0x80); + return ((buf[0] << 18) + + (buf[1] << 12) + + (buf[2] << 6) + + buf[3] - 0x3C82080u); + } + return 0xFFFD; +} + +void +puglDispatchEvent(PuglView* view, const PuglEvent* event) +{ + switch (event->type) { + case PUGL_NOTHING: + break; + case PUGL_CONFIGURE: + view->width = (int)event->configure.width; + view->height = (int)event->configure.height; + puglEnterContext(view, false); + view->eventFunc(view, event); + puglLeaveContext(view, false); + break; + case PUGL_EXPOSE: + if (event->expose.count == 0) { + puglEnterContext(view, true); + view->eventFunc(view, event); + puglLeaveContext(view, true); + } + break; + default: + view->eventFunc(view, event); + } +} |