From e0c77f71f90e3bb8495c5c88fb0fb054d71cf7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 21 May 2020 17:16:26 +0200 Subject: [PATCH] Null: Make platform more conformant This makes the null platform behave more like an actual stub. More queryable state is tracked and there is even a fake monitor with one whole fake video mode. --- src/null_init.c | 5 + src/null_monitor.c | 82 +++++++++- src/null_platform.h | 40 ++++- src/null_window.c | 365 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 462 insertions(+), 30 deletions(-) diff --git a/src/null_init.c b/src/null_init.c index 20c76dc5..57aafd5d 100644 --- a/src/null_init.c +++ b/src/null_init.c @@ -29,6 +29,8 @@ #include "internal.h" +#include + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -37,11 +39,14 @@ int _glfwPlatformInit(void) { _glfwInitTimerPOSIX(); + _glfwPollMonitorsNull(); + return GLFW_TRUE; } void _glfwPlatformTerminate(void) { + free(_glfw.null.clipboardString); _glfwTerminateOSMesa(); } diff --git a/src/null_monitor.c b/src/null_monitor.c index 0a7fe064..7271e810 100644 --- a/src/null_monitor.c +++ b/src/null_monitor.c @@ -29,6 +29,37 @@ #include "internal.h" +#include +#include +#include + +// The the sole (fake) video mode of our (sole) fake monitor +// +static GLFWvidmode getVideoMode(void) +{ + GLFWvidmode mode; + mode.width = 1920; + mode.height = 1080; + mode.redBits = 8; + mode.greenBits = 8; + mode.blueBits = 8; + mode.refreshRate = 60; + return mode; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPollMonitorsNull(void) +{ + const float dpi = 141.f; + const GLFWvidmode mode = getVideoMode(); + _GLFWmonitor* monitor = _glfwAllocMonitor("Null SuperNoop 0", + (int) (mode.width * 25.4f / dpi), + (int) (mode.height * 25.4f / dpi)); + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_FIRST); +} ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -36,6 +67,7 @@ void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { + _glfwFreeGammaArrays(&monitor->null.ramp); } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) @@ -55,23 +87,69 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { + const GLFWvidmode mode = getVideoMode(); + + if (xpos) + *xpos = 10; + if (ypos) + ypos = 0; + if (width) + *width = mode.width; + if (height) + *height = mode.height - 10; } GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { - return NULL; + GLFWvidmode* mode = calloc(1, sizeof(GLFWvidmode)); + *mode = getVideoMode(); + *found = 1; + return mode; } void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { + *mode = getVideoMode(); } GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { - return GLFW_FALSE; + if (!monitor->null.ramp.size) + { + _glfwAllocGammaArrays(&monitor->null.ramp, 256); + + for (unsigned int i = 0; i < monitor->null.ramp.size; i++) + { + const float gamma = 2.2f; + float value; + value = i / (float) (monitor->null.ramp.size - 1); + value = powf(value, 1.f / gamma) * 65535.f + 0.5f; + value = _glfw_fminf(value, 65535.f); + + monitor->null.ramp.red[i] = (unsigned short) value; + monitor->null.ramp.green[i] = (unsigned short) value; + monitor->null.ramp.blue[i] = (unsigned short) value; + } + } + + _glfwAllocGammaArrays(ramp, monitor->null.ramp.size); + memcpy(ramp->red, monitor->null.ramp.red, sizeof(short) * ramp->size); + memcpy(ramp->green, monitor->null.ramp.green, sizeof(short) * ramp->size); + memcpy(ramp->blue, monitor->null.ramp.blue, sizeof(short) * ramp->size); + return GLFW_TRUE; } void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { + if (monitor->null.ramp.size != ramp->size) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Null: Gamma ramp size must match current ramp size"); + return; + } + + memcpy(monitor->null.ramp.red, ramp->red, sizeof(short) * ramp->size); + memcpy(monitor->null.ramp.green, ramp->green, sizeof(short) * ramp->size); + memcpy(monitor->null.ramp.blue, ramp->blue, sizeof(short) * ramp->size); } diff --git a/src/null_platform.h b/src/null_platform.h index fdea9906..c0995be3 100644 --- a/src/null_platform.h +++ b/src/null_platform.h @@ -27,12 +27,12 @@ #include -#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNull null +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNull null #define _GLFW_PLATFORM_CONTEXT_STATE struct { int dummyContext; } -#define _GLFW_PLATFORM_MONITOR_STATE struct { int dummyMonitor; } #define _GLFW_PLATFORM_CURSOR_STATE struct { int dummyCursor; } -#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE struct { int dummyLibraryWindow; } #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE struct { int dummyLibraryContext; } #define _GLFW_EGL_CONTEXT_STATE struct { int dummyEGLContext; } #define _GLFW_EGL_LIBRARY_CONTEXT_STATE struct { int dummyEGLLibraryContext; } @@ -56,7 +56,37 @@ // typedef struct _GLFWwindowNull { - int width; - int height; + int xpos; + int ypos; + int width; + int height; + char* title; + GLFWbool visible; + GLFWbool iconified; + GLFWbool maximized; + GLFWbool resizable; + GLFWbool decorated; + GLFWbool floating; + GLFWbool transparent; + float opacity; } _GLFWwindowNull; +// Null-specific per-monitor data +// +typedef struct _GLFWmonitorNull +{ + GLFWgammaramp ramp; +} _GLFWmonitorNull; + +// Null-specific global data +// +typedef struct _GLFWlibraryNull +{ + int xcursor; + int ycursor; + char* clipboardString; + _GLFWwindow* focusedWindow; +} _GLFWlibraryNull; + +void _glfwPollMonitorsNull(void); + diff --git a/src/null_window.c b/src/null_window.c index 936400d3..ba85571b 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -29,12 +29,71 @@ #include "internal.h" +#include + +static void applySizeLimits(_GLFWwindow* window, int* width, int* height) +{ + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) + { + const float ratio = (float) window->numer / (float) window->denom; + *height = (int) (*width / ratio); + } + + if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth) + *width = window->minwidth; + else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth) + *width = window->maxwidth; + + if (window->minheight != GLFW_DONT_CARE && *height < window->minheight) + *height = window->minheight; + else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight) + *height = window->maxheight; +} + +static void fitToMonitor(_GLFWwindow* window) +{ + GLFWvidmode mode; + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, + &window->null.xpos, + &window->null.ypos); + window->null.width = mode.width; + window->null.height = mode.height; +} + +static void acquireMonitor(_GLFWwindow* window) +{ + _glfwInputMonitorWindow(window->monitor, window); +} + +static void releaseMonitor(_GLFWwindow* window) +{ + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindow(window->monitor, NULL); +} static int createNativeWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig) + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) { - window->null.width = wndconfig->width; - window->null.height = wndconfig->height; + if (window->monitor) + fitToMonitor(window); + else + { + window->null.xpos = 17; + window->null.ypos = 17; + window->null.width = wndconfig->width; + window->null.height = wndconfig->height; + } + + window->null.visible = wndconfig->visible; + window->null.decorated = wndconfig->decorated; + window->null.maximized = wndconfig->maximized; + window->null.floating = wndconfig->floating; + window->null.transparent = fbconfig->transparent; + window->null.opacity = 1.f; return GLFW_TRUE; } @@ -49,7 +108,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - if (!createNativeWindow(window, wndconfig)) + if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) @@ -69,11 +128,24 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, } } + if (window->monitor) + { + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + acquireMonitor(window); + } + return GLFW_TRUE; } void _glfwPlatformDestroyWindow(_GLFWwindow* window) { + if (window->monitor) + releaseMonitor(window); + + if (_glfw.null.focusedWindow == window) + _glfw.null.focusedWindow = NULL; + if (window->context.destroy) window->context.destroy(window); } @@ -93,14 +165,54 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, int width, int height, int refreshRate) { + if (window->monitor == monitor) + { + if (!monitor) + { + _glfwPlatformSetWindowPos(window, xpos, ypos); + _glfwPlatformSetWindowSize(window, width, height); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitor(window, monitor); + + if (window->monitor) + { + window->null.visible = GLFW_TRUE; + acquireMonitor(window); + fitToMonitor(window); + } + else + { + _glfwPlatformSetWindowPos(window, xpos, ypos); + _glfwPlatformSetWindowSize(window, width, height); + } } void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { + if (xpos) + *xpos = window->null.xpos; + if (ypos) + *ypos = window->null.ypos; } void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { + if (window->monitor) + return; + + if (window->null.xpos != xpos || window->null.ypos != ypos) + { + window->null.xpos = xpos; + window->null.ypos = ypos; + _glfwInputWindowPos(window, xpos, ypos); + } } void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) @@ -113,18 +225,34 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { - window->null.width = width; - window->null.height = height; + if (window->monitor) + return; + + if (window->null.width != width || window->null.height != height) + { + window->null.width = width; + window->null.height = height; + _glfwInputWindowSize(window, width, height); + _glfwInputFramebufferSize(window, width, height); + } } void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { + int width = window->null.width; + int height = window->null.height; + applySizeLimits(window, &width, &height); + _glfwPlatformSetWindowSize(window, width, height); } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d) { + int width = window->null.width; + int height = window->null.height; + applySizeLimits(window, &width, &height); + _glfwPlatformSetWindowSize(window, width, height); } void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) @@ -139,6 +267,13 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { + if (window->null.decorated && !window->monitor) + { + *left = 1; + *top = 10; + *right = 1; + *bottom = 1; + } } void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, @@ -152,50 +287,89 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, void _glfwPlatformIconifyWindow(_GLFWwindow* window) { + if (_glfw.null.focusedWindow == window) + { + _glfw.null.focusedWindow = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); + } + + if (!window->null.iconified) + { + window->null.iconified = GLFW_TRUE; + _glfwInputWindowIconify(window, GLFW_TRUE); + + if (window->monitor) + releaseMonitor(window); + } } void _glfwPlatformRestoreWindow(_GLFWwindow* window) { + if (window->null.iconified) + { + window->null.iconified = GLFW_FALSE; + _glfwInputWindowIconify(window, GLFW_FALSE); + + if (window->monitor) + acquireMonitor(window); + } + else if (window->null.maximized) + { + window->null.maximized = GLFW_FALSE; + _glfwInputWindowMaximize(window, GLFW_FALSE); + } } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { + if (!window->null.maximized) + { + window->null.maximized = GLFW_TRUE; + _glfwInputWindowMaximize(window, GLFW_TRUE); + } } int _glfwPlatformWindowMaximized(_GLFWwindow* window) { - return GLFW_FALSE; + return window->null.maximized; } int _glfwPlatformWindowHovered(_GLFWwindow* window) { - return GLFW_FALSE; + return _glfw.null.xcursor >= window->null.xpos && + _glfw.null.ycursor >= window->null.ypos && + _glfw.null.xcursor <= window->null.xpos + window->null.width - 1 && + _glfw.null.ycursor <= window->null.ypos + window->null.height - 1; } int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { - return GLFW_FALSE; + return window->null.transparent; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { + window->null.resizable = enabled; } void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { + window->null.decorated = enabled; } void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { + window->null.floating = enabled; } float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { - return 1.f; + return window->null.opacity; } void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { + window->null.opacity = opacity; } void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) @@ -204,43 +378,63 @@ void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) GLFWbool _glfwPlatformRawMouseMotionSupported(void) { - return GLFW_FALSE; + return GLFW_TRUE; } void _glfwPlatformShowWindow(_GLFWwindow* window) { + window->null.visible = GLFW_TRUE; } - void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { } -void _glfwPlatformUnhideWindow(_GLFWwindow* window) -{ -} - void _glfwPlatformHideWindow(_GLFWwindow* window) { + if (_glfw.null.focusedWindow == window) + { + _glfw.null.focusedWindow = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); + } + + window->null.visible = GLFW_FALSE; } void _glfwPlatformFocusWindow(_GLFWwindow* window) { + if (_glfw.null.focusedWindow == window) + return; + + if (!window->null.visible) + return; + + _GLFWwindow* previous = _glfw.null.focusedWindow; + _glfw.null.focusedWindow = window; + + if (previous) + { + _glfwInputWindowFocus(previous, GLFW_FALSE); + if (previous->monitor && previous->autoIconify) + _glfwPlatformIconifyWindow(previous); + } + + _glfwInputWindowFocus(window, GLFW_TRUE); } int _glfwPlatformWindowFocused(_GLFWwindow* window) { - return GLFW_FALSE; + return _glfw.null.focusedWindow == window; } int _glfwPlatformWindowIconified(_GLFWwindow* window) { - return GLFW_FALSE; + return window->null.iconified; } int _glfwPlatformWindowVisible(_GLFWwindow* window) { - return GLFW_FALSE; + return window->null.visible; } void _glfwPlatformPollEvents(void) @@ -261,10 +455,16 @@ void _glfwPlatformPostEmptyEvent(void) void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { + if (xpos) + *xpos = _glfw.null.xcursor - window->null.xpos; + if (ypos) + *ypos = _glfw.null.ycursor - window->null.ypos; } void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { + _glfw.null.xcursor = window->null.xpos + (int) x; + _glfw.null.ycursor = window->null.ypos + (int) y; } void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) @@ -293,21 +493,140 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwPlatformSetClipboardString(const char* string) { + char* copy = _glfw_strdup(string); + free(_glfw.null.clipboardString); + _glfw.null.clipboardString = copy; } const char* _glfwPlatformGetClipboardString(void) { - return NULL; + return _glfw.null.clipboardString; } const char* _glfwPlatformGetScancodeName(int scancode) { - return ""; + switch (scancode) + { + case GLFW_KEY_APOSTROPHE: + return "'"; + case GLFW_KEY_COMMA: + return ","; + case GLFW_KEY_MINUS: + case GLFW_KEY_KP_SUBTRACT: + return "-"; + case GLFW_KEY_PERIOD: + case GLFW_KEY_KP_DECIMAL: + return "."; + case GLFW_KEY_SLASH: + case GLFW_KEY_KP_DIVIDE: + return "/"; + case GLFW_KEY_SEMICOLON: + return ";"; + case GLFW_KEY_EQUAL: + case GLFW_KEY_KP_EQUAL: + return "="; + case GLFW_KEY_LEFT_BRACKET: + return "["; + case GLFW_KEY_RIGHT_BRACKET: + return "]"; + case GLFW_KEY_KP_MULTIPLY: + return "*"; + case GLFW_KEY_KP_ADD: + return "+"; + case GLFW_KEY_BACKSLASH: + case GLFW_KEY_WORLD_1: + case GLFW_KEY_WORLD_2: + return "\\"; + case GLFW_KEY_0: + case GLFW_KEY_KP_0: + return "0"; + case GLFW_KEY_1: + case GLFW_KEY_KP_1: + return "1"; + case GLFW_KEY_2: + case GLFW_KEY_KP_2: + return "2"; + case GLFW_KEY_3: + case GLFW_KEY_KP_3: + return "3"; + case GLFW_KEY_4: + case GLFW_KEY_KP_4: + return "4"; + case GLFW_KEY_5: + case GLFW_KEY_KP_5: + return "5"; + case GLFW_KEY_6: + case GLFW_KEY_KP_6: + return "6"; + case GLFW_KEY_7: + case GLFW_KEY_KP_7: + return "7"; + case GLFW_KEY_8: + case GLFW_KEY_KP_8: + return "8"; + case GLFW_KEY_9: + case GLFW_KEY_KP_9: + return "9"; + case GLFW_KEY_A: + return "a"; + case GLFW_KEY_B: + return "b"; + case GLFW_KEY_C: + return "c"; + case GLFW_KEY_D: + return "d"; + case GLFW_KEY_E: + return "e"; + case GLFW_KEY_F: + return "f"; + case GLFW_KEY_G: + return "g"; + case GLFW_KEY_H: + return "h"; + case GLFW_KEY_I: + return "i"; + case GLFW_KEY_J: + return "j"; + case GLFW_KEY_K: + return "k"; + case GLFW_KEY_L: + return "l"; + case GLFW_KEY_M: + return "m"; + case GLFW_KEY_N: + return "n"; + case GLFW_KEY_O: + return "o"; + case GLFW_KEY_P: + return "p"; + case GLFW_KEY_Q: + return "q"; + case GLFW_KEY_R: + return "r"; + case GLFW_KEY_S: + return "s"; + case GLFW_KEY_T: + return "t"; + case GLFW_KEY_U: + return "u"; + case GLFW_KEY_V: + return "v"; + case GLFW_KEY_W: + return "w"; + case GLFW_KEY_X: + return "x"; + case GLFW_KEY_Y: + return "y"; + case GLFW_KEY_Z: + return "z"; + } + + return NULL; } int _glfwPlatformGetKeyScancode(int key) { - return -1; + return key; } void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) @@ -327,6 +646,6 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, VkSurfaceKHR* surface) { // This seems like the most appropriate error to return here - return VK_ERROR_INITIALIZATION_FAILED; + return VK_ERROR_EXTENSION_NOT_PRESENT; }