From 7c070f55be333769c30b8dd3d759dcbc3b8e0830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Mar 2017 14:40:21 +0100 Subject: [PATCH 001/222] EGL: Add support for Cygwin --- src/egl_context.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/egl_context.c b/src/egl_context.c index 368cba969..80e9bca0d 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -291,6 +291,8 @@ GLFWbool _glfwInitEGL(void) "EGL.dll", #elif defined(_GLFW_COCOA) "libEGL.dylib", +#elif defined(__CYGWIN__) + "libEGL-1.so", #else "libEGL.so.1", #endif @@ -609,6 +611,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, "libGLESv2.dll", #elif defined(_GLFW_COCOA) "libGLESv2.dylib", +#elif defined(__CYGWIN__) + "libGLESv2-2.so", #else "libGLESv2.so.2", #endif From 27a8b3c17baf3952f74948b7842c2350144c8ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Mar 2017 17:37:33 +0100 Subject: [PATCH 002/222] EGL: Add support for EGL_KHR_context_flush_control --- README.md | 1 + src/egl_context.c | 28 +++++++++++++++++++--------- src/egl_context.h | 4 ++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 60e8dce5e..939aba181 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Iconified full screen windows could not be restored (#848) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) +- [EGL] Added support for `EGL_KHR_context_flush_control` - [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid diff --git a/src/egl_context.c b/src/egl_context.c index 80e9bca0d..e73fc0b46 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -403,6 +403,8 @@ GLFWbool _glfwInitEGL(void) extensionSupportedEGL("EGL_KHR_gl_colorspace"); _glfw.egl.KHR_get_all_proc_addresses = extensionSupportedEGL("EGL_KHR_get_all_proc_addresses"); + _glfw.egl.KHR_context_flush_control = + extensionSupportedEGL("EGL_KHR_context_flush_control"); return GLFW_TRUE; } @@ -440,6 +442,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, EGLint attribs[40]; EGLConfig config; EGLContext share = NULL; + int index = 0; if (!_glfw.egl.display) { @@ -480,7 +483,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (_glfw.egl.KHR_create_context) { - int index = 0, mask = 0, flags = 0; + int mask = 0, flags = 0; if (ctxconfig->client == GLFW_OPENGL_API) { @@ -529,21 +532,28 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (flags) setEGLattrib(EGL_CONTEXT_FLAGS_KHR, flags); - - setEGLattrib(EGL_NONE, EGL_NONE); } else { - int index = 0; - if (ctxconfig->client == GLFW_OPENGL_ES_API) setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); - - setEGLattrib(EGL_NONE, EGL_NONE); } - // Context release behaviors (GL_KHR_context_flush_control) are not yet - // supported on EGL but are not a hard constraint, so ignore and continue + if (_glfw.egl.KHR_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setEGLattrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setEGLattrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); + } + } + + setEGLattrib(EGL_NONE, EGL_NONE); window->context.egl.handle = eglCreateContext(_glfw.egl.display, config, share, attribs); diff --git a/src/egl_context.h b/src/egl_context.h index e1040acd5..f8393a49f 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -110,6 +110,9 @@ typedef MirEGLNativeWindowType EGLNativeWindowType; #define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 #define EGL_GL_COLORSPACE_KHR 0x309d #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 typedef int EGLint; typedef unsigned int EGLBoolean; @@ -181,6 +184,7 @@ typedef struct _GLFWlibraryEGL GLFWbool KHR_create_context_no_error; GLFWbool KHR_gl_colorspace; GLFWbool KHR_get_all_proc_addresses; + GLFWbool KHR_context_flush_control; void* handle; From 7410346c5cb1b5774a43b286d260973f04aa584f Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 16 Mar 2017 15:23:59 +0100 Subject: [PATCH 003/222] Cocoa: Allow undecorated windows to become main --- src/cocoa_window.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 92635035d..d2aab85f9 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -777,6 +777,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; return YES; } +- (BOOL)canBecomeMainWindow +{ + return YES; +} + @end From bff31f006eef29f9d2d68df19bde02677f1552b4 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 16 Mar 2017 16:22:00 +0100 Subject: [PATCH 004/222] Formatting --- include/GLFW/glfw3native.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index 477d0ed12..ba59913ec 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -464,7 +464,7 @@ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); * @param[out] buffer Where to store the address of the color buffer, or * `NULL`. * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an - * [error](@ref error_handling) occurred. + * [error](@ref error_handling) occurred. * * @thread_safety This function may be called from any thread. Access is not * synchronized. @@ -485,7 +485,7 @@ GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height * @param[out] buffer Where to store the address of the depth buffer, or * `NULL`. * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an - * [error](@ref error_handling) occurred. + * [error](@ref error_handling) occurred. * * @thread_safety This function may be called from any thread. Access is not * synchronized. From 6a65341e14bc7745c52fe86fe53be08dbd682dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Mar 2017 23:07:59 +0100 Subject: [PATCH 005/222] X11: Fix multiple issues in XDND support The code blindly expected UTF8_STRING for files. It did not downgrade based on source protocol version. It did not handle hostnames in text/uri-list data. It did not specify the source time stamp when converting the selection. It did not search the XdndTypeList when necessary. It did not ignore sources that specified invalid versions. While better, this is still not fully conformant. Hostnames are not validated and it does not guard against source crashes. Fixes #968. --- README.md | 1 + src/x11_init.c | 3 +- src/x11_platform.h | 5 +- src/x11_window.c | 159 ++++++++++++++++++++++++++++++++++----------- 4 files changed, 129 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 939aba181..76b384a37 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X - [X11] Bugfix: Dynamic X11 library loading did not use full sonames (#941) - [X11] Bugfix: Window creation on 64-bit would read past top of stack (#951) +- [X11] Bugfix: XDND support had multiple non-conformance issues (#968) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Cocoa] Added support for Vulkan window surface creation via [MoltenVK](https://moltengl.com/moltenvk/) (#870) diff --git a/src/x11_init.c b/src/x11_init.c index 22600c965..734c89cc4 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -629,9 +629,10 @@ static GLFWbool initExtensions(void) _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False); _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False); _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False); - _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", False); _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); + _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False); + _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False); // ICCCM, EWMH and Motif window property atoms // These can be set safely even without WM support diff --git a/src/x11_platform.h b/src/x11_platform.h index b2e4f5de0..4ca5a1dae 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -208,9 +208,10 @@ typedef struct _GLFWlibraryX11 Atom XdndStatus; Atom XdndActionCopy; Atom XdndDrop; - Atom XdndLeave; Atom XdndFinished; Atom XdndSelection; + Atom XdndTypeList; + Atom text_uri_list; // Selection (clipboard) atoms Atom TARGETS; @@ -253,7 +254,9 @@ typedef struct _GLFWlibraryX11 } saver; struct { + int version; Window source; + Atom format; } xdnd; struct { diff --git a/src/x11_window.c b/src/x11_window.c index cc8ffd974..327bd750a 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -48,6 +48,8 @@ #define Button6 6 #define Button7 7 +#define _GLFW_XDND_VERSION 5 + // Wait for data to arrive using select // This avoids blocking other threads via the per-display Xlib lock that also @@ -415,7 +417,12 @@ static char** parseUriList(char* text, int* count) continue; if (strncmp(line, prefix, strlen(prefix)) == 0) + { line += strlen(prefix); + // TODO: Validate hostname + while (*line != '/') + line++; + } (*count)++; @@ -619,10 +626,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, XFree(hint); } - if (_glfw.x11.XdndAware) + // Announce support for Xdnd (drag and drop) { - // Announce support for Xdnd (drag and drop) - const Atom version = 5; + const Atom version = _GLFW_XDND_VERSION; XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*) &version, 1); @@ -1307,44 +1313,121 @@ static void processEvent(XEvent *event) else if (event->xclient.message_type == _glfw.x11.XdndEnter) { // A drag operation has entered the window - // TODO: Check if UTF-8 string is supported by the source + unsigned long i, count; + Atom* formats = NULL; + const GLFWbool list = event->xclient.data.l[1] & 1; + + _glfw.x11.xdnd.source = event->xclient.data.l[0]; + _glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24; + _glfw.x11.xdnd.format = None; + + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + if (list) + { + count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source, + _glfw.x11.XdndTypeList, + XA_ATOM, + (unsigned char**) &formats); + } + else + { + count = 3; + formats = (Atom*) event->xclient.data.l + 2; + } + + for (i = 0; i < count; i++) + { + if (formats[i] == _glfw.x11.text_uri_list) + { + _glfw.x11.xdnd.format = _glfw.x11.text_uri_list; + break; + } + } + + if (list && formats) + XFree(formats); } else if (event->xclient.message_type == _glfw.x11.XdndDrop) { - // The drag operation has finished dropping on - // the window, ask to convert it to a UTF-8 string - _glfw.x11.xdnd.source = event->xclient.data.l[0]; - XConvertSelection(_glfw.x11.display, - _glfw.x11.XdndSelection, - _glfw.x11.UTF8_STRING, - _glfw.x11.XdndSelection, - window->x11.handle, CurrentTime); + // The drag operation has finished by dropping on the window + Time time = CurrentTime; + + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + if (_glfw.x11.xdnd.format) + { + if (_glfw.x11.xdnd.version >= 1) + time = event->xclient.data.l[2]; + + // Request the chosen format from the source window + XConvertSelection(_glfw.x11.display, + _glfw.x11.XdndSelection, + _glfw.x11.xdnd.format, + _glfw.x11.XdndSelection, + window->x11.handle, + time); + } + else if (_glfw.x11.xdnd.version >= 2) + { + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = 0; // The drag was rejected + reply.xclient.data.l[2] = None; + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } } else if (event->xclient.message_type == _glfw.x11.XdndPosition) { // The drag operation has moved over the window - const int absX = (event->xclient.data.l[2] >> 16) & 0xFFFF; - const int absY = (event->xclient.data.l[2]) & 0xFFFF; - int x, y; + const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff; + const int yabs = (event->xclient.data.l[2]) & 0xffff; + Window dummy; + int xpos, ypos; - _glfwPlatformGetWindowPos(window, &x, &y); - _glfwInputCursorPos(window, absX - x, absY - y); + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + XTranslateCoordinates(_glfw.x11.display, + window->x11.handle, + _glfw.x11.root, + xabs, yabs, + &xpos, &ypos, + &dummy); + + _glfwInputCursorPos(window, xpos, ypos); - // Reply that we are ready to copy the dragged data XEvent reply; memset(&reply, 0, sizeof(reply)); reply.type = ClientMessage; - reply.xclient.window = event->xclient.data.l[0]; + reply.xclient.window = _glfw.x11.xdnd.source; reply.xclient.message_type = _glfw.x11.XdndStatus; reply.xclient.format = 32; reply.xclient.data.l[0] = window->x11.handle; - reply.xclient.data.l[1] = 1; // Always accept the dnd with no rectangle reply.xclient.data.l[2] = 0; // Specify an empty rectangle reply.xclient.data.l[3] = 0; - reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; - XSendEvent(_glfw.x11.display, event->xclient.data.l[0], + if (_glfw.x11.xdnd.format) + { + // Reply that we are ready to copy the dragged data + reply.xclient.data.l[1] = 1; // Accept with no rectangle + if (_glfw.x11.xdnd.version >= 2) + reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; + } + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, False, NoEventMask, &reply); XFlush(_glfw.x11.display); } @@ -1354,11 +1437,11 @@ static void processEvent(XEvent *event) case SelectionNotify: { - if (event->xselection.property) + if (event->xselection.property == _glfw.x11.XdndSelection) { // The converted data from the drag operation has arrived char* data; - const int result = + const unsigned long result = _glfwGetWindowPropertyX11(event->xselection.requestor, event->xselection.property, event->xselection.target, @@ -1379,21 +1462,23 @@ static void processEvent(XEvent *event) if (data) XFree(data); - XEvent reply; - memset(&reply, 0, sizeof(reply)); + if (_glfw.x11.xdnd.version >= 2) + { + XEvent reply; + memset(&reply, 0, sizeof(reply)); - reply.type = ClientMessage; - reply.xclient.window = _glfw.x11.xdnd.source; - reply.xclient.message_type = _glfw.x11.XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = window->x11.handle; - reply.xclient.data.l[1] = result; - reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; + reply.type = ClientMessage; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; - // Reply that all is well - XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, - False, NoEventMask, &reply); - XFlush(_glfw.x11.display); + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } } return; From 2376d3b16abfd1f35c91bfa7115240b459745c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 17 Mar 2017 01:10:20 +0100 Subject: [PATCH 006/222] Formatting --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index acdac20b9..e4c6682eb 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2002-2006 Marcus Geelnard +Copyright (c) 2002-2006 Marcus Geelnard Copyright (c) 2006-2016 Camilla Löwy This software is provided 'as-is', without any express or implied From 62414bff6e2fc76c775cac8086e9330f8e6f22d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 17 Mar 2017 14:09:07 +0100 Subject: [PATCH 007/222] X11: Fix inverted coordinate transform --- src/x11_window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11_window.c b/src/x11_window.c index 327bd750a..907fa7946 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1400,8 +1400,8 @@ static void processEvent(XEvent *event) return; XTranslateCoordinates(_glfw.x11.display, - window->x11.handle, _glfw.x11.root, + window->x11.handle, xabs, yabs, &xpos, &ypos, &dummy); From aaf2800c9cf741faeade57932be3143bf9c5b755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 8 Mar 2017 13:58:09 +0100 Subject: [PATCH 008/222] Add internal TLS support Related to #970. --- src/cocoa_init.m | 4 --- src/context.c | 12 ++++----- src/egl_context.c | 6 ++--- src/glx_context.c | 4 +-- src/init.c | 5 ++++ src/internal.h | 21 ++++++++++++---- src/mir_init.c | 4 --- src/nsgl_context.m | 4 +-- src/null_init.c | 4 --- src/osmesa_context.c | 2 +- src/posix_tls.c | 58 +++++++++++++++++++++++-------------------- src/posix_tls.h | 9 +++---- src/wgl_context.c | 8 +++--- src/win32_init.c | 4 --- src/win32_platform.h | 9 +++---- src/win32_tls.c | 59 +++++++++++++++++++++++--------------------- src/window.c | 4 +-- src/wl_init.c | 4 --- src/x11_init.c | 4 --- 19 files changed, 109 insertions(+), 116 deletions(-) diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 0913c476a..ba5ddb629 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -311,9 +311,6 @@ int _glfwPlatformInit(void) if (!initializeTIS()) return GLFW_FALSE; - if (!_glfwInitThreadLocalStoragePOSIX()) - return GLFW_FALSE; - _glfwInitTimerNS(); _glfwInitJoysticksNS(); @@ -362,7 +359,6 @@ void _glfwPlatformTerminate(void) _glfwTerminateNSGL(); _glfwTerminateJoysticksNS(); - _glfwTerminateThreadLocalStoragePOSIX(); [_glfw.ns.autoreleasePool release]; _glfw.ns.autoreleasePool = nil; diff --git a/src/context.c b/src/context.c index ed921a4b5..498e0e16a 100644 --- a/src/context.c +++ b/src/context.c @@ -331,7 +331,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) NULL }; - window = _glfwPlatformGetCurrentContext(); + window = _glfwPlatformGetTls(&_glfw.context); window->context.source = ctxconfig->source; window->context.client = GLFW_OPENGL_API; @@ -578,7 +578,7 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFWwindow* previous = _glfwPlatformGetCurrentContext(); + _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.context); _GLFW_REQUIRE_INIT(); @@ -601,7 +601,7 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) GLFWAPI GLFWwindow* glfwGetCurrentContext(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return (GLFWwindow*) _glfwPlatformGetCurrentContext(); + return _glfwPlatformGetTls(&_glfw.context); } GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) @@ -626,7 +626,7 @@ GLFWAPI void glfwSwapInterval(int interval) _GLFW_REQUIRE_INIT(); - window = _glfwPlatformGetCurrentContext(); + window = _glfwPlatformGetTls(&_glfw.context); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); @@ -643,7 +643,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); - window = _glfwPlatformGetCurrentContext(); + window = _glfwPlatformGetTls(&_glfw.context); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); @@ -708,7 +708,7 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - window = _glfwPlatformGetCurrentContext(); + window = _glfwPlatformGetTls(&_glfw.context); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); diff --git a/src/egl_context.c b/src/egl_context.c index e73fc0b46..328a04578 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -199,12 +199,12 @@ static void makeContextCurrentEGL(_GLFWwindow* window) } } - _glfwPlatformSetCurrentContext(window); + _glfwPlatformSetTls(&_glfw.context, window); } static void swapBuffersEGL(_GLFWwindow* window) { - if (window != _glfwPlatformGetCurrentContext()) + if (window != _glfwPlatformGetTls(&_glfw.context)) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: The context must be current on the calling thread when swapping buffers"); @@ -233,7 +233,7 @@ static int extensionSupportedEGL(const char* extension) static GLFWglproc getProcAddressEGL(const char* procname) { - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); if (window->context.egl.client) { diff --git a/src/glx_context.c b/src/glx_context.c index 2faf599ca..9c2ccb12c 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -165,7 +165,7 @@ static void makeContextCurrentGLX(_GLFWwindow* window) } } - _glfwPlatformSetCurrentContext(window); + _glfwPlatformSetTls(&_glfw.context, window); } static void swapBuffersGLX(_GLFWwindow* window) @@ -175,7 +175,7 @@ static void swapBuffersGLX(_GLFWwindow* window) static void swapIntervalGLX(int interval) { - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); if (_glfw.glx.EXT_swap_control) { diff --git a/src/init.c b/src/init.c index b2da9a770..92450b59a 100644 --- a/src/init.c +++ b/src/init.c @@ -113,6 +113,8 @@ static void terminate(void) _glfwTerminateVulkan(); _glfwPlatformTerminate(); + _glfwPlatformDestroyTls(&_glfw.context); + memset(&_glfw, 0, sizeof(_glfw)); } @@ -162,6 +164,9 @@ GLFWAPI int glfwInit(void) memset(&_glfw, 0, sizeof(_glfw)); _glfw.hints.init = _glfwInitHints; + if (!_glfwPlatformCreateTls(&_glfw.context)) + return GLFW_FALSE; + if (!_glfwPlatformInit()) { terminate(); diff --git a/src/internal.h b/src/internal.h index 13214b071..d3a4f6878 100644 --- a/src/internal.h +++ b/src/internal.h @@ -69,6 +69,7 @@ typedef struct _GLFWlibrary _GLFWlibrary; typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; typedef struct _GLFWjoystick _GLFWjoystick; +typedef struct _GLFWtls _GLFWtls; typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); @@ -485,6 +486,14 @@ struct _GLFWjoystick _GLFW_PLATFORM_JOYSTICK_STATE; }; +/*! @brief Thread local storage structure. + */ +struct _GLFWtls +{ + // This is defined in the platform's tls.h + _GLFW_PLATFORM_TLS_STATE; +}; + /*! @brief Library global data. */ struct _GLFWlibrary @@ -510,6 +519,8 @@ struct _GLFWlibrary uint64_t timerOffset; + _GLFWtls context; + struct { GLFWbool available; void* handle; @@ -546,8 +557,6 @@ struct _GLFWlibrary _GLFW_PLATFORM_LIBRARY_TIME_STATE; // This is defined in the platform's joystick.h _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; - // This is defined in the platform's tls.h - _GLFW_PLATFORM_LIBRARY_TLS_STATE; // This is defined in egl_context.h _GLFW_EGL_LIBRARY_CONTEXT_STATE; // This is defined in osmesa_context.h @@ -634,13 +643,15 @@ void _glfwPlatformWaitEvents(void); void _glfwPlatformWaitEventsTimeout(double timeout); void _glfwPlatformPostEmptyEvent(void); -void _glfwPlatformSetCurrentContext(_GLFWwindow* context); -_GLFWwindow* _glfwPlatformGetCurrentContext(void); - void _glfwPlatformGetRequiredInstanceExtensions(char** extensions); int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); +void _glfwPlatformDestroyTls(_GLFWtls* tls); +void* _glfwPlatformGetTls(_GLFWtls* tls); +void _glfwPlatformSetTls(_GLFWtls* tls, void* value); + /*! @} */ diff --git a/src/mir_init.c b/src/mir_init.c index 5df5d981e..3a96c78aa 100644 --- a/src/mir_init.c +++ b/src/mir_init.c @@ -190,9 +190,6 @@ int _glfwPlatformInit(void) createKeyTables(); - if (!_glfwInitThreadLocalStoragePOSIX()) - return GLFW_FALSE; - if (!_glfwInitJoysticksLinux()) return GLFW_FALSE; @@ -222,7 +219,6 @@ void _glfwPlatformTerminate(void) { _glfwTerminateEGL(); _glfwTerminateJoysticksLinux(); - _glfwTerminateThreadLocalStoragePOSIX(); _glfwDeleteEventQueueMir(_glfw.mir.eventQueue); diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 976636443..f2902d7fa 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -34,7 +34,7 @@ static void makeContextCurrentNSGL(_GLFWwindow* window) else [NSOpenGLContext clearCurrentContext]; - _glfwPlatformSetCurrentContext(window); + _glfwPlatformSetTls(&_glfw.context, window); } static void swapBuffersNSGL(_GLFWwindow* window) @@ -45,7 +45,7 @@ static void swapBuffersNSGL(_GLFWwindow* window) static void swapIntervalNSGL(int interval) { - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); GLint sync = interval; [window->context.nsgl.object setValues:&sync diff --git a/src/null_init.c b/src/null_init.c index e2c9c74bd..341473880 100644 --- a/src/null_init.c +++ b/src/null_init.c @@ -34,9 +34,6 @@ int _glfwPlatformInit(void) { - if (!_glfwInitThreadLocalStoragePOSIX()) - return GLFW_FALSE; - _glfwInitTimerPOSIX(); return GLFW_TRUE; } @@ -44,7 +41,6 @@ int _glfwPlatformInit(void) void _glfwPlatformTerminate(void) { _glfwTerminateOSMesa(); - _glfwTerminateThreadLocalStoragePOSIX(); } const char* _glfwPlatformGetVersionString(void) diff --git a/src/osmesa_context.c b/src/osmesa_context.c index 579dc391d..7ea656276 100644 --- a/src/osmesa_context.c +++ b/src/osmesa_context.c @@ -63,7 +63,7 @@ static void makeContextCurrentOSMesa(_GLFWwindow* window) } } - _glfwPlatformSetCurrentContext(window); + _glfwPlatformSetTls(&_glfw.context, window); } static GLFWglproc getProcAddressOSMesa(const char* procname) diff --git a/src/posix_tls.c b/src/posix_tls.c index 1b913a0f0..980ff23ba 100644 --- a/src/posix_tls.c +++ b/src/posix_tls.c @@ -27,42 +27,46 @@ #include "internal.h" - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWbool _glfwInitThreadLocalStoragePOSIX(void) -{ - if (pthread_key_create(&_glfw.posix_tls.context, NULL) != 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "POSIX: Failed to create context TLS"); - return GLFW_FALSE; - } - - _glfw.posix_tls.allocated = GLFW_TRUE; - return GLFW_TRUE; -} - -void _glfwTerminateThreadLocalStoragePOSIX(void) -{ - if (_glfw.posix_tls.allocated) - pthread_key_delete(_glfw.posix_tls.context); -} +#include +#include ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformSetCurrentContext(_GLFWwindow* context) +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) { - pthread_setspecific(_glfw.posix_tls.context, context); + assert(tls->posix.allocated == GLFW_FALSE); + + if (pthread_key_create(&tls->posix.key, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "POSIX: Failed to create context TLS"); + return GLFW_FALSE; + } + + tls->posix.allocated = GLFW_TRUE; + return GLFW_TRUE; } -_GLFWwindow* _glfwPlatformGetCurrentContext(void) +void _glfwPlatformDestroyTls(_GLFWtls* tls) { - return pthread_getspecific(_glfw.posix_tls.context); + assert(tls->posix.allocated == GLFW_TRUE); + if (tls->posix.allocated) + pthread_key_delete(tls->posix.key); + memset(tls, 0, sizeof(_GLFWtls)); +} + +void* _glfwPlatformGetTls(_GLFWtls* tls) +{ + assert(tls->posix.allocated == GLFW_TRUE); + return pthread_getspecific(tls->posix.key); +} + +void _glfwPlatformSetTls(_GLFWtls* tls, void* value) +{ + assert(tls->posix.allocated == GLFW_TRUE); + pthread_setspecific(tls->posix.key, value); } diff --git a/src/posix_tls.h b/src/posix_tls.h index 8d033fba0..5d0e7c369 100644 --- a/src/posix_tls.h +++ b/src/posix_tls.h @@ -30,20 +30,17 @@ #include -#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsPOSIX posix_tls +#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix -// POSIX-specific global TLS data +// POSIX-specific thread local storage data // typedef struct _GLFWtlsPOSIX { GLFWbool allocated; - pthread_key_t context; + pthread_key_t key; } _GLFWtlsPOSIX; -GLFWbool _glfwInitThreadLocalStoragePOSIX(void); -void _glfwTerminateThreadLocalStoragePOSIX(void); - #endif // _glfw3_posix_tls_h_ diff --git a/src/wgl_context.c b/src/wgl_context.c index 0cbb68f53..c59997fc4 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -233,12 +233,12 @@ static void makeContextCurrentWGL(_GLFWwindow* window) if (window) { if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) - _glfwPlatformSetCurrentContext(window); + _glfwPlatformSetTls(&_glfw.context, window); else { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to make context current"); - _glfwPlatformSetCurrentContext(NULL); + _glfwPlatformSetTls(&_glfw.context, NULL); } } else @@ -249,7 +249,7 @@ static void makeContextCurrentWGL(_GLFWwindow* window) "WGL: Failed to clear current context"); } - _glfwPlatformSetCurrentContext(NULL); + _glfwPlatformSetTls(&_glfw.context, NULL); } } @@ -268,7 +268,7 @@ static void swapBuffersWGL(_GLFWwindow* window) static void swapIntervalWGL(int interval) { - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); window->context.wgl.interval = interval; diff --git a/src/win32_init.c b/src/win32_init.c index 785d75d34..636851288 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -435,9 +435,6 @@ void _glfwInputErrorWin32(int error, const char* description) int _glfwPlatformInit(void) { - if (!_glfwInitThreadLocalStorageWin32()) - return GLFW_FALSE; - // To make SetForegroundWindow work as we want, we need to fiddle // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early // as possible in the hope of still being the foreground process) @@ -489,7 +486,6 @@ void _glfwPlatformTerminate(void) _glfwTerminateEGL(); _glfwTerminateJoysticksWin32(); - _glfwTerminateThreadLocalStorageWin32(); freeLibraries(); } diff --git a/src/win32_platform.h b/src/win32_platform.h index 8cf2b5a48..c77358e2d 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -221,9 +221,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)( #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 #define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time -#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsWin32 win32_tls #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 +#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32 // Win32-specific per-window data @@ -328,12 +328,12 @@ typedef struct _GLFWtimeWin32 } _GLFWtimeWin32; -// Win32-specific global TLS data +// Win32-specific thread local storage data // typedef struct _GLFWtlsWin32 { GLFWbool allocated; - DWORD context; + DWORD index; } _GLFWtlsWin32; @@ -341,9 +341,6 @@ typedef struct _GLFWtlsWin32 GLFWbool _glfwRegisterWindowClassWin32(void); void _glfwUnregisterWindowClassWin32(void); -GLFWbool _glfwInitThreadLocalStorageWin32(void); -void _glfwTerminateThreadLocalStorageWin32(void); - WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); void _glfwInputErrorWin32(int error, const char* description); diff --git a/src/win32_tls.c b/src/win32_tls.c index 2bcb68a54..944f7e5e0 100644 --- a/src/win32_tls.c +++ b/src/win32_tls.c @@ -27,43 +27,46 @@ #include "internal.h" - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWbool _glfwInitThreadLocalStorageWin32(void) -{ - _glfw.win32_tls.context = TlsAlloc(); - if (_glfw.win32_tls.context == TLS_OUT_OF_INDEXES) - { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to allocate TLS index"); - return GLFW_FALSE; - } - - _glfw.win32_tls.allocated = GLFW_TRUE; - return GLFW_TRUE; -} - -void _glfwTerminateThreadLocalStorageWin32(void) -{ - if (_glfw.win32_tls.allocated) - TlsFree(_glfw.win32_tls.context); -} +#include ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformSetCurrentContext(_GLFWwindow* context) +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) { - TlsSetValue(_glfw.win32_tls.context, context); + assert(tls->win32.allocated == GLFW_FALSE); + + tls->win32.index = TlsAlloc(); + if (tls->win32.index == TLS_OUT_OF_INDEXES) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate TLS index"); + return GLFW_FALSE; + } + + tls->win32.allocated = GLFW_TRUE; + return GLFW_TRUE; } -_GLFWwindow* _glfwPlatformGetCurrentContext(void) +void _glfwPlatformDestroyTls(_GLFWtls* tls) { - return TlsGetValue(_glfw.win32_tls.context); + assert(tls->win32.allocated == GLFW_TRUE); + if (tls->win32.allocated) + TlsFree(tls->win32.index); + memset(tls, 0, sizeof(_GLFWtls)); +} + +void* _glfwPlatformGetTls(_GLFWtls* tls) +{ + assert(tls->win32.allocated == GLFW_TRUE); + return TlsGetValue(tls->win32.index); +} + +void _glfwPlatformSetTls(_GLFWtls* tls, void* value) +{ + assert(tls->win32.allocated == GLFW_TRUE); + TlsSetValue(tls->win32.index, value); } diff --git a/src/window.c b/src/window.c index d16f75c59..bf98723ea 100644 --- a/src/window.c +++ b/src/window.c @@ -192,7 +192,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->denom = GLFW_DONT_CARE; // Save the currently current context so it can be restored later - previous = _glfwPlatformGetCurrentContext(); + previous = _glfwPlatformGetTls(&_glfw.context); if (ctxconfig.client != GLFW_NO_API) glfwMakeContextCurrent(NULL); @@ -408,7 +408,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) // The window's context must not be current on another thread when the // window is destroyed - if (window == _glfwPlatformGetCurrentContext()) + if (window == _glfwPlatformGetTls(&_glfw.context)) glfwMakeContextCurrent(NULL); _glfwPlatformDestroyWindow(window); diff --git a/src/wl_init.c b/src/wl_init.c index ecc94f2a7..8e12bafa7 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -667,9 +667,6 @@ int _glfwPlatformInit(void) // Sync so we got all initial output events wl_display_roundtrip(_glfw.wl.display); - if (!_glfwInitThreadLocalStoragePOSIX()) - return GLFW_FALSE; - if (!_glfwInitJoysticksLinux()) return GLFW_FALSE; @@ -695,7 +692,6 @@ void _glfwPlatformTerminate(void) { _glfwTerminateEGL(); _glfwTerminateJoysticksLinux(); - _glfwTerminateThreadLocalStoragePOSIX(); xkb_compose_state_unref(_glfw.wl.xkb.composeState); xkb_keymap_unref(_glfw.wl.xkb.keymap); diff --git a/src/x11_init.c b/src/x11_init.c index 734c89cc4..ca271546b 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -822,9 +822,6 @@ int _glfwPlatformInit(void) } } - if (!_glfwInitThreadLocalStoragePOSIX()) - return GLFW_FALSE; - #if defined(__linux__) if (!_glfwInitJoysticksLinux()) return GLFW_FALSE; @@ -885,7 +882,6 @@ void _glfwPlatformTerminate(void) #if defined(__linux__) _glfwTerminateJoysticksLinux(); #endif - _glfwTerminateThreadLocalStoragePOSIX(); } const char* _glfwPlatformGetVersionString(void) From 1982543cd2943151ab538ccb31ee48cd857ab2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sat, 18 Mar 2017 23:09:34 +0100 Subject: [PATCH 009/222] Cleanup --- src/cocoa_platform.h | 6 +++--- src/cocoa_time.c | 4 ++-- src/init.c | 2 +- src/input.c | 4 ++-- src/internal.h | 10 ++++++---- src/posix_time.c | 12 ++++++------ src/posix_time.h | 6 +++--- src/win32_platform.h | 6 +++--- src/win32_time.c | 12 ++++++------ 9 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 0b47d611b..74db7fa59 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -66,7 +66,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacO #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns -#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeNS ns_time +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerNS ns #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns @@ -151,11 +151,11 @@ typedef struct _GLFWcursorNS // Cocoa-specific global timer data // -typedef struct _GLFWtimeNS +typedef struct _GLFWtimerNS { uint64_t frequency; -} _GLFWtimeNS; +} _GLFWtimerNS; void _glfwInitTimerNS(void); diff --git a/src/cocoa_time.c b/src/cocoa_time.c index 8bbeb0103..3b2703515 100644 --- a/src/cocoa_time.c +++ b/src/cocoa_time.c @@ -40,7 +40,7 @@ void _glfwInitTimerNS(void) mach_timebase_info_data_t info; mach_timebase_info(&info); - _glfw.ns_time.frequency = (info.denom * 1e9) / info.numer; + _glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer; } @@ -55,6 +55,6 @@ uint64_t _glfwPlatformGetTimerValue(void) uint64_t _glfwPlatformGetTimerFrequency(void) { - return _glfw.ns_time.frequency; + return _glfw.timer.ns.frequency; } diff --git a/src/init.c b/src/init.c index 92450b59a..7585c567d 100644 --- a/src/init.c +++ b/src/init.c @@ -174,7 +174,7 @@ GLFWAPI int glfwInit(void) } _glfw.initialized = GLFW_TRUE; - _glfw.timerOffset = _glfwPlatformGetTimerValue(); + _glfw.timer.offset = _glfwPlatformGetTimerValue(); // Not all window hints have zero as their default value glfwDefaultWindowHints(); diff --git a/src/input.c b/src/input.c index 115eefb27..16459b3f5 100644 --- a/src/input.c +++ b/src/input.c @@ -770,7 +770,7 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) GLFWAPI double glfwGetTime(void) { _GLFW_REQUIRE_INIT_OR_RETURN(0.0); - return (double) (_glfwPlatformGetTimerValue() - _glfw.timerOffset) / + return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) / _glfwPlatformGetTimerFrequency(); } @@ -784,7 +784,7 @@ GLFWAPI void glfwSetTime(double time) return; } - _glfw.timerOffset = _glfwPlatformGetTimerValue() - + _glfw.timer.offset = _glfwPlatformGetTimerValue() - (uint64_t) (time * _glfwPlatformGetTimerFrequency()); } diff --git a/src/internal.h b/src/internal.h index d3a4f6878..be9ced898 100644 --- a/src/internal.h +++ b/src/internal.h @@ -517,10 +517,14 @@ struct _GLFWlibrary _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; - uint64_t timerOffset; - _GLFWtls context; + struct { + uint64_t offset; + // This is defined in the platform's time.h + _GLFW_PLATFORM_LIBRARY_TIMER_STATE; + } timer; + struct { GLFWbool available; void* handle; @@ -553,8 +557,6 @@ struct _GLFWlibrary _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; // This is defined in the context API's context.h _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE; - // This is defined in the platform's time.h - _GLFW_PLATFORM_LIBRARY_TIME_STATE; // This is defined in the platform's joystick.h _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; // This is defined in egl_context.h diff --git a/src/posix_time.c b/src/posix_time.c index a0e276910..00b2831d1 100644 --- a/src/posix_time.c +++ b/src/posix_time.c @@ -44,14 +44,14 @@ void _glfwInitTimerPOSIX(void) if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { - _glfw.posix_time.monotonic = GLFW_TRUE; - _glfw.posix_time.frequency = 1000000000; + _glfw.timer.posix.monotonic = GLFW_TRUE; + _glfw.timer.posix.frequency = 1000000000; } else #endif { - _glfw.posix_time.monotonic = GLFW_FALSE; - _glfw.posix_time.frequency = 1000000; + _glfw.timer.posix.monotonic = GLFW_FALSE; + _glfw.timer.posix.frequency = 1000000; } } @@ -63,7 +63,7 @@ void _glfwInitTimerPOSIX(void) uint64_t _glfwPlatformGetTimerValue(void) { #if defined(CLOCK_MONOTONIC) - if (_glfw.posix_time.monotonic) + if (_glfw.timer.posix.monotonic) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -80,6 +80,6 @@ uint64_t _glfwPlatformGetTimerValue(void) uint64_t _glfwPlatformGetTimerFrequency(void) { - return _glfw.posix_time.frequency; + return _glfw.timer.posix.frequency; } diff --git a/src/posix_time.h b/src/posix_time.h index 17d5c17fd..f4cf4db1e 100644 --- a/src/posix_time.h +++ b/src/posix_time.h @@ -28,19 +28,19 @@ #ifndef _glfw3_posix_time_h_ #define _glfw3_posix_time_h_ -#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimePOSIX posix_time +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix #include // POSIX-specific global timer data // -typedef struct _GLFWtimePOSIX +typedef struct _GLFWtimerPOSIX { GLFWbool monotonic; uint64_t frequency; -} _GLFWtimePOSIX; +} _GLFWtimerPOSIX; void _glfwInitTimerPOSIX(void); diff --git a/src/win32_platform.h b/src/win32_platform.h index c77358e2d..d51dee25c 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -220,7 +220,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)( #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 -#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerWin32 win32 #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32 @@ -321,12 +321,12 @@ typedef struct _GLFWcursorWin32 // Win32-specific global timer data // -typedef struct _GLFWtimeWin32 +typedef struct _GLFWtimerWin32 { GLFWbool hasPC; uint64_t frequency; -} _GLFWtimeWin32; +} _GLFWtimerWin32; // Win32-specific thread local storage data // diff --git a/src/win32_time.c b/src/win32_time.c index a533c3772..f333cd444 100644 --- a/src/win32_time.c +++ b/src/win32_time.c @@ -40,13 +40,13 @@ void _glfwInitTimerWin32(void) if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) { - _glfw.win32_time.hasPC = GLFW_TRUE; - _glfw.win32_time.frequency = frequency; + _glfw.timer.win32.hasPC = GLFW_TRUE; + _glfw.timer.win32.frequency = frequency; } else { - _glfw.win32_time.hasPC = GLFW_FALSE; - _glfw.win32_time.frequency = 1000; + _glfw.timer.win32.hasPC = GLFW_FALSE; + _glfw.timer.win32.frequency = 1000; } } @@ -57,7 +57,7 @@ void _glfwInitTimerWin32(void) uint64_t _glfwPlatformGetTimerValue(void) { - if (_glfw.win32_time.hasPC) + if (_glfw.timer.win32.hasPC) { uint64_t value; QueryPerformanceCounter((LARGE_INTEGER*) &value); @@ -69,6 +69,6 @@ uint64_t _glfwPlatformGetTimerValue(void) uint64_t _glfwPlatformGetTimerFrequency(void) { - return _glfw.win32_time.frequency; + return _glfw.timer.win32.frequency; } From 55d0560746632deb2df0807f4ba190383a353ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 23 Mar 2017 15:54:34 +0100 Subject: [PATCH 010/222] Cocoa: Fix range handling for hats and buttons Fixes #888. --- README.md | 1 + src/cocoa_joystick.m | 29 ++++++++++++----------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 76b384a37..9baa86bfc 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Leaving video mode with `glfwSetWindowMonitor` would set incorrect position and size (#748) - [Cocoa] Bugfix: Iconified full screen windows could not be restored (#848) +- [Cocoa] Bugfix: Value range was ignored for joystick hats and buttons (#888) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) - [EGL] Added support for `EGL_KHR_context_flush_control` diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index e828002b0..61d85a9f4 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -53,29 +53,19 @@ typedef struct _GLFWjoyelementNS // static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element) { - IOReturn result = kIOReturnSuccess; IOHIDValueRef valueRef; long value = 0; - if (js && element && js->ns.device) + if (js->ns.device) { - result = IOHIDDeviceGetValue(js->ns.device, - element->native, - &valueRef); - - if (kIOReturnSuccess == result) + if (IOHIDDeviceGetValue(js->ns.device, + element->native, + &valueRef) == kIOReturnSuccess) { value = IOHIDValueGetIntegerValue(valueRef); - - // Record min and max for auto calibration - if (value < element->minimum) - element->minimum = value; - if (value > element->maximum) - element->maximum = value; } } - // Auto user scale return value; } @@ -349,8 +339,13 @@ int _glfwPlatformPollJoystick(int jid, int mode) CFArrayGetValueAtIndex(js->ns.axes, i); const long value = getElementValue(js, axis); - const long delta = axis->maximum - axis->minimum; + // Perform auto calibration + if (value < axis->minimum) + axis->minimum = value; + if (value > axis->maximum) + axis->maximum = value; + const long delta = axis->maximum - axis->minimum; if (delta == 0) _glfwInputJoystickAxis(jid, i, value); else @@ -365,7 +360,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) { _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.buttons, i); - const char value = getElementValue(js, button) ? 1 : 0; + const char value = getElementValue(js, button) - button->minimum; _glfwInputJoystickButton(jid, i, value); } @@ -386,7 +381,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) _GLFWjoyelementNS* hat = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.hats, i); - long state = getElementValue(js, hat); + long state = getElementValue(js, hat) - hat->minimum; if (state < 0 || state > 8) state = 8; From cf2eab5b4ee2de1808e80a2a49096f011fbd0b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 23 Mar 2017 17:30:39 +0100 Subject: [PATCH 011/222] Cocoa: Made axis auto-calibration less jumpy --- src/cocoa_joystick.m | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 61d85a9f4..d1a230352 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -338,18 +338,21 @@ int _glfwPlatformPollJoystick(int jid, int mode) _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.axes, i); - const long value = getElementValue(js, axis); + const long raw = getElementValue(js, axis); // Perform auto calibration - if (value < axis->minimum) - axis->minimum = value; - if (value > axis->maximum) - axis->maximum = value; + if (raw < axis->minimum) + axis->minimum = raw; + if (raw > axis->maximum) + axis->maximum = raw; const long delta = axis->maximum - axis->minimum; if (delta == 0) - _glfwInputJoystickAxis(jid, i, value); + _glfwInputJoystickAxis(jid, i, 0.f); else - _glfwInputJoystickAxis(jid, i, (2.f * (value - axis->minimum) / delta) - 1.f); + { + const float value = (2.f * (raw - axis->minimum) / delta) - 1.f; + _glfwInputJoystickAxis(jid, i, value); + } } } else if (mode == _GLFW_POLL_BUTTONS) From 5fe4dfb511e12b954f9fba11d989df48f5f203fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 19 Mar 2017 05:30:27 +0100 Subject: [PATCH 012/222] X11: Narrow criteria for disabling RandR Fixes #972. --- README.md | 1 + src/x11_init.c | 19 ++++++++----------- src/x11_monitor.c | 7 ------- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 9baa86bfc..f537aeade 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Dynamic X11 library loading did not use full sonames (#941) - [X11] Bugfix: Window creation on 64-bit would read past top of stack (#951) - [X11] Bugfix: XDND support had multiple non-conformance issues (#968) +- [X11] Bugfix: The RandR monitor path was disabled despite working RandR (#972) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Cocoa] Added support for Vulkan window surface creation via [MoltenVK](https://moltengl.com/moltenvk/) (#870) diff --git a/src/x11_init.c b/src/x11_init.c index ca271546b..f283e6a55 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -530,26 +530,23 @@ static GLFWbool initExtensions(void) if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0])) { - // This is either a headless system or an older Nvidia binary driver - // with broken gamma support - // Flag it as useless and fall back to Xf86VidMode gamma, if - // available - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Detected broken RandR gamma ramp support"); + // This is likely an older Nvidia driver with broken gamma support + // Flag it as useless and fall back to xf86vm gamma, if available _glfw.x11.randr.gammaBroken = GLFW_TRUE; } - if (!sr->ncrtc || !sr->noutput || !sr->nmode) + if (!sr->ncrtc) { - // This is either a headless system or broken Cygwin/X RandR - // Flag it as useless and fall back to Xlib display functions - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Detected broken RandR monitor support"); + // A system without CRTCs is likely a system with broken RandR + // Disable the RandR monitor path and fall back to core functions _glfw.x11.randr.monitorBroken = GLFW_TRUE; } XRRFreeScreenResources(sr); + } + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { XRRSelectInput(_glfw.x11.display, _glfw.x11.root, RROutputChangeNotifyMask); } diff --git a/src/x11_monitor.c b/src/x11_monitor.c index a32d01f4e..3d6172bae 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -202,13 +202,6 @@ void _glfwPollMonitorsX11(void) } free(disconnected); - - if (!_glfw.monitorCount) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: RandR monitor support seems broken"); - _glfw.x11.randr.monitorBroken = GLFW_TRUE; - } } if (!_glfw.monitorCount) From b215a989f5f6b7af5fdb86d83547a989debc0dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 19 Mar 2017 22:21:46 +0100 Subject: [PATCH 013/222] Win32: Check for monitor object creation failure --- src/win32_monitor.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/win32_monitor.c b/src/win32_monitor.c index d91a02f83..06e0e0cf3 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -94,6 +94,7 @@ void _glfwPollMonitorsWin32(void) _GLFWmonitor** disconnected = NULL; DWORD adapterIndex, displayIndex; DISPLAY_DEVICEW adapter, display; + _GLFWmonitor* monitor; disconnectedCount = _glfw.monitorCount; if (disconnectedCount) @@ -145,8 +146,14 @@ void _glfwPollMonitorsWin32(void) if (i < disconnectedCount) continue; - _glfwInputMonitor(createMonitor(&adapter, &display), - GLFW_CONNECTED, type); + monitor = createMonitor(&adapter, &display); + if (!monitor) + { + free(disconnected); + return; + } + + _glfwInputMonitor(monitor, GLFW_CONNECTED, type); type = _GLFW_INSERT_LAST; } @@ -169,8 +176,14 @@ void _glfwPollMonitorsWin32(void) if (i < disconnectedCount) continue; - _glfwInputMonitor(createMonitor(&adapter, NULL), - GLFW_CONNECTED, type); + monitor = createMonitor(&adapter, NULL); + if (!monitor) + { + free(disconnected); + return; + } + + _glfwInputMonitor(monitor, GLFW_CONNECTED, type); } } From 6abb5cbcbb90c7f9c2111f1453db72d4d95f0eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 19 Mar 2017 22:25:11 +0100 Subject: [PATCH 014/222] Formatting --- src/x11_monitor.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/x11_monitor.c b/src/x11_monitor.c index 3d6172bae..f8d25e37f 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -430,9 +430,9 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) _glfwAllocGammaArrays(ramp, size); - memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); + memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); - memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); + memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); XRRFreeGamma(gamma); } @@ -455,9 +455,9 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); - memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); + memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); - memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); + memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); XRRFreeGamma(gamma); From 120082ee3a5697b9170b1899a0ff74f80db3663c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Mar 2017 01:17:21 +0100 Subject: [PATCH 015/222] Add Git commit message article --- .github/CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2584ec3f2..6d85f5cd5 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -336,6 +336,9 @@ other bugs and features to work on. If the patch fixes a bug introduced after the last release, it should not get a change log entry. +If you haven't already, read the excellent article [How to Write a Git Commit +Message](https://chris.beams.io/posts/git-commit/). + ## Contributing a feature @@ -373,6 +376,9 @@ If it adds a new OpenGL, OpenGL ES or Vulkan option or extension, support for it must be added to `tests/glfwinfo.c` and the behavior of the library when the extension is missing documented in `docs/compat.dox`. +If you haven't already, read the excellent article [How to Write a Git Commit +Message](https://chris.beams.io/posts/git-commit/). + Features will not be rejected because they don't include all the above parts, but please keep in mind that maintainer time is finite and that there are many other features and bugs to work on. From b0277a129b11588f2801c9ef6e4b2ab1d4a0c2ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Mar 2017 17:48:45 +0100 Subject: [PATCH 016/222] Fix comment --- src/x11_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11_init.c b/src/x11_init.c index f283e6a55..8b6685895 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -455,7 +455,7 @@ static void detectEWMH(void) XFree(supportedAtoms); } -// Initialize X11 display and look for supported X11 extensions +// Look for and initialize supported X11 extensions // static GLFWbool initExtensions(void) { From 9b81d72c46065fd3e37ed0724bf7c16eb0e848ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Mar 2017 17:49:05 +0100 Subject: [PATCH 017/222] X11: Fix libXi soname --- src/x11_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11_init.c b/src/x11_init.c index 8b6685895..a13f23f07 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -477,7 +477,7 @@ static GLFWbool initExtensions(void) &_glfw.x11.vidmode.errorBase); } - _glfw.x11.xi.handle = dlopen("libXi.so", RTLD_LAZY | RTLD_GLOBAL); + _glfw.x11.xi.handle = dlopen("libXi.so.6", RTLD_LAZY | RTLD_GLOBAL); if (_glfw.x11.xi.handle) { _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) From 11c15b562d2619ea47187726d2bd243fb6923765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Mar 2017 17:50:21 +0100 Subject: [PATCH 018/222] Remove superfluous comments --- src/x11_init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index a13f23f07..02ffcb577 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -503,7 +503,6 @@ static GLFWbool initExtensions(void) } } - // Check for RandR extension if (XRRQueryExtension(_glfw.x11.display, &_glfw.x11.randr.eventBase, &_glfw.x11.randr.errorBase)) @@ -559,7 +558,6 @@ static GLFWbool initExtensions(void) _glfw.x11.xinerama.available = GLFW_TRUE; } - // Check if Xkb is supported on this display _glfw.x11.xkb.major = 1; _glfw.x11.xkb.minor = 0; _glfw.x11.xkb.available = From 72d58d7b9318199a26ac01bb3040834bb10e3d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Mar 2017 17:51:03 +0100 Subject: [PATCH 019/222] Cleanup --- src/x11_init.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 02ffcb577..1767b6954 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -660,11 +660,8 @@ static GLFWbool initExtensions(void) // static Cursor createHiddenCursor(void) { - unsigned char pixels[16 * 16 * 4]; + unsigned char pixels[16 * 16 * 4] = { 0 }; GLFWimage image = { 16, 16, pixels }; - - memset(pixels, 0, sizeof(pixels)); - return _glfwCreateCursorX11(&image, 0, 0); } From 4ff66a7818e3eaa5362c828a18220b12f1cd9bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 27 Mar 2017 01:19:41 +0200 Subject: [PATCH 020/222] X11: Fix IM-duplicated key events leaking through Fixes #747. Fixes #964. --- README.md | 1 + src/x11_platform.h | 3 +-- src/x11_window.c | 13 ++++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f537aeade..8ec76cde4 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Window creation on 64-bit would read past top of stack (#951) - [X11] Bugfix: XDND support had multiple non-conformance issues (#968) - [X11] Bugfix: The RandR monitor path was disabled despite working RandR (#972) +- [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Cocoa] Added support for Vulkan window surface creation via [MoltenVK](https://moltengl.com/moltenvk/) (#870) diff --git a/src/x11_platform.h b/src/x11_platform.h index 4ca5a1dae..bafe88f4b 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -141,8 +141,7 @@ typedef struct _GLFWwindowX11 // The last position the cursor was warped to by GLFW int warpCursorPosX, warpCursorPosY; - // The information from the last KeyPress event - unsigned int lastKeyCode; + // The time of the last KeyPress event Time lastKeyTime; } _GLFWwindowX11; diff --git a/src/x11_window.c b/src/x11_window.c index 907fa7946..e1c2a3e3e 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -992,17 +992,16 @@ static void processEvent(XEvent *event) if (window->x11.ic) { // HACK: Ignore duplicate key press events generated by ibus - // Corresponding release events are filtered out by the - // GLFW key repeat logic - if (window->x11.lastKeyCode != keycode || - window->x11.lastKeyTime != event->xkey.time) + // These have the same timestamp as the original event + // Corresponding release events are filtered out + // implicitly by the GLFW key repeat logic + if (window->x11.lastKeyTime < event->xkey.time) { if (keycode) _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - } - window->x11.lastKeyCode = keycode; - window->x11.lastKeyTime = event->xkey.time; + window->x11.lastKeyTime = event->xkey.time; + } if (!filtered) { From 9f63a8abfac11ad6681b8f2937267992180b3549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 27 Mar 2017 18:40:04 +0200 Subject: [PATCH 021/222] Update changelog Issue #682 was implicitly fixed by 77a8f103d8f8519d1a723bbd8b0490b448f1f430. Closes #682. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8ec76cde4..65420ef84 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,8 @@ information on what to include when reporting a bug. incorrect position and size (#748) - [Cocoa] Bugfix: Iconified full screen windows could not be restored (#848) - [Cocoa] Bugfix: Value range was ignored for joystick hats and buttons (#888) +- [Cocoa] Bugfix: Full screen framebuffer was incorrectly sized for some video + modes (#682) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) - [EGL] Added support for `EGL_KHR_context_flush_control` From c9003b554735810f69985eb9e0882fdca0583e27 Mon Sep 17 00:00:00 2001 From: Brandon Schaefer Date: Tue, 28 Mar 2017 19:03:29 -0700 Subject: [PATCH 022/222] Mir: Get ready for Mir 1.0 Clean up CMake finding and check version. Change last remaining deprecations. Closes #979. --- CMake/modules/FindMir.cmake | 51 ++++---- CMakeLists.txt | 2 +- include/GLFW/glfw3native.h | 6 +- src/mir_init.c | 6 +- src/mir_monitor.c | 91 ++++++++----- src/mir_platform.h | 30 ++--- src/mir_window.c | 254 ++++++++++++++++++------------------ 7 files changed, 228 insertions(+), 212 deletions(-) diff --git a/CMake/modules/FindMir.cmake b/CMake/modules/FindMir.cmake index 3f1fb0b3e..2104df8a3 100644 --- a/CMake/modules/FindMir.cmake +++ b/CMake/modules/FindMir.cmake @@ -1,37 +1,34 @@ -# Try to find Mir on a Unix system +# FindMir +# ------- +# Finds the Mir library # -# This will define: +# This will will define the following variables:: # -# MIR_FOUND - System has Mir -# MIR_LIBRARIES - Link these to use Mir -# MIR_INCLUDE_DIR - Include directory for Mir -# MIR_DEFINITIONS - Compiler switches required for using Mir +# MIR_FOUND - the system has Mir +# MIR_INCLUDE_DIRS - the Mir include directory +# MIR_LIBRARIES - the Mir libraries +# MIR_DEFINITIONS - the Mir definitions -if (NOT WIN32) - find_package (PkgConfig) - pkg_check_modules (PKG_MIR QUIET mirclient) - set(MIR_DEFINITIONS ${PKG_MIR_CFLAGS_OTHER}) +find_package (PkgConfig) +if(PKG_CONFIG_FOUND) + pkg_check_modules (PC_MIR mirclient>=0.26.2 QUIET) - find_path(MIR_INCLUDE_DIR - NAMES xkbcommon/xkbcommon.h - HINTS ${PC_XKBCOMMON_INCLUDE_DIR} ${PC_XKBCOMMON_INCLUDE_DIRS} - ) + find_path(MIR_INCLUDE_DIR NAMES mir_toolkit/mir_client_library.h + PATHS ${PC_MIR_INCLUDE_DIRS}) - find_library(MIR_LIBRARY - NAMES mirclient - HINTS ${PKG_MIR_LIBRARIES} ${MIR_LIBRARY_DIRS} - ) - - set (MIR_INCLUDE_DIR ${PKG_MIR_INCLUDE_DIRS}) - set (MIR_LIBRARIES ${MIR_LIBRARY}) + find_library(MIR_LIBRARY NAMES mirclient + PATHS ${PC_MIR_LIBRARIES} ${PC_MIR_LIBRARY_DIRS}) include (FindPackageHandleStandardArgs) - find_package_handle_standard_args (MIR DEFAULT_MSG - MIR_LIBRARIES - MIR_INCLUDE_DIR - ) + find_package_handle_standard_args (MIR + REQUIRED_VARS MIR_LIBRARY MIR_INCLUDE_DIR) - mark_as_advanced (MIR_LIBRARIES MIR_INCLUDE_DIR) + if (MIR_FOUND) + set(MIR_LIBRARIES ${MIR_LIBRARY}) + set(MIR_INCLUDE_DIRS ${PC_MIR_INCLUDE_DIRS}) + set(MIR_DEFINITIONS -DHAVE_MIR=1) + endif() -endif () + mark_as_advanced (MIR_LIBRARY MIR_INCLUDE_DIR) +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e8d46fe3..67b13332d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,7 +308,7 @@ if (_GLFW_MIR) find_package(Mir REQUIRED) list(APPEND glfw_PKG_DEPS "mirclient") - list(APPEND glfw_INCLUDE_DIRS "${MIR_INCLUDE_DIR}") + list(APPEND glfw_INCLUDE_DIRS "${MIR_INCLUDE_DIRS}") list(APPEND glfw_LIBRARIES "${MIR_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") find_package(XKBCommon REQUIRED) diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index ba59913ec..982eaa656 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -394,9 +394,9 @@ GLFWAPI MirConnection* glfwGetMirDisplay(void); */ GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); -/*! @brief Returns the `MirSurface*` of the specified window. +/*! @brief Returns the `MirWindow*` of the specified window. * - * @return The `MirSurface*` of the specified window, or `NULL` if an + * @return The `MirWindow*` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * * @thread_safety This function may be called from any thread. Access is not @@ -406,7 +406,7 @@ GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); * * @ingroup native */ -GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); +GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_EGL) diff --git a/src/mir_init.c b/src/mir_init.c index 3a96c78aa..cf3dcf1ec 100644 --- a/src/mir_init.c +++ b/src/mir_init.c @@ -1,7 +1,7 @@ //======================================================================== // GLFW 3.3 Mir - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2014-2015 Brandon Schaefer +// Copyright (c) 2014-2017 Brandon Schaefer // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -195,10 +195,6 @@ int _glfwPlatformInit(void) _glfwInitTimerPOSIX(); - // Need the default conf for when we set a NULL cursor - _glfw.mir.defaultConf = mir_cursor_configuration_from_name(mir_default_cursor_name); - _glfw.mir.disabledConf = mir_cursor_configuration_from_name(mir_disabled_cursor_name); - _glfw.mir.eventQueue = calloc(1, sizeof(EventQueue)); _glfwInitEventQueueMir(_glfw.mir.eventQueue); diff --git a/src/mir_monitor.c b/src/mir_monitor.c index 9e2cdc96f..268485064 100644 --- a/src/mir_monitor.c +++ b/src/mir_monitor.c @@ -1,7 +1,7 @@ //======================================================================== // GLFW 3.3 Mir - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2014-2015 Brandon Schaefer +// Copyright (c) 2014-2017 Brandon Schaefer // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -38,33 +38,41 @@ void _glfwPollMonitorsMir(void) { int i; - MirDisplayConfiguration* displayConfig = - mir_connection_create_display_config(_glfw.mir.connection); + MirDisplayConfig* displayConfig = + mir_connection_create_display_configuration(_glfw.mir.connection); - for (i = 0; i < displayConfig->num_outputs; i++) + int numOutputs = mir_display_config_get_num_outputs(displayConfig); + + for (i = 0; i < numOutputs; i++) { - const MirDisplayOutput* out = displayConfig->outputs + i; + const MirOutput* output = mir_display_config_get_output(displayConfig, i); + MirOutputConnectionState state = mir_output_get_connection_state(output); + bool enabled = mir_output_is_enabled(output); - if (out->used && - out->connected && - out->num_modes && - out->current_mode < out->num_modes) + if (enabled && state == mir_output_connection_state_connected) { - _GLFWmonitor* monitor = _glfwAllocMonitor("Unknown", - out->physical_width_mm, - out->physical_height_mm); + int widthMM = mir_output_get_physical_width_mm(output); + int heightMM = mir_output_get_physical_height_mm(output); + int x = mir_output_get_position_x(output); + int y = mir_output_get_position_y(output); + int id = mir_output_get_id(output); + size_t currentMode = mir_output_get_current_mode_index(output); + const char* name = mir_output_type_name(mir_output_get_type(output)); - monitor->mir.x = out->position_x; - monitor->mir.y = out->position_y; - monitor->mir.outputId = out->output_id; - monitor->mir.curMode = out->current_mode; + _GLFWmonitor* monitor = _glfwAllocMonitor(name, + widthMM, + heightMM); + monitor->mir.x = x; + monitor->mir.y = y; + monitor->mir.outputId = id; + monitor->mir.curMode = currentMode; monitor->modes = _glfwPlatformGetVideoModes(monitor, &monitor->modeCount); _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } } - mir_display_config_destroy(displayConfig); + mir_display_config_release(displayConfig); } @@ -80,7 +88,7 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = monitor->mir.y; } -void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf) +static void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf) { switch (pf) { @@ -117,30 +125,52 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { int i; GLFWvidmode* modes = NULL; - MirDisplayConfiguration* displayConfig = - mir_connection_create_display_config(_glfw.mir.connection); + MirDisplayConfig* displayConfig = + mir_connection_create_display_configuration(_glfw.mir.connection); - for (i = 0; i < displayConfig->num_outputs; i++) + int numOutputs = mir_display_config_get_num_outputs(displayConfig); + + for (i = 0; i < numOutputs; i++) { - const MirDisplayOutput* out = displayConfig->outputs + i; - if (out->output_id != monitor->mir.outputId) + const MirOutput* output = mir_display_config_get_output(displayConfig, i); + int id = mir_output_get_id(output); + + if (id != monitor->mir.outputId) continue; - modes = calloc(out->num_modes, sizeof(GLFWvidmode)); + MirOutputConnectionState state = mir_output_get_connection_state(output); + bool enabled = mir_output_is_enabled(output); - for (*found = 0; *found < out->num_modes; (*found)++) + // We must have been disconnected + if (!enabled || state != mir_output_connection_state_connected) { - modes[*found].width = out->modes[*found].horizontal_resolution; - modes[*found].height = out->modes[*found].vertical_resolution; - modes[*found].refreshRate = out->modes[*found].refresh_rate; + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Monitor no longer connected"); + return NULL; + } - FillInRGBBitsFromPixelFormat(&modes[*found], out->output_formats[*found]); + int numModes = mir_output_get_num_modes(output); + modes = calloc(numModes, sizeof(GLFWvidmode)); + + for (*found = 0; *found < numModes; (*found)++) + { + const MirOutputMode* mode = mir_output_get_mode(output, *found); + int width = mir_output_mode_get_width(mode); + int height = mir_output_mode_get_height(mode); + double refreshRate = mir_output_mode_get_refresh_rate(mode); + MirPixelFormat currentFormat = mir_output_get_current_pixel_format(output); + + modes[*found].width = width; + modes[*found].height = height; + modes[*found].refreshRate = refreshRate; + + FillInRGBBitsFromPixelFormat(&modes[*found], currentFormat); } break; } - mir_display_config_destroy(displayConfig); + mir_display_config_release(displayConfig); return modes; } @@ -173,4 +203,3 @@ GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle) _GLFW_REQUIRE_INIT_OR_RETURN(0); return monitor->mir.outputId; } - diff --git a/src/mir_platform.h b/src/mir_platform.h index e9d60ecdd..d3fd10de0 100644 --- a/src/mir_platform.h +++ b/src/mir_platform.h @@ -1,7 +1,7 @@ //======================================================================== // GLFW 3.3 Mir - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2014-2015 Brandon Schaefer +// Copyright (c) 2014-2017 Brandon Schaefer // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -33,18 +33,18 @@ #include -typedef VkFlags VkMirSurfaceCreateFlagsKHR; +typedef VkFlags VkMirWindowCreateFlagsKHR; -typedef struct VkMirSurfaceCreateInfoKHR +typedef struct VkMirWindowCreateInfoKHR { VkStructureType sType; const void* pNext; - VkMirSurfaceCreateFlagsKHR flags; + VkMirWindowCreateFlagsKHR flags; MirConnection* connection; - MirSurface* mirSurface; -} VkMirSurfaceCreateInfoKHR; + MirWindow* mirWindow; +} VkMirWindowCreateInfoKHR; -typedef VkResult (APIENTRY *PFN_vkCreateMirSurfaceKHR)(VkInstance,const VkMirSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkResult (APIENTRY *PFN_vkCreateMirWindowKHR)(VkInstance,const VkMirWindowCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*); #include "posix_tls.h" @@ -58,7 +58,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(Vk #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) -#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.window) +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.nativeWindow) #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display) #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir @@ -81,10 +81,10 @@ typedef struct EventQueue // typedef struct _GLFWwindowMir { - MirSurface* surface; + MirWindow* window; int width; int height; - MirEGLNativeWindowType window; + MirEGLNativeWindowType nativeWindow; _GLFWcursor* currentCursor; } _GLFWwindowMir; @@ -106,18 +106,16 @@ typedef struct _GLFWlibraryMir { MirConnection* connection; MirEGLNativeDisplayType display; - MirCursorConfiguration* defaultConf; - MirCursorConfiguration* disabledConf; EventQueue* eventQueue; - short int keycodes[256]; - short int scancodes[GLFW_KEY_LAST + 1]; + short int keycodes[256]; + short int scancodes[GLFW_KEY_LAST + 1]; pthread_mutex_t eventMutex; pthread_cond_t eventCond; // The window whose disabled cursor mode is active - _GLFWwindow* disabledCursorWindow; + _GLFWwindow* disabledCursorWindow; } _GLFWlibraryMir; @@ -128,9 +126,11 @@ typedef struct _GLFWcursorMir { MirCursorConfiguration* conf; MirBufferStream* customCursor; + char const* cursorName; // only needed for system cursors } _GLFWcursorMir; +extern void _glfwPollMonitorsMir(void); extern void _glfwInitEventQueueMir(EventQueue* queue); extern void _glfwDeleteEventQueueMir(EventQueue* queue); diff --git a/src/mir_window.c b/src/mir_window.c index 00d50ada9..e380f4070 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -1,7 +1,7 @@ //======================================================================== // GLFW 3.3 Mir - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2014-2015 Brandon Schaefer +// Copyright (c) 2014-2017 Brandon Schaefer // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -89,9 +89,6 @@ static EventNode* dequeueEvent(EventQueue* queue) return node; } -/* FIXME Soon to be changed upstream mir! So we can use an egl config to figure out - the best pixel format! -*/ static MirPixelFormat findValidPixelFormat(void) { unsigned int i, validFormats, mirPixelFormats = 32; @@ -283,14 +280,14 @@ static void handleEvent(const MirEvent* event, _GLFWwindow* window) } } -static void addNewEvent(MirSurface* surface, const MirEvent* event, void* context) +static void addNewEvent(MirWindow* window, const MirEvent* event, void* context) { enqueueEvent(event, context); } -static GLFWbool createSurface(_GLFWwindow* window) +static GLFWbool createWindow(_GLFWwindow* window) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; MirBufferUsage buffer_usage = mir_buffer_usage_hardware; MirPixelFormat pixel_format = findValidPixelFormat(); @@ -301,40 +298,39 @@ static GLFWbool createSurface(_GLFWwindow* window) return GLFW_FALSE; } - spec = mir_connection_create_spec_for_normal_surface(_glfw.mir.connection, - window->mir.width, - window->mir.height, - pixel_format); + spec = mir_create_normal_window_spec(_glfw.mir.connection, + window->mir.width, + window->mir.height); - mir_surface_spec_set_buffer_usage(spec, buffer_usage); - mir_surface_spec_set_name(spec, "MirSurface"); + mir_window_spec_set_pixel_format(spec, pixel_format); + mir_window_spec_set_buffer_usage(spec, buffer_usage); - window->mir.surface = mir_surface_create_sync(spec); - mir_surface_spec_release(spec); + window->mir.window = mir_create_window_sync(spec); + mir_window_spec_release(spec); - if (!mir_surface_is_valid(window->mir.surface)) + if (!mir_window_is_valid(window->mir.window)) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unable to create surface: %s", - mir_surface_get_error_message(window->mir.surface)); + "Mir: Unable to create window: %s", + mir_window_get_error_message(window->mir.window)); return GLFW_FALSE; } - mir_surface_set_event_handler(window->mir.surface, addNewEvent, window); + mir_window_set_event_handler(window->mir.window, addNewEvent, window); return GLFW_TRUE; } -static void setSurfaceConfinement(_GLFWwindow* window, MirPointerConfinementState state) +static void setWindowConfinement(_GLFWwindow* window, MirPointerConfinementState state) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; - spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); - mir_surface_spec_set_pointer_confinement(spec, state); + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_pointer_confinement(spec, state); - mir_surface_apply_spec(window->mir.surface, spec); - mir_surface_spec_release(spec); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } ////////////////////////////////////////////////////////////////////////// @@ -381,12 +377,12 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, GLFWvidmode mode; _glfwPlatformGetVideoMode(window->monitor, &mode); - mir_surface_set_state(window->mir.surface, mir_surface_state_fullscreen); + mir_window_set_state(window->mir.window, mir_window_state_fullscreen); if (wndconfig->width > mode.width || wndconfig->height > mode.height) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Requested surface size too large: %ix%i", + "Mir: Requested window size too large: %ix%i", wndconfig->width, wndconfig->height); return GLFW_FALSE; @@ -397,11 +393,11 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, window->mir.height = wndconfig->height; window->mir.currentCursor = NULL; - if (!createSurface(window)) + if (!createWindow(window)) return GLFW_FALSE; - window->mir.window = mir_buffer_stream_get_egl_native_window( - mir_surface_get_buffer_stream(window->mir.surface)); + window->mir.nativeWindow = mir_buffer_stream_get_egl_native_window( + mir_window_get_buffer_stream(window->mir.window)); if (ctxconfig->client != GLFW_NO_API) { @@ -430,10 +426,10 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (_glfw.mir.disabledCursorWindow == window) _glfw.mir.disabledCursorWindow = NULL; - if (mir_surface_is_valid(window->mir.surface)) + if (mir_window_is_valid(window->mir.window)) { - mir_surface_release_sync(window->mir.surface); - window->mir.surface = NULL; + mir_window_release_sync(window->mir.window); + window->mir.window= NULL; } if (window->context.destroy) @@ -442,13 +438,12 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; - spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); - mir_surface_spec_set_name(spec, title); - - mir_surface_apply_spec(window->mir.surface, spec); - mir_surface_spec_release(spec); + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_name(spec, title); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } void _glfwPlatformSetWindowIcon(_GLFWwindow* window, @@ -460,22 +455,30 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; - spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); - mir_surface_spec_set_width (spec, width); - mir_surface_spec_set_height(spec, height); + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_width (spec, width); + mir_window_spec_set_height(spec, height); - mir_surface_apply_spec(window->mir.surface, spec); - mir_surface_spec_release(spec); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_max_width (spec, maxwidth); + mir_window_spec_set_max_height(spec, maxheight); + mir_window_spec_set_min_width (spec, minwidth); + mir_window_spec_set_min_height(spec, minheight); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) @@ -514,57 +517,57 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformIconifyWindow(_GLFWwindow* window) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; - spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); - mir_surface_spec_set_state(spec, mir_surface_state_minimized); + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_minimized); - mir_surface_apply_spec(window->mir.surface, spec); - mir_surface_spec_release(spec); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } void _glfwPlatformRestoreWindow(_GLFWwindow* window) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; - spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); - mir_surface_spec_set_state(spec, mir_surface_state_restored); + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_restored); - mir_surface_apply_spec(window->mir.surface, spec); - mir_surface_spec_release(spec); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; - spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); - mir_surface_spec_set_state(spec, mir_surface_state_maximized); + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_maximized); - mir_surface_apply_spec(window->mir.surface, spec); - mir_surface_spec_release(spec); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } void _glfwPlatformHideWindow(_GLFWwindow* window) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; - spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); - mir_surface_spec_set_state(spec, mir_surface_state_hidden); + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_hidden); - mir_surface_apply_spec(window->mir.surface, spec); - mir_surface_spec_release(spec); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } void _glfwPlatformShowWindow(_GLFWwindow* window) { - MirSurfaceSpec* spec; + MirWindowSpec* spec; - spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); - mir_surface_spec_set_state(spec, mir_surface_state_restored); + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_restored); - mir_surface_apply_spec(window->mir.surface, spec); - mir_surface_spec_release(spec); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); } void _glfwPlatformFocusWindow(_GLFWwindow* window) @@ -585,7 +588,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, int _glfwPlatformWindowFocused(_GLFWwindow* window) { - return mir_surface_get_focus(window->mir.surface) == mir_surface_focused; + return mir_window_get_focus_state(window->mir.window) == mir_window_focus_state_focused; } int _glfwPlatformWindowIconified(_GLFWwindow* window) @@ -597,12 +600,12 @@ int _glfwPlatformWindowIconified(_GLFWwindow* window) int _glfwPlatformWindowVisible(_GLFWwindow* window) { - return mir_surface_get_visibility(window->mir.surface) == mir_surface_visibility_exposed; + return mir_window_get_visibility(window->mir.window) == mir_window_visibility_exposed; } int _glfwPlatformWindowMaximized(_GLFWwindow* window) { - return mir_surface_get_state(window->mir.surface) == mir_surface_state_maximized; + return mir_window_get_state(window->mir.window) == mir_window_state_maximized; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) @@ -638,7 +641,7 @@ void _glfwPlatformWaitEvents(void) { pthread_mutex_lock(&_glfw.mir.eventMutex); - if (emptyEventQueue(_glfw.mir.eventQueue)) + while (emptyEventQueue(_glfw.mir.eventQueue)) pthread_cond_wait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex); pthread_mutex_unlock(&_glfw.mir.eventMutex); @@ -681,54 +684,40 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int xhot, int yhot) { MirBufferStream* stream; - MirPixelFormat pixel_format = findValidPixelFormat(); int i_w = image->width; int i_h = image->height; - if (pixel_format == mir_pixel_format_invalid) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unable to find a correct pixel format"); - return GLFW_FALSE; - } - stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection, i_w, i_h, - pixel_format, + mir_pixel_format_argb_8888, mir_buffer_usage_software); cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot); - char* dest; - unsigned char *pixels; - int i, r_stride, bytes_per_pixel, bytes_per_row; - MirGraphicsRegion region; mir_buffer_stream_get_graphics_region(stream, ®ion); - // FIXME Figure this out based on the current_pf - bytes_per_pixel = 4; - bytes_per_row = bytes_per_pixel * i_w; + unsigned char* pixels = image->pixels; + char* dest = region.vaddr; + int i; - dest = region.vaddr; - pixels = image->pixels; - - r_stride = region.stride; - - for (i = 0; i < i_h; i++) + for (i = 0; i < i_w * i_h; i++, pixels += 4) { - memcpy(dest, pixels, bytes_per_row); - dest += r_stride; - pixels += r_stride; + unsigned int alpha = pixels[3]; + *dest++ = (char)(pixels[2] * alpha / 255); + *dest++ = (char)(pixels[1] * alpha / 255); + *dest++ = (char)(pixels[0] * alpha / 255); + *dest++ = (char)alpha; } + mir_buffer_stream_swap_buffers_sync(stream); cursor->mir.customCursor = stream; return GLFW_TRUE; } -const char* getSystemCursorName(int shape) +static const char* getSystemCursorName(int shape) { switch (shape) { @@ -751,17 +740,11 @@ const char* getSystemCursorName(int shape) int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { - const char* cursor_name = getSystemCursorName(shape); + cursor->mir.conf = NULL; + cursor->mir.customCursor = NULL; + cursor->mir.cursorName = getSystemCursorName(shape); - if (cursor_name) - { - cursor->mir.conf = mir_cursor_configuration_from_name(cursor_name); - cursor->mir.customCursor = NULL; - - return GLFW_TRUE; - } - - return GLFW_FALSE; + return cursor->mir.cursorName != NULL; } void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) @@ -772,21 +755,32 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) mir_buffer_stream_release_sync(cursor->mir.customCursor); } +static void setCursorNameForWindow(MirWindow* window, char const* name) +{ + MirWindowSpec* spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_cursor_name(spec, name); + mir_window_apply_spec(window, spec); + mir_window_spec_release(spec); +} + void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { - if (cursor && cursor->mir.conf) + if (cursor) { window->mir.currentCursor = cursor; - mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf)); - if (cursor->mir.customCursor) + if (cursor->mir.cursorName) { - mir_buffer_stream_swap_buffers_sync(cursor->mir.customCursor); + setCursorNameForWindow(window->mir.window, cursor->mir.cursorName); + } + else if (cursor->mir.conf) + { + mir_window_configure_cursor(window->mir.window, cursor->mir.conf); } } else { - mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.defaultConf)); + setCursorNameForWindow(window->mir.window, mir_default_cursor_name); } } @@ -807,8 +801,8 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) if (mode == GLFW_CURSOR_DISABLED) { _glfw.mir.disabledCursorWindow = window; - setSurfaceConfinement(window, mir_pointer_confined_to_surface); - mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.disabledConf)); + setWindowConfinement(window, mir_pointer_confined_to_window); + setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name); } else { @@ -816,7 +810,7 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) if (_glfw.mir.disabledCursorWindow == window) { _glfw.mir.disabledCursorWindow = NULL; - setSurfaceConfinement(window, mir_pointer_unconfined); + setWindowConfinement(window, mir_pointer_unconfined); } if (window->cursorMode == GLFW_CURSOR_NORMAL) @@ -825,7 +819,7 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) } else if (window->cursorMode == GLFW_CURSOR_HIDDEN) { - mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.disabledConf)); + setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name); } } } @@ -890,12 +884,12 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, VkSurfaceKHR* surface) { VkResult err; - VkMirSurfaceCreateInfoKHR sci; - PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR; + VkMirWindowCreateInfoKHR sci; + PFN_vkCreateMirWindowKHR vkCreateMirWindowKHR; - vkCreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR) - vkGetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR"); - if (!vkCreateMirSurfaceKHR) + vkCreateMirWindowKHR = (PFN_vkCreateMirWindowKHR) + vkGetInstanceProcAddr(instance, "vkCreateMirWindowKHR"); + if (!vkCreateMirWindowKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); @@ -905,9 +899,9 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR; sci.connection = _glfw.mir.connection; - sci.mirSurface = window->mir.surface; + sci.mirWindow = window->mir.window; - err = vkCreateMirSurfaceKHR(instance, &sci, allocator, surface); + err = vkCreateMirWindowKHR(instance, &sci, allocator, surface); if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -929,10 +923,10 @@ GLFWAPI MirConnection* glfwGetMirDisplay(void) return _glfw.mir.connection; } -GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* handle) +GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return window->mir.surface; + return window->mir.window; } From 9558b85f7be3c7750f51224cf32346551273369b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 4 Apr 2017 18:05:36 +0200 Subject: [PATCH 023/222] Documentation work Related to #981. --- include/GLFW/glfw3.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 8b2efcec2..5436b9b48 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3392,11 +3392,12 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); -/*! @brief Returns the localized name of the specified printable key. +/*! @brief Returns the layout-specific name of the specified printable key. * - * This function returns the name of the specified printable key. This is - * typically the character that key would produce without any modifier keys, - * intended for displaying key bindings to the user. + * This function returns the name of the specified printable key, encoded as + * UTF-8. This is typically the character that key would produce without any + * modifier keys, intended for displaying key bindings to the user. For dead + * keys, it is typically the diacritic it would add to a character. * * __Do not use this function__ for [text input](@ref input_char). You will * break text input for many languages even if it happens to work for yours. @@ -3438,7 +3439,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); * * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. * @param[in] scancode The scancode of the key to query. - * @return The localized name of the key, or `NULL`. + * @return The UTF-8 encoded, layout-specific name of the key, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. From 2226e60944a9d12f68b89fe2ac029de637e07cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 5 Apr 2017 17:52:03 +0200 Subject: [PATCH 024/222] Formatting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 65420ef84..4c6562851 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ information on what to include when reporting a bug. - [Win32] Bugfix: Vulkan libraries have a new path as of SDK 1.0.42.0 (#956) - [Win32] Bugfix: Monitors with no display devices were not enumerated (#960) - [Win32] Bugfix: Monitor events were not emitted (#784) +- [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X - [X11] Bugfix: Dynamic X11 library loading did not use full sonames (#941) @@ -192,7 +193,6 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Value range was ignored for joystick hats and buttons (#888) - [Cocoa] Bugfix: Full screen framebuffer was incorrectly sized for some video modes (#682) -- [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) - [EGL] Added support for `EGL_KHR_context_flush_control` - [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid From 66b16f1fc1cfb1ee68ccbbc09e56646e3ab1e6fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 5 Apr 2017 17:53:00 +0200 Subject: [PATCH 025/222] X11: Add validation of RandR gamma ramp size --- README.md | 1 + src/x11_monitor.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/README.md b/README.md index 4c6562851..155e5ae50 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: XDND support had multiple non-conformance issues (#968) - [X11] Bugfix: The RandR monitor path was disabled despite working RandR (#972) - [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747) +- [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Cocoa] Added support for Vulkan window surface creation via [MoltenVK](https://moltengl.com/moltenvk/) (#870) diff --git a/src/x11_monitor.c b/src/x11_monitor.c index f8d25e37f..5c0516e67 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -453,6 +453,13 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) { + if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Gamma ramp size must match current ramp size"); + return; + } + XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); From 9457cf33d1db8bc604ac5a258c0406c7cf5b9ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 6 Apr 2017 02:02:16 +0200 Subject: [PATCH 026/222] Documentation work --- docs/build.dox | 9 +++++++++ docs/monitor.dox | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/build.dox b/docs/build.dox index a3c62885d..97dda32dc 100644 --- a/docs/build.dox +++ b/docs/build.dox @@ -243,6 +243,15 @@ target files generated when GLFW is installed. find_package(glfw3 3.3 REQUIRED) @endcode +Once GLFW has been added to the project, link against it with the `glfw` target. +This adds all link-time dependencies of GLFW as it is currently configured, +the include directory for the GLFW header and, when applicable, the @ref +GLFW_DLL macro. + +@code{.cmake} +target_link_libraries(myapp glfw) +@endcode + Note that the dependencies do not include OpenGL or GLU, as GLFW loads any OpenGL, OpenGL ES or Vulkan libraries it needs at runtime and does not use GLU. If your application calls OpenGL directly, instead of using a modern diff --git a/docs/monitor.dox b/docs/monitor.dox index ee9fced1a..708461f58 100644 --- a/docs/monitor.dox +++ b/docs/monitor.dox @@ -195,8 +195,8 @@ glfwSetGammaRamp(monitor, &ramp); The gamma ramp data is copied before the function returns, so there is no need to keep it around once the ramp has been set. -@note It is recommended to use gamma ramps of size 256, as that is the size -supported by all graphics cards on all platforms. +It is recommended that your gamma ramp have the same size as the current gamma +ramp for that monitor. The current gamma ramp for a monitor is returned by @ref glfwGetGammaRamp. See the reference documentation for the lifetime of the returned structure. From 488423236053d988f2b1f4b55e64bccbfce9abcb Mon Sep 17 00:00:00 2001 From: pengo Date: Thu, 13 Apr 2017 01:59:49 +0000 Subject: [PATCH 027/222] Wayland: Update serial on button callback The serial needs to be update for starting operations like moving and resizing a window. Closes #992. --- src/wl_init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wl_init.c b/src/wl_init.c index 8e12bafa7..0927a98a8 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -109,6 +109,8 @@ static void pointerHandleButton(void* data, if (!window) return; + _glfw.wl.pointerSerial = serial; + /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev * codes. */ glfwButton = button - BTN_LEFT; From 16ddfafeaad824b3a6f594c46e4449661da4d279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 2 May 2017 16:58:02 +0200 Subject: [PATCH 028/222] Allow object creation from callbacks --- docs/intro.dox | 8 ++------ include/GLFW/glfw3.h | 6 ------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/docs/intro.dox b/docs/intro.dox index 16456e5c8..de1b3ae06 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -238,14 +238,10 @@ releases. @subsection reentrancy Reentrancy -GLFW event processing and object creation and destruction are not reentrant. -This means that the following functions must not be called from any callback -function: +GLFW event processing and object destruction are not reentrant. This means that +the following functions must not be called from any callback function: - - @ref glfwCreateWindow - @ref glfwDestroyWindow - - @ref glfwCreateCursor - - @ref glfwCreateStandardCursor - @ref glfwDestroyCursor - @ref glfwPollEvents - @ref glfwWaitEvents diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 5436b9b48..2875dc5b3 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2148,8 +2148,6 @@ GLFWAPI void glfwWindowHint(int hint, int value); * * @remark @wayland Screensaver inhibition is currently unimplemented. * - * @reentrancy This function must not be called from a callback. - * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_creation @@ -3655,8 +3653,6 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @pointer_lifetime The specified image data is copied before this function * returns. * - * @reentrancy This function must not be called from a callback. - * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object @@ -3681,8 +3677,6 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @reentrancy This function must not be called from a callback. - * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object From 6350641f0aa27a4dd14c9c0b4e675680416b2c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 1 May 2017 19:20:57 +0200 Subject: [PATCH 029/222] Add glfwGetError Related to #970. If you have opinions on the design or implementation of this function, please come join us in #970 before it is frozen for release. --- README.md | 1 + docs/intro.dox | 44 ++++++++++++++++++++++++++++++-------------- docs/news.dox | 9 +++++++++ include/GLFW/glfw3.h | 35 +++++++++++++++++++++++++++++++++++ src/init.c | 38 +++++++++++++++++++++++++++++++++++--- src/internal.h | 2 ++ src/posix_tls.c | 6 +++++- src/win32_tls.c | 6 +++++- 8 files changed, 122 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 155e5ae50..d6aed688a 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ information on what to include when reporting a bug. ## Changelog +- Added `glfwGetError` function for querying the last error code (#970) - Added `glfwGetKeyScancode` function that allows retrieving platform dependent scancodes for keys (#830) - Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for diff --git a/docs/intro.dox b/docs/intro.dox index de1b3ae06..55aa7862d 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -30,6 +30,7 @@ successfully initialized, and only from the main thread. - @ref glfwGetVersion - @ref glfwGetVersionString + - @ref glfwGetError - @ref glfwSetErrorCallback - @ref glfwInitHint - @ref glfwInit @@ -131,9 +132,25 @@ not very helpful when trying to figure out _why_ the error occurred. Other functions have no return value reserved for errors, so error notification needs a separate channel. Finally, far from all GLFW functions have return values. -This is where the error callback comes in. This callback is called whenever an -error occurs. It is set with @ref glfwSetErrorCallback, a function that may be -called regardless of whether GLFW is initialized. +The last error code for the calling thread can be queried at any time with @ref +glfwGetError. + +@code +int error = glfwGetError(); +@endcode + +If no error has occurred since the last call, @ref GLFW_NO_ERROR is returned. +The error is cleared before the function returns. + +The error code indicates the general category of the error. Some error codes, +such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like +@ref GLFW_PLATFORM_ERROR are used for many different errors. + +GLFW usually has much more information about the error than its general category +at the point where it occurred. This is where the error callback comes in. +This callback is called whenever an error occurs. It is set with @ref +glfwSetErrorCallback, a function that may be called regardless of whether GLFW +is initialized. @code glfwSetErrorCallback(error_callback); @@ -150,24 +167,23 @@ void error_callback(int error, const char* description) } @endcode -The error code indicates the general category of the error. Some error codes, -such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like -@ref GLFW_PLATFORM_ERROR are used for many different errors. +The error callback is called after the error code is set, so calling @ref +glfwGetError from within the error callback returns the same value as the +callback argument. -Reported errors are never fatal. As long as GLFW was successfully initialized, -it will remain initialized and in a safe state until terminated regardless of -how many errors occur. If an error occurs during initialization that causes -@ref glfwInit to fail, any part of the library that was initialized will be -safely terminated. +__Reported errors are never fatal.__ As long as GLFW was successfully +initialized, it will remain initialized and in a safe state until terminated +regardless of how many errors occur. If an error occurs during initialization +that causes @ref glfwInit to fail, any part of the library that was initialized +will be safely terminated. The description string is only valid until the error callback returns, as it may have been generated specifically for that error. This lets GLFW provide much more specific error descriptions but means you must make a copy if you want to keep the description string. -@note Relying on erroneous behavior is not forward compatible. In other words, -do not rely on a currently invalid call to generate a specific error, as that -same call may in future versions generate a different error or become valid. +Do not rely on a currently invalid call to generate a specific error, as in the +future that same call may generate a different error or become valid. @section coordinate_systems Coordinate systems diff --git a/docs/news.dox b/docs/news.dox index 0be64b064..ad5de5aac 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -4,6 +4,15 @@ @section news_33 New features in 3.3 + +@subsection news_33_geterror Error query + +GLFW now supports querying the last error code for the calling thread with @ref +glfwGetError. + +@see @ref error_handling + + @subsection news_33_maximize Window maximization callback GLFW now supports window maximization notifications with @ref diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 2875dc5b3..f0426ffb5 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -546,6 +546,13 @@ extern "C" { * * @ingroup init * @{ */ +/*! @brief No error has occurred. + * + * No error has occurred. + * + * @analysis Yay. + */ +#define GLFW_NO_ERROR 0 /*! @brief GLFW has not been initialized. * * This occurs if a GLFW function was called that must not be called unless the @@ -1607,11 +1614,38 @@ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); */ GLFWAPI const char* glfwGetVersionString(void); +/*! @brief Returns and clears the last error for the calling thread. + * + * This function returns and clears the [error code](@ref error) of the last + * error that occurred on the calling thread. If no error has occurred since + * the last call, it returns @ref GLFW_NO_ERROR. + * + * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref error_handling + * @sa @ref glfwSetErrorCallback + * + * @since Added in version 3.3. + * + * @ingroup init + */ +GLFWAPI int glfwGetError(void); + /*! @brief Sets the error callback. * * This function sets the error callback, which is called with an error code * and a human-readable description each time a GLFW error occurs. * + * The error code is set before the callback is called. Calling @ref + * glfwGetError from the error callback will return the same value as the error + * code argument. + * * The error callback is called on the thread where the error occurred. If you * are using GLFW from multiple threads, your error callback needs to be * written accordingly. @@ -1634,6 +1668,7 @@ GLFWAPI const char* glfwGetVersionString(void); * @thread_safety This function must only be called from the main thread. * * @sa @ref error_handling + * @sa @ref glfwGetError * * @since Added in version 3.0. * diff --git a/src/init.c b/src/init.c index 7585c567d..a0c6e42e2 100644 --- a/src/init.c +++ b/src/init.c @@ -43,6 +43,7 @@ _GLFWlibrary _glfw = { GLFW_FALSE }; // These are outside of _glfw so they can be used before initialization and // after termination // +static int _glfwErrorCode; static GLFWerrorfun _glfwErrorCallback; static _GLFWinitconfig _glfwInitHints = { @@ -113,7 +114,11 @@ static void terminate(void) _glfwTerminateVulkan(); _glfwPlatformTerminate(); + if (_glfwPlatformIsValidTls(&_glfw.error)) + _glfwErrorCode = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error); + _glfwPlatformDestroyTls(&_glfw.context); + _glfwPlatformDestroyTls(&_glfw.error); memset(&_glfw, 0, sizeof(_glfw)); } @@ -125,6 +130,11 @@ static void terminate(void) void _glfwInputError(int error, const char* format, ...) { + if (_glfw.initialized) + _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) error); + else + _glfwErrorCode = error; + if (_glfwErrorCallback) { char buffer[8192]; @@ -164,15 +174,19 @@ GLFWAPI int glfwInit(void) memset(&_glfw, 0, sizeof(_glfw)); _glfw.hints.init = _glfwInitHints; - if (!_glfwPlatformCreateTls(&_glfw.context)) - return GLFW_FALSE; - if (!_glfwPlatformInit()) { terminate(); return GLFW_FALSE; } + if (!_glfwPlatformCreateTls(&_glfw.error)) + return GLFW_FALSE; + if (!_glfwPlatformCreateTls(&_glfw.context)) + return GLFW_FALSE; + + _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) _glfwErrorCode); + _glfw.initialized = GLFW_TRUE; _glfw.timer.offset = _glfwPlatformGetTimerValue(); @@ -223,6 +237,24 @@ GLFWAPI const char* glfwGetVersionString(void) return _glfwPlatformGetVersionString(); } +GLFWAPI int glfwGetError(void) +{ + int error; + + if (_glfw.initialized) + { + error = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error); + _glfwPlatformSetTls(&_glfw.error, (intptr_t) GLFW_NO_ERROR); + } + else + { + error = _glfwErrorCode; + _glfwErrorCode = GLFW_NO_ERROR; + } + + return error; +} + GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) { _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun); diff --git a/src/internal.h b/src/internal.h index be9ced898..b7c35be98 100644 --- a/src/internal.h +++ b/src/internal.h @@ -517,6 +517,7 @@ struct _GLFWlibrary _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; + _GLFWtls error; _GLFWtls context; struct { @@ -653,6 +654,7 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); void _glfwPlatformDestroyTls(_GLFWtls* tls); void* _glfwPlatformGetTls(_GLFWtls* tls); void _glfwPlatformSetTls(_GLFWtls* tls, void* value); +GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls); /*! @} */ diff --git a/src/posix_tls.c b/src/posix_tls.c index 980ff23ba..cf2ae6fa7 100644 --- a/src/posix_tls.c +++ b/src/posix_tls.c @@ -52,7 +52,6 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) void _glfwPlatformDestroyTls(_GLFWtls* tls) { - assert(tls->posix.allocated == GLFW_TRUE); if (tls->posix.allocated) pthread_key_delete(tls->posix.key); memset(tls, 0, sizeof(_GLFWtls)); @@ -70,3 +69,8 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value) pthread_setspecific(tls->posix.key, value); } +GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls) +{ + return tls->posix.allocated; +} + diff --git a/src/win32_tls.c b/src/win32_tls.c index 944f7e5e0..9c20aad04 100644 --- a/src/win32_tls.c +++ b/src/win32_tls.c @@ -52,7 +52,6 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) void _glfwPlatformDestroyTls(_GLFWtls* tls) { - assert(tls->win32.allocated == GLFW_TRUE); if (tls->win32.allocated) TlsFree(tls->win32.index); memset(tls, 0, sizeof(_GLFWtls)); @@ -70,3 +69,8 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value) TlsSetValue(tls->win32.index, value); } +GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls) +{ + return tls->win32.allocated; +} + From f737e8ce9ff0df6af912311bec98601e26304127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 5 May 2017 19:05:00 +0200 Subject: [PATCH 030/222] Documentation work --- docs/window.dox | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/window.dox b/docs/window.dox index 90aa7f01c..4bb115e94 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -332,6 +332,9 @@ __GLFW_CONTEXT_VERSION_MAJOR__ and __GLFW_CONTEXT_VERSION_MINOR__ specify the client API version that the created context must be compatible with. The exact behavior of these hints depend on the requested client API. +@note Do not confuse these hints with `GLFW_VERSION_MAJOR` and +`GLFW_VERSION_MINOR`, which provide the API version of the GLFW header. + @par __OpenGL:__ These hints are not hard constraints, but creation will fail if the OpenGL version of the created context is less than the one requested. It is @@ -1126,6 +1129,10 @@ __GLFW_CONTEXT_VERSION_MAJOR__, __GLFW_CONTEXT_VERSION_MINOR__ and __GLFW_CONTEXT_REVISION__ indicate the client API version of the window's context. +@note Do not confuse these attributes with `GLFW_VERSION_MAJOR`, +`GLFW_VERSION_MINOR` and `GLFW_VERSION_REVISION` which provide the API version +of the GLFW header. + @anchor GLFW_OPENGL_FORWARD_COMPAT_attrib __GLFW_OPENGL_FORWARD_COMPAT__ is `GLFW_TRUE` if the window's context is an OpenGL forward-compatible one, or `GLFW_FALSE` otherwise. From d6fcbdc38ba75b262a52886f0cfe15d6602e7763 Mon Sep 17 00:00:00 2001 From: Arkady Shapkin Date: Sun, 7 May 2017 00:02:52 +0300 Subject: [PATCH 031/222] Move CMAKE_LEGACY_CYGWIN_WIN32 to its proper place Closes #1006. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 67b13332d..5f3bedfd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ -set(CMAKE_LEGACY_CYGWIN_WIN32 OFF) +cmake_minimum_required(VERSION 2.8.12) project(GLFW C) -cmake_minimum_required(VERSION 2.8.12) +set(CMAKE_LEGACY_CYGWIN_WIN32 OFF) if (NOT CMAKE_VERSION VERSION_LESS "3.0") # Until all major package systems have moved to CMake 3, From b234e28d5dbe2a9de56f615511f718cbb7fcabb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 10 May 2017 17:18:35 +0200 Subject: [PATCH 032/222] Win32: Stop exporting GUIDs from static library --- src/win32_init.c | 5 +++-- src/win32_joystick.c | 35 ++++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/win32_init.c b/src/win32_init.c index 636851288..231b0a28b 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -30,8 +30,9 @@ #include #include -#include -DEFINE_GUID(GUID_DEVINTERFACE_HID,0x4d1e55b2,0xf16f,0x11cf,0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30); +static const GUID _glfw_GUID_DEVINTERFACE_HID = {0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}}; + +#define GUID_DEVINTERFACE_HID _glfw_GUID_DEVINTERFACE_HID #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index ecbf4b90e..a368d995e 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -29,8 +29,6 @@ #include -#include - #define _GLFW_TYPE_AXIS 0 #define _GLFW_TYPE_SLIDER 1 #define _GLFW_TYPE_BUTTON 2 @@ -49,18 +47,29 @@ typedef struct _GLFWobjenumWin32 int povCount; } _GLFWobjenumWin32; -// Define only the necessary GUIDs (it's bad enough that we're exporting these) +// Define local copies of the necessary GUIDs // -DEFINE_GUID(IID_IDirectInput8W,0xbf798031,0x483a,0x4da2,0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00); -DEFINE_GUID(GUID_XAxis,0xa36d02e0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); -DEFINE_GUID(GUID_YAxis,0xa36d02e1,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); -DEFINE_GUID(GUID_ZAxis,0xa36d02e2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); -DEFINE_GUID(GUID_RxAxis,0xa36d02f4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); -DEFINE_GUID(GUID_RyAxis,0xa36d02f5,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); -DEFINE_GUID(GUID_RzAxis,0xa36d02e3,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); -DEFINE_GUID(GUID_Slider,0xa36d02e4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); -DEFINE_GUID(GUID_Button,0xa36d02f0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); -DEFINE_GUID(GUID_POV,0xa36d02f2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +static const GUID _glfw_IID_IDirectInput8W = {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}}; +static const GUID _glfw_GUID_XAxis = {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_YAxis = {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_ZAxis = {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RxAxis = {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RyAxis = {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RzAxis = {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_Slider = {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_Button = {0xa36d02f0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_POV = {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; + +#define IID_IDirectInput8W _glfw_IID_IDirectInput8W +#define GUID_XAxis _glfw_GUID_XAxis +#define GUID_YAxis _glfw_GUID_YAxis +#define GUID_ZAxis _glfw_GUID_ZAxis +#define GUID_RxAxis _glfw_GUID_RxAxis +#define GUID_RyAxis _glfw_GUID_RyAxis +#define GUID_RzAxis _glfw_GUID_RzAxis +#define GUID_Slider _glfw_GUID_Slider +#define GUID_Button _glfw_GUID_Button +#define GUID_POV _glfw_GUID_POV // Object data array for our clone of c_dfDIJoystick // Generated with https://github.com/elmindreda/c_dfDIJoystick2 From 731ff91acd7c52abe74bcde0f333f1c11c16f3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 10 May 2017 17:24:40 +0200 Subject: [PATCH 033/222] WGL: Add support for WGL_EXT_colorspace --- README.md | 1 + src/wgl_context.c | 32 +++++++++++++++++++++++++------- src/wgl_context.h | 3 +++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d6aed688a..4df6f2b78 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Value range was ignored for joystick hats and buttons (#888) - [Cocoa] Bugfix: Full screen framebuffer was incorrectly sized for some video modes (#682) +- [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) - [EGL] Added support for `EGL_KHR_context_flush_control` - [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid diff --git a/src/wgl_context.c b/src/wgl_context.c index c59997fc4..ff1d2d4e9 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -54,7 +54,9 @@ static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib // Return a list of available and usable framebuffer configs // -static int choosePixelFormat(_GLFWwindow* window, const _GLFWfbconfig* desired) +static int choosePixelFormat(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; @@ -127,11 +129,25 @@ static int choosePixelFormat(_GLFWwindow* window, const _GLFWfbconfig* desired) if (_glfw.wgl.ARB_multisample) u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB); - if (_glfw.wgl.ARB_framebuffer_sRGB || - _glfw.wgl.EXT_framebuffer_sRGB) + if (ctxconfig->client == GLFW_OPENGL_API) { - if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) - u->sRGB = GLFW_TRUE; + if (_glfw.wgl.ARB_framebuffer_sRGB || + _glfw.wgl.EXT_framebuffer_sRGB) + { + if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) + u->sRGB = GLFW_TRUE; + } + } + else + { + if (_glfw.wgl.EXT_colorspace) + { + if (getPixelFormatAttrib(window, n, WGL_COLORSPACE_EXT) == + WGL_COLORSPACE_SRGB_EXT) + { + u->sRGB = GLFW_TRUE; + } + } } } else @@ -197,7 +213,7 @@ static int choosePixelFormat(_GLFWwindow* window, const _GLFWfbconfig* desired) return 0; } - closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount); if (!closest) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, @@ -404,6 +420,8 @@ static void loadWGLExtensions(void) extensionSupportedWGL("WGL_ARB_create_context_robustness"); _glfw.wgl.EXT_swap_control = extensionSupportedWGL("WGL_EXT_swap_control"); + _glfw.wgl.EXT_colorspace = + extensionSupportedWGL("WGL_EXT_colorspace"); _glfw.wgl.ARB_pixel_format = extensionSupportedWGL("WGL_ARB_pixel_format"); _glfw.wgl.ARB_context_flush_control = @@ -489,7 +507,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_FALSE; } - pixelFormat = choosePixelFormat(window, fbconfig); + pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig); if (!pixelFormat) return GLFW_FALSE; diff --git a/src/wgl_context.h b/src/wgl_context.h index e3a7e3725..3b7f02474 100644 --- a/src/wgl_context.h +++ b/src/wgl_context.h @@ -72,6 +72,8 @@ #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define WGL_COLORSPACE_EXT 0x309d +#define WGL_COLORSPACE_SRGB_EXT 0x3089 #define ERROR_INVALID_VERSION_ARB 0x2095 #define ERROR_INVALID_PROFILE_ARB 0x2096 @@ -135,6 +137,7 @@ typedef struct _GLFWlibraryWGL PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; GLFWbool EXT_swap_control; + GLFWbool EXT_colorspace; GLFWbool ARB_multisample; GLFWbool ARB_framebuffer_sRGB; GLFWbool EXT_framebuffer_sRGB; From 4e8e25a521ec0bf4efd8307a57a9f12c16f6e292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 11 May 2017 13:34:22 +0200 Subject: [PATCH 034/222] Documentation work --- docs/window.dox | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/window.dox b/docs/window.dox index 4bb115e94..653f2fd6c 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -271,11 +271,17 @@ the application has no preference. @anchor GLFW_SRGB_CAPABLE __GLFW_SRGB_CAPABLE__ specifies whether the framebuffer should be sRGB capable. -If supported, a created OpenGL context will support the `GL_FRAMEBUFFER_SRGB` -enable, also called `GL_FRAMEBUFFER_SRGB_EXT`) for controlling sRGB rendering -and a created OpenGL ES context will always have sRGB rendering enabled. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. +@par +__OpenGL:__ If enabled and supported by the system, the `GL_FRAMEBUFFER_SRGB` +enable will control sRGB rendering. By default, sRGB rendering will be +disabled. + +@par +__OpenGL ES:__ If enabled and supported by the system, the context will always +have sRGB rendering enabled. + @anchor GLFW_DOUBLEBUFFER __GLFW_DOUBLEBUFFER__ specifies whether the framebuffer should be double buffered. You nearly always want to use double buffering. This is a hard From 412eb6a6113f71f42ad56d8dd982003ba7094870 Mon Sep 17 00:00:00 2001 From: Felipe Ferreira da Silva Date: Tue, 21 Mar 2017 10:02:57 -0300 Subject: [PATCH 035/222] Add glfwRequestWindowAttention Related to #988. --- README.md | 2 ++ include/GLFW/glfw3.h | 20 ++++++++++++++++++++ src/cocoa_window.m | 5 +++++ src/internal.h | 1 + src/mir_window.c | 4 ++++ src/null_window.c | 5 +++++ src/win32_window.c | 5 +++++ src/window.c | 10 ++++++++++ src/wl_window.c | 4 ++++ src/x11_init.c | 2 ++ src/x11_platform.h | 1 + src/x11_window.c | 15 +++++++++++++++ 12 files changed, 74 insertions(+) diff --git a/README.md b/README.md index 4df6f2b78..e0a7fd58b 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ information on what to include when reporting a bug. ## Changelog - Added `glfwGetError` function for querying the last error code (#970) +- Added `glfwRequestWindowAttention` function that request attention to the + non-focused or minimized window - Added `glfwGetKeyScancode` function that allows retrieving platform dependent scancodes for keys (#830) - Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index f0426ffb5..fb2022095 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2784,6 +2784,26 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); */ GLFWAPI void glfwFocusWindow(GLFWwindow* window); +/*! @brief Request attention to the specified window. + * + * This function makes the specified window to request attention. + * + * @param[in] window The window to request attention. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos The attention request will be made for the application and + * not the window passed in the argument. + * + * @thread_safety This function must only be called from the main thread. + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwRequestWindowAttention(GLFWwindow* window); + /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is diff --git a/src/cocoa_window.m b/src/cocoa_window.m index d2aab85f9..d2b207bb9 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1277,6 +1277,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) [window->ns.object orderOut:nil]; } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + [NSApp requestUserAttention:NSInformationalRequest]; +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { // Make us the active application diff --git a/src/internal.h b/src/internal.h index b7c35be98..0772d8ee0 100644 --- a/src/internal.h +++ b/src/internal.h @@ -630,6 +630,7 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window); void _glfwPlatformRestoreWindow(_GLFWwindow* window); void _glfwPlatformMaximizeWindow(_GLFWwindow* window); void _glfwPlatformShowWindow(_GLFWwindow* window); +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); void _glfwPlatformHideWindow(_GLFWwindow* window); void _glfwPlatformFocusWindow(_GLFWwindow* window); void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); diff --git a/src/mir_window.c b/src/mir_window.c index e380f4070..aefb89338 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -570,6 +570,10 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) mir_window_spec_release(spec); } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/null_window.c b/src/null_window.c index 7f0101d44..137f80c8f 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -172,6 +172,11 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) { } + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ +} + void _glfwPlatformUnhideWindow(_GLFWwindow* window) { } diff --git a/src/win32_window.c b/src/win32_window.c index 363ef0f32..6d691e196 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1316,6 +1316,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) ShowWindow(window->win32.handle, SW_HIDE); } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + FlashWindow(window->win32.handle, TRUE); +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { BringWindowToTop(window->win32.handle); diff --git a/src/window.c b/src/window.c index bf98723ea..546d233d8 100644 --- a/src/window.c +++ b/src/window.c @@ -675,6 +675,16 @@ GLFWAPI void glfwShowWindow(GLFWwindow* handle) _glfwPlatformFocusWindow(window); } +GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformRequestWindowAttention(window); +} + GLFWAPI void glfwHideWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index e6c554527..9dace92a7 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -599,6 +599,10 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) } } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/x11_init.c b/src/x11_init.c index 1767b6954..a52216f07 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -438,6 +438,8 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); + _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); _glfw.x11.NET_WM_FULLSCREEN_MONITORS = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); _glfw.x11.NET_WM_WINDOW_TYPE = diff --git a/src/x11_platform.h b/src/x11_platform.h index bafe88f4b..a0037c88b 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -193,6 +193,7 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_STATE_FULLSCREEN; Atom NET_WM_STATE_MAXIMIZED_VERT; Atom NET_WM_STATE_MAXIMIZED_HORZ; + Atom NET_WM_STATE_DEMANDS_ATTENTION; Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_WM_FULLSCREEN_MONITORS; Atom NET_ACTIVE_WINDOW; diff --git a/src/x11_window.c b/src/x11_window.c index e1c2a3e3e..fca3270e2 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2077,6 +2077,21 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + XEvent xev; + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = window->x11.handle; + xev.xclient.message_type = _glfw.x11.NET_WM_STATE; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_ADD; + xev.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION; + + XSendEvent(_glfw.x11.display, DefaultRootWindow(_glfw.x11.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW) From baa9cd8968e1571cd10a7265b589d997febf611e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 11 May 2017 14:36:56 +0200 Subject: [PATCH 036/222] Cleanup Closes #988. --- README.md | 5 +++-- docs/news.dox | 6 ++++++ docs/window.dox | 18 ++++++++++++++++++ include/GLFW/glfw3.h | 21 ++++++++++++++++----- src/internal.h | 2 +- src/mir_window.c | 2 ++ src/wl_window.c | 3 +++ src/x11_window.c | 16 +++++----------- 8 files changed, 54 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e0a7fd58b..0580d62de 100644 --- a/README.md +++ b/README.md @@ -123,8 +123,8 @@ information on what to include when reporting a bug. ## Changelog - Added `glfwGetError` function for querying the last error code (#970) -- Added `glfwRequestWindowAttention` function that request attention to the - non-focused or minimized window +- Added `glfwRequestWindowAttention` function for requesting attention from the + user (#732,#988) - Added `glfwGetKeyScancode` function that allows retrieving platform dependent scancodes for keys (#830) - Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for @@ -251,6 +251,7 @@ skills. - Jonathan Dummer - Ralph Eastwood - Siavash Eliasi + - Felipe Ferreira - Michael Fogleman - Gerald Franz - Mário Freitas diff --git a/docs/news.dox b/docs/news.dox index ad5de5aac..b2c8571f9 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -13,6 +13,12 @@ glfwGetError. @see @ref error_handling +@subsection news_33_attention User attention request + +GLFW now supports requesting user attention with @ref +glfwRequestWindowAttention. + + @subsection news_33_maximize Window maximization callback GLFW now supports window maximization notifications with @ref diff --git a/docs/window.dox b/docs/window.dox index 653f2fd6c..c8d4a18ea 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -984,6 +984,10 @@ glfwFocusWindow. glfwFocusWindow(window); @endcode +Keep in mind that it can be very disruptive to the user when a window is forced +to the top. For a less disruptive way of getting the user's attention, see +[attention requests](@ref window_attention). + If you wish to be notified when a window gains or loses input focus, whether by the user, system or your own code, set a focus callback. @@ -1022,6 +1026,20 @@ glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE); @endcode +@subsection window_attention Window attention request + +If you wish to notify the user of an event without interrupting, you can request +attention with @ref glfwRequestWindowAttention. + +@code +glfwRequestWindowAttention(window); +@endcode + +The system will highlight the specified window, or on platforms where this is +not supported, the application as a whole. Once the user has given it +attention, the system will automatically end the request. + + @subsection window_refresh Window damage and refresh If you wish to be notified when the contents of a window is damaged and needs diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index fb2022095..706fb9584 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2766,6 +2766,9 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * you are certain that is what the user wants. Focus stealing can be * extremely disruptive. * + * For a less disruptive way of getting the user's attention, see + * [attention requests](@ref window_attention). + * * @param[in] window The window to give input focus. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref @@ -2777,6 +2780,7 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * @thread_safety This function must only be called from the main thread. * * @sa @ref window_focus + * @sa @ref window_attention * * @since Added in version 3.2. * @@ -2784,20 +2788,27 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); */ GLFWAPI void glfwFocusWindow(GLFWwindow* window); -/*! @brief Request attention to the specified window. +/*! @brief Requests user attention to the specified window. * - * This function makes the specified window to request attention. + * This function requests user attention to the specified window. On + * platforms where this is not supported, attention is requested to the + * application as a whole. * - * @param[in] window The window to request attention. + * Once the user has given attention, usually by focusing the window or + * application, the system will end the request automatically. + * + * @param[in] window The window to request attention to. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @macos The attention request will be made for the application and - * not the window passed in the argument. + * @remark @macos Attention is requested to the application as a whole, not the + * specific window. * * @thread_safety This function must only be called from the main thread. * + * @sa @ref window_attention + * * @since Added in version 3.3. * * @ingroup window diff --git a/src/internal.h b/src/internal.h index 0772d8ee0..c2b358133 100644 --- a/src/internal.h +++ b/src/internal.h @@ -630,8 +630,8 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window); void _glfwPlatformRestoreWindow(_GLFWwindow* window); void _glfwPlatformMaximizeWindow(_GLFWwindow* window); void _glfwPlatformShowWindow(_GLFWwindow* window); -void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); void _glfwPlatformHideWindow(_GLFWwindow* window); +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); void _glfwPlatformFocusWindow(_GLFWwindow* window); void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); int _glfwPlatformWindowFocused(_GLFWwindow* window); diff --git a/src/mir_window.c b/src/mir_window.c index aefb89338..566f571c1 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -572,6 +572,8 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } void _glfwPlatformFocusWindow(_GLFWwindow* window) diff --git a/src/wl_window.c b/src/wl_window.c index 9dace92a7..e9c817d50 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -601,6 +601,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window attention request not implemented yet"); } void _glfwPlatformFocusWindow(_GLFWwindow* window) diff --git a/src/x11_window.c b/src/x11_window.c index fca3270e2..a683a821e 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2079,17 +2079,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { - XEvent xev; - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = window->x11.handle; - xev.xclient.message_type = _glfw.x11.NET_WM_STATE; - xev.xclient.format = 32; - xev.xclient.data.l[0] = _NET_WM_STATE_ADD; - xev.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION; - - XSendEvent(_glfw.x11.display, DefaultRootWindow(_glfw.x11.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION, + 0, 1, 0); } void _glfwPlatformFocusWindow(_GLFWwindow* window) From 2f5e2303380d084ab9b097765d34f98504324d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 11 May 2017 18:29:08 +0200 Subject: [PATCH 037/222] Add attention request to joystick test --- tests/joysticks.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/joysticks.c b/tests/joysticks.c index a51062db2..263bcb1c5 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -52,6 +52,7 @@ #define strdup(x) _strdup(x) #endif +static GLFWwindow* window; static int joysticks[GLFW_JOYSTICK_LAST + 1]; static int joystick_count = 0; @@ -79,6 +80,9 @@ static void joystick_callback(int jid, int event) joystick_count--; } + + if (!glfwGetWindowAttrib(window, GLFW_FOCUSED)) + glfwRequestWindowAttention(window); } static const char* joystick_label(int jid) @@ -91,7 +95,6 @@ static const char* joystick_label(int jid) int main(void) { int jid, hat_buttons = GLFW_FALSE; - GLFWwindow* window; struct nk_context* nk; struct nk_font_atlas* atlas; From 85c6168bbab6d924352a6fd2551ddbbf2fa02377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 16 May 2017 14:33:08 +0200 Subject: [PATCH 038/222] Fix missing type cast Thanks, Clang! --- src/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.c b/src/init.c index a0c6e42e2..19ae4c1db 100644 --- a/src/init.c +++ b/src/init.c @@ -244,7 +244,7 @@ GLFWAPI int glfwGetError(void) if (_glfw.initialized) { error = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error); - _glfwPlatformSetTls(&_glfw.error, (intptr_t) GLFW_NO_ERROR); + _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) GLFW_NO_ERROR); } else { From d1d08ef99f9b4ea6726df92ef313e320caf32f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Thu, 6 Apr 2017 16:00:09 +0200 Subject: [PATCH 039/222] Cocoa: Fix EGL support This adds support for using GLFW with EGL backends on macOS. While EGL isn't available by default on macOS, there are third-party implementations like SwiftShader. The addition of MoltenVK support added an override to makeBackingLayer. In non-Vulkan mode, this means that we are returning nil from that function. The NSGL implementation creates this layer manually later on, but other OpenGL backends don't necessarily do that. Closes #985. --- src/cocoa_window.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index d2b207bb9..0c40c71a9 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -423,6 +423,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (id)makeBackingLayer { + if (!window->ns.layer) { + window->ns.layer = [super makeBackingLayer]; + } return window->ns.layer; } From 244d6d782375f4277123e43c5dc2ede7d41aa4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 16 May 2017 15:42:51 +0200 Subject: [PATCH 040/222] Allow OpenGL ES header inclusion on macOS Related to #985. --- include/GLFW/glfw3.h | 52 ++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 706fb9584..f58022229 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -139,7 +139,32 @@ extern "C" { /* Include the chosen client API headers. */ -#if defined(__APPLE__) +#if defined(GLFW_INCLUDE_ES1) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif +#elif defined(GLFW_INCLUDE_ES2) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif +#elif defined(GLFW_INCLUDE_ES3) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif +#elif defined(GLFW_INCLUDE_ES31) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif +#elif defined(GLFW_INCLUDE_ES32) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif +#elif defined(__APPLE__) #if defined(GLFW_INCLUDE_GLCOREARB) #include #if defined(GLFW_INCLUDE_GLEXT) @@ -157,31 +182,6 @@ extern "C" { #else #if defined(GLFW_INCLUDE_GLCOREARB) #include - #elif defined(GLFW_INCLUDE_ES1) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES2) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES3) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES31) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES32) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif #elif !defined(GLFW_INCLUDE_NONE) #include #if defined(GLFW_INCLUDE_GLEXT) From 018ae69b33f3bef10b9387d6606b45371735b730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 16 May 2017 14:54:46 +0200 Subject: [PATCH 041/222] Cleanup Related to #985. --- src/cocoa_window.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 0c40c71a9..17d2b2061 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -423,10 +423,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (id)makeBackingLayer { - if (!window->ns.layer) { - window->ns.layer = [super makeBackingLayer]; - } - return window->ns.layer; + if (window->ns.layer) + return window->ns.layer; + + return [super makeBackingLayer]; } - (void)cursorUpdate:(NSEvent *)event From fa0b5e1b85ce9178f5279f27ef99a9a114077f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 16 May 2017 14:54:17 +0200 Subject: [PATCH 042/222] Additional client API logic cleanup --- include/GLFW/glfw3.h | 64 +++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index f58022229..f3c8e1ff2 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -134,71 +134,97 @@ extern "C" { #include /* Include because it is needed by Vulkan and related functions. + * Include it unconditionally to avoid surprising side-effects. */ #include -/* Include the chosen client API headers. +/* Include the chosen OpenGL or OpenGL ES headers. */ #if defined(GLFW_INCLUDE_ES1) + #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif + #elif defined(GLFW_INCLUDE_ES2) + #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif + #elif defined(GLFW_INCLUDE_ES3) + #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif + #elif defined(GLFW_INCLUDE_ES31) + #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif + #elif defined(GLFW_INCLUDE_ES32) + #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif -#elif defined(__APPLE__) - #if defined(GLFW_INCLUDE_GLCOREARB) + +#elif defined(GLFW_INCLUDE_GLCOREARB) + + #if defined(__APPLE__) + #include #if defined(GLFW_INCLUDE_GLEXT) #include - #endif - #elif !defined(GLFW_INCLUDE_NONE) + #endif /*GLFW_INCLUDE_GLEXT*/ + + #else /*__APPLE__*/ + + #include + + #endif /*__APPLE__*/ + +#elif !defined(GLFW_INCLUDE_NONE) + + #if defined(__APPLE__) + #if !defined(GLFW_INCLUDE_GLEXT) #define GL_GLEXT_LEGACY #endif #include - #endif - #if defined(GLFW_INCLUDE_GLU) - #include - #endif -#else - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #elif !defined(GLFW_INCLUDE_NONE) + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #else /*__APPLE__*/ + #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif - #endif - #if defined(GLFW_INCLUDE_GLU) - #include - #endif -#endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #endif /*__APPLE__*/ + +#endif /* OpenGL and OpenGL ES headers */ + #if defined(GLFW_INCLUDE_VULKAN) + #if defined(__APPLE__) #include #else #include #endif -#endif + +#endif /* Vulkan header */ #if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) /* GLFW_DLL must be defined by applications that are linking against the DLL From e4e3e508674f33fa89a282cd81c867714e9314a3 Mon Sep 17 00:00:00 2001 From: Jonathan Hale Date: Tue, 16 May 2017 16:22:24 +0200 Subject: [PATCH 043/222] Fix Travis build By setting dist explicitly to trusty, which has cmake >= 2.8.12 in their official package repository and installing newly non-default packages explicitly. Closes #1015. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index ff1c6c352..72ac4bfe2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,17 @@ os: - linux - osx sudo: false +dist: trusty addons: apt: sources: - kubuntu-backports packages: - cmake + - libxrandr-dev + - libxinerama-dev + - libxcursor-dev + - libxi-dev env: - BUILD_SHARED_LIBS=ON - BUILD_SHARED_LIBS=OFF From 4f7102be26b5b00a6ac585030a7a425412b6ddc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 17 May 2017 20:41:33 +0200 Subject: [PATCH 044/222] Clarify joystick ID error message --- src/input.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/input.c b/src/input.c index 16459b3f5..7d7ccf3fc 100644 --- a/src/input.c +++ b/src/input.c @@ -624,7 +624,7 @@ GLFWAPI int glfwJoystickPresent(int jid) if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return GLFW_FALSE; } @@ -646,7 +646,7 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } @@ -672,7 +672,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } @@ -705,7 +705,7 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } @@ -728,7 +728,7 @@ GLFWAPI const char* glfwGetJoystickName(int jid) if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } From 8597002a177beb56db09cd1a9fca0025687dc706 Mon Sep 17 00:00:00 2001 From: Denis Bernard Date: Wed, 5 Apr 2017 03:41:12 +0200 Subject: [PATCH 045/222] X11: Make glfwGetKeyName return UTF-8 strings Fixes #981. Closes #983. --- src/x11_window.c | 49 ++++++++++++++++++++++++++++++++++++------- src/xkb_unicode.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 8 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index a683a821e..bbe217991 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -876,6 +876,36 @@ static void releaseMonitor(_GLFWwindow* window) } } +// Encode a Unicode code point to a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +static size_t encodeUTF8(char *dest, uint32_t ch) +{ + if (ch < 0x80) { + dest[0] = (char)ch; + return 1; + } + if (ch < 0x800) { + dest[0] = (ch>>6) | 0xC0; + dest[1] = (ch & 0x3F) | 0x80; + return 2; + } + if (ch < 0x10000) { + dest[0] = (ch>>12) | 0xE0; + dest[1] = ((ch>>6) & 0x3F) | 0x80; + dest[2] = (ch & 0x3F) | 0x80; + return 3; + } + if (ch < 0x110000) { + dest[0] = (ch>>18) | 0xF0; + dest[1] = ((ch>>12) & 0x3F) | 0x80; + dest[2] = ((ch>>6) & 0x3F) | 0x80; + dest[3] = (ch & 0x3F) | 0x80; + return 4; + } + return 0; +} + // Decode a Unicode code point from a UTF-8 stream // Based on cutef8 by Jeff Bezanson (Public Domain) // @@ -2446,7 +2476,8 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) const char* _glfwPlatformGetKeyName(int key, int scancode) { KeySym keysym; - int extra; + long ch; + size_t sz; if (!_glfw.x11.xkb.available) return NULL; @@ -2459,15 +2490,17 @@ const char* _glfwPlatformGetKeyName(int key, int scancode) keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); if (keysym == NoSymbol) - return NULL; - - XkbTranslateKeySym(_glfw.x11.display, &keysym, 0, - _glfw.x11.keyName, sizeof(_glfw.x11.keyName), - &extra); - - if (!strlen(_glfw.x11.keyName)) return NULL; + ch = _glfwKeySym2Unicode(keysym); + if (ch == -1) + return NULL; + + sz = encodeUTF8(_glfw.x11.keyName, (uint32_t)ch); + if (sz == 0) + return NULL; + _glfw.x11.keyName[sz] = '\0'; + return _glfw.x11.keyName; } diff --git a/src/xkb_unicode.c b/src/xkb_unicode.c index 4c7f43739..d095405e5 100644 --- a/src/xkb_unicode.c +++ b/src/xkb_unicode.c @@ -826,6 +826,59 @@ static const struct codepair { { 0x13bd, 0x0153 }, { 0x13be, 0x0178 }, { 0x20ac, 0x20ac }, + // dead keys + { 0xfe50, '`' }, + { 0xfe51, 0x00b4 }, + { 0xfe52, '^' }, + { 0xfe53, '~' }, + { 0xfe54, 0x00af }, + { 0xfe55, 0x02d8 }, + { 0xfe56, 0x02d9 }, + { 0xfe57, 0x00a8 }, + { 0xfe58, 0x02da }, + { 0xfe59, 0x02dd }, + { 0xfe5a, 0x02c7 }, + { 0xfe5b, 0x00b8 }, + { 0xfe5c, 0x02db }, + { 0xfe5d, 0x037a }, + { 0xfe5e, 0x309b }, + { 0xfe5f, 0x309c }, + // { 0xfe60, 0x0323 }, // XK_dead_belowdot + // { 0xfe61, 0x0309 }, // XK_dead_hook + // { 0xfe62, 0x031b }, // XK_dead_horn + { 0xfe63, '/' }, + { 0xfe64, 0x02bc }, + { 0xfe65, 0x02bd }, + { 0xfe66, 0x02f5 }, + { 0xfe67, 0x02f3 }, + { 0xfe68, 0x02cd }, + { 0xfe69, 0xa788 }, + { 0xfe6a, 0x02f7 }, + // { 0xfe6b, 0x032e }, // XK_dead_belowbreve + // { 0xfe6c, 0x0324 }, // XK_dead_belowdiaeresis + // { 0xfe6d, 0x0311 }, // XK_dead_invertedbreve + { 0xfe6e, ',' }, + { 0xfe6f, 0x00a4 }, + // dead vowels for universal syllable entry + { 0xfe80, 'a' }, // XK_dead_a + { 0xfe81, 'A' }, // XK_dead_A + { 0xfe82, 'e' }, // XK_dead_e + { 0xfe83, 'E' }, // XK_dead_E + { 0xfe84, 'i' }, // XK_dead_i + { 0xfe85, 'I' }, // XK_dead_I + { 0xfe86, 'o' }, // XK_dead_o + { 0xfe87, 'O' }, // XK_dead_O + { 0xfe88, 'u' }, // XK_dead_u + { 0xfe89, 'U' }, // XK_dead_U + { 0xfe8a, 0x0259 }, + { 0xfe8b, 0x018f }, + // other + { 0xfe8c, 0x00b5 }, + // extra dead elements for German T3 layout + { 0xfe90, '_' }, + { 0xfe91, 0x02c8 }, + { 0xfe92, 0x02cc }, + // { 0xfe93, 0x0338 }, // XK_dead_longsolidusoverlay // Numeric keypad with numlock on { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, { 0xffbd /*XKB_KEY_KP_Equal*/, '=' }, From 2023095d8e63e50fb48f28d1d5643591eec19124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 17 May 2017 22:10:24 +0200 Subject: [PATCH 046/222] XKB: Fix Unicode lookup regression This fixes a sorting error introduced by 8597002a177beb56db09cd1a9fca0025687dc706. The array must be sorted for the binary search. --- src/xkb_unicode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xkb_unicode.c b/src/xkb_unicode.c index d095405e5..a6cb0e29b 100644 --- a/src/xkb_unicode.c +++ b/src/xkb_unicode.c @@ -881,7 +881,6 @@ static const struct codepair { // { 0xfe93, 0x0338 }, // XK_dead_longsolidusoverlay // Numeric keypad with numlock on { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, - { 0xffbd /*XKB_KEY_KP_Equal*/, '=' }, { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' }, { 0xffab /*XKB_KEY_KP_Add*/, '+' }, { 0xffac /*XKB_KEY_KP_Separator*/, ',' }, @@ -897,7 +896,8 @@ static const struct codepair { { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 }, { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 }, { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 }, - { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 } + { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 }, + { 0xffbd /*XKB_KEY_KP_Equal*/, '=' } }; From c8ea64976f562008e096b8b893319de993b3ba49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 17 May 2017 22:12:26 +0200 Subject: [PATCH 047/222] XKB: Workaround for Num Lock Related to #983. --- src/xkb_unicode.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/xkb_unicode.c b/src/xkb_unicode.c index a6cb0e29b..fdd3db717 100644 --- a/src/xkb_unicode.c +++ b/src/xkb_unicode.c @@ -881,6 +881,16 @@ static const struct codepair { // { 0xfe93, 0x0338 }, // XK_dead_longsolidusoverlay // Numeric keypad with numlock on { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, + { 0xff95 /*XKB_KEY_KP_7*/, 0x0037 }, + { 0xff96 /*XKB_KEY_KP_4*/, 0x0034 }, + { 0xff97 /*XKB_KEY_KP_8*/, 0x0038 }, + { 0xff98 /*XKB_KEY_KP_6*/, 0x0036 }, + { 0xff99 /*XKB_KEY_KP_2*/, 0x0032 }, + { 0xff9a /*XKB_KEY_KP_9*/, 0x0039 }, + { 0xff9b /*XKB_KEY_KP_3*/, 0x0033 }, + { 0xff9c /*XKB_KEY_KP_1*/, 0x0031 }, + { 0xff9d /*XKB_KEY_KP_5*/, 0x0035 }, + { 0xff9e /*XKB_KEY_KP_0*/, 0x0030 }, { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' }, { 0xffab /*XKB_KEY_KP_Add*/, '+' }, { 0xffac /*XKB_KEY_KP_Separator*/, ',' }, From 186d03b32affdbea65356b9314957873803c50af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 17 May 2017 22:12:47 +0200 Subject: [PATCH 048/222] Cleanup Related to #983. --- README.md | 2 ++ src/x11_platform.h | 2 +- src/x11_window.c | 57 ++++++++++++++++++++++------------------------ src/xkb_unicode.c | 12 ---------- 4 files changed, 30 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 0580d62de..8856b2f45 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: The RandR monitor path was disabled despite working RandR (#972) - [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747) - [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size +- [X11] Bugfix: Key name string encoding depended on current locale (#981,#983) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Cocoa] Added support for Vulkan window surface creation via [MoltenVK](https://moltengl.com/moltenvk/) (#870) @@ -233,6 +234,7 @@ skills. - John Bartholomew - Niklas Behrens - Niklas Bergström + - Denis Bernard - Doug Binks - blanco - Kyle Brenneman diff --git a/src/x11_platform.h b/src/x11_platform.h index a0037c88b..4d6c44fbd 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -167,7 +167,7 @@ typedef struct _GLFWlibraryX11 // Clipboard string (while the selection is owned) char* clipboardString; // Key name string - char keyName[64]; + char keyName[5]; // X11 keycode to GLFW key LUT short int keycodes[256]; // GLFW key to X11 keycode LUT diff --git a/src/x11_window.c b/src/x11_window.c index bbe217991..ed5a0f297 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -879,31 +879,32 @@ static void releaseMonitor(_GLFWwindow* window) // Encode a Unicode code point to a UTF-8 stream // Based on cutef8 by Jeff Bezanson (Public Domain) // -static size_t encodeUTF8(char *dest, uint32_t ch) +static size_t encodeUTF8(char* s, unsigned int ch) { - if (ch < 0x80) { - dest[0] = (char)ch; - return 1; + size_t count = 0; + + if (ch < 0x80) + s[count++] = (char) ch; + else if (ch < 0x800) + { + s[count++] = (ch >> 6) | 0xc0; + s[count++] = (ch & 0x3f) | 0x80; } - if (ch < 0x800) { - dest[0] = (ch>>6) | 0xC0; - dest[1] = (ch & 0x3F) | 0x80; - return 2; + else if (ch < 0x10000) + { + s[count++] = (ch >> 12) | 0xe0; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; } - if (ch < 0x10000) { - dest[0] = (ch>>12) | 0xE0; - dest[1] = ((ch>>6) & 0x3F) | 0x80; - dest[2] = (ch & 0x3F) | 0x80; - return 3; + else if (ch < 0x110000) + { + s[count++] = (ch >> 18) | 0xf0; + s[count++] = ((ch >> 12) & 0x3f) | 0x80; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; } - if (ch < 0x110000) { - dest[0] = (ch>>18) | 0xF0; - dest[1] = ((ch>>12) & 0x3F) | 0x80; - dest[2] = ((ch>>6) & 0x3F) | 0x80; - dest[3] = (ch & 0x3F) | 0x80; - return 4; - } - return 0; + + return count; } // Decode a Unicode code point from a UTF-8 stream @@ -2475,10 +2476,6 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) const char* _glfwPlatformGetKeyName(int key, int scancode) { - KeySym keysym; - long ch; - size_t sz; - if (!_glfw.x11.xkb.available) return NULL; @@ -2488,19 +2485,19 @@ const char* _glfwPlatformGetKeyName(int key, int scancode) if (!_glfwIsPrintable(_glfw.x11.keycodes[scancode])) return NULL; - keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); + const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); if (keysym == NoSymbol) return NULL; - ch = _glfwKeySym2Unicode(keysym); + const long ch = _glfwKeySym2Unicode(keysym); if (ch == -1) return NULL; - sz = encodeUTF8(_glfw.x11.keyName, (uint32_t)ch); - if (sz == 0) + const size_t count = encodeUTF8(_glfw.x11.keyName, (unsigned int) ch); + if (count == 0) return NULL; - _glfw.x11.keyName[sz] = '\0'; + _glfw.x11.keyName[count] = '\0'; return _glfw.x11.keyName; } diff --git a/src/xkb_unicode.c b/src/xkb_unicode.c index fdd3db717..ecfdc2aff 100644 --- a/src/xkb_unicode.c +++ b/src/xkb_unicode.c @@ -826,7 +826,6 @@ static const struct codepair { { 0x13bd, 0x0153 }, { 0x13be, 0x0178 }, { 0x20ac, 0x20ac }, - // dead keys { 0xfe50, '`' }, { 0xfe51, 0x00b4 }, { 0xfe52, '^' }, @@ -843,9 +842,6 @@ static const struct codepair { { 0xfe5d, 0x037a }, { 0xfe5e, 0x309b }, { 0xfe5f, 0x309c }, - // { 0xfe60, 0x0323 }, // XK_dead_belowdot - // { 0xfe61, 0x0309 }, // XK_dead_hook - // { 0xfe62, 0x031b }, // XK_dead_horn { 0xfe63, '/' }, { 0xfe64, 0x02bc }, { 0xfe65, 0x02bd }, @@ -854,12 +850,8 @@ static const struct codepair { { 0xfe68, 0x02cd }, { 0xfe69, 0xa788 }, { 0xfe6a, 0x02f7 }, - // { 0xfe6b, 0x032e }, // XK_dead_belowbreve - // { 0xfe6c, 0x0324 }, // XK_dead_belowdiaeresis - // { 0xfe6d, 0x0311 }, // XK_dead_invertedbreve { 0xfe6e, ',' }, { 0xfe6f, 0x00a4 }, - // dead vowels for universal syllable entry { 0xfe80, 'a' }, // XK_dead_a { 0xfe81, 'A' }, // XK_dead_A { 0xfe82, 'e' }, // XK_dead_e @@ -872,14 +864,10 @@ static const struct codepair { { 0xfe89, 'U' }, // XK_dead_U { 0xfe8a, 0x0259 }, { 0xfe8b, 0x018f }, - // other { 0xfe8c, 0x00b5 }, - // extra dead elements for German T3 layout { 0xfe90, '_' }, { 0xfe91, 0x02c8 }, { 0xfe92, 0x02cc }, - // { 0xfe93, 0x0338 }, // XK_dead_longsolidusoverlay - // Numeric keypad with numlock on { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, { 0xff95 /*XKB_KEY_KP_7*/, 0x0037 }, { 0xff96 /*XKB_KEY_KP_4*/, 0x0034 }, From bc7ebc1a896c6e4f599f155966f5b029c157ba51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 22 May 2017 15:16:47 +0200 Subject: [PATCH 049/222] Fix joystick test attention request Fixes #1020. --- tests/joysticks.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/joysticks.c b/tests/joysticks.c index 263bcb1c5..3a7a90c77 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -105,14 +105,6 @@ int main(void) if (!glfwInit()) exit(EXIT_FAILURE); - for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) - { - if (glfwJoystickPresent(jid)) - joystick_callback(jid, GLFW_CONNECTED); - } - - glfwSetJoystickCallback(joystick_callback); - window = glfwCreateWindow(640, 480, "Joystick Test", NULL, NULL); if (!window) { @@ -128,6 +120,14 @@ int main(void) nk_glfw3_font_stash_begin(&atlas); nk_glfw3_font_stash_end(); + for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (glfwJoystickPresent(jid)) + joysticks[joystick_count++] = jid; + } + + glfwSetJoystickCallback(joystick_callback); + while (!glfwWindowShouldClose(window)) { int i, width, height; From 372e908682f1b467b7aa31090b0abb2e25e921b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 25 May 2017 19:35:13 +0200 Subject: [PATCH 050/222] Remove internal header inclusion guards Inclusion of internal headers is already both centralized and follows strict rules. Inclusion guards are both an unneccessary maintenance burden and may hide inclusion order bugs. --- src/cocoa_joystick.h | 4 ---- src/cocoa_platform.h | 4 ---- src/egl_context.h | 4 ---- src/glx_context.h | 4 ---- src/internal.h | 5 ----- src/linux_joystick.h | 4 ---- src/mir_platform.h | 4 ---- src/nsgl_context.h | 4 ---- src/null_joystick.h | 5 ----- src/null_platform.h | 5 ----- src/osmesa_context.h | 4 ---- src/posix_time.h | 4 ---- src/posix_tls.h | 5 ----- src/wgl_context.h | 5 ----- src/win32_joystick.h | 4 ---- src/win32_platform.h | 4 ---- src/wl_platform.h | 4 ---- src/x11_platform.h | 4 ---- src/xkb_unicode.h | 5 ----- 19 files changed, 82 deletions(-) diff --git a/src/cocoa_joystick.h b/src/cocoa_joystick.h index 9cb12e651..5a668c8c7 100644 --- a/src/cocoa_joystick.h +++ b/src/cocoa_joystick.h @@ -24,9 +24,6 @@ // //======================================================================== -#ifndef _glfw3_cocoa_joystick_h_ -#define _glfw3_cocoa_joystick_h_ - #include #include #include @@ -50,4 +47,3 @@ typedef struct _GLFWjoystickNS void _glfwInitJoysticksNS(void); void _glfwTerminateJoysticksNS(void); -#endif // _glfw3_cocoa_joystick_h_ diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 74db7fa59..f744f78ce 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -24,9 +24,6 @@ // //======================================================================== -#ifndef _glfw3_cocoa_platform_h_ -#define _glfw3_cocoa_platform_h_ - #include #include @@ -164,4 +161,3 @@ void _glfwPollMonitorsNS(void); GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor); -#endif // _glfw3_cocoa_platform_h_ diff --git a/src/egl_context.h b/src/egl_context.h index f8393a49f..bfab5111f 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -25,9 +25,6 @@ // //======================================================================== -#ifndef _glfw3_egl_context_h_ -#define _glfw3_egl_context_h_ - #if defined(_GLFW_USE_EGLPLATFORM_H) #include #elif defined(_GLFW_WIN32) @@ -219,4 +216,3 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, Visual** visual, int* depth); #endif /*_GLFW_X11*/ -#endif // _glfw3_egl_context_h_ diff --git a/src/glx_context.h b/src/glx_context.h index 285861f93..3a427bd20 100644 --- a/src/glx_context.h +++ b/src/glx_context.h @@ -25,9 +25,6 @@ // //======================================================================== -#ifndef _glfw3_glx_context_h_ -#define _glfw3_glx_context_h_ - #define GLX_VENDOR 1 #define GLX_RGBA_BIT 0x00000001 #define GLX_WINDOW_BIT 0x00000001 @@ -180,4 +177,3 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); -#endif // _glfw3_glx_context_h_ diff --git a/src/internal.h b/src/internal.h index c2b358133..bd4c53078 100644 --- a/src/internal.h +++ b/src/internal.h @@ -25,10 +25,6 @@ // //======================================================================== -#ifndef _glfw3_internal_h_ -#define _glfw3_internal_h_ - - #if defined(_GLFW_USE_CONFIG_H) #include "glfw_config.h" #endif @@ -961,4 +957,3 @@ void _glfwTerminateVulkan(void); */ const char* _glfwGetVulkanResultString(VkResult result); -#endif // _glfw3_internal_h_ diff --git a/src/linux_joystick.h b/src/linux_joystick.h index 3698b7e07..311becf64 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -24,9 +24,6 @@ // //======================================================================== -#ifndef _glfw3_linux_joystick_h_ -#define _glfw3_linux_joystick_h_ - #include #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs @@ -55,4 +52,3 @@ GLFWbool _glfwInitJoysticksLinux(void); void _glfwTerminateJoysticksLinux(void); void _glfwDetectJoystickConnectionLinux(void); -#endif // _glfw3_linux_joystick_h_ diff --git a/src/mir_platform.h b/src/mir_platform.h index d3fd10de0..3dac43ecc 100644 --- a/src/mir_platform.h +++ b/src/mir_platform.h @@ -24,9 +24,6 @@ // //======================================================================== -#ifndef _glfw3_mir_platform_h_ -#define _glfw3_mir_platform_h_ - #include #include #include @@ -134,4 +131,3 @@ extern void _glfwPollMonitorsMir(void); extern void _glfwInitEventQueueMir(EventQueue* queue); extern void _glfwDeleteEventQueueMir(EventQueue* queue); -#endif // _glfw3_mir_platform_h_ diff --git a/src/nsgl_context.h b/src/nsgl_context.h index 45847769e..18042dee6 100644 --- a/src/nsgl_context.h +++ b/src/nsgl_context.h @@ -24,9 +24,6 @@ // //======================================================================== -#ifndef _glfw3_nsgl_context_h_ -#define _glfw3_nsgl_context_h_ - #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl @@ -57,4 +54,3 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextNSGL(_GLFWwindow* window); -#endif // _glfw3_nsgl_context_h_ diff --git a/src/null_joystick.h b/src/null_joystick.h index 8d2e315a1..3de734583 100644 --- a/src/null_joystick.h +++ b/src/null_joystick.h @@ -24,11 +24,6 @@ // //======================================================================== -#ifndef _glfw3_null_joystick_h_ -#define _glfw3_null_joystick_h_ - #define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs - -#endif // _glfw3_null_joystick_h_ diff --git a/src/null_platform.h b/src/null_platform.h index 3218610db..dfb88a16c 100644 --- a/src/null_platform.h +++ b/src/null_platform.h @@ -25,9 +25,6 @@ // //======================================================================== -#ifndef _glfw3_null_platform_h_ -#define _glfw3_null_platform_h_ - #include #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null @@ -63,5 +60,3 @@ typedef struct _GLFWwindowNull int height; } _GLFWwindowNull; - -#endif // _glfw3_null_platform_h_ diff --git a/src/osmesa_context.h b/src/osmesa_context.h index 275546f18..e6ae57810 100644 --- a/src/osmesa_context.h +++ b/src/osmesa_context.h @@ -25,9 +25,6 @@ // //======================================================================== -#ifndef _glfw3_osmesa_context_h_ -#define _glfw3_osmesa_context_h_ - #define OSMESA_RGBA 0x1908 #define OSMESA_FORMAT 0x22 #define OSMESA_DEPTH_BITS 0x30 @@ -95,4 +92,3 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -#endif // _glfw3_osmesa_context_h_ diff --git a/src/posix_time.h b/src/posix_time.h index f4cf4db1e..f1a69eb24 100644 --- a/src/posix_time.h +++ b/src/posix_time.h @@ -25,9 +25,6 @@ // //======================================================================== -#ifndef _glfw3_posix_time_h_ -#define _glfw3_posix_time_h_ - #define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix #include @@ -45,4 +42,3 @@ typedef struct _GLFWtimerPOSIX void _glfwInitTimerPOSIX(void); -#endif // _glfw3_posix_time_h_ diff --git a/src/posix_tls.h b/src/posix_tls.h index 5d0e7c369..f738dc0de 100644 --- a/src/posix_tls.h +++ b/src/posix_tls.h @@ -25,9 +25,6 @@ // //======================================================================== -#ifndef _glfw3_posix_tls_h_ -#define _glfw3_posix_tls_h_ - #include #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix @@ -42,5 +39,3 @@ typedef struct _GLFWtlsPOSIX } _GLFWtlsPOSIX; - -#endif // _glfw3_posix_tls_h_ diff --git a/src/wgl_context.h b/src/wgl_context.h index 3b7f02474..e02cc0ecc 100644 --- a/src/wgl_context.h +++ b/src/wgl_context.h @@ -25,10 +25,6 @@ // //======================================================================== -#ifndef _glfw3_wgl_context_h_ -#define _glfw3_wgl_context_h_ - - #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 @@ -157,4 +153,3 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -#endif // _glfw3_wgl_context_h_ diff --git a/src/win32_joystick.h b/src/win32_joystick.h index 8070a4259..54102e62f 100644 --- a/src/win32_joystick.h +++ b/src/win32_joystick.h @@ -24,9 +24,6 @@ // //======================================================================== -#ifndef _glfw3_win32_joystick_h_ -#define _glfw3_win32_joystick_h_ - #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickWin32 win32 #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int dummy @@ -56,4 +53,3 @@ void _glfwTerminateJoysticksWin32(void); void _glfwDetectJoystickConnectionWin32(void); void _glfwDetectJoystickDisconnectionWin32(void); -#endif // _glfw3_win32_joystick_h_ diff --git a/src/win32_platform.h b/src/win32_platform.h index d51dee25c..3e0c93b0c 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -25,9 +25,6 @@ // //======================================================================== -#ifndef _glfw3_win32_platform_h_ -#define _glfw3_win32_platform_h_ - // We don't need all the fancy stuff #ifndef NOMINMAX #define NOMINMAX @@ -351,4 +348,3 @@ void _glfwPollMonitorsWin32(void); GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor); -#endif // _glfw3_win32_platform_h_ diff --git a/src/wl_platform.h b/src/wl_platform.h index bea32350b..620698570 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -24,9 +24,6 @@ // //======================================================================== -#ifndef _glfw3_wayland_platform_h_ -#define _glfw3_wayland_platform_h_ - #include #include #include @@ -169,4 +166,3 @@ typedef struct _GLFWcursorWayland void _glfwAddOutputWayland(uint32_t name, uint32_t version); -#endif // _glfw3_wayland_platform_h_ diff --git a/src/x11_platform.h b/src/x11_platform.h index 4d6c44fbd..48ee88b1b 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -25,9 +25,6 @@ // //======================================================================== -#ifndef _glfw3_x11_platform_h_ -#define _glfw3_x11_platform_h_ - #include #include #include @@ -335,4 +332,3 @@ void _glfwInputErrorX11(int error, const char* message); void _glfwPushSelectionToManagerX11(void); -#endif // _glfw3_x11_platform_h_ diff --git a/src/xkb_unicode.h b/src/xkb_unicode.h index 164a6fa8a..f95e14f10 100644 --- a/src/xkb_unicode.h +++ b/src/xkb_unicode.h @@ -24,10 +24,5 @@ // //======================================================================== -#ifndef _glfw3_xkb_unicode_h_ -#define _glfw3_xkb_unicode_h_ - - long _glfwKeySym2Unicode(unsigned int keysym); -#endif // _glfw3_xkb_unicode_h_ From c48127fa9ec900f3bf2c7cfce33ca86ffdf31aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 6 Jun 2017 17:35:47 +0200 Subject: [PATCH 051/222] Fix some CSS issues caused by Doxygen 1.8.12 --- docs/extra.css | 2 +- docs/extra.less | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/extra.css b/docs/extra.css index e9896fae1..7d9a30496 100644 --- a/docs/extra.css +++ b/docs/extra.css @@ -1 +1 @@ -#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code{background:none}#titlearea,.footer,.contents,div.header,.memdoc,table.doxtable td,table.doxtable th,hr,.memSeparator{border:none}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.reflist dt a.el,.levels span,.directory .levels span{text-shadow:none}.memdoc,dl.reflist dd{box-shadow:none}div.headertitle,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,table.doxtable code{padding:0}#nav-path,.directory .levels,span.lineno{display:none}html,#titlearea,.footer,tr.even,.directory tr.even,.doxtable tr:nth-child(even),.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,code{background:#f2f2f2}body{color:#4d4d4d}h1,h2,h2.groupheader,h3,div.toc h3,h4,h5,h6,strong,em{color:#1a1a1a;border-bottom:none}h1{padding-top:0.5em;font-size:180%}h2{padding-top:0.5em;margin-bottom:0;font-size:140%}h3{padding-top:0.5em;margin-bottom:0;font-size:110%}.glfwheader{font-size:16px;height:64px;max-width:920px;min-width:800px;padding:0 32px;margin:0 auto}#glfwhome{line-height:64px;padding-right:48px;color:#666;font-size:2.5em;background:url("http://www.glfw.org/css/arrow.png") no-repeat right}.glfwnavbar{list-style-type:none;margin:0 auto;float:right}#glfwhome,.glfwnavbar li{float:left}.glfwnavbar a,.glfwnavbar a:visited{line-height:64px;margin-left:2em;display:block;color:#666}#glfwhome,.glfwnavbar a,.glfwnavbar a:visited{transition:.35s ease}#titlearea,.footer{color:#666}address.footer{text-align:center;padding:2em;margin-top:3em}#top{background:#666}#navrow1,#navrow2,#navrow3,#navrow4{max-width:920px;min-width:800px;margin:0 auto;font-size:13px}.tablist{height:36px;display:block;position:relative}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a{color:#f2f2f2}.tablist li.current a{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}.contents{min-height:590px}div.contents,div.header{max-width:920px;margin:0 auto;padding:0 32px;background:#fff none}table.doxtable th,dl.reflist dt{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}dl.reflist dt a.el{color:#f60;padding:.2em;border-radius:4px;background-color:#ffe0cc}div.toc{float:none;width:auto}div.toc h3{font-size:1.17em}div.toc ul{padding-left:1.5em}div.toc li{font-size:1em;padding-left:0;list-style-type:disc}div.toc,.memproto,div.qindex,div.ah{background:linear-gradient(to bottom, #f2f2f2 0, #e6e6e6 100%);box-shadow:inset 0 0 32px #e6e6e6;text-shadow:0 1px 1px #fff;color:#1a1a1a;border:2px solid #e6e6e6;border-radius:4px}.paramname{color:#803300}dl.reflist dt{border:2px solid #f60;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:none}dl.reflist dd{border:2px solid #f60;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:none}table.doxtable{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,.tablist a:hover,span.lineno a:hover{color:#f60;text-decoration:none}div.directory{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}hr,.memSeparator{height:2px;background:linear-gradient(to right, #f2f2f2 0, #d9d9d9 50%, #f2f2f2 100%)}dl.note,dl.pre,dl.post,dl.invariant{background:linear-gradient(to bottom, #ddfad1 0, #cbf7ba 100%);box-shadow:inset 0 0 32px #baf5a3;color:#1e5309;border:2px solid #afe599}dl.warning,dl.attention{background:linear-gradient(to bottom, #fae8d1 0, #f7ddba 100%);box-shadow:inset 0 0 32px #f5d1a3;color:#533309;border:2px solid #e5c499}dl.deprecated,dl.bug{background:linear-gradient(to bottom, #fad1e3 0, #f7bad6 100%);box-shadow:inset 0 0 32px #f5a3c8;color:#53092a;border:2px solid #e599bb}dl.todo,dl.test{background:linear-gradient(to bottom, #d1ecfa 0, #bae3f7 100%);box-shadow:inset 0 0 32px #a3daf5;color:#093a53;border:2px solid #99cce5}dl.note,dl.pre,dl.post,dl.invariant,dl.warning,dl.attention,dl.deprecated,dl.bug,dl.todo,dl.test{border-radius:4px;padding:1em;text-shadow:0 1px 1px #fff;margin:1em 0}.note a,.pre a,.post a,.invariant a,.warning a,.attention a,.deprecated a,.bug a,.todo a,.test a,.note a:visited,.pre a:visited,.post a:visited,.invariant a:visited,.warning a:visited,.attention a:visited,.deprecated a:visited,.bug a:visited,.todo a:visited,.test a:visited{color:inherit}div.line{line-height:inherit}div.fragment,pre.fragment{background:#f2f2f2;border-radius:4px;border:none;padding:1em;overflow:auto;border-left:4px solid #ccc;margin:1em 0}.lineno a,.lineno a:visited,.line,pre.fragment{color:#4d4d4d}span.preprocessor,span.comment{color:#007899}a.code,a.code:visited{color:#e64500}span.keyword,span.keywordtype,span.keywordflow{color:#404040;font-weight:bold}span.stringliteral{color:#360099}code{padding:.1em;border-radius:4px} +.sm-dox,.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted,.sm-dox ul a:hover{background:none;text-shadow:none}.sm-dox ul a:hover{background:#666;text-shadow:none}#main-nav,#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code{background:none}#titlearea,.footer,.contents,div.header,.memdoc,table.doxtable td,table.doxtable th,hr,.memSeparator{border:none}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.reflist dt a.el,.levels span,.directory .levels span{text-shadow:none}.memdoc,dl.reflist dd{box-shadow:none}div.headertitle,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,table.doxtable code{padding:0}#nav-path,.directory .levels,span.lineno{display:none}html,#titlearea,.footer,tr.even,.directory tr.even,.doxtable tr:nth-child(even),.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,code{background:#f2f2f2}body{color:#4d4d4d}h1,h2,h2.groupheader,h3,div.toc h3,h4,h5,h6,strong,em{color:#1a1a1a;border-bottom:none}h1{padding-top:0.5em;font-size:180%}h2{padding-top:0.5em;margin-bottom:0;font-size:140%}h3{padding-top:0.5em;margin-bottom:0;font-size:110%}.glfwheader{font-size:16px;height:64px;max-width:920px;min-width:800px;padding:0 32px;margin:0 auto}#glfwhome{line-height:64px;padding-right:48px;color:#666;font-size:2.5em;background:url("http://www.glfw.org/css/arrow.png") no-repeat right}.glfwnavbar{list-style-type:none;margin:0 auto;float:right}#glfwhome,.glfwnavbar li{float:left}.glfwnavbar a,.glfwnavbar a:visited{line-height:64px;margin-left:2em;display:block;color:#666}#glfwhome,.glfwnavbar a,.glfwnavbar a:visited{transition:.35s ease}#titlearea,.footer{color:#666}address.footer{text-align:center;padding:2em;margin-top:3em}#top{background:#666}#main-nav{max-width:960px;min-width:800px;margin:0 auto;font-size:13px}#navrow1,#navrow2,#navrow3,#navrow4{max-width:920px;min-width:800px;margin:0 auto;font-size:13px}.memtitle{display:none}.memproto,.memname{font-weight:bold;text-shadow:none}.tablist{height:36px;display:block;position:relative}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a{color:#f2f2f2}.tablist li.current a{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}.contents{min-height:590px}div.contents,div.header{max-width:920px;margin:0 auto;padding:0 32px;background:#fff none}table.doxtable th,dl.reflist dt{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}dl.reflist dt a.el{color:#f60;padding:.2em;border-radius:4px;background-color:#ffe0cc}div.toc{float:none;width:auto}div.toc h3{font-size:1.17em}div.toc ul{padding-left:1.5em}div.toc li{font-size:1em;padding-left:0;list-style-type:disc}div.toc,.memproto,div.qindex,div.ah{background:linear-gradient(to bottom, #f2f2f2 0, #e6e6e6 100%);box-shadow:inset 0 0 32px #e6e6e6;text-shadow:0 1px 1px #fff;color:#1a1a1a;border:2px solid #e6e6e6;border-radius:4px}.paramname{color:#803300}dl.reflist dt{border:2px solid #f60;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:none}dl.reflist dd{border:2px solid #f60;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:none}table.doxtable{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,.tablist a:hover,span.lineno a:hover{color:#f60;text-decoration:none}div.directory{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}hr,.memSeparator{height:2px;background:linear-gradient(to right, #f2f2f2 0, #d9d9d9 50%, #f2f2f2 100%)}dl.note,dl.pre,dl.post,dl.invariant{background:linear-gradient(to bottom, #ddfad1 0, #cbf7ba 100%);box-shadow:inset 0 0 32px #baf5a3;color:#1e5309;border:2px solid #afe599}dl.warning,dl.attention{background:linear-gradient(to bottom, #fae8d1 0, #f7ddba 100%);box-shadow:inset 0 0 32px #f5d1a3;color:#533309;border:2px solid #e5c499}dl.deprecated,dl.bug{background:linear-gradient(to bottom, #fad1e3 0, #f7bad6 100%);box-shadow:inset 0 0 32px #f5a3c8;color:#53092a;border:2px solid #e599bb}dl.todo,dl.test{background:linear-gradient(to bottom, #d1ecfa 0, #bae3f7 100%);box-shadow:inset 0 0 32px #a3daf5;color:#093a53;border:2px solid #99cce5}dl.note,dl.pre,dl.post,dl.invariant,dl.warning,dl.attention,dl.deprecated,dl.bug,dl.todo,dl.test{border-radius:4px;padding:1em;text-shadow:0 1px 1px #fff;margin:1em 0}.note a,.pre a,.post a,.invariant a,.warning a,.attention a,.deprecated a,.bug a,.todo a,.test a,.note a:visited,.pre a:visited,.post a:visited,.invariant a:visited,.warning a:visited,.attention a:visited,.deprecated a:visited,.bug a:visited,.todo a:visited,.test a:visited{color:inherit}div.line{line-height:inherit}div.fragment,pre.fragment{background:#f2f2f2;border-radius:4px;border:none;padding:1em;overflow:auto;border-left:4px solid #ccc;margin:1em 0}.lineno a,.lineno a:visited,.line,pre.fragment{color:#4d4d4d}span.preprocessor,span.comment{color:#007899}a.code,a.code:visited{color:#e64500}span.keyword,span.keywordtype,span.keywordflow{color:#404040;font-weight:bold}span.stringliteral{color:#360099}code{padding:.1em;border-radius:4px} diff --git a/docs/extra.less b/docs/extra.less index 9d0ce9759..c5f5eea5f 100644 --- a/docs/extra.less +++ b/docs/extra.less @@ -76,8 +76,17 @@ border:2px solid desaturate(darken(@base-color, 10%), 20%); } +.sm-dox,.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted,.sm-dox ul a:hover { + background:none; + text-shadow:none; +} -#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code { +.sm-dox ul a:hover { + background:@header-footer-link-color; + text-shadow:none; +} + +#main-nav,#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code { background:none; } @@ -183,6 +192,13 @@ address.footer { background:@header-footer-link-color; } +#main-nav { + max-width:960px; + min-width:800px; + margin:0 auto; + font-size:13px; +} + #navrow1,#navrow2,#navrow3,#navrow4 { max-width:920px; min-width:800px; @@ -190,6 +206,15 @@ address.footer { font-size:13px; } +.memtitle { + display:none; +} + +.memproto,.memname { + font-weight:bold; + text-shadow:none; +} + .tablist { height:36px; display:block; From beaeb0d4af53b62a86c7880b7180597c7f164145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 6 Jun 2017 18:17:58 +0200 Subject: [PATCH 052/222] Add missing pixel format documentation Fixes #1027. --- docs/input.dox | 4 ++-- docs/window.dox | 4 ++++ include/GLFW/glfw3.h | 11 +++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/input.dox b/docs/input.dox index b5b853aad..bc1d1a7b2 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -346,8 +346,8 @@ If cursor creation fails, `NULL` will be returned, so it is necessary to check the return value. The image data is 32-bit, little-endian, non-premultiplied RGBA, i.e. eight bits -per channel. The pixels are arranged canonically as sequential rows, starting -from the top-left corner. +per channel with the red channel first. The pixels are arranged canonically as +sequential rows, starting from the top-left corner. @subsubsection cursor_standard Standard cursor creation diff --git a/docs/window.dox b/docs/window.dox index c8d4a18ea..8bd87e135 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -785,6 +785,10 @@ images[1] = load_icon("my_icon_small.png"); glfwSetWindowIcon(window, 2, images); @endcode +The image data is 32-bit, little-endian, non-premultiplied RGBA, i.e. eight bits +per channel with the red channel first. The pixels are arranged canonically as +sequential rows, starting from the top-left corner. + To revert to the default window icon, pass in an empty image array. @code diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index f3c8e1ff2..3b2d5b852 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1458,6 +1458,9 @@ typedef struct GLFWgammaramp } GLFWgammaramp; /*! @brief Image data. + * + * This describes a single 2D image. See the documentation for each related + * function what the expected pixel format is. * * @sa @ref cursor_custom * @sa @ref window_icon @@ -2323,6 +2326,10 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * selected. If no images are specified, the window reverts to its default * icon. * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel with the red channel first. They are arranged canonically + * as packed sequential rows, starting from the top-left corner. + * * The desired image sizes varies depending on platform and system settings. * The selected images will be rescaled as needed. Good sizes include 16x16, * 32x32 and 48x48. @@ -3726,8 +3733,8 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * Any remaining cursors are destroyed by @ref glfwTerminate. * * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight - * bits per channel. They are arranged canonically as packed sequential rows, - * starting from the top-left corner. + * bits per channel with the red channel first. They are arranged canonically + * as packed sequential rows, starting from the top-left corner. * * The cursor hotspot is specified in pixels, relative to the upper-left corner * of the cursor image. Like all other coordinate systems in GLFW, the X-axis From 14a3fe0ac014c7ec95fee67371ecb742b6d87e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 25 May 2017 18:23:09 +0200 Subject: [PATCH 053/222] Make glfwGetError also provide description Related to #970. --- README.md | 3 +- docs/intro.dox | 60 +++++++++++++--------- docs/news.dox | 4 +- include/GLFW/glfw3.h | 13 +++-- src/context.c | 12 ++--- src/egl_context.c | 6 +-- src/glx_context.c | 4 +- src/init.c | 117 ++++++++++++++++++++++++++----------------- src/internal.h | 36 ++++++++++--- src/nsgl_context.m | 4 +- src/osmesa_context.c | 2 +- src/posix_tls.c | 31 +++++++++++- src/posix_tls.h | 12 ++++- src/wgl_context.c | 8 +-- src/win32_platform.h | 10 ++++ src/win32_tls.c | 25 ++++++++- src/window.c | 4 +- 17 files changed, 244 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 8856b2f45..516c913bc 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,8 @@ information on what to include when reporting a bug. ## Changelog -- Added `glfwGetError` function for querying the last error code (#970) +- Added `glfwGetError` function for querying the last error code and its + description (#970) - Added `glfwRequestWindowAttention` function for requesting attention from the user (#732,#988) - Added `glfwGetKeyScancode` function that allows retrieving platform dependent diff --git a/docs/intro.dox b/docs/intro.dox index 55aa7862d..180f63fdb 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -128,15 +128,19 @@ immediately. @section error_handling Error handling Some GLFW functions have return values that indicate an error, but this is often -not very helpful when trying to figure out _why_ the error occurred. Other -functions have no return value reserved for errors, so error notification needs -a separate channel. Finally, far from all GLFW functions have return values. +not very helpful when trying to figure out what happened or why it occurred. +Other functions have no return value reserved for errors, so error notification +needs a separate channel. Finally, far from all GLFW functions have return +values. -The last error code for the calling thread can be queried at any time with @ref -glfwGetError. +The last [error code](@ref errors) for the calling thread can be queried at any +time with @ref glfwGetError. @code -int error = glfwGetError(); +int code = glfwGetError(NULL); + +if (code != GLFW_NO_ERROR) + handle_error(code); @endcode If no error has occurred since the last call, @ref GLFW_NO_ERROR is returned. @@ -146,42 +150,52 @@ The error code indicates the general category of the error. Some error codes, such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like @ref GLFW_PLATFORM_ERROR are used for many different errors. -GLFW usually has much more information about the error than its general category -at the point where it occurred. This is where the error callback comes in. -This callback is called whenever an error occurs. It is set with @ref -glfwSetErrorCallback, a function that may be called regardless of whether GLFW -is initialized. +GLFW often has more information about an error than its general category. You +can retrieve a UTF-8 encoded human-readable description along with the error +code. If no error has occurred since the last call, the description is set to +`NULL`. + +@code +const char* description; +int code = glfwGetError(&description); + +if (description) + display_error_message(code, description); +@endcode + +The retrieved description string is only valid until the next error occurs. +This means you must make a copy of it if you want to keep it. + +You can also set an error callback, which will be called each time an error +occurs. It is set with @ref glfwSetErrorCallback. @code glfwSetErrorCallback(error_callback); @endcode -The error callback receives a human-readable description of the error and (when -possible) its cause. The description encoded as UTF-8. The callback is also -provided with an [error code](@ref errors). +The error callback receives the same error code and human-readable description +returned by @ref glfwGetError. @code -void error_callback(int error, const char* description) +void error_callback(int code, const char* description) { - puts(description); + display_error_message(code, description); } @endcode -The error callback is called after the error code is set, so calling @ref -glfwGetError from within the error callback returns the same value as the +The error callback is called after the error is stored, so calling @ref +glfwGetError from within the error callback returns the same values as the callback argument. +The description string passed to the callback is only valid until the error +callback returns. This means you must make a copy of it if you want to keep it. + __Reported errors are never fatal.__ As long as GLFW was successfully initialized, it will remain initialized and in a safe state until terminated regardless of how many errors occur. If an error occurs during initialization that causes @ref glfwInit to fail, any part of the library that was initialized will be safely terminated. -The description string is only valid until the error callback returns, as it may -have been generated specifically for that error. This lets GLFW provide much -more specific error descriptions but means you must make a copy if you want to -keep the description string. - Do not rely on a currently invalid call to generate a specific error, as in the future that same call may generate a different error or become valid. diff --git a/docs/news.dox b/docs/news.dox index b2c8571f9..39ad4eaae 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -7,8 +7,8 @@ @subsection news_33_geterror Error query -GLFW now supports querying the last error code for the calling thread with @ref -glfwGetError. +GLFW now supports querying the last error code for the calling thread and its +human-readable description with @ref glfwGetError. @see @ref error_handling diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 3b2d5b852..fb18edec5 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1646,13 +1646,20 @@ GLFWAPI const char* glfwGetVersionString(void); /*! @brief Returns and clears the last error for the calling thread. * * This function returns and clears the [error code](@ref error) of the last - * error that occurred on the calling thread. If no error has occurred since - * the last call, it returns @ref GLFW_NO_ERROR. + * error that occurred on the calling thread, and optionally a UTF-8 encoded + * human-readable description of it. If no error has occurred since the last + * call, it returns @ref GLFW_NO_ERROR and the description pointer is set to + * `NULL`. * + * @param[in] description Where to store the error description pointer, or `NULL`. * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR. * * @errors None. * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * next error occurs or the library is terminated. + * * @remark This function may be called before @ref glfwInit. * * @thread_safety This function may be called from any thread. @@ -1664,7 +1671,7 @@ GLFWAPI const char* glfwGetVersionString(void); * * @ingroup init */ -GLFWAPI int glfwGetError(void); +GLFWAPI int glfwGetError(const char** description); /*! @brief Sets the error callback. * diff --git a/src/context.c b/src/context.c index 498e0e16a..5a4c33729 100644 --- a/src/context.c +++ b/src/context.c @@ -331,7 +331,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) NULL }; - window = _glfwPlatformGetTls(&_glfw.context); + window = _glfwPlatformGetTls(&_glfw.contextSlot); window->context.source = ctxconfig->source; window->context.client = GLFW_OPENGL_API; @@ -578,7 +578,7 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot); _GLFW_REQUIRE_INIT(); @@ -601,7 +601,7 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) GLFWAPI GLFWwindow* glfwGetCurrentContext(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetTls(&_glfw.context); + return _glfwPlatformGetTls(&_glfw.contextSlot); } GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) @@ -626,7 +626,7 @@ GLFWAPI void glfwSwapInterval(int interval) _GLFW_REQUIRE_INIT(); - window = _glfwPlatformGetTls(&_glfw.context); + window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); @@ -643,7 +643,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); - window = _glfwPlatformGetTls(&_glfw.context); + window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); @@ -708,7 +708,7 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - window = _glfwPlatformGetTls(&_glfw.context); + window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); diff --git a/src/egl_context.c b/src/egl_context.c index 328a04578..e101315a1 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -199,12 +199,12 @@ static void makeContextCurrentEGL(_GLFWwindow* window) } } - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); } static void swapBuffersEGL(_GLFWwindow* window) { - if (window != _glfwPlatformGetTls(&_glfw.context)) + if (window != _glfwPlatformGetTls(&_glfw.contextSlot)) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: The context must be current on the calling thread when swapping buffers"); @@ -233,7 +233,7 @@ static int extensionSupportedEGL(const char* extension) static GLFWglproc getProcAddressEGL(const char* procname) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); if (window->context.egl.client) { diff --git a/src/glx_context.c b/src/glx_context.c index 9c2ccb12c..3e6ff96f0 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -165,7 +165,7 @@ static void makeContextCurrentGLX(_GLFWwindow* window) } } - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); } static void swapBuffersGLX(_GLFWwindow* window) @@ -175,7 +175,7 @@ static void swapBuffersGLX(_GLFWwindow* window) static void swapIntervalGLX(int interval) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); if (_glfw.glx.EXT_swap_control) { diff --git a/src/init.c b/src/init.c index 19ae4c1db..b999149cd 100644 --- a/src/init.c +++ b/src/init.c @@ -43,7 +43,7 @@ _GLFWlibrary _glfw = { GLFW_FALSE }; // These are outside of _glfw so they can be used before initialization and // after termination // -static int _glfwErrorCode; +static _GLFWerror _glfwMainThreadError; static GLFWerrorfun _glfwErrorCallback; static _GLFWinitconfig _glfwInitHints = { @@ -56,9 +56,9 @@ static _GLFWinitconfig _glfwInitHints = // Returns a generic string representation of the specified error // -static const char* getErrorString(int error) +static const char* getErrorString(int code) { - switch (error) + switch (code) { case GLFW_NOT_INITIALIZED: return "The GLFW library is not initialized"; @@ -114,11 +114,18 @@ static void terminate(void) _glfwTerminateVulkan(); _glfwPlatformTerminate(); - if (_glfwPlatformIsValidTls(&_glfw.error)) - _glfwErrorCode = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error); + _glfw.initialized = GLFW_FALSE; - _glfwPlatformDestroyTls(&_glfw.context); - _glfwPlatformDestroyTls(&_glfw.error); + while (_glfw.errorListHead) + { + _GLFWerror* error = _glfw.errorListHead; + _glfw.errorListHead = error->next; + free(error); + } + + _glfwPlatformDestroyTls(&_glfw.contextSlot); + _glfwPlatformDestroyTls(&_glfw.errorSlot); + _glfwPlatformDestroyMutex(&_glfw.errorLock); memset(&_glfw, 0, sizeof(_glfw)); } @@ -128,37 +135,47 @@ static void terminate(void) ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwInputError(int error, const char* format, ...) +void _glfwInputError(int code, const char* format, ...) { - if (_glfw.initialized) - _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) error); + _GLFWerror* error; + char description[1024]; + + if (format) + { + int count; + va_list vl; + + va_start(vl, format); + count = vsnprintf(description, sizeof(description), format, vl); + va_end(vl); + + if (count < 0) + description[sizeof(description) - 1] = '\0'; + } else - _glfwErrorCode = error; + strcpy(description, getErrorString(code)); + + if (_glfw.initialized) + { + error = _glfwPlatformGetTls(&_glfw.errorSlot); + if (!error) + { + error = calloc(1, sizeof(_GLFWerror)); + _glfwPlatformSetTls(&_glfw.errorSlot, error); + _glfwPlatformLockMutex(&_glfw.errorLock); + error->next = _glfw.errorListHead; + _glfw.errorListHead = error; + _glfwPlatformUnlockMutex(&_glfw.errorLock); + } + } + else + error = &_glfwMainThreadError; + + error->code = code; + strcpy(error->description, description); if (_glfwErrorCallback) - { - char buffer[8192]; - const char* description; - - if (format) - { - int count; - va_list vl; - - va_start(vl, format); - count = vsnprintf(buffer, sizeof(buffer), format, vl); - va_end(vl); - - if (count < 0) - buffer[sizeof(buffer) - 1] = '\0'; - - description = buffer; - } - else - description = getErrorString(error); - - _glfwErrorCallback(error, description); - } + _glfwErrorCallback(code, description); } @@ -180,12 +197,14 @@ GLFWAPI int glfwInit(void) return GLFW_FALSE; } - if (!_glfwPlatformCreateTls(&_glfw.error)) + if (!_glfwPlatformCreateMutex(&_glfw.errorLock)) return GLFW_FALSE; - if (!_glfwPlatformCreateTls(&_glfw.context)) + if (!_glfwPlatformCreateTls(&_glfw.errorSlot)) + return GLFW_FALSE; + if (!_glfwPlatformCreateTls(&_glfw.contextSlot)) return GLFW_FALSE; - _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) _glfwErrorCode); + _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); _glfw.initialized = GLFW_TRUE; _glfw.timer.offset = _glfwPlatformGetTimerValue(); @@ -237,22 +256,28 @@ GLFWAPI const char* glfwGetVersionString(void) return _glfwPlatformGetVersionString(); } -GLFWAPI int glfwGetError(void) +GLFWAPI int glfwGetError(const char** description) { - int error; + _GLFWerror* error; + int code = GLFW_NO_ERROR; + + if (description) + *description = NULL; if (_glfw.initialized) - { - error = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error); - _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) GLFW_NO_ERROR); - } + error = _glfwPlatformGetTls(&_glfw.errorSlot); else + error = &_glfwMainThreadError; + + if (error) { - error = _glfwErrorCode; - _glfwErrorCode = GLFW_NO_ERROR; + code = error->code; + error->code = GLFW_NO_ERROR; + if (description && code) + *description = error->description; } - return error; + return code; } GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) diff --git a/src/internal.h b/src/internal.h index bd4c53078..72ac953e6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -55,6 +55,7 @@ typedef int GLFWbool; +typedef struct _GLFWerror _GLFWerror; typedef struct _GLFWinitconfig _GLFWinitconfig; typedef struct _GLFWwndconfig _GLFWwndconfig; typedef struct _GLFWctxconfig _GLFWctxconfig; @@ -66,6 +67,7 @@ typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; typedef struct _GLFWjoystick _GLFWjoystick; typedef struct _GLFWtls _GLFWtls; +typedef struct _GLFWmutex _GLFWmutex; typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); @@ -257,6 +259,13 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void); // Platform-independent structures //======================================================================== +struct _GLFWerror +{ + _GLFWerror* next; + int code; + char description[1024]; +}; + /*! @brief Initialization configuration. * * Parameters relating to the initialization of the library. @@ -490,6 +499,14 @@ struct _GLFWtls _GLFW_PLATFORM_TLS_STATE; }; +/*! @brief Mutex structure. + */ +struct _GLFWmutex +{ + // This is defined in the platform's tls.h + _GLFW_PLATFORM_MUTEX_STATE; +}; + /*! @brief Library global data. */ struct _GLFWlibrary @@ -504,8 +521,8 @@ struct _GLFWlibrary int refreshRate; } hints; + _GLFWerror* errorListHead; _GLFWcursor* cursorListHead; - _GLFWwindow* windowListHead; _GLFWmonitor** monitors; @@ -513,8 +530,9 @@ struct _GLFWlibrary _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; - _GLFWtls error; - _GLFWtls context; + _GLFWtls errorSlot; + _GLFWtls contextSlot; + _GLFWmutex errorLock; struct { uint64_t offset; @@ -651,7 +669,11 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); void _glfwPlatformDestroyTls(_GLFWtls* tls); void* _glfwPlatformGetTls(_GLFWtls* tls); void _glfwPlatformSetTls(_GLFWtls* tls, void* value); -GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls); + +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex); +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex); +void _glfwPlatformLockMutex(_GLFWmutex* mutex); +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex); /*! @} */ @@ -798,15 +820,15 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement); void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window); /*! @brief Notifies shared code of an error. - * @param[in] error The error code most suitable for the error. + * @param[in] code The error code most suitable for the error. * @param[in] format The `printf` style format string of the error * description. * @ingroup event */ #if defined(__GNUC__) -void _glfwInputError(int error, const char* format, ...) __attribute__((format(printf, 2, 3))); +void _glfwInputError(int code, const char* format, ...) __attribute__((format(printf, 2, 3))); #else -void _glfwInputError(int error, const char* format, ...); +void _glfwInputError(int code, const char* format, ...); #endif /*! @brief Notifies shared code of files or directories dropped on a window. diff --git a/src/nsgl_context.m b/src/nsgl_context.m index f2902d7fa..cc2615fab 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -34,7 +34,7 @@ static void makeContextCurrentNSGL(_GLFWwindow* window) else [NSOpenGLContext clearCurrentContext]; - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); } static void swapBuffersNSGL(_GLFWwindow* window) @@ -45,7 +45,7 @@ static void swapBuffersNSGL(_GLFWwindow* window) static void swapIntervalNSGL(int interval) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); GLint sync = interval; [window->context.nsgl.object setValues:&sync diff --git a/src/osmesa_context.c b/src/osmesa_context.c index 7ea656276..aa18aa62d 100644 --- a/src/osmesa_context.c +++ b/src/osmesa_context.c @@ -63,7 +63,7 @@ static void makeContextCurrentOSMesa(_GLFWwindow* window) } } - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); } static GLFWglproc getProcAddressOSMesa(const char* procname) diff --git a/src/posix_tls.c b/src/posix_tls.c index cf2ae6fa7..ce0bc39b9 100644 --- a/src/posix_tls.c +++ b/src/posix_tls.c @@ -69,8 +69,35 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value) pthread_setspecific(tls->posix.key, value); } -GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls) +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) { - return tls->posix.allocated; + assert(mutex->posix.allocated == GLFW_FALSE); + + if (pthread_mutex_init(&mutex->posix.handle, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create mutex"); + return GLFW_FALSE; + } + + return mutex->posix.allocated = GLFW_TRUE; +} + +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) +{ + if (mutex->posix.allocated) + pthread_mutex_destroy(&mutex->posix.handle); + memset(mutex, 0, sizeof(_GLFWmutex)); +} + +void _glfwPlatformLockMutex(_GLFWmutex* mutex) +{ + assert(mutex->posix.allocated == GLFW_TRUE); + pthread_mutex_lock(&mutex->posix.handle); +} + +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) +{ + assert(mutex->posix.allocated == GLFW_TRUE); + pthread_mutex_unlock(&mutex->posix.handle); } diff --git a/src/posix_tls.h b/src/posix_tls.h index f738dc0de..bdddf41a2 100644 --- a/src/posix_tls.h +++ b/src/posix_tls.h @@ -27,7 +27,8 @@ #include -#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix +#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix +#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix // POSIX-specific thread local storage data @@ -39,3 +40,12 @@ typedef struct _GLFWtlsPOSIX } _GLFWtlsPOSIX; +// POSIX-specific mutex data +// +typedef struct _GLFWmutexPOSIX +{ + GLFWbool allocated; + pthread_mutex_t handle; + +} _GLFWmutexPOSIX; + diff --git a/src/wgl_context.c b/src/wgl_context.c index ff1d2d4e9..fc1b39700 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -249,12 +249,12 @@ static void makeContextCurrentWGL(_GLFWwindow* window) if (window) { if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); else { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to make context current"); - _glfwPlatformSetTls(&_glfw.context, NULL); + _glfwPlatformSetTls(&_glfw.contextSlot, NULL); } } else @@ -265,7 +265,7 @@ static void makeContextCurrentWGL(_GLFWwindow* window) "WGL: Failed to clear current context"); } - _glfwPlatformSetTls(&_glfw.context, NULL); + _glfwPlatformSetTls(&_glfw.contextSlot, NULL); } } @@ -284,7 +284,7 @@ static void swapBuffersWGL(_GLFWwindow* window) static void swapIntervalWGL(int interval) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); window->context.wgl.interval = interval; diff --git a/src/win32_platform.h b/src/win32_platform.h index 3e0c93b0c..c21d5ce3a 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -221,6 +221,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)( #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32 +#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexWin32 win32 // Win32-specific per-window data @@ -334,6 +335,15 @@ typedef struct _GLFWtlsWin32 } _GLFWtlsWin32; +// Win32-specific mutex data +// +typedef struct _GLFWmutexWin32 +{ + GLFWbool allocated; + CRITICAL_SECTION section; + +} _GLFWmutexWin32; + GLFWbool _glfwRegisterWindowClassWin32(void); void _glfwUnregisterWindowClassWin32(void); diff --git a/src/win32_tls.c b/src/win32_tls.c index 9c20aad04..98231c1ed 100644 --- a/src/win32_tls.c +++ b/src/win32_tls.c @@ -69,8 +69,29 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value) TlsSetValue(tls->win32.index, value); } -GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls) +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) { - return tls->win32.allocated; + assert(mutex->win32.allocated == GLFW_FALSE); + InitializeCriticalSection(&mutex->win32.section); + return mutex->win32.allocated = GLFW_TRUE; +} + +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) +{ + if (mutex->win32.allocated) + DeleteCriticalSection(&mutex->win32.section); + memset(mutex, 0, sizeof(_GLFWmutex)); +} + +void _glfwPlatformLockMutex(_GLFWmutex* mutex) +{ + assert(mutex->win32.allocated == GLFW_TRUE); + EnterCriticalSection(&mutex->win32.section); +} + +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) +{ + assert(mutex->win32.allocated == GLFW_TRUE); + LeaveCriticalSection(&mutex->win32.section); } diff --git a/src/window.c b/src/window.c index 546d233d8..1d717c30b 100644 --- a/src/window.c +++ b/src/window.c @@ -192,7 +192,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->denom = GLFW_DONT_CARE; // Save the currently current context so it can be restored later - previous = _glfwPlatformGetTls(&_glfw.context); + previous = _glfwPlatformGetTls(&_glfw.contextSlot); if (ctxconfig.client != GLFW_NO_API) glfwMakeContextCurrent(NULL); @@ -408,7 +408,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) // The window's context must not be current on another thread when the // window is destroyed - if (window == _glfwPlatformGetTls(&_glfw.context)) + if (window == _glfwPlatformGetTls(&_glfw.contextSlot)) glfwMakeContextCurrent(NULL); _glfwPlatformDestroyWindow(window); From a3007b9b0ea104690a965f25fb2dfdc482a7db55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 25 May 2017 19:25:47 +0200 Subject: [PATCH 054/222] Rename thread source files This to reflect that they now contain more than TLS. --- src/CMakeLists.txt | 22 +++++++++++----------- src/cocoa_platform.h | 2 +- src/internal.h | 4 ++-- src/mir_platform.h | 2 +- src/null_platform.h | 2 +- src/{posix_tls.c => posix_thread.c} | 0 src/{posix_tls.h => posix_thread.h} | 0 src/{win32_tls.c => win32_thread.c} | 0 src/wl_platform.h | 2 +- src/x11_platform.h | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) rename src/{posix_tls.c => posix_thread.c} (100%) rename src/{posix_tls.h => posix_thread.h} (100%) rename src/{win32_tls.c => win32_thread.c} (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 438a7dea0..0ccf2f146 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,21 +7,21 @@ set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c) if (_GLFW_COCOA) set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h - posix_tls.h nsgl_context.h egl_context.h osmesa_context.c) + posix_thread.h nsgl_context.h egl_context.h osmesa_context.c) set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m - cocoa_monitor.m cocoa_window.m cocoa_time.c posix_tls.c + cocoa_monitor.m cocoa_window.m cocoa_time.c posix_thread.c nsgl_context.m egl_context.c osmesa_context.c) elseif (_GLFW_WIN32) set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h wgl_context.h egl_context.h osmesa_context.h) set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c - win32_monitor.c win32_time.c win32_tls.c win32_window.c + win32_monitor.c win32_time.c win32_thread.c win32_window.c wgl_context.c egl_context.c osmesa_context.c) elseif (_GLFW_X11) set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h posix_time.h - posix_tls.h glx_context.h egl_context.h osmesa_context.h) + posix_thread.h glx_context.h egl_context.h osmesa_context.h) set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c - xkb_unicode.c posix_time.c posix_tls.c glx_context.c + xkb_unicode.c posix_time.c posix_thread.c glx_context.c egl_context.c osmesa_context.c) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") @@ -33,10 +33,10 @@ elseif (_GLFW_X11) endif() elseif (_GLFW_WAYLAND) set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h - posix_time.h posix_tls.h xkb_unicode.h egl_context.h + posix_time.h posix_thread.h xkb_unicode.h egl_context.h osmesa_context.h) set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c - linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c + linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c egl_context.c osmesa_context.c) ecm_add_wayland_client_protocol(glfw_SOURCES @@ -49,16 +49,16 @@ elseif (_GLFW_WAYLAND) BASENAME pointer-constraints-unstable-v1) elseif (_GLFW_MIR) set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h - posix_time.h posix_tls.h xkb_unicode.h egl_context.h + posix_time.h posix_thread.h xkb_unicode.h egl_context.h osmesa_context.h) set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c - linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c + linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c egl_context.c osmesa_context.c) elseif (_GLFW_OSMESA) set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h - posix_time.h posix_tls.h osmesa_context.h) + posix_time.h posix_thread.h osmesa_context.h) set(glfw_SOURCES ${common_SOURCES} null_init.c null_monitor.c null_window.c - null_joystick.c posix_time.c posix_tls.c osmesa_context.c) + null_joystick.c posix_time.c posix_thread.c osmesa_context.c) endif() if (APPLE) diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index f744f78ce..b8e0bc983 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -48,7 +48,7 @@ typedef struct VkMacOSSurfaceCreateInfoMVK typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*); -#include "posix_tls.h" +#include "posix_thread.h" #include "cocoa_joystick.h" #include "nsgl_context.h" #include "egl_context.h" diff --git a/src/internal.h b/src/internal.h index 72ac953e6..0da36741b 100644 --- a/src/internal.h +++ b/src/internal.h @@ -495,7 +495,7 @@ struct _GLFWjoystick */ struct _GLFWtls { - // This is defined in the platform's tls.h + // This is defined in the platform's thread.h _GLFW_PLATFORM_TLS_STATE; }; @@ -503,7 +503,7 @@ struct _GLFWtls */ struct _GLFWmutex { - // This is defined in the platform's tls.h + // This is defined in the platform's thread.h _GLFW_PLATFORM_MUTEX_STATE; }; diff --git a/src/mir_platform.h b/src/mir_platform.h index 3dac43ecc..da00a326a 100644 --- a/src/mir_platform.h +++ b/src/mir_platform.h @@ -44,7 +44,7 @@ typedef struct VkMirWindowCreateInfoKHR typedef VkResult (APIENTRY *PFN_vkCreateMirWindowKHR)(VkInstance,const VkMirWindowCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*); -#include "posix_tls.h" +#include "posix_thread.h" #include "posix_time.h" #include "linux_joystick.h" #include "xkb_unicode.h" diff --git a/src/null_platform.h b/src/null_platform.h index dfb88a16c..2d67c50c2 100644 --- a/src/null_platform.h +++ b/src/null_platform.h @@ -39,7 +39,7 @@ #include "osmesa_context.h" #include "posix_time.h" -#include "posix_tls.h" +#include "posix_thread.h" #include "null_joystick.h" #if defined(_GLFW_WIN32) diff --git a/src/posix_tls.c b/src/posix_thread.c similarity index 100% rename from src/posix_tls.c rename to src/posix_thread.c diff --git a/src/posix_tls.h b/src/posix_thread.h similarity index 100% rename from src/posix_tls.h rename to src/posix_thread.h diff --git a/src/win32_tls.c b/src/win32_thread.c similarity index 100% rename from src/win32_tls.c rename to src/win32_thread.c diff --git a/src/wl_platform.h b/src/wl_platform.h index 620698570..c543d82c4 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -43,7 +43,7 @@ typedef struct VkWaylandSurfaceCreateInfoKHR typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*); -#include "posix_tls.h" +#include "posix_thread.h" #include "posix_time.h" #include "linux_joystick.h" #include "xkb_unicode.h" diff --git a/src/x11_platform.h b/src/x11_platform.h index 48ee88b1b..e56630cfb 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -92,7 +92,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(V typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t); -#include "posix_tls.h" +#include "posix_thread.h" #include "posix_time.h" #include "xkb_unicode.h" #include "glx_context.h" From d2779aa765affd6706d5968080c30b0a09a06ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 7 Jun 2017 12:25:57 +0200 Subject: [PATCH 055/222] Documentation work [ci skip] --- docs/build.dox | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/docs/build.dox b/docs/build.dox index 97dda32dc..e428594e3 100644 --- a/docs/build.dox +++ b/docs/build.dox @@ -15,27 +15,27 @@ specific compiler of your chosen development environment. The compilation and linking process should be explained in your C programming material and in the documentation for your development environment. + @section build_include Including the GLFW header file -In the source files of your application where you use OpenGL or GLFW, you should -include the GLFW header file, i.e.: +You should include the GLFW header in the source files where you use OpenGL or +GLFW. @code #include @endcode -The GLFW header declares the GLFW API and by default also includes the OpenGL -header of your development environment, which in turn defines all the constants, -types and function prototypes of the OpenGL API. +This header declares the GLFW API and by default also includes the OpenGL header +from your development environment. See below for how to control this. -The GLFW header also defines everything necessary for your OpenGL header to -function. For example, under Windows you are normally required to include -`windows.h` before the OpenGL header, which would pollute your code namespace -with the entire Win32 API. +The GLFW header also defines any platform-specific macros needed by your OpenGL +header, so it can be included without needing any window system headers. -Instead, the GLFW header takes care of this for you, not by including -`windows.h`, but by duplicating only the very few necessary parts of it. It -does this only when needed, so if `windows.h` _is_ included, the GLFW header +For example, under Windows you are normally required to include `windows.h` +before the OpenGL header, which would bring in the whole Win32 API. The GLFW +header duplicates the small number of macros needed. + +It does this only when needed, so if `windows.h` _is_ included, the GLFW header does not try to redefine those symbols. The reverse is not true, i.e. `windows.h` cannot cope if any of its symbols have already been defined. @@ -49,8 +49,21 @@ In other words: If you are using an OpenGL extension loading library such as [glad](https://github.com/Dav1dde/glad), the extension loader header should -either be included _before_ the GLFW one, or the @ref GLFW_INCLUDE_NONE macro -(described below) should be defined. +be included _before_ the GLFW one. + +@code +#include +#include +@endcode + +Alternatively the @ref GLFW_INCLUDE_NONE macro (described below) can be used to +prevent the GLFW header from including the OpenGL header. + +@code +#define GLFW_INCLUDE_NONE +#include +#include +@endcode @subsection build_macros GLFW header option macros From 52f76844877d3e6f976db31923c07fb2c24c77a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 8 Jun 2017 15:20:24 +0200 Subject: [PATCH 056/222] WGL: Add WGL_ARB_create_context_no_error support --- README.md | 1 + src/wgl_context.c | 17 +++++++++++++++-- src/wgl_context.h | 3 +++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 516c913bc..3058a40a7 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Full screen framebuffer was incorrectly sized for some video modes (#682) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts +- [WGL] Added support for `WGL_ARB_create_context_no_error` - [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) - [EGL] Added support for `EGL_KHR_context_flush_control` - [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid diff --git a/src/wgl_context.c b/src/wgl_context.c index fc1b39700..92bd70e6c 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -418,6 +418,8 @@ static void loadWGLExtensions(void) extensionSupportedWGL("WGL_EXT_create_context_es2_profile"); _glfw.wgl.ARB_create_context_robustness = extensionSupportedWGL("WGL_ARB_create_context_robustness"); + _glfw.wgl.ARB_create_context_no_error = + extensionSupportedWGL("WGL_ARB_create_context_no_error"); _glfw.wgl.EXT_swap_control = extensionSupportedWGL("WGL_EXT_swap_control"); _glfw.wgl.EXT_colorspace = @@ -579,8 +581,6 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, if (ctxconfig->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; - if (ctxconfig->noerror) - flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR; if (ctxconfig->robustness) { @@ -618,6 +618,14 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } } + if (ctxconfig->noerror) + { + if (_glfw.wgl.ARB_create_context_no_error) + { + setWGLattrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + } + } + // NOTE: Only request an explicitly versioned context when necessary, as // explicitly requesting version 1.0 does not always return the // highest version supported by the driver @@ -664,6 +672,11 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Driver does not support the requested OpenGL profile"); } + else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "WGL: The share context is not compatible with the requested context"); + } else { if (ctxconfig->client == GLFW_OPENGL_API) diff --git a/src/wgl_context.h b/src/wgl_context.h index e02cc0ecc..9fae91141 100644 --- a/src/wgl_context.h +++ b/src/wgl_context.h @@ -68,11 +68,13 @@ #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 #define WGL_COLORSPACE_EXT 0x309d #define WGL_COLORSPACE_SRGB_EXT 0x3089 #define ERROR_INVALID_VERSION_ARB 0x2095 #define ERROR_INVALID_PROFILE_ARB 0x2096 +#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); @@ -142,6 +144,7 @@ typedef struct _GLFWlibraryWGL GLFWbool ARB_create_context_profile; GLFWbool EXT_create_context_es2_profile; GLFWbool ARB_create_context_robustness; + GLFWbool ARB_create_context_no_error; GLFWbool ARB_context_flush_control; } _GLFWlibraryWGL; From f4ea29cd06b8f42f9614f7a3f29a44532d3e90f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 8 Jun 2017 15:23:04 +0200 Subject: [PATCH 057/222] GLX: Add GLX_ARB_create_context_no_error support --- README.md | 1 + src/glx_context.c | 13 +++++++++++-- src/glx_context.h | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3058a40a7..9ab9eae66 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,7 @@ information on what to include when reporting a bug. modes (#682) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` +- [GLX] Added support for `GLX_ARB_create_context_no_error` - [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) - [EGL] Added support for `EGL_KHR_context_flush_control` - [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid diff --git a/src/glx_context.c b/src/glx_context.c index 3e6ff96f0..a39781670 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -397,6 +397,9 @@ GLFWbool _glfwInitGLX(void) if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile")) _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; + if (extensionSupportedGLX("GLX_ARB_create_context_no_error")) + _glfw.glx.ARB_create_context_no_error = GLFW_TRUE; + if (extensionSupportedGLX("GLX_ARB_context_flush_control")) _glfw.glx.ARB_context_flush_control = GLFW_TRUE; @@ -498,8 +501,6 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; - if (ctxconfig->noerror) - flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR; if (ctxconfig->robustness) { @@ -537,6 +538,14 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, } } + if (ctxconfig->noerror) + { + if (_glfw.glx.ARB_create_context_no_error) + { + setGLXattrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + } + } + // NOTE: Only request an explicitly versioned context when necessary, as // explicitly requesting version 1.0 does not always return the // highest version supported by the driver diff --git a/src/glx_context.h b/src/glx_context.h index 3a427bd20..30743c112 100644 --- a/src/glx_context.h +++ b/src/glx_context.h @@ -64,6 +64,7 @@ #define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 #define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 typedef XID GLXWindow; typedef XID GLXDrawable; @@ -162,6 +163,7 @@ typedef struct _GLFWlibraryGLX GLFWbool ARB_create_context_profile; GLFWbool ARB_create_context_robustness; GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_create_context_no_error; GLFWbool ARB_context_flush_control; } _GLFWlibraryGLX; From 2bb8517e9e458287fe5d31ed4a82cf2fdd072817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 8 Jun 2017 15:37:28 +0200 Subject: [PATCH 058/222] EGL: Fix EGL_KHR_create_context_no_error support --- src/egl_context.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/egl_context.c b/src/egl_context.c index e101315a1..dd5bcf15f 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -494,12 +494,6 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; - - if (_glfw.egl.KHR_create_context_no_error) - { - if (ctxconfig->noerror) - flags |= EGL_CONTEXT_OPENGL_NO_ERROR_KHR; - } } if (ctxconfig->debug) @@ -521,6 +515,12 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; } + if (ctxconfig->noerror) + { + if (_glfw.egl.KHR_create_context_no_error) + setEGLattrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); + } + if (ctxconfig->major != 1 || ctxconfig->minor != 0) { setEGLattrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); From 0321bec232ef0fb49ce44671355b1e73da24161e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 8 Jun 2017 15:44:07 +0200 Subject: [PATCH 059/222] Documentation work [ci skip] --- docs/compat.dox | 12 ++++++------ docs/window.dox | 8 -------- src/nsgl_context.m | 10 ++++++++-- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/compat.dox b/docs/compat.dox index 32618e81f..cabe18c33 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -164,21 +164,21 @@ extensions to provide support for sRGB framebuffers. Where both of these extension are unavailable, the `GLFW_SRGB_CAPABLE` hint will have no effect. -@section compat_osx OpenGL 3.2 and later on macOS +@section compat_osx OpenGL on macOS Support for OpenGL 3.2 and above was introduced with OS X 10.7 and even then only forward-compatible, core profile contexts are supported. Support for OpenGL 4.1 was introduced with OS X 10.9, also limited to forward-compatible, core profile contexts. There is also still no mechanism for requesting debug -contexts. Versions of Mac OS X earlier than 10.7 support at most OpenGL -version 2.1. +contexts or no-error contexts. Versions of Mac OS X earlier than 10.7 support +at most OpenGL version 2.1. Because of this, on OS X 10.7 and later, the `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` hints will cause @ref glfwCreateWindow to fail if -given version 3.0 or 3.1, the `GLFW_OPENGL_FORWARD_COMPAT` hint must be set to +given version 3.0 or 3.1. The `GLFW_OPENGL_FORWARD_COMPAT` hint must be set to `GLFW_TRUE` and the `GLFW_OPENGL_PROFILE` hint must be set to -`GLFW_OPENGL_CORE_PROFILE` when creating OpenGL 3.2 and later contexts and the -`GLFW_OPENGL_DEBUG_CONTEXT` hint is ignored. +`GLFW_OPENGL_CORE_PROFILE` when creating OpenGL 3.2 and later contexts. The +`GLFW_OPENGL_DEBUG_CONTEXT` and `GLFW_CONTEXT_NO_ERROR` hints are ignored. Also, on Mac OS X 10.6 and below, the `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` hints will fail if given a version above 2.1, diff --git a/docs/window.dox b/docs/window.dox index 8bd87e135..7d187d65b 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -426,14 +426,6 @@ The no error mode for OpenGL and OpenGL ES is described in detail by the [GL_KHR_no_error](https://www.opengl.org/registry/specs/KHR/no_error.txt) extension. -@note This hint is experimental in its current state. There are currently -(October 2015) no corresponding WGL or GLX extensions. That makes this hint -a [hard constraint](@ref window_hints_hard) for those backends, as creation will -fail if unsupported context flags are requested. Once the extensions are -available, they will be required and creation of `GL_KHR_no_error` contexts may -fail on early drivers where this flag is supported without those extensions -being listed. - @subsubsection window_hints_osx macOS specific hints diff --git a/src/nsgl_context.m b/src/nsgl_context.m index cc2615fab..2aebed456 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -145,11 +145,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, } } - // Context robustness modes (GL_KHR_robustness) are not yet supported on + // Context robustness modes (GL_KHR_robustness) are not yet supported by // macOS but are not a hard constraint, so ignore and continue // Context release behaviors (GL_KHR_context_flush_control) are not yet - // supported on macOS but are not a hard constraint, so ignore and continue + // supported by macOS but are not a hard constraint, so ignore and continue + + // Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not + // a hard constraint, so ignore and continue + + // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but + // are not a hard constraint, so ignore and continue #define ADD_ATTR(x) { attributes[attributeCount++] = x; } #define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); } From 32f482a6d8dc2a27def530ce0f922942ec6d6896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 8 Jun 2017 15:52:55 +0200 Subject: [PATCH 060/222] Cleanup --- src/egl_context.c | 46 +++++++++++++++++------------------- src/glx_context.c | 40 +++++++++++++++---------------- src/nsgl_context.m | 56 +++++++++++++++++++++++--------------------- src/osmesa_context.c | 8 +++---- src/wgl_context.c | 40 +++++++++++++++---------------- 5 files changed, 93 insertions(+), 97 deletions(-) diff --git a/src/egl_context.c b/src/egl_context.c index dd5bcf15f..d1bbbf08d 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -426,11 +426,11 @@ void _glfwTerminateEGL(void) } } -#define setEGLattrib(attribName, attribValue) \ +#define setAttrib(a, v) \ { \ - attribs[index++] = attribName; \ - attribs[index++] = attribValue; \ - assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ + assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ } // Create the OpenGL or OpenGL ES context @@ -503,13 +503,13 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, - EGL_NO_RESET_NOTIFICATION_KHR); + setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_NO_RESET_NOTIFICATION_KHR); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, - EGL_LOSE_CONTEXT_ON_RESET_KHR); + setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_LOSE_CONTEXT_ON_RESET_KHR); } flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; @@ -518,42 +518,42 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.egl.KHR_create_context_no_error) - setEGLattrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); + setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); } if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setEGLattrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); - setEGLattrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); + setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); + setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); } if (mask) - setEGLattrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); + setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); if (flags) - setEGLattrib(EGL_CONTEXT_FLAGS_KHR, flags); + setAttrib(EGL_CONTEXT_FLAGS_KHR, flags); } else { if (ctxconfig->client == GLFW_OPENGL_ES_API) - setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); + setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); } if (_glfw.egl.KHR_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setEGLattrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, - EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); + setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setEGLattrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, - EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); + setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); } } - setEGLattrib(EGL_NONE, EGL_NONE); + setAttrib(EGL_NONE, EGL_NONE); window->context.egl.handle = eglCreateContext(_glfw.egl.display, config, share, attribs); @@ -573,12 +573,10 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (fbconfig->sRGB) { if (_glfw.egl.KHR_gl_colorspace) - { - setEGLattrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); - } + setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); } - setEGLattrib(EGL_NONE, EGL_NONE); + setAttrib(EGL_NONE, EGL_NONE); } window->context.egl.surface = @@ -678,7 +676,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, return GLFW_TRUE; } -#undef setEGLattrib +#undef setAttrib // Returns the Visual and depth of the chosen EGLConfig // diff --git a/src/glx_context.c b/src/glx_context.c index a39781670..1d11bfb0d 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -420,11 +420,11 @@ void _glfwTerminateGLX(void) } } -#define setGLXattrib(attribName, attribValue) \ +#define setAttrib(a, v) \ { \ - attribs[index++] = attribName; \ - attribs[index++] = attribValue; \ - assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ + assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ } // Create the OpenGL or OpenGL ES context @@ -508,13 +508,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_NO_RESET_NOTIFICATION_ARB); + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_LOSE_CONTEXT_ON_RESET_ARB); + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB); } flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; @@ -527,13 +527,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } @@ -541,9 +541,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.glx.ARB_create_context_no_error) - { - setGLXattrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); - } + setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as @@ -551,17 +549,17 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (mask) - setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (flags) - setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags); + setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); - setGLXattrib(None, None); + setAttrib(None, None); window->context.glx.handle = _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, @@ -618,7 +616,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, return GLFW_TRUE; } -#undef setGLXattrib +#undef setAttrib // Returns the Visual and depth of the chosen GLXFBConfig // diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 2aebed456..8504f0b97 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -119,8 +119,6 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - unsigned int attributeCount = 0; - if (ctxconfig->client == GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_API_UNAVAILABLE, @@ -157,43 +155,47 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but // are not a hard constraint, so ignore and continue -#define ADD_ATTR(x) { attributes[attributeCount++] = x; } -#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); } +#define addAttrib(a) \ +{ \ + assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ +} +#define setAttrib(a, v) { addAttrib(a); addAttrib(v); } - // Arbitrary array size here - NSOpenGLPixelFormatAttribute attributes[40]; + NSOpenGLPixelFormatAttribute attribs[40]; + int index = 0; - ADD_ATTR(NSOpenGLPFAAccelerated); - ADD_ATTR(NSOpenGLPFAClosestPolicy); + addAttrib(NSOpenGLPFAAccelerated); + addAttrib(NSOpenGLPFAClosestPolicy); if (ctxconfig->nsgl.offline) { - ADD_ATTR(NSOpenGLPFAAllowOfflineRenderers); + addAttrib(NSOpenGLPFAAllowOfflineRenderers); // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in // Info.plist for unbundled applications // HACK: This assumes that NSOpenGLPixelFormat will remain // a straightforward wrapper of its CGL counterpart #if MAC_OS_X_VERSION_MAX_ALLOWED >= 100800 - ADD_ATTR(kCGLPFASupportsAutomaticGraphicsSwitching); + addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching); #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 if (ctxconfig->major >= 4) { - ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); + setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); } else #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ if (ctxconfig->major >= 3) { - ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); + setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); } if (ctxconfig->major <= 2) { if (fbconfig->auxBuffers != GLFW_DONT_CARE) - ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); + setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); if (fbconfig->accumRedBits != GLFW_DONT_CARE && fbconfig->accumGreenBits != GLFW_DONT_CARE && @@ -205,7 +207,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, fbconfig->accumBlueBits + fbconfig->accumAlphaBits; - ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits); + setAttrib(NSOpenGLPFAAccumSize, accumBits); } } @@ -223,17 +225,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, else if (colorBits < 15) colorBits = 15; - ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); + setAttrib(NSOpenGLPFAColorSize, colorBits); } if (fbconfig->alphaBits != GLFW_DONT_CARE) - ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); + setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); if (fbconfig->depthBits != GLFW_DONT_CARE) - ADD_ATTR2(NSOpenGLPFADepthSize, fbconfig->depthBits); + setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits); if (fbconfig->stencilBits != GLFW_DONT_CARE) - ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits); + setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits); if (fbconfig->stereo) { @@ -242,36 +244,36 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, "NSGL: Stereo rendering is deprecated"); return GLFW_FALSE; #else - ADD_ATTR(NSOpenGLPFAStereo); + addAttrib(NSOpenGLPFAStereo); #endif } if (fbconfig->doublebuffer) - ADD_ATTR(NSOpenGLPFADoubleBuffer); + addAttrib(NSOpenGLPFADoubleBuffer); if (fbconfig->samples != GLFW_DONT_CARE) { if (fbconfig->samples == 0) { - ADD_ATTR2(NSOpenGLPFASampleBuffers, 0); + setAttrib(NSOpenGLPFASampleBuffers, 0); } else { - ADD_ATTR2(NSOpenGLPFASampleBuffers, 1); - ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples); + setAttrib(NSOpenGLPFASampleBuffers, 1); + setAttrib(NSOpenGLPFASamples, fbconfig->samples); } } // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB // framebuffer, so there's no need (and no way) to request it - ADD_ATTR(0); + addAttrib(0); -#undef ADD_ATTR -#undef ADD_ATTR2 +#undef addAttrib +#undef setAttrib window->context.nsgl.pixelFormat = - [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; if (window->context.nsgl.pixelFormat == nil) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, diff --git a/src/osmesa_context.c b/src/osmesa_context.c index aa18aa62d..46102fbab 100644 --- a/src/osmesa_context.c +++ b/src/osmesa_context.c @@ -184,11 +184,11 @@ void _glfwTerminateOSMesa(void) } } -#define setAttrib(attribName, attribValue) \ +#define setAttrib(a, v) \ { \ - attribs[index++] = attribName; \ - attribs[index++] = attribValue; \ - assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ + assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ } GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, diff --git a/src/wgl_context.c b/src/wgl_context.c index 92bd70e6c..f209dbf6c 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -477,11 +477,11 @@ void _glfwTerminateWGL(void) FreeLibrary(_glfw.wgl.instance); } -#define setWGLattrib(attribName, attribValue) \ +#define setAttrib(a, v) \ { \ - attribs[index++] = attribName; \ - attribs[index++] = attribValue; \ - assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ + assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ } // Create the OpenGL or OpenGL ES context @@ -588,13 +588,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - WGL_NO_RESET_NOTIFICATION_ARB); + setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - WGL_LOSE_CONTEXT_ON_RESET_ARB); + setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_LOSE_CONTEXT_ON_RESET_ARB); } flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; @@ -607,13 +607,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, - WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, - WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } @@ -621,9 +621,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.wgl.ARB_create_context_no_error) - { - setWGLattrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); - } + setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as @@ -631,17 +629,17 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (flags) - setWGLattrib(WGL_CONTEXT_FLAGS_ARB, flags); + setAttrib(WGL_CONTEXT_FLAGS_ARB, flags); if (mask) - setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); + setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); - setWGLattrib(0, 0); + setAttrib(0, 0); window->context.wgl.handle = _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc, @@ -725,7 +723,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_TRUE; } -#undef setWGLattrib +#undef setAttrib ////////////////////////////////////////////////////////////////////////// From 4dee58d480dc034d0cc188c7a7f2cc9328f5c1d1 Mon Sep 17 00:00:00 2001 From: "ryogo.yoshimura" Date: Sat, 27 May 2017 15:00:05 +0900 Subject: [PATCH 061/222] Cocoa: Fix conversion between NSPoint and CGPoint GLFW still supports versions of macOS before these became the same underlying type. Closes #1023. --- README.md | 1 + src/cocoa_window.m | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ab9eae66..c53173d28 100644 --- a/README.md +++ b/README.md @@ -354,6 +354,7 @@ skills. - Jay Weisskopf - Frank Wille - yuriks + - Ryogo Yoshimura - Santi Zupancic - Jonas Ådahl - Lasse Öörni diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 17d2b2061..2c94a8a2b 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1030,7 +1030,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, else { [window->ns.object center]; - _glfw.ns.cascadePoint = [window->ns.object cascadeTopLeftFromPoint:_glfw.ns.cascadePoint]; + _glfw.ns.cascadePoint = + NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint: + NSPointFromCGPoint(_glfw.ns.cascadePoint)]); if (wndconfig->resizable) { From 5bcf9c76fd71d2e538f187c085a843694ac0afb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 8 Jun 2017 19:23:06 +0200 Subject: [PATCH 062/222] Linux: Fix path buffer length warning Fixes #1025. --- README.md | 1 + src/linux_joystick.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c53173d28..90729f3bc 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size - [X11] Bugfix: Key name string encoding depended on current locale (#981,#983) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) +- [Linux] Bugfix: The joystick device path could be truncated (#1025) - [Cocoa] Added support for Vulkan window surface creation via [MoltenVK](https://moltengl.com/moltenvk/) (#870) - [Cocoa] Added support for loading a `MainMenu.nib` when available diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 6e4b6a8c9..da6c490d8 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -160,15 +160,24 @@ GLFWbool _glfwInitJoysticksLinux(void) while ((entry = readdir(dir))) { - char path[20]; regmatch_t match; + char* path = NULL; if (regexec(&_glfw.linjs.regex, entry->d_name, 1, &match, 0) != 0) continue; - snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name); + if (asprintf(&path, "%s/%s", dirname, entry->d_name) < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to construct device path: %s", + strerror(errno)); + continue; + } + if (openJoystickDevice(path)) count++; + + free(path); } closedir(dir); From 2ca9a0979e1c8cf84636deb2157694a6cb5473d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 9 Jun 2017 16:32:24 +0200 Subject: [PATCH 063/222] Add note on extra-cmake-modules dependency The Wayland backend requires this package to generate headers from XML protocol descriptions. Although this package was created by the KDE project, it does not depend on any part of KDE. Fixes #1013. [ci skip] --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 90729f3bc..0481934f6 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,9 @@ in the documentation for more information. GLFW itself depends only on the headers and libraries for your window system. +The (experimental) Wayland backend also depends on the `extra-cmake-modules` +package, which is used to generated Wayland protocol headers. + The examples and test programs depend on a number of tiny libraries. These are located in the `deps/` directory. From 78666204a1bb374a4f4752804ff48c55c070906d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 11 Jun 2017 23:15:44 +0200 Subject: [PATCH 064/222] Linux: Fix path buffer length warning --- src/linux_joystick.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index da6c490d8..25bfa65c1 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -161,18 +161,14 @@ GLFWbool _glfwInitJoysticksLinux(void) while ((entry = readdir(dir))) { regmatch_t match; - char* path = NULL; if (regexec(&_glfw.linjs.regex, entry->d_name, 1, &match, 0) != 0) continue; - if (asprintf(&path, "%s/%s", dirname, entry->d_name) < 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Linux: Failed to construct device path: %s", - strerror(errno)); - continue; - } + const size_t length = strlen(dirname) + strlen(entry->d_name) + 1; + char* path = calloc(length + 1, 1); + + snprintf(path, length + 1, "%s/%s", dirname, entry->d_name); if (openJoystickDevice(path)) count++; From d1a2ec4d20d5757e6f0188476993ee8623f9cbaf Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Sat, 6 May 2017 16:34:56 -0400 Subject: [PATCH 065/222] Linux: Move to evdev for joystick input Closes #1005. --- src/linux_joystick.c | 156 ++++++++++++++++++++++++++++++++++++------- src/linux_joystick.h | 17 +++-- 2 files changed, 143 insertions(+), 30 deletions(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 25bfa65c1..38c6a5035 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -27,8 +27,6 @@ #include "internal.h" -#include - #include #include #include @@ -40,15 +38,93 @@ #include #include +#define NUM_BITS(size) ((size) / 8) +#define TEST_BIT(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) + +static void handleKeyEvent(_GLFWjoystick* js, int code, int value) +{ + int jid = js - _glfw.joysticks; + int button = js->linjs.keyMap[code]; + + _glfwInputJoystickButton(jid, button, value ? 1 : 0); +} + +static void handleAbsEvent(_GLFWjoystick* js, int code, int value) +{ + int jid = js - _glfw.joysticks; + int index = js->linjs.absMap[code]; + + if (code >= ABS_HAT0X && code <= ABS_HAT3Y) + { + static const char stateMap[3][3] = + { + {GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN}, + {GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN}, + {GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN}, + }; + + int hat = (code - ABS_HAT0X) / 2; + int axis = (code - ABS_HAT0X) % 2; + int *state = js->linjs.hats[hat]; + + // Looking at several input drivers, it seems all hat events use + // -1 for left / up, 0 for centered and 1 for right / down + if (value == 0) + state[axis] = 0; + else if (value < 0) + state[axis] = 1; + else if (value > 0) + state[axis] = 2; + + _glfwInputJoystickHat(jid, index, stateMap[state[0]][state[1]]); + } + else + { + struct input_absinfo *info = &js->linjs.absInfo[code]; + int range = info->maximum - info->minimum; + float normalized = value; + + if (range != 0) + { + // Normalize from 0.0 -> 1.0 + normalized = (normalized - info->minimum) / range; + // Normalize from -1.0 -> 1.0 + normalized = normalized * 2.0f - 1.0f; + } + + _glfwInputJoystickAxis(jid, index, normalized); + } +} + +static void pollJoystick(_GLFWjoystick* js) +{ + int i; + + for (i = ABS_X; i < ABS_MAX; i++) + { + struct input_absinfo *info = &js->linjs.absInfo[i]; + + if (ioctl(js->linjs.fd, EVIOCGABS(i), info) < 0) + continue; + + handleAbsEvent(js, i, info->value); + } +} // Attempt to open the specified joystick device // static GLFWbool openJoystickDevice(const char* path) { - char axisCount, buttonCount; + int jid, fd, i; char name[256] = ""; - int jid, fd, version; - _GLFWjoystick* js; + char evBits[NUM_BITS(EV_MAX)] = {0}; + char keyBits[NUM_BITS(KEY_MAX)] = {0}; + char absBits[NUM_BITS(ABS_MAX)] = {0}; + int axisCount = 0; + int buttonCount = 0; + int hatCount = 0; + _GLFWjoystickLinux linjs = {0}; + _GLFWjoystick* js = NULL; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { @@ -62,30 +138,61 @@ static GLFWbool openJoystickDevice(const char* path) if (fd == -1) return GLFW_FALSE; - // Verify that the joystick driver version is at least 1.0 - ioctl(fd, JSIOCGVERSION, &version); - if (version < 0x010000) + // Ensure this device supports the events expected of a joystick + if (ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 || + ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 || + ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 || + !TEST_BIT(EV_KEY, evBits) || !TEST_BIT(EV_ABS, evBits)) { - // It's an old 0.x interface (we don't support it) close(fd); return GLFW_FALSE; } - if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) + if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) strncpy(name, "Unknown", sizeof(name)); - ioctl(fd, JSIOCGAXES, &axisCount); - ioctl(fd, JSIOCGBUTTONS, &buttonCount); + for (i = BTN_MISC; i < KEY_MAX; i++) + { + if (!TEST_BIT(i, keyBits)) + continue; - js = _glfwAllocJoystick(name, axisCount, buttonCount, 0); + linjs.keyMap[i] = buttonCount++; + } + + for (i = ABS_X; i < ABS_MAX; i++) + { + if (!TEST_BIT(i, absBits)) + continue; + + if (i >= ABS_HAT0X && i <= ABS_HAT3Y) + { + linjs.absMap[i] = hatCount++; + + // Skip the Y axis + i++; + } + else + { + if (ioctl(fd, EVIOCGABS(i), &linjs.absInfo[i]) < 0) + continue; + + linjs.absMap[i] = axisCount++; + } + } + + js = _glfwAllocJoystick(name, axisCount, buttonCount, hatCount); if (!js) { close(fd); return GLFW_FALSE; } - js->linjs.path = strdup(path); - js->linjs.fd = fd; + linjs.fd = fd; + strncpy(linjs.path, path, sizeof(linjs.path)); + memcpy(&js->linjs, &linjs, sizeof(linjs)); + + // Set initial values for absolute axes + pollJoystick(js); _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED); return GLFW_TRUE; @@ -96,7 +203,6 @@ static GLFWbool openJoystickDevice(const char* path) static void closeJoystick(_GLFWjoystick* js) { close(js->linjs.fd); - free(js->linjs.path); _glfwFreeJoystick(js); _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_DISCONNECTED); } @@ -147,7 +253,7 @@ GLFWbool _glfwInitJoysticksLinux(void) // Continue without device connection notifications } - if (regcomp(&_glfw.linjs.regex, "^js[0-9]\\+$", 0) != 0) + if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0) { _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); return GLFW_FALSE; @@ -265,7 +371,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) // Read all queued events (non-blocking) for (;;) { - struct js_event e; + struct input_event e; errno = 0; if (read(js->linjs.fd, &e, sizeof(e)) < 0) @@ -277,13 +383,13 @@ int _glfwPlatformPollJoystick(int jid, int mode) break; } - // Clear the initial-state bit - e.type &= ~JS_EVENT_INIT; - - if (e.type == JS_EVENT_AXIS) - _glfwInputJoystickAxis(jid, e.number, e.value / 32767.0f); - else if (e.type == JS_EVENT_BUTTON) - _glfwInputJoystickButton(jid, e.number, e.value ? 1 : 0); + if (e.type == EV_KEY) + handleKeyEvent(js, e.code, e.value); + else if (e.type == EV_ABS) + handleAbsEvent(js, e.code, e.value); + else if (e.type == EV_SYN && e.code == SYN_DROPPED) + // Refresh axes + pollJoystick(js); } return js->present; diff --git a/src/linux_joystick.h b/src/linux_joystick.h index 311becf64..73b4819f6 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -24,27 +24,34 @@ // //======================================================================== +#include +#include #include #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs +#define HATS_MAX ((ABS_HAT3Y - ABS_HAT0X) / 2) // Linux-specific joystick data // typedef struct _GLFWjoystickLinux { - int fd; - char* path; + int fd; + char path[PATH_MAX]; + int keyMap[KEY_MAX]; + int absMap[ABS_MAX]; + struct input_absinfo absInfo[ABS_MAX]; + int hats[HATS_MAX][2]; } _GLFWjoystickLinux; // Linux-specific joystick API data // typedef struct _GLFWlibraryLinux { - int inotify; - int watch; - regex_t regex; + int inotify; + int watch; + regex_t regex; } _GLFWlibraryLinux; From 206f9ca4bcebba1b232a0080d7051070e52a5e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 15 Jun 2017 16:03:04 +0200 Subject: [PATCH 066/222] Linux: Fix joystick array bugs Related to #1005. --- src/linux_joystick.c | 17 ++++++++++------- src/linux_joystick.h | 10 ++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 38c6a5035..c0a951ff2 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -38,7 +38,6 @@ #include #include -#define NUM_BITS(size) ((size) / 8) #define TEST_BIT(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) static void handleKeyEvent(_GLFWjoystick* js, int code, int value) @@ -100,8 +99,11 @@ static void pollJoystick(_GLFWjoystick* js) { int i; - for (i = ABS_X; i < ABS_MAX; i++) + for (i = 0; i < ABS_CNT; i++) { + if (js->linjs.absMap[i] < 0) + continue; + struct input_absinfo *info = &js->linjs.absInfo[i]; if (ioctl(js->linjs.fd, EVIOCGABS(i), info) < 0) @@ -117,9 +119,9 @@ static GLFWbool openJoystickDevice(const char* path) { int jid, fd, i; char name[256] = ""; - char evBits[NUM_BITS(EV_MAX)] = {0}; - char keyBits[NUM_BITS(KEY_MAX)] = {0}; - char absBits[NUM_BITS(ABS_MAX)] = {0}; + char evBits[(EV_CNT + 7) / 8] = {0}; + char keyBits[(KEY_CNT + 7) / 8] = {0}; + char absBits[(ABS_CNT + 7) / 8] = {0}; int axisCount = 0; int buttonCount = 0; int hatCount = 0; @@ -151,7 +153,7 @@ static GLFWbool openJoystickDevice(const char* path) if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) strncpy(name, "Unknown", sizeof(name)); - for (i = BTN_MISC; i < KEY_MAX; i++) + for (i = BTN_MISC; i < KEY_CNT; i++) { if (!TEST_BIT(i, keyBits)) continue; @@ -159,8 +161,9 @@ static GLFWbool openJoystickDevice(const char* path) linjs.keyMap[i] = buttonCount++; } - for (i = ABS_X; i < ABS_MAX; i++) + for (i = 0; i < ABS_CNT; i++) { + linjs.absMap[i] = -1; if (!TEST_BIT(i, absBits)) continue; diff --git a/src/linux_joystick.h b/src/linux_joystick.h index 73b4819f6..127a44857 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -31,18 +31,16 @@ #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs -#define HATS_MAX ((ABS_HAT3Y - ABS_HAT0X) / 2) - // Linux-specific joystick data // typedef struct _GLFWjoystickLinux { int fd; char path[PATH_MAX]; - int keyMap[KEY_MAX]; - int absMap[ABS_MAX]; - struct input_absinfo absInfo[ABS_MAX]; - int hats[HATS_MAX][2]; + int keyMap[KEY_CNT]; + int absMap[ABS_CNT]; + struct input_absinfo absInfo[ABS_CNT]; + int hats[4][2]; } _GLFWjoystickLinux; // Linux-specific joystick API data From d2952e4e92b4c06d0da6f7fe220d9095ba5028a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 15 Jun 2017 17:13:23 +0200 Subject: [PATCH 067/222] Cleanup Related to #1005. --- README.md | 2 + include/GLFW/glfw3.h | 2 - src/linux_joystick.c | 128 +++++++++++++++++++++++-------------------- src/linux_joystick.h | 18 +++--- 4 files changed, 81 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 0481934f6..84fe31912 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747) - [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size - [X11] Bugfix: Key name string encoding depended on current locale (#981,#983) +- [Linux] Moved to evdev for joystick input (#906,#1005) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Linux] Bugfix: The joystick device path could be truncated (#1025) - [Cocoa] Added support for Vulkan window surface creation via @@ -314,6 +315,7 @@ skills. - Peoro - Braden Pellett - Arturo J. Pérez + - Anthony Pesch - Orson Peters - Emmanuel Gil Peyrot - Cyril Pichard diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index fb18edec5..3e09eacf0 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4234,8 +4234,6 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @bug @linux Joystick hats are currently unimplemented. - * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified joystick is * disconnected, this function is called again for that joystick or the library diff --git a/src/linux_joystick.c b/src/linux_joystick.c index c0a951ff2..360e7a282 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -38,36 +38,37 @@ #include #include -#define TEST_BIT(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) - +// Apply an EV_KEY event to the specified joystick +// static void handleKeyEvent(_GLFWjoystick* js, int code, int value) { - int jid = js - _glfw.joysticks; - int button = js->linjs.keyMap[code]; - - _glfwInputJoystickButton(jid, button, value ? 1 : 0); + _glfwInputJoystickButton(_GLFW_JOYSTICK_ID(js), + js->linjs.keyMap[code - BTN_MISC], + value ? GLFW_PRESS : GLFW_RELEASE); } +// Apply an EV_ABS event to the specified joystick +// static void handleAbsEvent(_GLFWjoystick* js, int code, int value) { - int jid = js - _glfw.joysticks; - int index = js->linjs.absMap[code]; + const int jid = _GLFW_JOYSTICK_ID(js); + const int index = js->linjs.absMap[code]; if (code >= ABS_HAT0X && code <= ABS_HAT3Y) { static const char stateMap[3][3] = { - {GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN}, - {GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN}, - {GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN}, + { GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN }, + { GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN }, + { GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN }, }; - int hat = (code - ABS_HAT0X) / 2; - int axis = (code - ABS_HAT0X) % 2; - int *state = js->linjs.hats[hat]; + const int hat = (code - ABS_HAT0X) / 2; + const int axis = (code - ABS_HAT0X) % 2; + int* state = js->linjs.hats[hat]; - // Looking at several input drivers, it seems all hat events use - // -1 for left / up, 0 for centered and 1 for right / down + // NOTE: Looking at several input drivers, it seems all hat events use + // -1 for left / up, 0 for centered and 1 for right / down if (value == 0) state[axis] = 0; else if (value < 0) @@ -79,15 +80,15 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value) } else { - struct input_absinfo *info = &js->linjs.absInfo[code]; - int range = info->maximum - info->minimum; + const struct input_absinfo* info = &js->linjs.absInfo[code]; float normalized = value; - if (range != 0) + const int range = info->maximum - info->minimum; + if (range) { - // Normalize from 0.0 -> 1.0 + // Normalize to 0.0 -> 1.0 normalized = (normalized - info->minimum) / range; - // Normalize from -1.0 -> 1.0 + // Normalize to -1.0 -> 1.0 normalized = normalized * 2.0f - 1.0f; } @@ -95,36 +96,38 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value) } } -static void pollJoystick(_GLFWjoystick* js) +// Poll state of absolute axes +// +static void pollAbsState(_GLFWjoystick* js) { - int i; + int code; - for (i = 0; i < ABS_CNT; i++) + for (code = 0; code < ABS_CNT; code++) { - if (js->linjs.absMap[i] < 0) + if (js->linjs.absMap[code] < 0) continue; - struct input_absinfo *info = &js->linjs.absInfo[i]; + struct input_absinfo* info = &js->linjs.absInfo[code]; - if (ioctl(js->linjs.fd, EVIOCGABS(i), info) < 0) + if (ioctl(js->linjs.fd, EVIOCGABS(code), info) < 0) continue; - handleAbsEvent(js, i, info->value); + handleAbsEvent(js, code, info->value); } } +#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) + // Attempt to open the specified joystick device // static GLFWbool openJoystickDevice(const char* path) { - int jid, fd, i; + int jid, code; char name[256] = ""; char evBits[(EV_CNT + 7) / 8] = {0}; char keyBits[(KEY_CNT + 7) / 8] = {0}; char absBits[(ABS_CNT + 7) / 8] = {0}; - int axisCount = 0; - int buttonCount = 0; - int hatCount = 0; + int axisCount = 0, buttonCount = 0, hatCount = 0; _GLFWjoystickLinux linjs = {0}; _GLFWjoystick* js = NULL; @@ -136,71 +139,81 @@ static GLFWbool openJoystickDevice(const char* path) return GLFW_FALSE; } - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd == -1) + linjs.fd = open(path, O_RDONLY | O_NONBLOCK); + if (linjs.fd == -1) return GLFW_FALSE; + if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 || + ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 || + ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to query input device elements: %s", + strerror(errno)); + close(linjs.fd); + return GLFW_FALSE; + } + // Ensure this device supports the events expected of a joystick - if (ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 || - ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 || - ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 || - !TEST_BIT(EV_KEY, evBits) || !TEST_BIT(EV_ABS, evBits)) + if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits)) { - close(fd); + close(linjs.fd); return GLFW_FALSE; } - if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) + if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0) strncpy(name, "Unknown", sizeof(name)); - for (i = BTN_MISC; i < KEY_CNT; i++) + for (code = BTN_MISC; code < KEY_CNT; code++) { - if (!TEST_BIT(i, keyBits)) + if (!isBitSet(code, keyBits)) continue; - linjs.keyMap[i] = buttonCount++; + linjs.keyMap[code - BTN_MISC] = buttonCount; + buttonCount++; } - for (i = 0; i < ABS_CNT; i++) + for (code = 0; code < ABS_CNT; code++) { - linjs.absMap[i] = -1; - if (!TEST_BIT(i, absBits)) + linjs.absMap[code] = -1; + if (!isBitSet(code, absBits)) continue; - if (i >= ABS_HAT0X && i <= ABS_HAT3Y) + if (code >= ABS_HAT0X && code <= ABS_HAT3Y) { - linjs.absMap[i] = hatCount++; - + linjs.absMap[code] = hatCount; + hatCount++; // Skip the Y axis - i++; + code++; } else { - if (ioctl(fd, EVIOCGABS(i), &linjs.absInfo[i]) < 0) + if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0) continue; - linjs.absMap[i] = axisCount++; + linjs.absMap[code] = axisCount; + axisCount++; } } js = _glfwAllocJoystick(name, axisCount, buttonCount, hatCount); if (!js) { - close(fd); + close(linjs.fd); return GLFW_FALSE; } - linjs.fd = fd; strncpy(linjs.path, path, sizeof(linjs.path)); memcpy(&js->linjs, &linjs, sizeof(linjs)); - // Set initial values for absolute axes - pollJoystick(js); + pollAbsState(js); _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED); return GLFW_TRUE; } +#undef isBitSet + // Frees all resources associated with the specified joystick // static void closeJoystick(_GLFWjoystick* js) @@ -391,8 +404,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) else if (e.type == EV_ABS) handleAbsEvent(js, e.code, e.value); else if (e.type == EV_SYN && e.code == SYN_DROPPED) - // Refresh axes - pollJoystick(js); + pollAbsState(js); } return js->present; diff --git a/src/linux_joystick.h b/src/linux_joystick.h index 127a44857..c364cf76d 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -35,21 +35,21 @@ // typedef struct _GLFWjoystickLinux { - int fd; - char path[PATH_MAX]; - int keyMap[KEY_CNT]; - int absMap[ABS_CNT]; - struct input_absinfo absInfo[ABS_CNT]; - int hats[4][2]; + int fd; + char path[PATH_MAX]; + int keyMap[KEY_CNT - BTN_MISC]; + int absMap[ABS_CNT]; + struct input_absinfo absInfo[ABS_CNT]; + int hats[4][2]; } _GLFWjoystickLinux; // Linux-specific joystick API data // typedef struct _GLFWlibraryLinux { - int inotify; - int watch; - regex_t regex; + int inotify; + int watch; + regex_t regex; } _GLFWlibraryLinux; From 6da26c8d6c868e0864d2173cf46f32ce6238f1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 15 Jun 2017 17:40:57 +0200 Subject: [PATCH 068/222] Linux: Ignore partial state after SYN_DROPPED Related to #1005. --- src/linux_joystick.c | 16 ++++++++++++++-- src/linux_joystick.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 360e7a282..156e425c4 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -399,12 +399,24 @@ int _glfwPlatformPollJoystick(int jid, int mode) break; } + if (e.type == EV_SYN) + { + if (e.code == SYN_DROPPED) + _glfw.linjs.dropped = GLFW_TRUE; + else if (e.code == SYN_REPORT) + { + _glfw.linjs.dropped = GLFW_FALSE; + pollAbsState(js); + } + } + + if (_glfw.linjs.dropped) + continue; + if (e.type == EV_KEY) handleKeyEvent(js, e.code, e.value); else if (e.type == EV_ABS) handleAbsEvent(js, e.code, e.value); - else if (e.type == EV_SYN && e.code == SYN_DROPPED) - pollAbsState(js); } return js->present; diff --git a/src/linux_joystick.h b/src/linux_joystick.h index c364cf76d..227a6ed9b 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -50,6 +50,7 @@ typedef struct _GLFWlibraryLinux int inotify; int watch; regex_t regex; + GLFWbool dropped; } _GLFWlibraryLinux; From 99762ad7f083c6fd8ae7e56c03043a0e3bec04ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 15 Jun 2017 19:56:25 +0200 Subject: [PATCH 069/222] Cleanup --- src/linux_joystick.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 156e425c4..c314cdca4 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -287,15 +287,12 @@ GLFWbool _glfwInitJoysticksLinux(void) if (regexec(&_glfw.linjs.regex, entry->d_name, 1, &match, 0) != 0) continue; - const size_t length = strlen(dirname) + strlen(entry->d_name) + 1; - char* path = calloc(length + 1, 1); + char path[PATH_MAX]; - snprintf(path, length + 1, "%s/%s", dirname, entry->d_name); + snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name); if (openJoystickDevice(path)) count++; - - free(path); } closedir(dir); @@ -349,29 +346,29 @@ void _glfwDetectJoystickConnectionLinux(void) regmatch_t match; const struct inotify_event* e = (struct inotify_event*) (buffer + offset); - if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) == 0) + offset += sizeof(struct inotify_event) + e->len; + + if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) != 0) + continue; + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/dev/input/%s", e->name); + + if (e->mask & (IN_CREATE | IN_ATTRIB)) + openJoystickDevice(path); + else if (e->mask & IN_DELETE) { - char path[20]; - snprintf(path, sizeof(path), "/dev/input/%s", e->name); + int jid; - if (e->mask & (IN_CREATE | IN_ATTRIB)) - openJoystickDevice(path); - else if (e->mask & IN_DELETE) + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - int jid; - - for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) { - if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) - { - closeJoystick(_glfw.joysticks + jid); - break; - } + closeJoystick(_glfw.joysticks + jid); + break; } } } - - offset += sizeof(struct inotify_event) + e->len; } } From d5de48ab537027599d150220a77df5427464c598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 27 Jun 2017 16:35:18 +0200 Subject: [PATCH 070/222] Report invalid constants in the appropriate base If the expected constants are defined in hexadecimal in the header then the error string should also use hexadecimal. Idea by IntellectualKitty. Related to #970. --- src/context.c | 10 +++++----- src/init.c | 2 +- src/input.c | 8 ++++---- src/window.c | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/context.c b/src/context.c index 5a4c33729..1a26356e1 100644 --- a/src/context.c +++ b/src/context.c @@ -45,7 +45,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->source != GLFW_OSMESA_CONTEXT_API) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid context creation API %i", + "Invalid context creation API 0x%08X", ctxconfig->source); return GLFW_FALSE; } @@ -55,7 +55,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->client != GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid client API %i", + "Invalid client API 0x%08X", ctxconfig->client); return GLFW_FALSE; } @@ -85,7 +85,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid OpenGL profile %i", + "Invalid OpenGL profile 0x%08X", ctxconfig->profile); return GLFW_FALSE; } @@ -134,7 +134,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid context robustness mode %i", + "Invalid context robustness mode 0x%08X", ctxconfig->robustness); return GLFW_FALSE; } @@ -146,7 +146,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid context release behavior %i", + "Invalid context release behavior 0x%08X", ctxconfig->release); return GLFW_FALSE; } diff --git a/src/init.c b/src/init.c index b999149cd..307ca0099 100644 --- a/src/init.c +++ b/src/init.c @@ -238,7 +238,7 @@ GLFWAPI void glfwInitHint(int hint, int value) return; } - _glfwInputError(GLFW_INVALID_ENUM, "Invalid init hint %i", hint); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid init hint 0x%08X", hint); } GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) diff --git a/src/input.c b/src/input.c index 7d7ccf3fc..6a510ec78 100644 --- a/src/input.c +++ b/src/input.c @@ -225,7 +225,7 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) case GLFW_STICKY_MOUSE_BUTTONS: return window->stickyMouseButtons; default: - _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); return 0; } } @@ -246,7 +246,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) value != GLFW_CURSOR_DISABLED) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid cursor mode %i", + "Invalid cursor mode 0x%08X", value); return; } @@ -309,7 +309,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) } } - _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); } GLFWAPI const char* glfwGetKeyName(int key, int scancode) @@ -466,7 +466,7 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) shape != GLFW_HRESIZE_CURSOR && shape != GLFW_VRESIZE_CURSOR) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor %i", shape); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); return NULL; } diff --git a/src/window.c b/src/window.c index 1d717c30b..b7498e1be 100644 --- a/src/window.c +++ b/src/window.c @@ -388,7 +388,7 @@ GLFWAPI void glfwWindowHint(int hint, int value) _glfw.hints.refreshRate = value; break; default: - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint %i", hint); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); break; } } @@ -757,7 +757,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->context.noerror; } - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute %i", attrib); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); return 0; } @@ -804,7 +804,7 @@ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) return; } - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute %i", attrib); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); } GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) From 58c05ba8ee93272a806cb3c0d3153ef228567ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 28 Jun 2017 11:30:11 +0200 Subject: [PATCH 071/222] Fix library destination for DLL platforms Fixes #1035. --- README.md | 1 + src/CMakeLists.txt | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 84fe31912..f26d0204f 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,7 @@ information on what to include when reporting a bug. - [Win32] Bugfix: Vulkan libraries have a new path as of SDK 1.0.42.0 (#956) - [Win32] Bugfix: Monitors with no display devices were not enumerated (#960) - [Win32] Bugfix: Monitor events were not emitted (#784) +- [Win32] Bugfix: The Cygwin DLL was installed to the wrong directory (#1035) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ccf2f146..2d38f10d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,6 +129,10 @@ if (MSVC) endif() if (GLFW_INSTALL) - install(TARGETS glfw EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX}) + install(TARGETS glfw + EXPORT glfwTargets + RUNTIME DESTINATION "bin" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + LIBRARY DESTINATION "lib${LIB_SUFFIX}") endif() From 539a728063339da095dbfbfe300fa3a124d541d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 11 Jun 2017 18:04:17 +0200 Subject: [PATCH 072/222] Documentation work [ci skip] --- docs/intro.dox | 6 ++-- docs/main.dox | 2 +- docs/news.dox | 69 +++++++++++++++++++++++++++++--------------- docs/window.dox | 2 +- include/GLFW/glfw3.h | 7 +++-- 5 files changed, 54 insertions(+), 32 deletions(-) diff --git a/docs/intro.dox b/docs/intro.dox index 180f63fdb..e5de73032 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -84,7 +84,7 @@ buttons, for compatibility with earlier versions of GLFW that did not have @ref glfwGetJoystickHats. -@subsubsection init_hints_osx macOS specific hints +@subsubsection init_hints_osx macOS specific init hints @anchor GLFW_COCOA_CHDIR_RESOURCES __GLFW_COCOA_CHDIR_RESOURCES__ specifies whether to set the current directory to @@ -143,8 +143,8 @@ if (code != GLFW_NO_ERROR) handle_error(code); @endcode -If no error has occurred since the last call, @ref GLFW_NO_ERROR is returned. -The error is cleared before the function returns. +If no error has occurred since the last call, @ref GLFW_NO_ERROR (zero) is +returned. The error is cleared before the function returns. The error code indicates the general category of the error. Some error codes, such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like diff --git a/docs/main.dox b/docs/main.dox index fc95cc4eb..a1a093f56 100644 --- a/docs/main.dox +++ b/docs/main.dox @@ -8,7 +8,7 @@ GLFW is a free, Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan application development. It provides a simple, platform-independent API for creating windows, contexts and surfaces, reading input, handling events, etc. -See @ref news_33 for release highlights or the +See @ref news_33 for highlights or the [version history](http://www.glfw.org/changelog.html) for details. @ref quick_guide is a guide for users new to GLFW. It takes you through how to diff --git a/docs/news.dox b/docs/news.dox index 39ad4eaae..8ff7e2a28 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -1,8 +1,8 @@ /*! -@page news New features +@page news Release notes -@section news_33 New features in 3.3 +@section news_33 Release notes for 3.3 @subsection news_33_geterror Error query @@ -15,20 +15,26 @@ human-readable description with @ref glfwGetError. @subsection news_33_attention User attention request -GLFW now supports requesting user attention with @ref -glfwRequestWindowAttention. +GLFW now supports requesting user attention to a specific window (on macOS to +the application as a whole) with @ref glfwRequestWindowAttention. + +@see @ref window_attention @subsection news_33_maximize Window maximization callback -GLFW now supports window maximization notifications with @ref -glfwSetWindowMaximizeCallback. +GLFW now supports notifying the application that the window has been maximized +@ref glfwSetWindowMaximizeCallback. + +@see @ref window_maximize @subsection news_33_keyscancode Platform-specific key scancode query -GLFW now supports querying the platform dependent scancode of any key with -@ref glfwGetKeyScancode. +GLFW now supports querying the platform dependent scancode of any physical key +with @ref glfwGetKeyScancode. + +@see @ref input_key @subsection news_33_setwindowattrib Support for updating window attributes @@ -39,33 +45,46 @@ GLFW now supports changing the [GLFW_DECORATED](@ref GLFW_DECORATED_attrib), [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) attributes for existing windows with @ref glfwSetWindowAttrib. - -@subsection news_33_joyhats Support for joystick hats - -GLFW now supports querying the hats of a joystick with @ref glfwGetJoystickHats -and controlling whether hats are also exposed as buttons with the @ref -GLFW_JOYSTICK_HAT_BUTTONS init hint. +@see @ref window_attribs @subsection news_33_inithint Support for initialization hints GLFW now supports setting library initialization hints with @ref glfwInitHint. -Currently the macOS specific @ref -GLFW_COCOA_CHDIR_RESOURCES and @ref GLFW_COCOA_MENUBAR init hints are supported, -replacing the corresponding compile-time options. +These must be set before initialization to take effect. + +@see @ref init_hints + + +@subsection news_33_platformhints Support for platform specific hints + +GLFW now supports platform specific init and window hints to control system +features that are only available on a single platform. + +@see @ref init_hints_osx +@see @ref window_hints_osx + + +@subsection news_33_joyhats Support for joystick hats + +GLFW now supports querying the hats (or POVs or D-pads) of a joystick with @ref +glfwGetJoystickHats. Hats are by default also exposed as buttons, but this can +be disabled with the @ref GLFW_JOYSTICK_HAT_BUTTONS init hint. + +@see @ref joystick_hat @subsection news_33_centercursor Cursor centering window hint GLFW now supports controlling whether the cursor is centered over newly created full screen windows with the [GLFW_CENTER_CURSOR](@ref GLFW_CENTER_CURSOR_hint) -window hint. +window hint. It is enabled by default. @subsection news_33_rawmotion Support for raw mouse motion -GLFW now supports raw mouse motion in disabled cursor mode on platforms where -this is available. +GLFW now uses raw (unscaled and unaccelerated) mouse motion in disabled cursor +mode on platforms where this is available, specifically Windows and X11. @subsection news_33_moltenvk Support for Vulkan on macOS via MoltenVK @@ -73,6 +92,8 @@ this is available. GLFW now supports the `VK_MVK_macos_surface` window surface creation extension provided by [MoltenVK](https://moltengl.com/moltenvk/). +@see @ref vulkan_guide + @subsection news_33_osmesa OSMesa backend for headless software rendering @@ -81,12 +102,12 @@ GLFW now supports creating offscreen OpenGL contexts using [GLFW_CONTEXT_CREATION_API](@ref GLFW_CONTEXT_CREATION_API_hint) to `GLFW_OSMESA_CONTEXT_API`. -There is also a new headless backend that uses OSMesa as its native context +There is also a new null backend that uses OSMesa as its native context creation API, intended for automated testing. This backend does not provide input. -@section news_32 New features in 3.2 +@section news_32 Release notes for 3.2 @subsection news_32_vulkan Support for Vulkan @@ -177,7 +198,7 @@ GLFW now supports being used as a easy linking with the library and its dependencies. -@section news_31 New features in 3.1 +@section news_31 Release notes for 3.1 These are the release highlights. For a full list of changes see the [version history](http://www.glfw.org/changelog.html). @@ -288,7 +309,7 @@ GLFW now has an _experimental_ Mir display server backend that can be selected on Linux with a CMake option. -@section news_30 New features in 3.0 +@section news_30 Release notes for 3.0 These are the release highlights. For a full list of changes see the [version history](http://www.glfw.org/changelog.html). diff --git a/docs/window.dox b/docs/window.dox index 7d187d65b..d9a837f63 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -427,7 +427,7 @@ The no error mode for OpenGL and OpenGL ES is described in detail by the extension. -@subsubsection window_hints_osx macOS specific hints +@subsubsection window_hints_osx macOS specific window hints @anchor GLFW_COCOA_RETINA_FRAMEBUFFER_hint __GLFW_COCOA_RETINA_FRAMEBUFFER__ specifies whether to use full resolution diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 3e09eacf0..382bd4eab 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1648,11 +1648,12 @@ GLFWAPI const char* glfwGetVersionString(void); * This function returns and clears the [error code](@ref error) of the last * error that occurred on the calling thread, and optionally a UTF-8 encoded * human-readable description of it. If no error has occurred since the last - * call, it returns @ref GLFW_NO_ERROR and the description pointer is set to - * `NULL`. + * call, it returns @ref GLFW_NO_ERROR (zero) and the description pointer is + * set to `NULL`. * * @param[in] description Where to store the error description pointer, or `NULL`. - * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR. + * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR + * (zero). * * @errors None. * From 9610d68f1979fd97bd2b6b454fec6aeccc8a3e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 30 Jun 2017 15:20:18 +0200 Subject: [PATCH 073/222] Fix linguist detection for Objective-C [ci skip] --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..96200d248 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.m linguist-language=Objective-C From 9bb5e880ae3de0b2d599ed355fb013ac45bee5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 28 Jun 2017 20:55:34 +0200 Subject: [PATCH 074/222] Win32: Fix XInput button bit mask array size --- src/win32_joystick.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index a368d995e..f3a9726cd 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -653,7 +653,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) DWORD result; XINPUT_STATE xis; float axes[6] = { 0.f, 0.f, 0.f, 0.f, -1.f, -1.f }; - const WORD buttons[14] = + const WORD buttons[10] = { XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, From 57f872054c1a9eac43866a1b5c42b24f747f66c7 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 2 Jul 2017 18:51:10 +0100 Subject: [PATCH 075/222] Fix GLAPIENTRY re-definition warning on OpenBSD Closes #1039. --- include/GLFW/glfw3.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 382bd4eab..775ce2090 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -107,12 +107,6 @@ extern "C" { #endif #endif /* APIENTRY */ -/* Some OpenGL related headers use GLAPIENTRY instead. - */ -#ifndef GLAPIENTRY - #define GLAPIENTRY APIENTRY -#endif /* GLAPIENTRY */ - /* Some Windows OpenGL headers need this. */ #if !defined(WINGDIAPI) && defined(_WIN32) @@ -215,6 +209,9 @@ extern "C" { #endif /*__APPLE__*/ #endif /* OpenGL and OpenGL ES headers */ +#ifndef GLAPIENTRY + #define GLAPIENTRY APIENTRY +#endif /* GLAPIENT #if defined(GLFW_INCLUDE_VULKAN) From be51c201dd171b2c6856f5e4c7986b50bc9a5056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 3 Jul 2017 14:25:47 +0200 Subject: [PATCH 076/222] Cleanup Related to #1039. --- README.md | 1 + include/GLFW/glfw3.h | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f26d0204f..6f91c3fcf 100644 --- a/README.md +++ b/README.md @@ -248,6 +248,7 @@ skills. - blanco - Kyle Brenneman - Martin Capitanio + - David Carlier - Chi-kwan Chan - Lambert Clara - Andrew Corrigan diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 775ce2090..8ddcfd8b9 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -209,9 +209,6 @@ extern "C" { #endif /*__APPLE__*/ #endif /* OpenGL and OpenGL ES headers */ -#ifndef GLAPIENTRY - #define GLAPIENTRY APIENTRY -#endif /* GLAPIENT #if defined(GLFW_INCLUDE_VULKAN) @@ -4909,6 +4906,13 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window #undef GLFW_CALLBACK_DEFINED #endif +/* Some OpenGL related headers need GLAPIENTRY, but it is unconditionally + * defined by some gl.h variants (OpenBSD) so define it after if needed. + */ +#ifndef GLAPIENTRY + #define GLAPIENTRY APIENTRY +#endif + /* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ From 8c0512027f0d2a181d274a4f52394ecbafe5503f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 4 Jul 2017 20:03:04 +0200 Subject: [PATCH 077/222] Fix table header text alignment [ci skip] --- docs/extra.css | 2 +- docs/extra.less | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/extra.css b/docs/extra.css index 7d9a30496..df978c0cb 100644 --- a/docs/extra.css +++ b/docs/extra.css @@ -1 +1 @@ -.sm-dox,.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted,.sm-dox ul a:hover{background:none;text-shadow:none}.sm-dox ul a:hover{background:#666;text-shadow:none}#main-nav,#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code{background:none}#titlearea,.footer,.contents,div.header,.memdoc,table.doxtable td,table.doxtable th,hr,.memSeparator{border:none}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.reflist dt a.el,.levels span,.directory .levels span{text-shadow:none}.memdoc,dl.reflist dd{box-shadow:none}div.headertitle,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,table.doxtable code{padding:0}#nav-path,.directory .levels,span.lineno{display:none}html,#titlearea,.footer,tr.even,.directory tr.even,.doxtable tr:nth-child(even),.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,code{background:#f2f2f2}body{color:#4d4d4d}h1,h2,h2.groupheader,h3,div.toc h3,h4,h5,h6,strong,em{color:#1a1a1a;border-bottom:none}h1{padding-top:0.5em;font-size:180%}h2{padding-top:0.5em;margin-bottom:0;font-size:140%}h3{padding-top:0.5em;margin-bottom:0;font-size:110%}.glfwheader{font-size:16px;height:64px;max-width:920px;min-width:800px;padding:0 32px;margin:0 auto}#glfwhome{line-height:64px;padding-right:48px;color:#666;font-size:2.5em;background:url("http://www.glfw.org/css/arrow.png") no-repeat right}.glfwnavbar{list-style-type:none;margin:0 auto;float:right}#glfwhome,.glfwnavbar li{float:left}.glfwnavbar a,.glfwnavbar a:visited{line-height:64px;margin-left:2em;display:block;color:#666}#glfwhome,.glfwnavbar a,.glfwnavbar a:visited{transition:.35s ease}#titlearea,.footer{color:#666}address.footer{text-align:center;padding:2em;margin-top:3em}#top{background:#666}#main-nav{max-width:960px;min-width:800px;margin:0 auto;font-size:13px}#navrow1,#navrow2,#navrow3,#navrow4{max-width:920px;min-width:800px;margin:0 auto;font-size:13px}.memtitle{display:none}.memproto,.memname{font-weight:bold;text-shadow:none}.tablist{height:36px;display:block;position:relative}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a{color:#f2f2f2}.tablist li.current a{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}.contents{min-height:590px}div.contents,div.header{max-width:920px;margin:0 auto;padding:0 32px;background:#fff none}table.doxtable th,dl.reflist dt{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}dl.reflist dt a.el{color:#f60;padding:.2em;border-radius:4px;background-color:#ffe0cc}div.toc{float:none;width:auto}div.toc h3{font-size:1.17em}div.toc ul{padding-left:1.5em}div.toc li{font-size:1em;padding-left:0;list-style-type:disc}div.toc,.memproto,div.qindex,div.ah{background:linear-gradient(to bottom, #f2f2f2 0, #e6e6e6 100%);box-shadow:inset 0 0 32px #e6e6e6;text-shadow:0 1px 1px #fff;color:#1a1a1a;border:2px solid #e6e6e6;border-radius:4px}.paramname{color:#803300}dl.reflist dt{border:2px solid #f60;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:none}dl.reflist dd{border:2px solid #f60;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:none}table.doxtable{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,.tablist a:hover,span.lineno a:hover{color:#f60;text-decoration:none}div.directory{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}hr,.memSeparator{height:2px;background:linear-gradient(to right, #f2f2f2 0, #d9d9d9 50%, #f2f2f2 100%)}dl.note,dl.pre,dl.post,dl.invariant{background:linear-gradient(to bottom, #ddfad1 0, #cbf7ba 100%);box-shadow:inset 0 0 32px #baf5a3;color:#1e5309;border:2px solid #afe599}dl.warning,dl.attention{background:linear-gradient(to bottom, #fae8d1 0, #f7ddba 100%);box-shadow:inset 0 0 32px #f5d1a3;color:#533309;border:2px solid #e5c499}dl.deprecated,dl.bug{background:linear-gradient(to bottom, #fad1e3 0, #f7bad6 100%);box-shadow:inset 0 0 32px #f5a3c8;color:#53092a;border:2px solid #e599bb}dl.todo,dl.test{background:linear-gradient(to bottom, #d1ecfa 0, #bae3f7 100%);box-shadow:inset 0 0 32px #a3daf5;color:#093a53;border:2px solid #99cce5}dl.note,dl.pre,dl.post,dl.invariant,dl.warning,dl.attention,dl.deprecated,dl.bug,dl.todo,dl.test{border-radius:4px;padding:1em;text-shadow:0 1px 1px #fff;margin:1em 0}.note a,.pre a,.post a,.invariant a,.warning a,.attention a,.deprecated a,.bug a,.todo a,.test a,.note a:visited,.pre a:visited,.post a:visited,.invariant a:visited,.warning a:visited,.attention a:visited,.deprecated a:visited,.bug a:visited,.todo a:visited,.test a:visited{color:inherit}div.line{line-height:inherit}div.fragment,pre.fragment{background:#f2f2f2;border-radius:4px;border:none;padding:1em;overflow:auto;border-left:4px solid #ccc;margin:1em 0}.lineno a,.lineno a:visited,.line,pre.fragment{color:#4d4d4d}span.preprocessor,span.comment{color:#007899}a.code,a.code:visited{color:#e64500}span.keyword,span.keywordtype,span.keywordflow{color:#404040;font-weight:bold}span.stringliteral{color:#360099}code{padding:.1em;border-radius:4px} +.sm-dox,.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted,.sm-dox ul a:hover{background:none;text-shadow:none}.sm-dox ul a:hover{background:#666;text-shadow:none}#main-nav,#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code{background:none}#titlearea,.footer,.contents,div.header,.memdoc,table.doxtable td,table.doxtable th,hr,.memSeparator{border:none}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.reflist dt a.el,.levels span,.directory .levels span{text-shadow:none}.memdoc,dl.reflist dd{box-shadow:none}div.headertitle,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,table.doxtable code{padding:0}#nav-path,.directory .levels,span.lineno{display:none}html,#titlearea,.footer,tr.even,.directory tr.even,.doxtable tr:nth-child(even),.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,code{background:#f2f2f2}body{color:#4d4d4d}h1,h2,h2.groupheader,h3,div.toc h3,h4,h5,h6,strong,em{color:#1a1a1a;border-bottom:none}h1{padding-top:0.5em;font-size:180%}h2{padding-top:0.5em;margin-bottom:0;font-size:140%}h3{padding-top:0.5em;margin-bottom:0;font-size:110%}.glfwheader{font-size:16px;height:64px;max-width:920px;min-width:800px;padding:0 32px;margin:0 auto}#glfwhome{line-height:64px;padding-right:48px;color:#666;font-size:2.5em;background:url("http://www.glfw.org/css/arrow.png") no-repeat right}.glfwnavbar{list-style-type:none;margin:0 auto;float:right}#glfwhome,.glfwnavbar li{float:left}.glfwnavbar a,.glfwnavbar a:visited{line-height:64px;margin-left:2em;display:block;color:#666}#glfwhome,.glfwnavbar a,.glfwnavbar a:visited{transition:.35s ease}#titlearea,.footer{color:#666}address.footer{text-align:center;padding:2em;margin-top:3em}#top{background:#666}#main-nav{max-width:960px;min-width:800px;margin:0 auto;font-size:13px}#navrow1,#navrow2,#navrow3,#navrow4{max-width:920px;min-width:800px;margin:0 auto;font-size:13px}.memtitle{display:none}.memproto,.memname{font-weight:bold;text-shadow:none}.tablist{height:36px;display:block;position:relative}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a{color:#f2f2f2}.tablist li.current a{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}.contents{min-height:590px}div.contents,div.header{max-width:920px;margin:0 auto;padding:0 32px;background:#fff none}table.doxtable th,dl.reflist dt{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;text-align:left;color:#fff}dl.reflist dt a.el{color:#f60;padding:.2em;border-radius:4px;background-color:#ffe0cc}div.toc{float:none;width:auto}div.toc h3{font-size:1.17em}div.toc ul{padding-left:1.5em}div.toc li{font-size:1em;padding-left:0;list-style-type:disc}div.toc,.memproto,div.qindex,div.ah{background:linear-gradient(to bottom, #f2f2f2 0, #e6e6e6 100%);box-shadow:inset 0 0 32px #e6e6e6;text-shadow:0 1px 1px #fff;color:#1a1a1a;border:2px solid #e6e6e6;border-radius:4px}.paramname{color:#803300}dl.reflist dt{border:2px solid #f60;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:none}dl.reflist dd{border:2px solid #f60;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:none}table.doxtable{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,.tablist a:hover,span.lineno a:hover{color:#f60;text-decoration:none}div.directory{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}hr,.memSeparator{height:2px;background:linear-gradient(to right, #f2f2f2 0, #d9d9d9 50%, #f2f2f2 100%)}dl.note,dl.pre,dl.post,dl.invariant{background:linear-gradient(to bottom, #ddfad1 0, #cbf7ba 100%);box-shadow:inset 0 0 32px #baf5a3;color:#1e5309;border:2px solid #afe599}dl.warning,dl.attention{background:linear-gradient(to bottom, #fae8d1 0, #f7ddba 100%);box-shadow:inset 0 0 32px #f5d1a3;color:#533309;border:2px solid #e5c499}dl.deprecated,dl.bug{background:linear-gradient(to bottom, #fad1e3 0, #f7bad6 100%);box-shadow:inset 0 0 32px #f5a3c8;color:#53092a;border:2px solid #e599bb}dl.todo,dl.test{background:linear-gradient(to bottom, #d1ecfa 0, #bae3f7 100%);box-shadow:inset 0 0 32px #a3daf5;color:#093a53;border:2px solid #99cce5}dl.note,dl.pre,dl.post,dl.invariant,dl.warning,dl.attention,dl.deprecated,dl.bug,dl.todo,dl.test{border-radius:4px;padding:1em;text-shadow:0 1px 1px #fff;margin:1em 0}.note a,.pre a,.post a,.invariant a,.warning a,.attention a,.deprecated a,.bug a,.todo a,.test a,.note a:visited,.pre a:visited,.post a:visited,.invariant a:visited,.warning a:visited,.attention a:visited,.deprecated a:visited,.bug a:visited,.todo a:visited,.test a:visited{color:inherit}div.line{line-height:inherit}div.fragment,pre.fragment{background:#f2f2f2;border-radius:4px;border:none;padding:1em;overflow:auto;border-left:4px solid #ccc;margin:1em 0}.lineno a,.lineno a:visited,.line,pre.fragment{color:#4d4d4d}span.preprocessor,span.comment{color:#007899}a.code,a.code:visited{color:#e64500}span.keyword,span.keywordtype,span.keywordflow{color:#404040;font-weight:bold}span.stringliteral{color:#360099}code{padding:.1em;border-radius:4px} diff --git a/docs/extra.less b/docs/extra.less index c5f5eea5f..9221459a5 100644 --- a/docs/extra.less +++ b/docs/extra.less @@ -247,6 +247,7 @@ table.doxtable th,dl.reflist dt { background:linear-gradient(to bottom,@table-background-color2 0%,@table-background-color1 100%); box-shadow:inset 0 0 32px @table-background-color1; text-shadow:0 -1px 1px darken(@table-background-color1, 15%); + text-align:left; color:@table-text-color; } From 07bf2b166bbe9038ab60a0a0ae3b7a3ec2275f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 7 Jul 2017 10:23:58 +0200 Subject: [PATCH 078/222] GLX: Fix segfault when no GLXFBConfigs available Fixes #1040. --- README.md | 2 ++ src/glx_context.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f91c3fcf..b7b1353e4 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,8 @@ information on what to include when reporting a bug. - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` +- [GLX] Bugfix: Context creation could segfault if no GLXFBConfigs were + available (#1040) - [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) - [EGL] Added support for `EGL_KHR_context_flush_control` - [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid diff --git a/src/glx_context.c b/src/glx_context.c index 1d11bfb0d..dbac4ea77 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -64,7 +64,7 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res nativeConfigs = glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount); - if (!nativeCount) + if (!nativeConfigs || !nativeCount) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned"); return GLFW_FALSE; From 953106e74ddaf925eb2d100ea67bb36bf89167d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 18 Jun 2017 15:13:25 +0200 Subject: [PATCH 079/222] Add support for SDL_GameControllerDB This adds support for importing and applying mappings from the SDL_GameControllerDB database. Related to #900. --- README.md | 8 ++ docs/Doxyfile.in | 2 +- docs/input.dox | 137 +++++++++++++++++++ docs/news.dox | 10 ++ include/GLFW/glfw3.h | 219 ++++++++++++++++++++++++++++-- src/CMakeLists.txt | 2 +- src/cocoa_joystick.h | 1 + src/cocoa_joystick.m | 88 +++++++++++-- src/init.c | 7 +- src/input.c | 307 +++++++++++++++++++++++++++++++++++++++++++ src/internal.h | 32 ++++- src/linux_joystick.c | 31 ++++- src/linux_joystick.h | 2 + src/mappings.h | 230 ++++++++++++++++++++++++++++++++ src/null_joystick.c | 4 + src/null_joystick.h | 2 + src/win32_joystick.c | 45 ++++++- src/win32_joystick.h | 1 + tests/joysticks.c | 138 ++++++++++++------- 19 files changed, 1186 insertions(+), 80 deletions(-) create mode 100644 src/mappings.h diff --git a/README.md b/README.md index b7b1353e4..b2110b2ce 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,14 @@ information on what to include when reporting a bug. - Added `glfwGetError` function for querying the last error code and its description (#970) +- Added `glfwUpdateGamepadMappings` function for importing gamepad mappings in + SDL\_GameControllerDB format (#900) +- Added `glfwJoystickIsGamepad` function for querying whether a joystick has + a gamepad mapping (#900) +- Added `glfwGetGamepadName` function for querying the name provided by the + gamepad mapping (#900) +- Added `glfwGetGamepadState` function, `GLFW_GAMEPAD_*` and `GLFWgamepadstate` + for retrieving gamepad input state (#900) - Added `glfwRequestWindowAttention` function for requesting attention from the user (#732,#988) - Added `glfwGetKeyScancode` function that allows retrieving platform dependent diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 16562cc83..9bbd9245f 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -476,7 +476,7 @@ SORT_MEMBER_DOCS = NO # by member name. If set to NO (the default) the members will appear in # declaration order. -SORT_BRIEF_DOCS = YES +SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that diff --git a/docs/input.dox b/docs/input.dox index bc1d1a7b2..f11e6dc8a 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -653,6 +653,143 @@ called by joystick functions. The function will then return whatever it returns for a disconnected joystick. +@subsection gamepad Gamepad input + +The joystick functions provide unlabeled axes, buttons and hats, with no +indication of where they are located on the device. Their order may also vary +between platforms even with the same device. + +To solve this problem the SDL community crowdsourced the +[SDL_GameControllerDB](https://github.com/gabomdq/SDL_GameControllerDB) project, +a database of mappings from many different devices to an Xbox-like gamepad. + +GLFW supports this mapping format and contains a copy of the mappings +available at the time of release. See @ref gamepad_mapping for how to update +this at runtime. Mappings will be assigned to joysticks automatically any time +a joystick is connected or the mappings are updated. + +You can check whether a joystick is both present and has a gamepad mapping with +@ref glfwJoystickIsGamepad. + +@code +if (glfwJoystickIsGamepad(GLFW_JOYSTICK_2)) +{ + // Use as gamepad +} +@endcode + +If you are only interested in gamepad input you can use this function instead of +@ref glfwJoystickPresent. + +You can query the human-readable name provided by the gamepad mapping with @ref +glfwGetGamepadName. This may or may not be the same as the +[joystick name](@ref joystick_name). + +@code +const char* name = glfwGetGamepadName(GLFW_JOYSTICK_7); +@endcode + +To retrieve the gamepad state of a joystick, call @ref glfwGetGamepadState. + +@code +GLFWgamepadstate state; + +if (glfwGetGamepadState(GLFW_JOYSTICK_3, &state)) +{ + if (state.buttons[GLFW_GAMEPAD_BUTTON_A]) + { + input_jump(); + } + + input_speed(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER]); +} +@endcode + +The @ref GLFWgamepadstate struct has two arrays; one for button states and one +for axis states. The values for each button and axis are the same as for the +@ref glfwGetJoystickButtons and @ref glfwGetJoystickAxes functions, i.e. +`GLFW_PRESS` or `GLFW_RELEASE` for buttons and -1.0 to 1.0 inclusive for axes. + +The sizes of the arrays and the positions within each array are fixed. + +The [button indices](@ref gamepad_buttons) are `GLFW_GAMEPAD_BUTTON_A`, +`GLFW_GAMEPAD_BUTTON_B`, `GLFW_GAMEPAD_BUTTON_X`, `GLFW_GAMEPAD_BUTTON_Y`, +`GLFW_GAMEPAD_BUTTON_LEFT_BUMPER`, `GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER`, +`GLFW_GAMEPAD_BUTTON_BACK`, `GLFW_GAMEPAD_BUTTON_START`, +`GLFW_GAMEPAD_BUTTON_GUIDE`, `GLFW_GAMEPAD_BUTTON_LEFT_THUMB`, +`GLFW_GAMEPAD_BUTTON_RIGHT_THUMB`, `GLFW_GAMEPAD_BUTTON_DPAD_UP`, +`GLFW_GAMEPAD_BUTTON_DPAD_RIGHT`, `GLFW_GAMEPAD_BUTTON_DPAD_DOWN` and +`GLFW_GAMEPAD_BUTTON_DPAD_LEFT`. + +For those who prefer, there are also the `GLFW_GAMEPAD_BUTTON_CROSS`, +`GLFW_GAMEPAD_BUTTON_CIRCLE`, `GLFW_GAMEPAD_BUTTON_SQUARE` and +`GLFW_GAMEPAD_BUTTON_TRIANGLE` aliases for the A, B, X and Y button indices. + +The [axis indices](@ref gamepad_axes) are `GLFW_GAMEPAD_AXIS_LEFT_X`, +`GLFW_GAMEPAD_AXIS_LEFT_Y`, `GLFW_GAMEPAD_AXIS_RIGHT_X`, +`GLFW_GAMEPAD_AXIS_RIGHT_Y`, `GLFW_GAMEPAD_AXIS_LEFT_TRIGGER` and +`GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER`. + +The `GLFW_GAMEPAD_BUTTON_LAST` and `GLFW_GAMEPAD_AXIS_LAST` constants equal +the largest available index for each array. + + +@subsection gamepad_mapping Gamepad mappings + +Newer ones can be added with @ref glfwUpdateGamepadMappings. This function +supports everything from single lines up to the entire unmodified contents of +the `gamecontrollerdb.txt` file. + +@code +const char* mappings = load_file_contents("gamecontrollerdb.txt"); + +glfwUpdateGamepadMappings(mappings); +@endcode + +Below is a description of the mapping format. Please keep in mind that __this +description is not authoritative__. The format is defined by the SDL and +SDL_GameControllerDB projects and their documentation and code takes precedence. + +Each mapping is a single line of comma-separated values describing the GUID, +name and layout of the gamepad. Lines that do not begin with a hexadecimal +digit are ignored. + +The first value is always the gamepad GUID, a 32 character long hexadecimal +string that typically identifies its make, model, revision and the type of +connection to the computer. When this information is not available, the GUID is +generated using the gamepad name. GLFW uses the SDL 2.0.5+ GUID format but can +convert from the older formats. + +The second value is always the human-readable name of the gamepad. + +All subsequent values are in the form `:` and describe the layout +of the mapping. These fields may not all be present and may occur in any order. + +The button fields are `a`, `b`, `c`, `d`, `back`, `start`, `guide`, `dpup`, +`dpright`, `dpdown`, `dpleft`, `leftshoulder`, `rightshoulder`, `leftstick` and +`rightstick`. + +The axis fields are `leftx`, `lefty`, `rightx`, `righty`, `lefttrigger` and +`righttrigger`. + +The value of an axis or button field can be a joystick button, a joystick axis, +a hat bitmask or empty. Joystick buttons are specified as `bN`, for example +`b2` for the third button. Joystick axes are specified as `aN`, for example +`a7` for the eighth button. Joystick hat bit masks are specified as `hN.N`, for +example `h0.8` for left on the first hat. More than one bit may be set in the +mask. + +The hat bit mask match the [hat states](@ref hat_state) in the joystick +functions. + +There is also the special `platform` field that specifies which platform the +mapping is valid for. Possible values are `Windows`, `Mac OS X` and `Linux`. +Mappings without this field will always be considered valid. + +@note GLFW does not yet support the range and inversion modifiers `+`, `-` and +`~`. + + @section time Time input GLFW provides high-resolution time input, in seconds, with @ref glfwGetTime. diff --git a/docs/news.dox b/docs/news.dox index 8ff7e2a28..173508ec1 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -13,6 +13,16 @@ human-readable description with @ref glfwGetError. @see @ref error_handling +@subsection news_33_gamepad SDL_GameControllerDB support and gamepad input + +GLFW now supports remapping of gamepads and controllers to a 360-like controller +layout with @ref glfwJoystickIsGamepad, @ref glfwGetGamepadName, @ref +glfwGetGamepadState and @ref glfwUpdateGamepadMappings, and the input state +struct @ref GLFWgamepadstate. + +@sa @ref gamepad + + @subsection news_33_attention User attention request GLFW now supports requesting user attention to a specific window (on macOS to diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 8ddcfd8b9..599ab057e 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -559,6 +559,52 @@ extern "C" { #define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 /*! @} */ +/*! @defgroup gamepad_buttons Gamepad buttons + * @brief Gamepad buttons. + * + * See @ref gamepad for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_GAMEPAD_BUTTON_A 0 +#define GLFW_GAMEPAD_BUTTON_B 1 +#define GLFW_GAMEPAD_BUTTON_X 2 +#define GLFW_GAMEPAD_BUTTON_Y 3 +#define GLFW_GAMEPAD_BUTTON_LEFT_BUMPER 4 +#define GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER 5 +#define GLFW_GAMEPAD_BUTTON_BACK 6 +#define GLFW_GAMEPAD_BUTTON_START 7 +#define GLFW_GAMEPAD_BUTTON_GUIDE 8 +#define GLFW_GAMEPAD_BUTTON_LEFT_THUMB 9 +#define GLFW_GAMEPAD_BUTTON_RIGHT_THUMB 10 +#define GLFW_GAMEPAD_BUTTON_DPAD_UP 11 +#define GLFW_GAMEPAD_BUTTON_DPAD_RIGHT 12 +#define GLFW_GAMEPAD_BUTTON_DPAD_DOWN 13 +#define GLFW_GAMEPAD_BUTTON_DPAD_LEFT 14 +#define GLFW_GAMEPAD_BUTTON_LAST GLFW_GAMEPAD_BUTTON_DPAD_LEFT + +#define GLFW_GAMEPAD_BUTTON_CROSS GLFW_GAMEPAD_BUTTON_A +#define GLFW_GAMEPAD_BUTTON_CIRCLE GLFW_GAMEPAD_BUTTON_B +#define GLFW_GAMEPAD_BUTTON_SQUARE GLFW_GAMEPAD_BUTTON_X +#define GLFW_GAMEPAD_BUTTON_TRIANGLE GLFW_GAMEPAD_BUTTON_Y +/*! @} */ + +/*! @defgroup gamepad_axes Gamepad axes + * @brief Gamepad axes. + * + * See @ref gamepad for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_GAMEPAD_AXIS_LEFT_X 0 +#define GLFW_GAMEPAD_AXIS_LEFT_Y 1 +#define GLFW_GAMEPAD_AXIS_RIGHT_X 2 +#define GLFW_GAMEPAD_AXIS_RIGHT_Y 3 +#define GLFW_GAMEPAD_AXIS_LEFT_TRIGGER 4 +#define GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER 5 +#define GLFW_GAMEPAD_AXIS_LAST GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER +/*! @} */ + /*! @defgroup errors Error codes * @brief Error codes. * @@ -1475,6 +1521,27 @@ typedef struct GLFWimage unsigned char* pixels; } GLFWimage; +/*! @brief Gamepad input state + * + * This describes the input state of a gamepad. + * + * @sa @ref gamepad + * @sa @ref glfwGetGamepadState + * + * @since Added in version 3.3. + */ +typedef struct GLFWgamepadstate +{ + /*! The states of each [gamepad button](@ref gamepad_buttons), `GLFW_PRESS` + * or `GLFW_RELEASE`. + */ + char buttons[15]; + /*! The states of each [gamepad axis](@ref gamepad_axes), in the range -1.0 + * to 1.0 inclusive. + */ + float axes[6]; +} GLFWgamepadstate; + /************************************************************************* * GLFW API functions @@ -4118,9 +4185,9 @@ GLFWAPI int glfwJoystickPresent(int jid); * This function returns the values of all axes of the specified joystick. * Each element in the array is a value between -1.0 and 1.0. * - * Querying a joystick ID with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. Call @ref glfwJoystickPresent to check + * device presence. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of axis values in the returned @@ -4158,9 +4225,9 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count); * _left_. To disable these extra buttons, set the @ref * GLFW_JOYSTICK_HAT_BUTTONS init hint before initialization. * - * Querying a joystick ID with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. Call @ref glfwJoystickPresent to check + * device presence. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of button states in the returned @@ -4215,9 +4282,9 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); * } * @endcode * - * Querying a joystick ID with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. Call @ref glfwJoystickPresent to check + * device presence. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of hat states in the returned @@ -4250,9 +4317,9 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); * The returned string is allocated and freed by GLFW. You should not free it * yourself. * - * Querying a joystick ID with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. Call @ref glfwJoystickPresent to check + * device presence. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick @@ -4275,6 +4342,33 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); */ GLFWAPI const char* glfwGetJoystickName(int jid); +/*! @brief Returns whether the specified joystick has a gamepad mapping. + * + * This function returns whether the specified joystick is both present and has + * a gamepad mapping. + * + * If the specified joystick is present but does not have a gamepad mapping + * this function will return `GLFW_FALSE` but will not generate an error. Call + * @ref glfwJoystickPresent to only check device presence. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return `GLFW_TRUE` if a joystick is both present and has a gamepad mapping, + * or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwGetGamepadState + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwJoystickIsGamepad(int jid); + /*! @brief Sets the joystick configuration callback. * * This function sets the joystick configuration callback, or removes the @@ -4285,7 +4379,7 @@ GLFWAPI const char* glfwGetJoystickName(int jid); * platforms, you need to call one of the [event processing](@ref events) * functions. Joystick disconnection may also be detected and the callback * called by joystick functions. The function will then return whatever it - * returns for a disconnected joystick. + * returns if the joystick is not present. * * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. @@ -4304,6 +4398,105 @@ GLFWAPI const char* glfwGetJoystickName(int jid); */ GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); +/*! @brief Adds the specified SDL_GameControllerDB gamepad mappings. + * + * This function parses the specified ASCII encoded string and updates the + * internal list with any gamepad mappings it finds. This string may + * contain either a single gamepad mapping or many mappings separated by + * newlines. The parser supports the full format of the `gamecontrollerdb.txt` + * source file including empty lines and comments. + * + * See @ref gamepad_mapping for a description of the format. + * + * If there is already a gamepad mapping for a given GUID in the internal list, + * it will be replaced by the one passed to this function. If the library is + * terminated and re-initialized the internal list will revert to the built-in + * default. + * + * @param[in] string The string containing the gamepad mappings. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwJoystickIsGamepad + * @sa @ref glfwGetGamepadName + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwUpdateGamepadMappings(const char* string); + +/*! @brief Returns the human-readable gamepad name for the specified joystick. + * + * This function returns the human-readable name of the gamepad from the + * gamepad mapping assigned to the specified joystick. + * + * If the specified joystick is not present or does not have a gamepad mapping + * this function will return `NULL` but will not generate an error. Call @ref + * glfwJoystickIsGamepad to check whether it is present and has a gamepad mapping. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded name of the gamepad, or `NULL` if the + * joystick is not present, does not have a mapping or an + * [error](@ref error_handling) occurred. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, the gamepad mappings are updated or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwJoystickIsGamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetGamepadName(int jid); + +/*! @brief Retrieves the state of the specified joystick remapped as a gamepad. + * + * This function retrives the state of the specified joystick remapped to + * an Xbox-like gamepad. + * + * If the specified joystick is not present this function will return + * `GLFW_FALSE` but will not generate an error. Call @ref + * glfwJoystickIsGamepad to check whether it is present and has a gamepad + * mapping. + * + * The Guide button may not be available for input as it is often hooked by the + * system or the Steam client. + * + * Not all devices have all the buttons or axes provided by @ref + * GLFWgamepadstate. Unavailable buttons and axes will always report + * `GLFW_RELEASE` and 1.0 respectively. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] state The gamepad input state of the joystick. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if no joystick is + * connected, it has no gamepad mapping or an [error](@ref error_handling) + * occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @sa @ref gamepad + * @sa @ref glfwUpdateGamepadMappings + * @sa @ref glfwJoystickIsGamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); + /*! @brief Sets the clipboard to the specified string. * * This function sets the system clipboard to the specified, UTF-8 encoded diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2d38f10d0..87bd72073 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ -set(common_HEADERS internal.h +set(common_HEADERS internal.h mappings.h "${GLFW_BINARY_DIR}/src/glfw_config.h" "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") diff --git a/src/cocoa_joystick.h b/src/cocoa_joystick.h index 5a668c8c7..d18d032a6 100644 --- a/src/cocoa_joystick.h +++ b/src/cocoa_joystick.h @@ -32,6 +32,7 @@ #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE +#define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X" // Cocoa-specific per-joystick data // diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index d1a230352..02a96acc9 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -43,6 +43,8 @@ typedef struct _GLFWjoyelementNS { IOHIDElementRef native; + uint32_t usage; + int index; long minimum; long maximum; @@ -69,6 +71,23 @@ static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element) return value; } +// Comparison function for matching the SDL element order +// +static CFComparisonResult compareElements(const void* fp, const void* sp, void* user) +{ + const _GLFWjoyelementNS* fe = fp; + const _GLFWjoyelementNS* se = sp; + if (fe->usage < se->usage) + return kCFCompareLessThan; + if (fe->usage > se->usage) + return kCFCompareGreaterThan; + if (fe->index < se->index) + return kCFCompareLessThan; + if (fe->index > se->index) + return kCFCompareGreaterThan; + return kCFCompareEqualTo; +} + // Removes the specified joystick // static void closeJoystick(_GLFWjoystick* js) @@ -103,8 +122,10 @@ static void matchCallback(void* context, { int jid; char name[256]; + char guid[33]; CFIndex i; - CFStringRef productKey; + CFTypeRef property; + uint32_t vendor = 0, product = 0, version = 0; _GLFWjoystick* js; CFMutableArrayRef axes, buttons, hats; @@ -118,10 +139,10 @@ static void matchCallback(void* context, buttons = CFArrayCreateMutable(NULL, 0, NULL); hats = CFArrayCreateMutable(NULL, 0, NULL); - productKey = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); - if (productKey) + property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); + if (property) { - CFStringGetCString(productKey, + CFStringGetCString(property, name, sizeof(name), kCFStringEncodingUTF8); @@ -129,6 +150,34 @@ static void matchCallback(void* context, else strncpy(name, "Unknown", sizeof(name)); + property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)); + if (property) + CFNumberGetValue(property, kCFNumberSInt32Type, &vendor); + + property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)); + if (property) + CFNumberGetValue(property, kCFNumberSInt32Type, &product); + + property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey)); + if (property) + CFNumberGetValue(property, kCFNumberSInt32Type, &version); + + // Generate a joystick GUID that matches the SDL 2.0.5+ one + if (vendor && product) + { + sprintf(guid, "03000000%02x%02x0000%02x%02x0000%02x%02x0000", + (uint8_t) vendor, (uint8_t) (vendor >> 8), + (uint8_t) product, (uint8_t) (product >> 8), + (uint8_t) version, (uint8_t) (version >> 8)); + } + else + { + sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7], + name[8], name[9], name[10]); + } + CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); @@ -147,12 +196,13 @@ static void matchCallback(void* context, } CFMutableArrayRef target = NULL; + const uint32_t usage = IOHIDElementGetUsage(native); switch (IOHIDElementGetUsagePage(native)) { case kHIDPage_GenericDesktop: { - switch (IOHIDElementGetUsage(native)) + switch (usage) { case kHIDUsage_GD_X: case kHIDUsage_GD_Y: @@ -184,6 +234,8 @@ static void matchCallback(void* context, { _GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS)); element->native = native; + element->usage = usage; + element->index = (int) CFArrayGetCount(target); element->minimum = IOHIDElementGetLogicalMin(native); element->maximum = IOHIDElementGetLogicalMax(native); CFArrayAppendValue(target, element); @@ -192,7 +244,14 @@ static void matchCallback(void* context, CFRelease(elements); - js = _glfwAllocJoystick(name, + CFArraySortValues(axes, CFRangeMake(0, CFArrayGetCount(axes)), + compareElements, NULL); + CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)), + compareElements, NULL); + CFArraySortValues(hats, CFRangeMake(0, CFArrayGetCount(hats)), + compareElements, NULL); + + js = _glfwAllocJoystick(name, guid, CFArrayGetCount(axes), CFArrayGetCount(buttons), CFArrayGetCount(hats)); @@ -329,7 +388,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (mode == _GLFW_POLL_AXES) + if (mode & _GLFW_POLL_AXES) { CFIndex i; @@ -355,7 +414,8 @@ int _glfwPlatformPollJoystick(int jid, int mode) } } } - else if (mode == _GLFW_POLL_BUTTONS) + + if (mode & _GLFW_POLL_BUTTONS) { CFIndex i; @@ -395,3 +455,15 @@ int _glfwPlatformPollJoystick(int jid, int mode) return js->present; } +void _glfwPlatformUpdateGamepadGUID(char* guid) +{ + if ((strncmp(guid + 4, "000000000000", 12) == 0) && + (strncmp(guid + 20, "000000000000", 12) == 0)) + { + char original[33]; + strcpy(original, guid); + sprintf(guid, "03000000%.4s0000%.4s000000000000", + original, original + 16); + } +} + diff --git a/src/init.c b/src/init.c index 307ca0099..7f7d87eab 100644 --- a/src/init.c +++ b/src/init.c @@ -26,6 +26,7 @@ //======================================================================== #include "internal.h" +#include "mappings.h" #include #include @@ -111,6 +112,10 @@ static void terminate(void) _glfw.monitors = NULL; _glfw.monitorCount = 0; + free(_glfw.mappings); + _glfw.mappings = NULL; + _glfw.mappingCount = 0; + _glfwTerminateVulkan(); _glfwPlatformTerminate(); @@ -209,8 +214,8 @@ GLFWAPI int glfwInit(void) _glfw.initialized = GLFW_TRUE; _glfw.timer.offset = _glfwPlatformGetTimerValue(); - // Not all window hints have zero as their default value glfwDefaultWindowHints(); + glfwUpdateGamepadMappings(_glfwDefaultMappings); return GLFW_TRUE; } diff --git a/src/input.c b/src/input.c index 6a510ec78..ea4aa136d 100644 --- a/src/input.c +++ b/src/input.c @@ -29,12 +29,144 @@ #include #include +#include #include #include +#include // Internal key state used for sticky keys #define _GLFW_STICK 3 +// Internal constants for gamepad mapping source types +#define _GLFW_JOYSTICK_AXIS 1 +#define _GLFW_JOYSTICK_BUTTON 2 +#define _GLFW_JOYSTICK_HATBIT 3 + +// Finds a mapping based on joystick GUID +// +static _GLFWmapping* findMapping(const char* guid) +{ + int i; + + for (i = 0; i < _glfw.mappingCount; i++) + { + if (strcmp(_glfw.mappings[i].guid, guid) == 0) + return _glfw.mappings + i; + } + + return NULL; +} + +// Parses an SDL_GameControllerDB line and adds it to the mapping list +// +static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) +{ + const char* c = string; + size_t i, length; + struct + { + const char* name; + _GLFWmapelement* element; + } fields[] = + { + { "platform", NULL }, + { "a", mapping->buttons + GLFW_GAMEPAD_BUTTON_A }, + { "b", mapping->buttons + GLFW_GAMEPAD_BUTTON_B }, + { "x", mapping->buttons + GLFW_GAMEPAD_BUTTON_X }, + { "y", mapping->buttons + GLFW_GAMEPAD_BUTTON_Y }, + { "back", mapping->buttons + GLFW_GAMEPAD_BUTTON_BACK }, + { "start", mapping->buttons + GLFW_GAMEPAD_BUTTON_START }, + { "guide", mapping->buttons + GLFW_GAMEPAD_BUTTON_GUIDE }, + { "leftshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_BUMPER }, + { "rightshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER }, + { "leftstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_THUMB }, + { "rightstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_THUMB }, + { "dpup", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_UP }, + { "dpright", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_RIGHT }, + { "dpdown", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_DOWN }, + { "dpleft", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_LEFT }, + { "lefttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_TRIGGER }, + { "righttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER }, + { "leftx", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_X }, + { "lefty", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_Y }, + { "rightx", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_X }, + { "righty", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_Y } + }; + + length = strcspn(c, ","); + if (length != 32 || c[length] != ',') + { + _glfwInputError(GLFW_INVALID_VALUE, NULL); + return GLFW_FALSE; + } + + memcpy(mapping->guid, c, length); + c += length + 1; + + length = strcspn(c, ","); + if (length >= sizeof(mapping->name) || c[length] != ',') + { + _glfwInputError(GLFW_INVALID_VALUE, NULL); + return GLFW_FALSE; + } + + memcpy(mapping->name, c, length); + c += length + 1; + + while (*c) + { + for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) + { + length = strlen(fields[i].name); + if (strncmp(c, fields[i].name, length) != 0 || c[length] != ':') + continue; + + c += length + 1; + + if (fields[i].element) + { + if (*c == 'a') + fields[i].element->type = _GLFW_JOYSTICK_AXIS; + else if (*c == 'b') + fields[i].element->type = _GLFW_JOYSTICK_BUTTON; + else if (*c == 'h') + fields[i].element->type = _GLFW_JOYSTICK_HATBIT; + else + break; + + if (fields[i].element->type == _GLFW_JOYSTICK_HATBIT) + { + const unsigned int hat = strtoul(c + 1, (char**) &c, 10); + const unsigned int bit = strtoul(c + 1, (char**) &c, 10); + fields[i].element->value = (hat << 4) | bit; + } + else + fields[i].element->value = (uint8_t) strtoul(c + 1, (char**) &c, 10); + } + else + { + length = strlen(_GLFW_PLATFORM_MAPPING_NAME); + if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0) + return GLFW_FALSE; + } + + break; + } + + c += strcspn(c, ","); + c += strspn(c, ","); + } + + for (i = 0; i < 32; i++) + { + if (mapping->guid[i] >= 'A' && mapping->guid[i] <= 'F') + mapping->guid[i] += 'a' - 'A'; + } + + _glfwPlatformUpdateGamepadGUID(mapping->guid); + return GLFW_TRUE; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW event API ////// @@ -166,6 +298,7 @@ GLFWbool _glfwIsPrintable(int key) } _GLFWjoystick* _glfwAllocJoystick(const char* name, + const char* guid, int axisCount, int buttonCount, int hatCount) @@ -191,6 +324,9 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, js->axisCount = axisCount; js->buttonCount = buttonCount; js->hatCount = hatCount; + js->mapping = findMapping(guid); + + strcpy(js->guid, guid); return js; } @@ -748,6 +884,177 @@ GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) return cbfun; } +GLFWAPI int glfwUpdateGamepadMappings(const char* string) +{ + int jid; + const char* c = string; + + assert(string != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + while (*c) + { + if (isxdigit(*c)) + { + char line[1024]; + + const size_t length = strcspn(c, "\r\n"); + if (length < sizeof(line)) + { + _GLFWmapping mapping = {{0}}; + + memcpy(line, c, length); + line[length] = '\0'; + + if (parseMapping(&mapping, line)) + { + _GLFWmapping* previous = findMapping(mapping.guid); + if (previous) + *previous = mapping; + else + { + _glfw.mappingCount++; + _glfw.mappings = + realloc(_glfw.mappings, + sizeof(_GLFWmapping) * _glfw.mappingCount); + _glfw.mappings[_glfw.mappingCount - 1] = mapping; + } + } + } + + c += length; + } + else + { + c += strcspn(c, "\r\n"); + c += strspn(c, "\r\n"); + } + } + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks + jid; + if (js->present) + js->mapping = findMapping(js->guid); + } + + return GLFW_TRUE; +} + +GLFWAPI int glfwJoystickIsGamepad(int jid) +{ + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return GLFW_FALSE; + } + + if (!_glfw.joysticks[jid].present) + return GLFW_FALSE; + + if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE)) + return GLFW_FALSE; + + return _glfw.joysticks[jid].mapping != NULL; +} + +GLFWAPI const char* glfwGetGamepadName(int jid) +{ + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return NULL; + } + + if (!_glfw.joysticks[jid].present) + return NULL; + + if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE)) + return NULL; + + if (!_glfw.joysticks[jid].mapping) + return NULL; + + return _glfw.joysticks[jid].mapping->name; +} + +GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) +{ + int i; + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(state != NULL); + + memset(state, 0, sizeof(GLFWgamepadstate)); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return GLFW_FALSE; + } + + js = _glfw.joysticks + jid; + + if (!js->present) + return GLFW_FALSE; + + if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_ALL)) + return GLFW_FALSE; + + if (!js->mapping) + return GLFW_FALSE; + + for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) + { + if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_AXIS) + { + if (fabs(js->axes[js->mapping->buttons[i].value]) > 0.5) + state->buttons[i] = GLFW_PRESS; + } + else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) + { + const unsigned int hat = js->mapping->buttons[i].value >> 4; + const unsigned int bit = js->mapping->buttons[i].value & 0xf; + if (js->hats[hat] & bit) + state->buttons[i] = GLFW_PRESS; + } + else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_BUTTON) + state->buttons[i] = js->buttons[js->mapping->buttons[i].value]; + } + + for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) + { + if (js->mapping->axes[i].type == _GLFW_JOYSTICK_AXIS) + state->axes[i] = js->axes[js->mapping->axes[i].value]; + else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) + { + const unsigned int hat = js->mapping->buttons[i].value >> 4; + const unsigned int bit = js->mapping->buttons[i].value & 0xf; + if (js->hats[hat] & bit) + state->axes[i] = 1.f; + } + else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_BUTTON) + state->axes[i] = (float) js->buttons[js->mapping->axes[i].value]; + } + + return GLFW_TRUE; +} + GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/internal.h b/src/internal.h index 0da36741b..1ec302ce6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -52,6 +52,7 @@ #define _GLFW_POLL_PRESENCE 0 #define _GLFW_POLL_AXES 1 #define _GLFW_POLL_BUTTONS 2 +#define _GLFW_POLL_ALL (_GLFW_POLL_AXES | _GLFW_POLL_BUTTONS) typedef int GLFWbool; @@ -65,6 +66,8 @@ typedef struct _GLFWwindow _GLFWwindow; typedef struct _GLFWlibrary _GLFWlibrary; typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; +typedef struct _GLFWmapelement _GLFWmapelement; +typedef struct _GLFWmapping _GLFWmapping; typedef struct _GLFWjoystick _GLFWjoystick; typedef struct _GLFWtls _GLFWtls; typedef struct _GLFWmutex _GLFWmutex; @@ -474,6 +477,24 @@ struct _GLFWcursor _GLFW_PLATFORM_CURSOR_STATE; }; +/*! @brief Gamepad mapping element structure + */ +struct _GLFWmapelement +{ + uint8_t type; + uint8_t value; +}; + +/*! @brief Gamepad mapping structure + */ +struct _GLFWmapping +{ + char name[128]; + char guid[33]; + _GLFWmapelement buttons[15]; + _GLFWmapelement axes[6]; +}; + /*! @brief Joystick structure */ struct _GLFWjoystick @@ -486,6 +507,8 @@ struct _GLFWjoystick unsigned char* hats; int hatCount; char* name; + char guid[33]; + _GLFWmapping* mapping; // This is defined in the joystick API's joystick.h _GLFW_PLATFORM_JOYSTICK_STATE; @@ -529,6 +552,8 @@ struct _GLFWlibrary int monitorCount; _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; + _GLFWmapping* mappings; + int mappingCount; _GLFWtls errorSlot; _GLFWtls contextSlot; @@ -621,6 +646,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); int _glfwPlatformPollJoystick(int jid, int mode); +void _glfwPlatformUpdateGamepadGUID(char* guid); uint64_t _glfwPlatformGetTimerValue(void); uint64_t _glfwPlatformGetTimerFrequency(void); @@ -956,7 +982,11 @@ void _glfwFreeMonitor(_GLFWmonitor* monitor); /*! @brief Returns an available joystick object with arrays and name allocated. * @ingroup utility */ -_GLFWjoystick* _glfwAllocJoystick(const char* name, int axisCount, int buttonCount, int hatCount); +_GLFWjoystick* _glfwAllocJoystick(const char* name, + const char* guid, + int axisCount, + int buttonCount, + int hatCount); /*! @brief Frees arrays and name and flags the joystick object as unused. * @ingroup utility diff --git a/src/linux_joystick.c b/src/linux_joystick.c index c314cdca4..172de93bd 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -124,10 +124,12 @@ static GLFWbool openJoystickDevice(const char* path) { int jid, code; char name[256] = ""; + char guid[33] = ""; char evBits[(EV_CNT + 7) / 8] = {0}; char keyBits[(KEY_CNT + 7) / 8] = {0}; char absBits[(ABS_CNT + 7) / 8] = {0}; int axisCount = 0, buttonCount = 0, hatCount = 0; + struct input_id id; _GLFWjoystickLinux linjs = {0}; _GLFWjoystick* js = NULL; @@ -145,10 +147,11 @@ static GLFWbool openJoystickDevice(const char* path) if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 || ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 || - ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0) + ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 || + ioctl(linjs.fd, EVIOCGID, &id) < 0) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Linux: Failed to query input device elements: %s", + "Linux: Failed to query input device: %s", strerror(errno)); close(linjs.fd); return GLFW_FALSE; @@ -164,6 +167,24 @@ static GLFWbool openJoystickDevice(const char* path) if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0) strncpy(name, "Unknown", sizeof(name)); + // Generate a joystick GUID that matches the SDL 2.0.5+ one + if (id.vendor && id.product && id.version) + { + sprintf(guid, "%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000", + id.bustype & 0xff, id.bustype >> 8, + id.vendor & 0xff, id.vendor >> 8, + id.product & 0xff, id.product >> 8, + id.version & 0xff, id.version >> 8); + } + else + { + sprintf(guid, "%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", + id.bustype & 0xff, id.bustype >> 8, + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7], + name[8], name[9], name[10]); + } + for (code = BTN_MISC; code < KEY_CNT; code++) { if (!isBitSet(code, keyBits)) @@ -196,7 +217,7 @@ static GLFWbool openJoystickDevice(const char* path) } } - js = _glfwAllocJoystick(name, axisCount, buttonCount, hatCount); + js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount); if (!js) { close(linjs.fd); @@ -419,3 +440,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) return js->present; } +void _glfwPlatformUpdateGamepadGUID(char* guid) +{ +} + diff --git a/src/linux_joystick.h b/src/linux_joystick.h index 227a6ed9b..2eabfa134 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -31,6 +31,8 @@ #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs +#define _GLFW_PLATFORM_MAPPING_NAME "Linux" + // Linux-specific joystick data // typedef struct _GLFWjoystickLinux diff --git a/src/mappings.h b/src/mappings.h new file mode 100644 index 000000000..2141e520d --- /dev/null +++ b/src/mappings.h @@ -0,0 +1,230 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +// All gamepad mappings not labeled GLFW are copied from the +// SDL_GameControllerDB project under the following license: +// +// Simple DirectMedia Layer +// Copyright (C) 1997-2013 Sam Lantinga +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +const char* _glfwDefaultMappings = +"8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,\n" +"6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,\n" +"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,\n" +"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,\n" +"4c05c405000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,\n" +"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" +"00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" +"00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" +"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" +"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,\n" +"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,\n" +"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" +"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,\n" +"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,\n" +"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" +"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,\n" +"63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"ff113133000000000000504944564944,Gembird JPD-DualForce,platform:Windows,a:b2,b:b3,x:b0,y:b1,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11,\n" +"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" +"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,\n" +"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,\n" +"79000600000000000000504944564944,NGS Phantom,a:b2,b:b3,y:b1,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,\n" +"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" +"6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" +"6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" +"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" +"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,\n" +"4c05000000000000c405000000000000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" +"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" +"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" +"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,\n" +"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,\n" +"8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" +"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" +"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,\n" +"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X,\n" +"5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,\n" +"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,\n" +"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" +"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,\n" +"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,\n" +"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,\n" +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,\n" +"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,\n" +"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" +"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,\n" +"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" +"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,\n" +"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,\n" +"030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" +"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" +"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" +"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,\n" +"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,\n" +"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,\n" +"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,\n" +"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" +"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" +"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,\n" +"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,\n" +"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" +"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" +"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" +"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a3,rightx:a1,righty:a4,\n" +"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,\n" +"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" +"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" +"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" +"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,\n" +"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,\n" +"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7\n" +"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000790000001100000010010000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,\n" +"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" +"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,\n" +"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" +"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,\n" +"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,\n" +"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,\n" +"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,\n" +"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" +"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,\n" +"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,\n" +"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" +"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" +"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,\n" +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n"; + diff --git a/src/null_joystick.c b/src/null_joystick.c index 276de3bf0..2311d91f7 100644 --- a/src/null_joystick.c +++ b/src/null_joystick.c @@ -36,3 +36,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) return GLFW_FALSE; } +void _glfwPlatformUpdateGamepadGUID(char* guid) +{ +} + diff --git a/src/null_joystick.h b/src/null_joystick.h index 3de734583..3075815d0 100644 --- a/src/null_joystick.h +++ b/src/null_joystick.h @@ -27,3 +27,5 @@ #define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs +#define _GLFW_PLATFORM_MAPPING_NAME "" + diff --git a/src/win32_joystick.c b/src/win32_joystick.c index f3a9726cd..fe00747a3 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -27,6 +27,7 @@ #include "internal.h" +#include #include #define _GLFW_TYPE_AXIS 0 @@ -155,9 +156,9 @@ static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic) case XINPUT_DEVSUBTYPE_GAMEPAD: { if (xic->Flags & XINPUT_CAPS_WIRELESS) - return "Wireless Xbox 360 Controller"; + return "Wireless Xbox Controller"; else - return "Xbox 360 Controller"; + return "Xbox Controller"; } } @@ -257,7 +258,7 @@ static void closeJoystick(_GLFWjoystick* js) } // DirectInput device object enumeration callback -// Insights gleaned from SDL2 +// Insights gleaned from SDL // static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi, void* user) @@ -339,6 +340,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) IDirectInputDevice8* device; _GLFWobjenumWin32 data; _GLFWjoystick* js; + char guid[33]; char name[256]; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) @@ -434,7 +436,24 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) return DIENUM_STOP; } - js = _glfwAllocJoystick(name, + // Generate a joystick GUID that matches the SDL 2.0.5+ one + if (memcmp(&di->guidProduct.Data4[2], "PIDVID", 6) == 0) + { + sprintf(guid, "03000000%02x%02x0000%02x%02x000000000000", + (uint8_t) di->guidProduct.Data1, + (uint8_t) (di->guidProduct.Data1 >> 8), + (uint8_t) (di->guidProduct.Data1 >> 16), + (uint8_t) (di->guidProduct.Data1 >> 24)); + } + else + { + sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7], + name[8], name[9], name[10]); + } + + js = _glfwAllocJoystick(name, guid, data.axisCount + data.sliderCount, data.buttonCount, data.povCount); @@ -503,6 +522,7 @@ void _glfwDetectJoystickConnectionWin32(void) for (index = 0; index < XUSER_MAX_COUNT; index++) { int jid; + char guid[33]; XINPUT_CAPABILITIES xic; _GLFWjoystick* js; @@ -522,7 +542,11 @@ void _glfwDetectJoystickConnectionWin32(void) if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS) continue; - js = _glfwAllocJoystick(getDeviceDescription(&xic), 6, 10, 1); + // Generate a joystick GUID that matches the SDL 2.0.5+ one + sprintf(guid, "78696e707574%02x000000000000000000", + xic.SubType & 0xff); + + js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1); if (!js) continue; @@ -727,3 +751,14 @@ int _glfwPlatformPollJoystick(int jid, int mode) return GLFW_TRUE; } +void _glfwPlatformUpdateGamepadGUID(char* guid) +{ + if (strcmp(guid + 20, "504944564944") == 0) + { + char original[33]; + strcpy(original, guid); + sprintf(guid, "03000000%.4s0000%.4s000000000000", + original, original + 4); + } +} + diff --git a/src/win32_joystick.h b/src/win32_joystick.h index 54102e62f..9156f6c15 100644 --- a/src/win32_joystick.h +++ b/src/win32_joystick.h @@ -27,6 +27,7 @@ #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickWin32 win32 #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int dummy +#define _GLFW_PLATFORM_MAPPING_NAME "Windows" // Joystick element (axis, button or slider) // diff --git a/tests/joysticks.c b/tests/joysticks.c index 3a7a90c77..8a6ff7445 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -92,6 +92,55 @@ static const char* joystick_label(int jid) return label; } +static void hat_widget(struct nk_context* nk, unsigned char state) +{ + float radius; + struct nk_rect area; + struct nk_vec2 center; + + if (nk_widget(&area, nk) != NK_WIDGET_VALID) + return; + + center = nk_vec2(area.x + area.w / 2.f, area.y + area.h / 2.f); + radius = NK_MIN(area.w, area.h) / 2.f; + + nk_stroke_circle(nk_window_get_canvas(nk), + nk_rect(center.x - radius, + center.y - radius, + radius * 2.f, + radius * 2.f), + 1.f, + nk_rgb(175, 175, 175)); + + if (state) + { + const float angles[] = + { + 0.f, 0.f, + NK_PI * 1.5f, NK_PI * 1.75f, + NK_PI, 0.f, + NK_PI * 1.25f, 0.f, + NK_PI * 0.5f, NK_PI * 0.25f, + 0.f, 0.f, + NK_PI * 0.75f, 0.f, + }; + const float cosa = nk_cos(angles[state]); + const float sina = nk_sin(angles[state]); + const struct nk_vec2 p0 = nk_vec2(0.f, -radius); + const struct nk_vec2 p1 = nk_vec2( radius / 2.f, -radius / 3.f); + const struct nk_vec2 p2 = nk_vec2(-radius / 2.f, -radius / 3.f); + + nk_fill_triangle(nk_window_get_canvas(nk), + center.x + cosa * p0.x + sina * p0.y, + center.y + cosa * p0.y - sina * p0.x, + center.x + cosa * p1.x + sina * p1.y, + center.y + cosa * p1.y - sina * p1.x, + center.x + cosa * p2.x + sina * p2.y, + center.y + cosa * p2.y - sina * p2.x, + nk_rgb(175, 175, 175)); + } +} + int main(void) { int jid, hat_buttons = GLFW_FALSE; @@ -105,7 +154,7 @@ int main(void) if (!glfwInit()) exit(EXIT_FAILURE); - window = glfwCreateWindow(640, 480, "Joystick Test", NULL, NULL); + window = glfwCreateWindow(800, 600, "Joystick Test", NULL, NULL); if (!window) { glfwTerminate(); @@ -165,7 +214,7 @@ int main(void) { if (nk_begin(nk, joystick_label(joysticks[i]), - nk_rect(i * 20.f, i * 20.f, 400.f, 400.f), + nk_rect(i * 20.f, i * 20.f, 550.f, 570.f), NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE | @@ -176,8 +225,10 @@ int main(void) const float* axes; const unsigned char* buttons; const unsigned char* hats; + GLFWgamepadstate state; nk_layout_row_dynamic(nk, 30, 1); + nk_label(nk, "Joystick state", NK_TEXT_LEFT); axes = glfwGetJoystickAxes(joysticks[i], &axis_count); buttons = glfwGetJoystickButtons(joysticks[i], &button_count); @@ -189,7 +240,7 @@ int main(void) for (j = 0; j < axis_count; j++) nk_slide_float(nk, -1.f, axes[j], 1.f, 0.1f); - nk_layout_row_dynamic(nk, 30, 8); + nk_layout_row_dynamic(nk, 30, 12); for (j = 0; j < button_count; j++) { @@ -201,54 +252,47 @@ int main(void) nk_layout_row_dynamic(nk, 30, 8); for (j = 0; j < hat_count; j++) + hat_widget(nk, hats[j]); + + nk_layout_row_dynamic(nk, 30, 1); + + if (glfwGetGamepadState(joysticks[i], &state)) { - float radius; - struct nk_rect area; - struct nk_vec2 center; - - if (nk_widget(&area, nk) != NK_WIDGET_VALID) - continue; - - center = nk_vec2(area.x + area.w / 2.f, - area.y + area.h / 2.f); - radius = NK_MIN(area.w, area.h) / 2.f; - - nk_stroke_circle(nk_window_get_canvas(nk), - nk_rect(center.x - radius, - center.y - radius, - radius * 2.f, - radius * 2.f), - 1.f, - nk_rgb(175, 175, 175)); - - if (hats[j]) + int hat = 0; + const char* names[GLFW_GAMEPAD_BUTTON_LAST + 1 - 4] = { - const float angles[] = - { - 0.f, 0.f, - NK_PI * 1.5f, NK_PI * 1.75f, - NK_PI, 0.f, - NK_PI * 1.25f, 0.f, - NK_PI * 0.5f, NK_PI * 0.25f, - 0.f, 0.f, - NK_PI * 0.75f, 0.f, - }; - const float cosa = nk_cos(angles[hats[j]]); - const float sina = nk_sin(angles[hats[j]]); - const struct nk_vec2 p0 = nk_vec2(0.f, -radius); - const struct nk_vec2 p1 = nk_vec2( radius / 2.f, -radius / 3.f); - const struct nk_vec2 p2 = nk_vec2(-radius / 2.f, -radius / 3.f); + "A", "B", "X", "Y", + "LB", "RB", + "Back", "Start", "Guide", + "LT", "RT", + }; - nk_fill_triangle(nk_window_get_canvas(nk), - center.x + cosa * p0.x + sina * p0.y, - center.y + cosa * p0.y - sina * p0.x, - center.x + cosa * p1.x + sina * p1.y, - center.y + cosa * p1.y - sina * p1.x, - center.x + cosa * p2.x + sina * p2.y, - center.y + cosa * p2.y - sina * p2.x, - nk_rgb(175, 175, 175)); - } + nk_label(nk, "Gamepad state", NK_TEXT_LEFT); + + nk_layout_row_dynamic(nk, 30, 2); + + for (j = 0; j <= GLFW_GAMEPAD_AXIS_LAST; j++) + nk_slide_float(nk, -1.f, state.axes[j], 1.f, 0.1f); + + nk_layout_row_dynamic(nk, 30, GLFW_GAMEPAD_BUTTON_LAST + 1 - 4); + + for (j = 0; j <= GLFW_GAMEPAD_BUTTON_LAST - 4; j++) + nk_select_label(nk, names[j], NK_TEXT_CENTERED, state.buttons[j]); + + if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP]) + hat |= GLFW_HAT_UP; + if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT]) + hat |= GLFW_HAT_RIGHT; + if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN]) + hat |= GLFW_HAT_DOWN; + if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT]) + hat |= GLFW_HAT_LEFT; + + nk_layout_row_dynamic(nk, 30, 8); + hat_widget(nk, hat); } + else + nk_label(nk, "Joystick has no gamepad mapping", NK_TEXT_LEFT); } nk_end(nk); From 617c42b20ab48715934f4fa27af5cae738837eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 9 Jul 2017 14:01:48 +0200 Subject: [PATCH 080/222] Cleanup --- src/cocoa_joystick.m | 16 ++++---- src/input.c | 92 ++++++++++++++++++++++++++------------------ src/internal.h | 21 +++++----- src/linux_joystick.c | 15 +++----- src/win32_joystick.c | 22 +++++------ 5 files changed, 86 insertions(+), 80 deletions(-) diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 02a96acc9..81c7e2dca 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -110,7 +110,7 @@ static void closeJoystick(_GLFWjoystick* js) CFRelease(js->ns.hats); _glfwFreeJoystick(js); - _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_DISCONNECTED); + _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Callback for user-initiated joystick addition @@ -261,7 +261,7 @@ static void matchCallback(void* context, js->ns.buttons = buttons; js->ns.hats = hats; - _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED); + _glfwInputJoystick(js, GLFW_CONNECTED); } // Callback for user-initiated joystick removal @@ -384,10 +384,8 @@ void _glfwTerminateJoysticksNS(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformPollJoystick(int jid, int mode) +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { - _GLFWjoystick* js = _glfw.joysticks + jid; - if (mode & _GLFW_POLL_AXES) { CFIndex i; @@ -406,11 +404,11 @@ int _glfwPlatformPollJoystick(int jid, int mode) const long delta = axis->maximum - axis->minimum; if (delta == 0) - _glfwInputJoystickAxis(jid, i, 0.f); + _glfwInputJoystickAxis(js, i, 0.f); else { const float value = (2.f * (raw - axis->minimum) / delta) - 1.f; - _glfwInputJoystickAxis(jid, i, value); + _glfwInputJoystickAxis(js, i, value); } } } @@ -424,7 +422,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.buttons, i); const char value = getElementValue(js, button) - button->minimum; - _glfwInputJoystickButton(jid, i, value); + _glfwInputJoystickButton(js, i, value); } for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) @@ -448,7 +446,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) if (state < 0 || state > 8) state = 8; - _glfwInputJoystickHat(jid, i, states[state]); + _glfwInputJoystickHat(js, i, states[state]); } } diff --git a/src/input.c b/src/input.c index ea4aa136d..523bfa98a 100644 --- a/src/input.c +++ b/src/input.c @@ -256,25 +256,24 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) window->callbacks.drop((GLFWwindow*) window, count, paths); } -void _glfwInputJoystick(int jid, int event) +void _glfwInputJoystick(_GLFWjoystick* js, int event) { if (_glfw.callbacks.joystick) - _glfw.callbacks.joystick(jid, event); + _glfw.callbacks.joystick(js - _glfw.joysticks, event); } -void _glfwInputJoystickAxis(int jid, int axis, float value) +void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) { - _glfw.joysticks[jid].axes[axis] = value; + js->axes[axis] = value; } -void _glfwInputJoystickButton(int jid, int button, char value) +void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) { - _glfw.joysticks[jid].buttons[button] = value; + js->buttons[button] = value; } -void _glfwInputJoystickHat(int jid, int hat, char value) +void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) { - _GLFWjoystick* js = _glfw.joysticks + jid; const int base = js->buttonCount + hat * 4; js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; @@ -753,6 +752,8 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) GLFWAPI int glfwJoystickPresent(int jid) { + _GLFWjoystick* js; + assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); @@ -764,14 +765,17 @@ GLFWAPI int glfwJoystickPresent(int jid) return GLFW_FALSE; } - if (!_glfw.joysticks[jid].present) + js = _glfw.joysticks + jid; + if (!js->present) return GLFW_FALSE; - return _glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE); + return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); } GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) { + _GLFWjoystick* js; + assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); assert(count != NULL); @@ -786,18 +790,21 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) return NULL; } - if (!_glfw.joysticks[jid].present) + js = _glfw.joysticks + jid; + if (!js->present) return NULL; - if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_AXES)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) return NULL; - *count = _glfw.joysticks[jid].axisCount; - return _glfw.joysticks[jid].axes; + *count = js->axisCount; + return js->axes; } GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) { + _GLFWjoystick* js; + assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); assert(count != NULL); @@ -812,25 +819,25 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) return NULL; } - if (!_glfw.joysticks[jid].present) + js = _glfw.joysticks + jid; + if (!js->present) return NULL; - if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_BUTTONS)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) return NULL; if (_glfw.hints.init.hatButtons) - { - *count = _glfw.joysticks[jid].buttonCount + - _glfw.joysticks[jid].hatCount * 4; - } + *count = js->buttonCount + js->hatCount * 4; else - *count = _glfw.joysticks[jid].buttonCount; + *count = js->buttonCount; - return _glfw.joysticks[jid].buttons; + return js->buttons; } GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) { + _GLFWjoystick* js; + assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); assert(count != NULL); @@ -845,18 +852,21 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) return NULL; } - if (!_glfw.joysticks[jid].present) + js = _glfw.joysticks + jid; + if (!js->present) return NULL; - if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_BUTTONS)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) return NULL; - *count = _glfw.joysticks[jid].hatCount; - return _glfw.joysticks[jid].hats; + *count = js->hatCount; + return js->hats; } GLFWAPI const char* glfwGetJoystickName(int jid) { + _GLFWjoystick* js; + assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); @@ -868,13 +878,14 @@ GLFWAPI const char* glfwGetJoystickName(int jid) return NULL; } - if (!_glfw.joysticks[jid].present) + js = _glfw.joysticks + jid; + if (!js->present) return NULL; - if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; - return _glfw.joysticks[jid].name; + return js->name; } GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) @@ -944,6 +955,8 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) GLFWAPI int glfwJoystickIsGamepad(int jid) { + _GLFWjoystick* js; + assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); @@ -955,17 +968,20 @@ GLFWAPI int glfwJoystickIsGamepad(int jid) return GLFW_FALSE; } - if (!_glfw.joysticks[jid].present) + js = _glfw.joysticks + jid; + if (!js->present) return GLFW_FALSE; - if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return GLFW_FALSE; - return _glfw.joysticks[jid].mapping != NULL; + return js->mapping != NULL; } GLFWAPI const char* glfwGetGamepadName(int jid) { + _GLFWjoystick* js; + assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); @@ -977,16 +993,17 @@ GLFWAPI const char* glfwGetGamepadName(int jid) return NULL; } - if (!_glfw.joysticks[jid].present) + js = _glfw.joysticks + jid; + if (!js->present) return NULL; - if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; - if (!_glfw.joysticks[jid].mapping) + if (!js->mapping) return NULL; - return _glfw.joysticks[jid].mapping->name; + return js->mapping->name; } GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) @@ -1009,11 +1026,10 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) } js = _glfw.joysticks + jid; - if (!js->present) return GLFW_FALSE; - if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_ALL)) + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) return GLFW_FALSE; if (!js->mapping) diff --git a/src/internal.h b/src/internal.h index 1ec302ce6..d00c7fc0f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -254,9 +254,6 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void); y = t; \ } -// Maps a joystick pointer to an ID -#define _GLFW_JOYSTICK_ID(js) ((int) ((js) - _glfw.joysticks)) - //======================================================================== // Platform-independent structures @@ -645,7 +642,7 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); -int _glfwPlatformPollJoystick(int jid, int mode); +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); void _glfwPlatformUpdateGamepadGUID(char* guid); uint64_t _glfwPlatformGetTimerValue(void); @@ -866,32 +863,32 @@ void _glfwInputError(int code, const char* format, ...); void _glfwInputDrop(_GLFWwindow* window, int count, const char** names); /*! @brief Notifies shared code of a joystick connection or disconnection. - * @param[in] jid The joystick that was connected or disconnected. + * @param[in] js The joystick that was connected or disconnected. * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. * @ingroup event */ -void _glfwInputJoystick(int jid, int event); +void _glfwInputJoystick(_GLFWjoystick* js, int event); /*! @brief Notifies shared code of the new value of a joystick axis. - * @param[in] jid The joystick whose axis to update. + * @param[in] js The joystick whose axis to update. * @param[in] axis The index of the axis to update. * @param[in] value The new value of the axis. */ -void _glfwInputJoystickAxis(int jid, int axis, float value); +void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value); /*! @brief Notifies shared code of the new value of a joystick button. - * @param[in] jid The joystick whose button to update. + * @param[in] js The joystick whose button to update. * @param[in] button The index of the button to update. * @param[in] value The new value of the button. */ -void _glfwInputJoystickButton(int jid, int button, char value); +void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value); /*! @brief Notifies shared code of the new value of a joystick hat. - * @param[in] jid The joystick whose hat to update. + * @param[in] js The joystick whose hat to update. * @param[in] button The index of the hat to update. * @param[in] value The new value of the hat. */ -void _glfwInputJoystickHat(int jid, int hat, char value); +void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value); //======================================================================== diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 172de93bd..a16f208c8 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -42,7 +42,7 @@ // static void handleKeyEvent(_GLFWjoystick* js, int code, int value) { - _glfwInputJoystickButton(_GLFW_JOYSTICK_ID(js), + _glfwInputJoystickButton(js, js->linjs.keyMap[code - BTN_MISC], value ? GLFW_PRESS : GLFW_RELEASE); } @@ -51,7 +51,6 @@ static void handleKeyEvent(_GLFWjoystick* js, int code, int value) // static void handleAbsEvent(_GLFWjoystick* js, int code, int value) { - const int jid = _GLFW_JOYSTICK_ID(js); const int index = js->linjs.absMap[code]; if (code >= ABS_HAT0X && code <= ABS_HAT3Y) @@ -76,7 +75,7 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value) else if (value > 0) state[axis] = 2; - _glfwInputJoystickHat(jid, index, stateMap[state[0]][state[1]]); + _glfwInputJoystickHat(js, index, stateMap[state[0]][state[1]]); } else { @@ -92,7 +91,7 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value) normalized = normalized * 2.0f - 1.0f; } - _glfwInputJoystickAxis(jid, index, normalized); + _glfwInputJoystickAxis(js, index, normalized); } } @@ -229,7 +228,7 @@ static GLFWbool openJoystickDevice(const char* path) pollAbsState(js); - _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED); + _glfwInputJoystick(js, GLFW_CONNECTED); return GLFW_TRUE; } @@ -241,7 +240,7 @@ static void closeJoystick(_GLFWjoystick* js) { close(js->linjs.fd); _glfwFreeJoystick(js); - _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_DISCONNECTED); + _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Lexically compare joysticks by name; used by qsort @@ -398,10 +397,8 @@ void _glfwDetectJoystickConnectionLinux(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformPollJoystick(int jid, int mode) +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { - _GLFWjoystick* js = _glfw.joysticks + jid; - // Read all queued events (non-blocking) for (;;) { diff --git a/src/win32_joystick.c b/src/win32_joystick.c index fe00747a3..759d1d44a 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -254,7 +254,7 @@ static void closeJoystick(_GLFWjoystick* js) } _glfwFreeJoystick(js); - _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_DISCONNECTED); + _glfwInputJoystick(js, GLFW_DISCONNECTED); } // DirectInput device object enumeration callback @@ -469,7 +469,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) js->win32.objects = data.objects; js->win32.objectCount = data.objectCount; - _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED); + _glfwInputJoystick(js, GLFW_CONNECTED); return DIENUM_CONTINUE; } @@ -552,7 +552,7 @@ void _glfwDetectJoystickConnectionWin32(void) js->win32.index = index; - _glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED); + _glfwInputJoystick(js, GLFW_CONNECTED); } } @@ -589,10 +589,8 @@ void _glfwDetectJoystickDisconnectionWin32(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformPollJoystick(int jid, int mode) +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { - _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->win32.device) { int i, ai = 0, bi = 0, pi = 0; @@ -631,7 +629,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) case _GLFW_TYPE_SLIDER: { const float value = (*((LONG*) data) + 0.5f) / 32767.5f; - _glfwInputJoystickAxis(jid, ai, value); + _glfwInputJoystickAxis(js, ai, value); ai++; break; } @@ -639,7 +637,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) case _GLFW_TYPE_BUTTON: { const char value = (*((BYTE*) data) & 0x80) != 0; - _glfwInputJoystickButton(jid, bi, value); + _glfwInputJoystickButton(js, bi, value); bi++; break; } @@ -664,7 +662,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) if (state < 0 || state > 8) state = 8; - _glfwInputJoystickHat(jid, pi, states[state]); + _glfwInputJoystickHat(js, pi, states[state]); pi++; break; } @@ -728,12 +726,12 @@ int _glfwPlatformPollJoystick(int jid, int mode) axes[5] = xis.Gamepad.bRightTrigger / 127.5f - 1.f; for (i = 0; i < 6; i++) - _glfwInputJoystickAxis(jid, i, axes[i]); + _glfwInputJoystickAxis(js, i, axes[i]); for (i = 0; i < 10; i++) { const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0; - _glfwInputJoystickButton(jid, i, value); + _glfwInputJoystickButton(js, i, value); } if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) @@ -745,7 +743,7 @@ int _glfwPlatformPollJoystick(int jid, int mode) if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) dpad |= GLFW_HAT_LEFT; - _glfwInputJoystickHat(jid, 0, dpad); + _glfwInputJoystickHat(js, 0, dpad); } return GLFW_TRUE; From 2e9aff759eb1abaffdcef42b6a3e3277817b9fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 9 Jul 2017 14:46:39 +0200 Subject: [PATCH 081/222] Fix @ref link --- include/GLFW/glfw3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 599ab057e..e396006ad 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1706,7 +1706,7 @@ GLFWAPI const char* glfwGetVersionString(void); /*! @brief Returns and clears the last error for the calling thread. * - * This function returns and clears the [error code](@ref error) of the last + * This function returns and clears the [error code](@ref errors) of the last * error that occurred on the calling thread, and optionally a UTF-8 encoded * human-readable description of it. If no error has occurred since the last * call, it returns @ref GLFW_NO_ERROR (zero) and the description pointer is From 2fa90ae19f2eecd766932cb212aedbee345eda40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 9 Jul 2017 18:37:24 +0200 Subject: [PATCH 082/222] Win32: Fix capture logic ignoring last mouse button --- src/win32_window.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/win32_window.c b/src/win32_window.c index 6d691e196..93abd68d7 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -628,24 +628,24 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, else action = GLFW_RELEASE; - for (i = 0; i < GLFW_MOUSE_BUTTON_LAST; i++) + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) { if (window->mouseButtons[i] == GLFW_PRESS) break; } - if (i == GLFW_MOUSE_BUTTON_LAST) + if (i > GLFW_MOUSE_BUTTON_LAST) SetCapture(hWnd); _glfwInputMouseClick(window, button, action, getKeyMods()); - for (i = 0; i < GLFW_MOUSE_BUTTON_LAST; i++) + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) { if (window->mouseButtons[i] == GLFW_PRESS) break; } - if (i == GLFW_MOUSE_BUTTON_LAST) + if (i > GLFW_MOUSE_BUTTON_LAST) ReleaseCapture(); if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) From 6634c47e573d87b0055c4c0e438d3adb2ab9382f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 9 Jul 2017 21:55:06 +0200 Subject: [PATCH 083/222] Documentation work --- docs/input.dox | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/input.dox b/docs/input.dox index f11e6dc8a..1dc217152 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -736,9 +736,10 @@ the largest available index for each array. @subsection gamepad_mapping Gamepad mappings -Newer ones can be added with @ref glfwUpdateGamepadMappings. This function -supports everything from single lines up to the entire unmodified contents of -the `gamecontrollerdb.txt` file. +GLFW contains a copy of the mappings available in +[SDL_GameControllerDB](https://github.com/gabomdq/SDL_GameControllerDB) at the +time of release. Newer ones can be added at runtime with @ref +glfwUpdateGamepadMappings. @code const char* mappings = load_file_contents("gamecontrollerdb.txt"); @@ -746,6 +747,9 @@ const char* mappings = load_file_contents("gamecontrollerdb.txt"); glfwUpdateGamepadMappings(mappings); @endcode +This function supports everything from single lines up to and including the +unmodified contents of the whole `gamecontrollerdb.txt` file. + Below is a description of the mapping format. Please keep in mind that __this description is not authoritative__. The format is defined by the SDL and SDL_GameControllerDB projects and their documentation and code takes precedence. @@ -786,8 +790,20 @@ There is also the special `platform` field that specifies which platform the mapping is valid for. Possible values are `Windows`, `Mac OS X` and `Linux`. Mappings without this field will always be considered valid. +Below is an example of what a gamepad mapping might look like. It is the +one built into GLFW for Xbox controllers accessed via the XInput API on Windows. +This example has been broken into several lines to fit on the page, but real +gamepad mappings must be a single line. + +@code{.unparsed} +78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0, +b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8, +rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4, +righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8, +@endcode + @note GLFW does not yet support the range and inversion modifiers `+`, `-` and -`~`. +`~` that were recently added to SDL. @section time Time input From ea6c50d9e22799f2a366185dfd57d6a623dfa950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 4 Jul 2017 17:22:29 +0200 Subject: [PATCH 084/222] Cleanup --- src/cocoa_joystick.m | 48 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 81c7e2dca..05745720e 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -196,39 +196,31 @@ static void matchCallback(void* context, } CFMutableArrayRef target = NULL; + const uint32_t usage = IOHIDElementGetUsage(native); - - switch (IOHIDElementGetUsagePage(native)) + const uint32_t page = IOHIDElementGetUsagePage(native); + if (page == kHIDPage_GenericDesktop) { - case kHIDPage_GenericDesktop: + switch (usage) { - switch (usage) - { - case kHIDUsage_GD_X: - case kHIDUsage_GD_Y: - case kHIDUsage_GD_Z: - case kHIDUsage_GD_Rx: - case kHIDUsage_GD_Ry: - case kHIDUsage_GD_Rz: - case kHIDUsage_GD_Slider: - case kHIDUsage_GD_Dial: - case kHIDUsage_GD_Wheel: - target = axes; - break; - case kHIDUsage_GD_Hatswitch: - target = hats; - break; - } - - break; + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + case kHIDUsage_GD_Dial: + case kHIDUsage_GD_Wheel: + target = axes; + break; + case kHIDUsage_GD_Hatswitch: + target = hats; + break; } - - case kHIDPage_Button: - target = buttons; - break; - default: - break; } + else if (page == kHIDPage_Button) + target = buttons; if (target) { From d55c57b504d84cda9737020209a70f7d127efff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 10 Jul 2017 12:55:58 +0200 Subject: [PATCH 085/222] Fix Clang -Wmissing-braces warning --- deps/linmath.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/linmath.h b/deps/linmath.h index 690a07a4f..9c2e2a0ab 100644 --- a/deps/linmath.h +++ b/deps/linmath.h @@ -192,7 +192,7 @@ static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, vec3 u = {x, y, z}; if(vec3_len(u) > 1e-4) { - mat4x4 T, C, S = {0}; + mat4x4 T, C, S = {{0}}; vec3_norm(u, u); mat4x4_from_vec3_mul_outer(T, u, u); From 8e899ccc29cc082f8d373718f1881ef5b8863f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 10 Jul 2017 17:07:59 +0200 Subject: [PATCH 086/222] Cocoa: Add support for MoltenVK dynamic library Tested with MoltenVK 0.18.0. Related to #870. --- CMake/modules/FindVulkan.cmake | 10 +++++----- README.md | 5 +++-- docs/vulkan.dox | 24 ++++++++++++++---------- include/GLFW/glfw3.h | 6 ------ src/vulkan.c | 11 +---------- tests/CMakeLists.txt | 6 ++++-- 6 files changed, 27 insertions(+), 35 deletions(-) diff --git a/CMake/modules/FindVulkan.cmake b/CMake/modules/FindVulkan.cmake index 078fd460f..5bdb55605 100644 --- a/CMake/modules/FindVulkan.cmake +++ b/CMake/modules/FindVulkan.cmake @@ -28,12 +28,12 @@ if (WIN32) "$ENV{VK_SDK_PATH}/Bin32") endif() elseif (APPLE) + set(CMAKE_FIND_FRAMEWORK NEVER) find_library(VULKAN_LIBRARY MoltenVK) - if (VULKAN_LIBRARY) - set(VULKAN_STATIC_LIBRARY ${VULKAN_LIBRARY}) - find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS - "${VULKAN_LIBRARY}/Headers") - endif() + set(CMAKE_FIND_FRAMEWORK ONLY) + find_library(VULKAN_STATIC_LIBRARY MoltenVK) + find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS + "${VULKAN_LIBRARY}/Headers") else() find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS "$ENV{VULKAN_SDK}/include") diff --git a/README.md b/README.md index b2110b2ce..685d927d5 100644 --- a/README.md +++ b/README.md @@ -108,8 +108,9 @@ located in the `deps/` directory. - [Vulkan headers](https://www.khronos.org/registry/vulkan/) for Vulkan tests The Vulkan example additionally requires the Vulkan SDK to be installed, or it -will not be included in the build. On macOS you need to set the path to the -MoltenVK SDK manually as it has no standard location. +will not be included in the build. On macOS you need to +[provide the path](@ref vulkan_loader) to the MoltenVK SDK manually as it has no +standard installation location. The documentation is generated with [Doxygen](http://doxygen.org/). If CMake does not find Doxygen, the documentation will not be generated when you build. diff --git a/docs/vulkan.dox b/docs/vulkan.dox index 60d049419..7de9cd646 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -20,6 +20,11 @@ The GLFW library does not need the Vulkan SDK to enable support for Vulkan. However, any Vulkan-specific test and example programs are built only if the CMake files find a Vulkan SDK. +@macos Because MoltenVK is typically not installed system-wide, you will need to +point CMake to it using the `CMAKE_FRAMEWORK_PATH` variable when configuring the +GLFW source tree. Set this variable to the `MoltenVK/macOS` subdirectory of the +SDK, either on the command-line or in the CMake GUI. + For details on a specific function in this category, see the @ref vulkan. There are also guides for the other areas of the GLFW API. @@ -34,19 +39,18 @@ are also guides for the other areas of the GLFW API. By default, GLFW will look for the Vulkan loader on demand at runtime via its standard name (`vulkan-1.dll` on Windows, `libvulkan.so.1` on Linux and other -Unix-like systems). This means that GLFW does not need to be linked against the -loader. However, it also means that if you are using the static library form of -the Vulkan loader GLFW will either fail to find it or (worse) use the wrong one. +Unix-like systems and `libMoltenVK.dylib` on macOS). This means that GLFW does +not need to be linked against the loader. However, it also means that if you +are using the static library form of the Vulkan loader GLFW will either fail to +find it or (worse) use the wrong one. The @ref GLFW_VULKAN_STATIC CMake option makes GLFW link directly against the -static form. Not linking against the Vulkan loader will then be a compile-time -error. +static library form. Not linking against the Vulkan loader will then be +a compile-time error. -@macos MoltenVK only provides the static library form of the Vulkan loader, but -GLFW is able to find it without @ref GLFW_VULKAN_STATIC as long as it is linked -into any of the binaries already loaded into the process. As it is a static -library, you must also link against its dependencies: the `Cocoa`, `Metal` and -`QuartzCore` frameworks and the `libc++` library. +@macos When using the static library form of MoltenVK (i.e. `MetalVK.framework` +and not `libMoltenVK.dylib`) you must also link against its dependencies: the +`Cocoa`, `Metal` and `QuartzCore` system frameworks and the `libc++` library. @section vulkan_include Including the Vulkan and GLFW header files diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index e396006ad..04b79ca40 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -211,13 +211,7 @@ extern "C" { #endif /* OpenGL and OpenGL ES headers */ #if defined(GLFW_INCLUDE_VULKAN) - - #if defined(__APPLE__) - #include - #else #include - #endif - #endif /* Vulkan header */ #if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) diff --git a/src/vulkan.c b/src/vulkan.c index 858a1e973..f2473cf6e 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -52,8 +52,7 @@ GLFWbool _glfwInitVulkan(int mode) #if defined(_GLFW_WIN32) _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); #elif defined(_GLFW_COCOA) - // NULL maps to RTLD_DEFAULT, which searches all loaded binaries - _glfw.vk.handle = _glfw_dlopen(NULL); + _glfw.vk.handle = _glfw_dlopen("libMoltenVK.dylib"); #else _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); #endif @@ -69,16 +68,8 @@ GLFWbool _glfwInitVulkan(int mode) _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr"); if (!_glfw.vk.GetInstanceProcAddr) { -#if defined(_GLFW_COCOA) - if (mode == _GLFW_REQUIRE_LOADER) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "Vulkan: vkGetInstanceProcAddr not found in process"); - } -#else _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader does not export vkGetInstanceProcAddr"); -#endif _glfwTerminateVulkan(); return GLFW_FALSE; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9f56bcb72..56d871b8f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -53,8 +53,10 @@ set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen if (VULKAN_FOUND) add_executable(vulkan WIN32 vulkan.c ${ICON}) target_include_directories(vulkan PRIVATE "${VULKAN_INCLUDE_DIR}") - if (NOT GLFW_VULKAN_STATIC) - target_link_libraries(vulkan "${VULKAN_LIBRARY}" ${GLFW_VULKAN_DEPS}) + if (GLFW_VULKAN_STATIC) + target_link_libraries(vulkan "${VULKAN_STATIC_LIBRARY}" ${GLFW_VULKAN_DEPS}) + else() + target_link_libraries(vulkan "${VULKAN_LIBRARY}") endif() list(APPEND WINDOWS_BINARIES vulkan) endif() From 67c9155f3bce1da59a0eb66b7c18d1b2a48fa1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 12 Jul 2017 00:21:17 +0200 Subject: [PATCH 087/222] Documentation work --- README.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 685d927d5..cfe4d6927 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,10 @@ fixes live in [other branches](https://github.com/glfw/glfw/branches/all) until they are stable enough to merge. If you are new to GLFW, you may find the -[tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW -3 useful. If you have used GLFW 2 in the past, there is a -[transition guide](http://www.glfw.org/docs/latest/moving.html) for moving to -the GLFW 3 API. +[tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW 3 useful. If +you have used GLFW 2 in the past, there is a [transition +guide](http://www.glfw.org/docs/latest/moving.html) for moving to the GLFW +3 API. ## Compiling GLFW @@ -53,12 +53,11 @@ MinGW-w64, on macOS with Clang and on Linux and other Unix-like systems with GCC and Clang. It will likely compile in other environments as well, but this is not regularly tested. -There are also [pre-compiled Windows -binaries](http://www.glfw.org/download.html) available for all compilers -supported on that platform. +There are [pre-compiled Windows binaries](http://www.glfw.org/download.html) +available for all supported compilers. See the [compilation guide](http://www.glfw.org/docs/latest/compile.html) for -more information about how to compile GLFW. +more information about how to compile GLFW yourself. ## Using GLFW @@ -108,12 +107,11 @@ located in the `deps/` directory. - [Vulkan headers](https://www.khronos.org/registry/vulkan/) for Vulkan tests The Vulkan example additionally requires the Vulkan SDK to be installed, or it -will not be included in the build. On macOS you need to -[provide the path](@ref vulkan_loader) to the MoltenVK SDK manually as it has no -standard installation location. +will not be included in the build. On macOS you need to provide the path to the +MoltenVK SDK manually as it has no standard installation location. -The documentation is generated with [Doxygen](http://doxygen.org/). If CMake -does not find Doxygen, the documentation will not be generated when you build. +The documentation is generated with [Doxygen](http://doxygen.org/) if CMake can +find that tool. ## Reporting bugs From d3247a8c8342dab6d4043e497607a77f3493e0c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 10 Jul 2017 01:28:44 +0200 Subject: [PATCH 088/222] Documentation work --- docs/input.dox | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/input.dox b/docs/input.dox index 1dc217152..6d444656d 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -181,12 +181,10 @@ GLFW supports text input in the form of a stream of operating system text input system. Unlike key input, text input obeys keyboard layouts and modifier keys and supports composing characters using [dead keys](https://en.wikipedia.org/wiki/Dead_key). Once received, you can -encode the code points into -[UTF-8](https://en.wikipedia.org/wiki/UTF-8) or any other encoding you prefer. +encode the code points into UTF-8 or any other encoding you prefer. Because an `unsigned int` is 32 bits long on all platforms supported by GLFW, -you can treat the code point argument as native endian -[UTF-32](https://en.wikipedia.org/wiki/UTF-32). +you can treat the code point argument as native endian UTF-32. There are two callbacks for receiving Unicode code points. If you wish to offer regular text input, set a character callback. From 82284b86ebde945951f35bbb20bfe582f2d7322b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 11 Jul 2017 23:00:17 +0200 Subject: [PATCH 089/222] Cleanup Thanks to glfwGetKeyScancode we can now pass only a scancode to the platform layer for glfwGetKeyName. --- src/cocoa_window.m | 8 +------- src/input.c | 22 ++++++++++++++-------- src/internal.h | 6 +----- src/mir_window.c | 2 +- src/null_window.c | 2 +- src/win32_window.c | 8 +------- src/wl_window.c | 2 +- src/x11_window.c | 8 +------- 8 files changed, 21 insertions(+), 37 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 2c94a8a2b..2acfa98b9 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1560,14 +1560,8 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) updateCursorImage(window); } -const char* _glfwPlatformGetKeyName(int key, int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { - if (key != GLFW_KEY_UNKNOWN) - scancode = _glfw.ns.scancodes[key]; - - if (!_glfwIsPrintable(_glfw.ns.keycodes[scancode])) - return NULL; - UInt32 deadKeyState = 0; UniChar characters[8]; UniCharCount characterCount = 0; diff --git a/src/input.c b/src/input.c index 523bfa98a..f4542b4e5 100644 --- a/src/input.c +++ b/src/input.c @@ -289,13 +289,6 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwIsPrintable(int key) -{ - return (key >= GLFW_KEY_APOSTROPHE && key <= GLFW_KEY_WORLD_2) || - (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) || - key == GLFW_KEY_KP_EQUAL; -} - _GLFWjoystick* _glfwAllocJoystick(const char* name, const char* guid, int axisCount, @@ -450,7 +443,20 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) GLFWAPI const char* glfwGetKeyName(int key, int scancode) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetKeyName(key, scancode); + + if (key != GLFW_KEY_UNKNOWN) + { + if (key != GLFW_KEY_KP_EQUAL && + (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) && + (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2)) + { + return NULL; + } + + scancode = _glfwPlatformGetKeyScancode(key); + } + + return _glfwPlatformGetScancodeName(scancode); } GLFWAPI int glfwGetKeyScancode(int key) diff --git a/src/internal.h b/src/internal.h index d00c7fc0f..e3ea78de3 100644 --- a/src/internal.h +++ b/src/internal.h @@ -630,7 +630,7 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); void _glfwPlatformDestroyCursor(_GLFWcursor* cursor); void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); -const char* _glfwPlatformGetKeyName(int key, int scancode); +const char* _glfwPlatformGetScancodeName(int scancode); int _glfwPlatformGetKeyScancode(int key); void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); @@ -990,10 +990,6 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, */ void _glfwFreeJoystick(_GLFWjoystick* js); -/*! @ingroup utility - */ -GLFWbool _glfwIsPrintable(int key); - /*! @ingroup utility */ GLFWbool _glfwInitVulkan(int mode); diff --git a/src/mir_window.c b/src/mir_window.c index 566f571c1..3e8d5c5bf 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -830,7 +830,7 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) } } -const char* _glfwPlatformGetKeyName(int key, int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); diff --git a/src/null_window.c b/src/null_window.c index 137f80c8f..2e627672c 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -261,7 +261,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return NULL; } -const char* _glfwPlatformGetKeyName(int key, int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { return ""; } diff --git a/src/win32_window.c b/src/win32_window.c index 93abd68d7..ef05898a6 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1609,16 +1609,10 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) updateCursorImage(window); } -const char* _glfwPlatformGetKeyName(int key, int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { WCHAR name[16]; - if (key != GLFW_KEY_UNKNOWN) - scancode = _glfw.win32.scancodes[key]; - - if (!_glfwIsPrintable(_glfw.win32.keycodes[scancode])) - return NULL; - if (!GetKeyNameTextW(scancode << 16, name, sizeof(name) / sizeof(WCHAR))) return NULL; diff --git a/src/wl_window.c b/src/wl_window.c index e9c817d50..fbd58ffbe 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -721,7 +721,7 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) _glfwPlatformSetCursor(window, window->wl.currentCursor); } -const char* _glfwPlatformGetKeyName(int key, int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { // TODO return NULL; diff --git a/src/x11_window.c b/src/x11_window.c index ed5a0f297..dcda51ea8 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2474,17 +2474,11 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) XFlush(_glfw.x11.display); } -const char* _glfwPlatformGetKeyName(int key, int scancode) +const char* _glfwPlatformGetScancodeName(int scancode) { if (!_glfw.x11.xkb.available) return NULL; - if (key != GLFW_KEY_UNKNOWN) - scancode = _glfw.x11.scancodes[key]; - - if (!_glfwIsPrintable(_glfw.x11.keycodes[scancode])) - return NULL; - const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); if (keysym == NoSymbol) return NULL; From afbd5893486130f7b454dc313e36bce18922d953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cicho=C5=84?= Date: Wed, 12 Jul 2017 23:24:08 +0200 Subject: [PATCH 090/222] Fix function signature in null joystick backend Related to #1043. --- src/null_joystick.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/null_joystick.c b/src/null_joystick.c index 2311d91f7..afd65e15d 100644 --- a/src/null_joystick.c +++ b/src/null_joystick.c @@ -31,7 +31,7 @@ ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformPollJoystick(int jid, int mode) +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { return GLFW_FALSE; } From 50a228394fa3498a990ef827412d1429a304941f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cicho=C5=84?= Date: Wed, 12 Jul 2017 23:25:38 +0200 Subject: [PATCH 091/222] Win32: Fix bad call to _glfwPlatformPollJoystick Related to #1043. --- src/win32_joystick.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 759d1d44a..d6bd6c5d4 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -576,11 +576,14 @@ void _glfwDetectJoystickConnectionWin32(void) void _glfwDetectJoystickDisconnectionWin32(void) { int jid; + _GLFWjoystick* js; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (_glfw.joysticks[jid].present) - _glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE); + js = &_glfw.joysticks[jid]; + + if (js->present) + _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); } } From e55e616f1f25a36caaa11c8ab7bcfed8f47c9b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 13 Jul 2017 01:35:15 +0200 Subject: [PATCH 092/222] Cleanup Replaces tabs with spaces. Makes code idiomatic. Adds credit. Closes #1043. --- README.md | 1 + src/win32_joystick.c | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index cfe4d6927..e1a638a3d 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,7 @@ skills. - Martin Capitanio - David Carlier - Chi-kwan Chan + - Michał Cichoń - Lambert Clara - Andrew Corrigan - Noel Cower diff --git a/src/win32_joystick.c b/src/win32_joystick.c index d6bd6c5d4..6db08467b 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -576,15 +576,13 @@ void _glfwDetectJoystickConnectionWin32(void) void _glfwDetectJoystickDisconnectionWin32(void) { int jid; - _GLFWjoystick* js; - - for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) - { - js = &_glfw.joysticks[jid]; + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks + jid; if (js->present) - _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); - } + _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); + } } From 472e5fc4a9c2003f05bafb659dc6b0502c0eb3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 17 Jul 2017 23:15:48 +0200 Subject: [PATCH 093/222] Fix warning --- src/input.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/input.c b/src/input.c index f4542b4e5..2a5dfef07 100644 --- a/src/input.c +++ b/src/input.c @@ -258,8 +258,10 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) void _glfwInputJoystick(_GLFWjoystick* js, int event) { + const int jid = (int) (js - _glfw.joysticks); + if (_glfw.callbacks.joystick) - _glfw.callbacks.joystick(js - _glfw.joysticks, event); + _glfw.callbacks.joystick(jid, event); } void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) From 2d8d8f5917ec669a76272338eec5ed8801fd9138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 17 Jul 2017 21:18:15 +0200 Subject: [PATCH 094/222] Fix signedness in GLFWgamepadstate The signedness did not match glfwGetJoystickButtons. --- include/GLFW/glfw3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 04b79ca40..820004e01 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1529,7 +1529,7 @@ typedef struct GLFWgamepadstate /*! The states of each [gamepad button](@ref gamepad_buttons), `GLFW_PRESS` * or `GLFW_RELEASE`. */ - char buttons[15]; + unsigned char buttons[15]; /*! The states of each [gamepad axis](@ref gamepad_axes), in the range -1.0 * to 1.0 inclusive. */ From c0bc10427c79ecd7e3aad5ce13a67ef7d553cf05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 17 Jul 2017 21:21:10 +0200 Subject: [PATCH 095/222] Fix warnings in Vulkan test --- tests/vulkan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/vulkan.c b/tests/vulkan.c index f734dca00..d0d4b3e3a 100644 --- a/tests/vulkan.c +++ b/tests/vulkan.c @@ -1721,7 +1721,7 @@ static void demo_init_vk(struct demo *demo) { err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); assert(!err); - instance_validation_layers = instance_validation_layers_alt1; + instance_validation_layers = (const char**) instance_validation_layers_alt1; if (instance_layer_count > 0) { VkLayerProperties *instance_layers = malloc(sizeof (VkLayerProperties) * instance_layer_count); @@ -1740,7 +1740,8 @@ static void demo_init_vk(struct demo *demo) { validation_layer_count = 1; } else { // use alternative set of validation layers - instance_validation_layers = instance_validation_layers_alt2; + instance_validation_layers = + (const char**) instance_validation_layers_alt2; demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2); validation_found = demo_check_layers( ARRAY_SIZE(instance_validation_layers_alt2), From 4feede6dd5f6cae5a0e90b23966b90b5dc635771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 17 Jul 2017 21:17:14 +0200 Subject: [PATCH 096/222] Make enabled warnings errors during CI builds Related to #1043. --- .appveyor.yml | 1 + .travis.yml | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index ae658cc37..68d7e69d8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -4,6 +4,7 @@ branches: - master skip_tags: true environment: + CFLAGS: /WX matrix: - BUILD_SHARED_LIBS: ON - BUILD_SHARED_LIBS: OFF diff --git a/.travis.yml b/.travis.yml index 72ac4bfe2..eed58c7f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,11 @@ addons: - libxcursor-dev - libxi-dev env: - - BUILD_SHARED_LIBS=ON - - BUILD_SHARED_LIBS=OFF + global: + - CFLAGS=-Werror + matrix: + - BUILD_SHARED_LIBS=ON + - BUILD_SHARED_LIBS=OFF script: - mkdir build - cd build From 00d2efb9ab96e6a1e67325b29421c8da98c78286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 17 Jul 2017 23:42:37 +0200 Subject: [PATCH 097/222] Enable verbose makefiles for CI --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 68d7e69d8..cde766645 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -13,7 +13,7 @@ matrix: build_script: - mkdir build - cd build - - cmake -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% .. + - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% .. - cmake --build . notifications: - provider: Email diff --git a/.travis.yml b/.travis.yml index eed58c7f1..ef11ea1a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ env: script: - mkdir build - cd build - - cmake -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} .. + - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} .. - cmake --build . notifications: email: From 213dd2d0d6201a1e17dacce2ff35bdc8dd14e309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 25 Jul 2017 01:55:08 +0200 Subject: [PATCH 098/222] Add glfwInitHintString Adds string type init hints. Adds X11 specific init hints for WM_CLASS components. Documentation work. Fixes #893. --- README.md | 4 ++- docs/intro.dox | 41 +++++++++++++++++++--------- docs/news.dox | 5 ++-- include/GLFW/glfw3.h | 63 +++++++++++++++++++++++++++++++++++++------- src/init.c | 34 +++++++++++++++++++++--- src/internal.h | 4 +++ src/x11_window.c | 22 ++++++++++++---- 7 files changed, 139 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index e1a638a3d..0892b4037 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ information on what to include when reporting a bug. - Added `glfwSetWindowAttrib` function for changing window attributes (#537) - Added `glfwGetJoystickHats` function for querying joystick hats (#889,#906,#934) -- Added `glfwInitHint` function for setting library initialization hints +- Added `glfwInitHint` and `glfwInitHintString` for setting initialization hints - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering @@ -154,6 +154,8 @@ information on what to include when reporting a bug. - Added macOS specific `GLFW_COCOA_GRAPHICS_SWITCHING` window hint (#377,#935) - Added macOS specific `GLFW_COCOA_CHDIR_RESOURCES` init hint - Added macOS specific `GLFW_COCOA_MENUBAR` init hint +- Added X11 specific `GLFW_X11_WM_CLASS_NAME` and `GLFW_X11_WM_CLASS_CLASS` init + hints (#893) - Added `GLFW_INCLUDE_ES32` for including the OpenGL ES 3.2 header - Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with [OSMesa](https://www.mesa3d.org/osmesa.html) (#281) diff --git a/docs/intro.dox b/docs/intro.dox index e5de73032..88245d9b0 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -33,6 +33,7 @@ successfully initialized, and only from the main thread. - @ref glfwGetError - @ref glfwSetErrorCallback - @ref glfwInitHint + - @ref glfwInitHintString - @ref glfwInit - @ref glfwTerminate @@ -65,23 +66,26 @@ system settings and these might not be restored without termination. @subsection init_hints Initialization hints -There are a number of hints that can be set before initialization, that affect -how the library behaves. +Initialization hints are set before @ref glfwInit and affect how the library +behaves until termination. Integer type hints are set with @ref glfwInitHint +and string type hints with @ref glfwInitHintString. -The values you set are not affected by initialization or termination, but they -are only read during initialization. Once GLFW has been initialized, setting -new hint values will not affect behavior until the next time it is terminated -and initialized. +@code +glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE); +@endcode -Some hints are platform specific. These are always valid to set on any -platform but they will only affect their specific platform. Other platforms -will simply ignore them. Setting these hints requires no platform specific -headers or calls. +The values you set hints to are never reset by GLFW, but they only take effect +during initialization. Once GLFW has been initialized, any values you set will +be ignored until the library is terminated and initialized again. + +Some hints are platform specific. These may be set on any platform but they +will only affect their specific platform. Other platforms will simply ignore +them. Setting these hints requires no platform specific headers or functions. @anchor GLFW_JOYSTICK_HAT_BUTTONS __GLFW_JOYSTICK_HAT_BUTTONS__ specifies whether to also expose joystick hats as buttons, for compatibility with earlier versions of GLFW that did not have @ref -glfwGetJoystickHats. +glfwGetJoystickHats. Set this with @ref glfwInitHint. @subsubsection init_hints_osx macOS specific init hints @@ -89,12 +93,21 @@ glfwGetJoystickHats. @anchor GLFW_COCOA_CHDIR_RESOURCES __GLFW_COCOA_CHDIR_RESOURCES__ specifies whether to set the current directory to the application to the `Contents/Resources` subdirectory of the application's -bundle, if present. +bundle, if present. Set this with @ref glfwInitHint. @anchor GLFW_COCOA_MENUBAR __GLFW_COCOA_MENUBAR__ specifies whether to create a basic menu bar, either from a nib or manually, when the first window is created, which is when AppKit is -initialized. +initialized. Set this with @ref glfwInitHint. + + +@subsubsection init_hints_x11 X11 specific init hints + +@anchor GLFW_X11_WM_CLASS_NAME +@anchor GLFW_X11_WM_CLASS_CLASS +__GLFW_X11_WM_CLASS_NAME__ and __GLFW_X11_WM_CLASS_CLASS__ specifies the desired +ASCII encoded name and class parts of the ICCCM `WM_CLASS` hint for all windows. +Set this with @ref glfwInitHintString. @subsubsection init_hints_values Supported and default values @@ -104,6 +117,8 @@ Init hint | Default value | Supported values @ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` +@ref GLFW_X11_WM_CLASS_NAME | `""` | An ASCII encoded `WM_CLASS` name +@ref GLFW_X11_WM_CLASS_CLASS | `""` | An ASCII encoded `WM_CLASS` class @subsection intro_init_terminate Terminating GLFW diff --git a/docs/news.dox b/docs/news.dox index 173508ec1..2d4b621d5 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -60,8 +60,9 @@ windows with @ref glfwSetWindowAttrib. @subsection news_33_inithint Support for initialization hints -GLFW now supports setting library initialization hints with @ref glfwInitHint. -These must be set before initialization to take effect. +GLFW now supports setting library initialization hints with @ref glfwInitHint +or @ref glfwInitHintString. These must be set before initialization to take +effect. @see @ref init_hints diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 820004e01..83fad7374 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1016,6 +1016,9 @@ extern "C" { #define GLFW_COCOA_CHDIR_RESOURCES 0x00051001 #define GLFW_COCOA_MENUBAR 0x00051002 + +#define GLFW_X11_WM_CLASS_NAME 0x00052001 +#define GLFW_X11_WM_CLASS_CLASS 0x00052002 /*! @} */ #define GLFW_DONT_CARE -1 @@ -1609,17 +1612,18 @@ GLFWAPI void glfwTerminate(void); /*! @brief Sets the specified init hint to the desired value. * - * This function sets hints for the next initialization of GLFW. + * This function sets hints for the next initialization of GLFW. Only integer + * type hints can be set with this function. * - * The values you set are not affected by initialization or termination, but - * they are only read during initialization. Once GLFW has been initialized, - * setting new hint values will not affect behavior until the next time the - * library is terminated and initialized. + * The values you set hints to are never reset by GLFW, but they only take + * effect during initialization. Once GLFW has been initialized, any values + * you set will be ignored until the library is terminated and initialized + * again. * - * Some hints are platform specific. These are always valid to set on any - * platform but they will only affect their specific platform. Other platforms - * will simply ignore them. Setting these hints requires no platform specific - * headers or calls. + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will simply + * ignore them. Setting these hints requires no platform specific headers or + * functions. * * @param[in] hint The [init hint](@ref init_hints) to set. * @param[in] value The new value of the init hint. @@ -1633,6 +1637,7 @@ GLFWAPI void glfwTerminate(void); * * @sa init_hints * @sa glfwInit + * @sa glfwInitHintString * * @since Added in version 3.3. * @@ -1640,6 +1645,41 @@ GLFWAPI void glfwTerminate(void); */ GLFWAPI void glfwInitHint(int hint, int value); +/*! @brief Sets the specified init hint to the desired value. + * + * This function sets hints for the next initialization of GLFW. Only string + * type hints can be set with this function. + * + * The values you set hints to are never reset by GLFW, but they only take + * effect during initialization. Once GLFW has been initialized, any values + * you set will be ignored until the library is terminated and initialized + * again. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will simply + * ignore them. Setting these hints requires no platform specific headers or + * functions. + * + * @param[in] hint The [init hint](@ref init_hints) to set. + * @param[in] value The new value of the init hint. + * + * @errors Possible errors include @ref GLFW_INVALID_ENUM and @ref + * GLFW_INVALID_VALUE. + * + * @remarks This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa init_hints + * @sa glfwInit + * @sa glfwInitHint + * + * @since Added in version 3.3. + * + * @ingroup init + */ +GLFWAPI void glfwInitHintString(int hint, const char* value); + /*! @brief Retrieves the version of the GLFW library. * * This function retrieves the major, minor and revision numbers of the GLFW @@ -2261,6 +2301,11 @@ GLFWAPI void glfwWindowHint(int hint, int value); * query the final size, position or other attributes directly after window * creation. * + * @remark @x11 The name and class of the `WM_CLASS` window property will by + * default be set to the window title passed to this function. Set the @ref + * GLFW_X11_WM_CLASS_NAME and @ref GLFW_X11_WM_CLASS_CLASS init hints before + * initialization to override this. + * * @remark @wayland The window frame is currently unimplemented, as if * [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`. * A compositor can still emit close, resize or maximize events, using for diff --git a/src/init.c b/src/init.c index 7f7d87eab..fd86c5be5 100644 --- a/src/init.c +++ b/src/init.c @@ -32,6 +32,7 @@ #include #include #include +#include // The global variables below comprise all global data in GLFW. @@ -48,10 +49,14 @@ static _GLFWerror _glfwMainThreadError; static GLFWerrorfun _glfwErrorCallback; static _GLFWinitconfig _glfwInitHints = { - GLFW_TRUE, // hat buttons + GLFW_TRUE, // hat buttons { - GLFW_TRUE, // menubar - GLFW_TRUE // chdir + GLFW_TRUE, // macOS menu bar + GLFW_TRUE // macOS bundle chdir + }, + { + "", // X11 WM_CLASS name + "" // X11 WM_CLASS class } }; @@ -243,7 +248,28 @@ GLFWAPI void glfwInitHint(int hint, int value) return; } - _glfwInputError(GLFW_INVALID_ENUM, "Invalid init hint 0x%08X", hint); + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid integer type init hint 0x%08X", hint); +} + +GLFWAPI void glfwInitHintString(int hint, const char* value) +{ + assert(value != NULL); + + switch (hint) + { + case GLFW_X11_WM_CLASS_NAME: + strncpy(_glfwInitHints.x11.className, value, + sizeof(_glfwInitHints.x11.className) - 1); + break; + case GLFW_X11_WM_CLASS_CLASS: + strncpy(_glfwInitHints.x11.classClass, value, + sizeof(_glfwInitHints.x11.classClass) - 1); + break; + } + + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid string type init hint 0x%08X", hint); } GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) diff --git a/src/internal.h b/src/internal.h index e3ea78de3..fdff84d01 100644 --- a/src/internal.h +++ b/src/internal.h @@ -277,6 +277,10 @@ struct _GLFWinitconfig GLFWbool menubar; GLFWbool chdir; } ns; + struct { + char className[256]; + char classClass[256]; + } x11; }; /*! @brief Window configuration. diff --git a/src/x11_window.c b/src/x11_window.c index dcda51ea8..cdaac5f8d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -614,13 +614,25 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, updateNormalHints(window, wndconfig->width, wndconfig->height); // Set ICCCM WM_CLASS property - // HACK: Until a mechanism for specifying the application name is added, the - // initial window title is used as the window class name - if (strlen(wndconfig->title)) { XClassHint* hint = XAllocClassHint(); - hint->res_name = (char*) wndconfig->title; - hint->res_class = (char*) wndconfig->title; + + if (strlen(_glfw.hints.init.x11.className) && + strlen(_glfw.hints.init.x11.classClass)) + { + hint->res_name = (char*) _glfw.hints.init.x11.className; + hint->res_class = (char*) _glfw.hints.init.x11.classClass; + } + else if (strlen(wndconfig->title)) + { + hint->res_name = (char*) wndconfig->title; + hint->res_class = (char*) wndconfig->title; + } + else + { + hint->res_name = (char*) "glfw-application"; + hint->res_class = (char*) "GLFW-Application"; + } XSetClassHint(_glfw.x11.display, window->x11.handle, hint); XFree(hint); From 85eda77d3523b3bd9df5a194fbbaaf5ba5c6168d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 30 Jul 2017 14:52:26 +0200 Subject: [PATCH 099/222] Update Nuklear to 1.40.0 --- deps/nuklear.h | 3049 ++++++++++++++++++++++++++++----------- deps/nuklear_glfw_gl2.h | 36 +- tests/gamma.c | 2 +- tests/joysticks.c | 2 +- 4 files changed, 2229 insertions(+), 860 deletions(-) diff --git a/deps/nuklear.h b/deps/nuklear.h index 0811e79c4..333acee78 100644 --- a/deps/nuklear.h +++ b/deps/nuklear.h @@ -1,7 +1,7 @@ /* - Nuklear - 1.33.0 - public domain + Nuklear - 1.40.0 - public domain no warrenty implied; use at your own risk. - authored from 2015-2016 by Micha Mettke + authored from 2015-2017 by Micha Mettke ABOUT: This is a minimal state graphical user interface single header toolkit @@ -108,7 +108,7 @@ OPTIONAL DEFINES: If used needs to be defined for implementation and header NK_INCLUDE_FONT_BAKING - Defining this adds the `stb_truetype` and `stb_rect_pack` implementation + Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it. @@ -262,7 +262,6 @@ extern "C" { #ifndef NK_SCROLLBAR_HIDING_TIMEOUT #define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f #endif - /* * ============================================================== * @@ -316,7 +315,6 @@ extern "C" { #define NK_MIN(a,b) ((a) < (b) ? (a) : (b)) #define NK_MAX(a,b) ((a) < (b) ? (b) : (a)) #define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i)) - /* * =============================================================== * @@ -476,7 +474,6 @@ enum nk_color_format {NK_RGB, NK_RGBA}; enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; -enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON}; typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); typedef void (*nk_plugin_free)(nk_handle, void *old); @@ -489,34 +486,6 @@ struct nk_allocator { nk_plugin_alloc alloc; nk_plugin_free free; }; - -struct nk_draw_null_texture { - nk_handle texture;/* texture handle to a texture with a white pixel */ - struct nk_vec2 uv; /* coordinates to a white pixel in the texture */ -}; -struct nk_convert_config { - float global_alpha; /* global alpha value */ - enum nk_anti_aliasing line_AA; /* line anti-aliasing flag can be turned off if you are tight on memory */ - enum nk_anti_aliasing shape_AA; /* shape anti-aliasing flag can be turned off if you are tight on memory */ - unsigned int circle_segment_count; /* number of segments used for circles: default to 22 */ - unsigned int arc_segment_count; /* number of segments used for arcs: default to 22 */ - unsigned int curve_segment_count; /* number of segments used for curves: default to 22 */ - struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */ - const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */ - nk_size vertex_size; /* sizeof one vertex for vertex packing */ - nk_size vertex_alignment; /* vertex alignment: Can be optained by NK_ALIGNOF */ -}; - -struct nk_list_view { -/* public: */ - int begin, end, count; -/* private: */ - int total_height; - struct nk_context *ctx; - nk_uint *scroll_pointer; - nk_uint scroll_value; -}; - enum nk_symbol_type { NK_SYMBOL_NONE, NK_SYMBOL_X, @@ -533,7 +502,161 @@ enum nk_symbol_type { NK_SYMBOL_MINUS, NK_SYMBOL_MAX }; - +/* ============================================================================= + * + * CONTEXT + * + * =============================================================================*/ +/* Contexts are the main entry point and the majestro of nuklear and contain all required state. + * They are used for window, memory, input, style, stack, commands and time management and need + * to be passed into all nuklear GUI specific functions. + * + * Usage + * ------------------- + * To use a context it first has to be initialized which can be achieved by calling + * one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`. + * Each takes in a font handle and a specific way of handling memory. Memory control + * hereby ranges from standard library to just specifing a fixed sized block of memory + * which nuklear has to manage itself from. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * [...] + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * Reference + * ------------------- + * nk_init_default - Initializes context with standard library memory alloction (malloc,free) + * nk_init_fixed - Initializes context from single fixed size memory block + * nk_init - Initializes context with memory allocator callbacks for alloc and free + * nk_init_custom - Initializes context from two buffers. One for draw commands the other for window/panel/table allocations + * nk_clear - Called at the end of the frame to reset and prepare the context for the next frame + * nk_free - Shutdown and free all memory allocated inside the context + * nk_set_user_data - Utility function to pass user data to draw command + */ +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +/* nk_init_default - Initializes a `nk_context` struct with a default standard library allocator. + * Should be used if you don't want to be bothered with memory management in nuklear. + * Parameters: + * @ctx must point to an either stack or heap allocated `nk_context` struct + * @font must point to a previously initialized font handle for more info look at font documentation + * Return values: + * true(1) on success + * false(0) on failure */ +NK_API int nk_init_default(struct nk_context*, const struct nk_user_font*); +#endif +/* nk_init_fixed - Initializes a `nk_context` struct from a single fixed size memory block + * Should be used if you want complete control over nuklears memory management. + * Especially recommended for system with little memory or systems with virtual memory. + * For the later case you can just allocate for example 16MB of virtual memory + * and only the required amount of memory will actually be commited. + * IMPORTANT: make sure the passed memory block is aligned correctly for `nk_draw_commands` + * Parameters: + * @ctx must point to an either stack or heap allocated `nk_context` struct + * @memory must point to a previously allocated memory block + * @size must contain the total size of @memory + * @font must point to a previously initialized font handle for more info look at font documentation + * Return values: + * true(1) on success + * false(0) on failure */ +NK_API int nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*); +/* nk_init - Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate + * memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation + * interface to nuklear. Can be useful for cases like monitoring memory consumption. + * Parameters: + * @ctx must point to an either stack or heap allocated `nk_context` struct + * @alloc must point to a previously allocated memory allocator + * @font must point to a previously initialized font handle for more info look at font documentation + * Return values: + * true(1) on success + * false(0) on failure */ +NK_API int nk_init(struct nk_context*, struct nk_allocator*, const struct nk_user_font*); +/* nk_init_custom - Initializes a `nk_context` struct from two different either fixed or growing + * buffers. The first buffer is for allocating draw commands while the second buffer is + * used for allocating windows, panels and state tables. + * Parameters: + * @ctx must point to an either stack or heap allocated `nk_context` struct + * @cmds must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into + * @pool must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables + * @font must point to a previously initialized font handle for more info look at font documentation + * Return values: + * true(1) on success + * false(0) on failure */ +NK_API int nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*); +/* nk_clear - Resets the context state at the end of the frame. This includes mostly + * garbage collector tasks like removing windows or table not called and therefore + * used anymore. + * Parameters: + * @ctx must point to a previously initialized `nk_context` struct */ +NK_API void nk_clear(struct nk_context*); +/* nk_free - Frees all memory allocated by nuklear. Not needed if context was + * initialized with `nk_init_fixed`. + * Parameters: + * @ctx must point to a previously initialized `nk_context` struct */ +NK_API void nk_free(struct nk_context*); +#ifdef NK_INCLUDE_COMMAND_USERDATA +/* nk_set_user_data - Sets the currently passed userdata passed down into each draw command. + * Parameters: + * @ctx must point to a previously initialized `nk_context` struct + * @data handle with either pointer or index to be passed into every draw commands */ +NK_API void nk_set_user_data(struct nk_context*, nk_handle handle); +#endif +/* ============================================================================= + * + * INPUT + * + * =============================================================================*/ +/* The input API is responsible for holding the current input state composed of + * mouse, key and text input states. + * It is worth noting that no direct os or window handling is done in nuklear. + * Instead all input state has to be provided by platform specific code. This in one hand + * expects more work from the user and complicates usage but on the other hand + * provides simple abstraction over a big number of platforms, libraries and other + * already provided functionality. + * + * Usage + * ------------------- + * Input state needs to be provided to nuklear by first calling `nk_input_begin` + * which resets internal state like delta mouse position and button transistions. + * After `nk_input_begin` all current input state needs to be provided. This includes + * mouse motion, button and key pressed and released, text input and scrolling. + * Both event- or state-based input handling are supported by this API + * and should work without problems. Finally after all input state has been + * mirrored `nk_input_end` needs to be called to finish input process. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * Event evt; + * nk_input_begin(&ctx); + * while (GetEvent(&evt)) { + * if (evt.type == MOUSE_MOVE) + * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); + * else if (evt.type == ...) { + * ... + * } + * } + * nk_input_end(&ctx); + * [...] + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * Reference + * ------------------- + * nk_input_begin - Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls + * nk_input_motion - Mirrors mouse cursor position + * nk_input_key - Mirrors key state with either pressed or released + * nk_input_button - Mirrors mouse button state with either pressed or released + * nk_input_scroll - Mirrors mouse scroll values + * nk_input_char - Adds a single ASCII text character into an internal text buffer + * nk_input_glyph - Adds a single multi-byte UTF-8 character into an internal text buffer + * nk_input_unicode - Adds a single unicode rune into an internal text buffer + * nk_input_end - Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call + */ enum nk_keys { NK_KEY_NONE, NK_KEY_SHIFT, @@ -549,7 +672,6 @@ enum nk_keys { NK_KEY_DOWN, NK_KEY_LEFT, NK_KEY_RIGHT, - /* Shortcuts: text field */ NK_KEY_TEXT_INSERT_MODE, NK_KEY_TEXT_REPLACE_MODE, @@ -563,23 +685,1455 @@ enum nk_keys { NK_KEY_TEXT_SELECT_ALL, NK_KEY_TEXT_WORD_LEFT, NK_KEY_TEXT_WORD_RIGHT, - /* Shortcuts: scrollbar */ NK_KEY_SCROLL_START, NK_KEY_SCROLL_END, NK_KEY_SCROLL_DOWN, NK_KEY_SCROLL_UP, - NK_KEY_MAX }; - enum nk_buttons { NK_BUTTON_LEFT, NK_BUTTON_MIDDLE, NK_BUTTON_RIGHT, + NK_BUTTON_DOUBLE, NK_BUTTON_MAX }; +/* nk_input_begin - Begins the input mirroring process by resetting text, scroll + * mouse previous mouse position and movement as well as key state transistions, + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct */ +NK_API void nk_input_begin(struct nk_context*); +/* nk_input_motion - Mirros current mouse position to nuklear + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @x must constain an integer describing the current mouse cursor x-position + * @y must constain an integer describing the current mouse cursor y-position */ +NK_API void nk_input_motion(struct nk_context*, int x, int y); +/* nk_input_key - Mirros state of a specific key to nuklear + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @key must be any value specified in enum `nk_keys` that needs to be mirrored + * @down must be 0 for key is up and 1 for key is down */ +NK_API void nk_input_key(struct nk_context*, enum nk_keys, int down); +/* nk_input_button - Mirros the state of a specific mouse button to nuklear + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @nk_buttons must be any value specified in enum `nk_buttons` that needs to be mirrored + * @x must constain an integer describing mouse cursor x-position on click up/down + * @y must constain an integer describing mouse cursor y-position on click up/down + * @down must be 0 for key is up and 1 for key is down */ +NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, int down); +/* nk_input_char - Copies a single ASCII character into an internal text buffer + * This is basically a helper function to quickly push ASCII characters into + * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into + * struct `nk_input` between `nk_input_begin` and `nk_input_end`. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @c must be a single ASCII character preferable one that can be printed */ +NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val); +/* nk_input_char - Copies a single ASCII character into an internal text buffer + * This is basically a helper function to quickly push ASCII characters into + * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into + * struct `nk_input` between `nk_input_begin` and `nk_input_end`. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @c must be a single ASCII character preferable one that can be printed */ +NK_API void nk_input_char(struct nk_context*, char); +/* nk_input_unicode - Converts a encoded unicode rune into UTF-8 and copies the result + * into an internal text buffer. + * Note that you can only push up to NK_INPUT_MAX bytes into + * struct `nk_input` between `nk_input_begin` and `nk_input_end`. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @glyph UTF-32 uncode codepoint */ +NK_API void nk_input_glyph(struct nk_context*, const nk_glyph); +/* nk_input_unicode - Converts a unicode rune into UTF-8 and copies the result + * into an internal text buffer. + * Note that you can only push up to NK_INPUT_MAX bytes into + * struct `nk_input` between `nk_input_begin` and `nk_input_end`. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @glyph UTF-32 uncode codepoint */ +NK_API void nk_input_unicode(struct nk_context*, nk_rune); +/* nk_input_end - End the input mirroring process by resetting mouse grabbing + * state to ensure the mouse cursor is not grabbed indefinitely. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct */ +NK_API void nk_input_end(struct nk_context*); +/* ============================================================================= + * + * DRAWING + * + * =============================================================================*/ +/* This library was designed to be render backend agnostic so it does + * not draw anything to screen directly. Instead all drawn shapes, widgets + * are made of, are buffered into memory and make up a command queue. + * Each frame therefore fills the command buffer with draw commands + * that then need to be executed by the user and his own render backend. + * After that the command buffer needs to be cleared and a new frame can be + * started. It is probably important to note that the command buffer is the main + * drawing API and the optional vertex buffer API only takes this format and + * converts it into a hardware accessible format. + * + * Usage + * ------------------- + * To draw all draw commands accumulated over a frame you need your own render + * backend able to draw a number of 2D primitives. This includes at least + * filled and stroked rectangles, circles, text, lines, triangles and scissors. + * As soon as this criterion is met you can iterate over each draw command + * and execute each draw command in a interpreter like fashion: + * + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * switch (cmd->type) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * + * In program flow context draw commands need to be executed after input has been + * gathered and the complete UI with windows and their contained widgets have + * been executed and before calling `nk_clear` which frees all previously + * allocated draw commands. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * Event evt; + * nk_input_begin(&ctx); + * while (GetEvent(&evt)) { + * if (evt.type == MOUSE_MOVE) + * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); + * else if (evt.type == [...]) { + * [...] + * } + * } + * nk_input_end(&ctx); + * + * [...] + * + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * switch (cmd->type) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * You probably noticed that you have to draw all of the UI each frame which is + * quite wasteful. While the actual UI updating loop is quite fast rendering + * without actually needing it is not. So there are multiple things you could do. + * + * First is only update on input. This of course is only an option if your + * application only depends on the UI and does not require any outside calculations. + * If you actually only update on input make sure to update the UI two times each + * frame and call `nk_clear` directly after the first pass and only draw in + * the second pass. In addition it is recommended to also add additional timers + * to make sure the UI is not drawn more than a fixed number of frames per second. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * [...wait for input ] + * + * [...do two UI passes ...] + * do_ui(...) + * nk_clear(&ctx); + * do_ui(...) + * + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * switch (cmd->type) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * The second probably more applicable trick is to only draw if anything changed. + * It is not really useful for applications with continous draw loop but + * quite useful for desktop applications. To actually get nuklear to only + * draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and + * allocate a memory buffer that will store each unique drawing output. + * After each frame you compare the draw command memory inside the library + * with your allocated buffer by memcmp. If memcmp detects differences + * you have to copy the command buffer into the allocated buffer + * and then draw like usual (this example uses fixed memory but you could + * use dynamically allocated memory). + * + * [... other defines ...] + * #define NK_ZERO_COMMAND_MEMORY + * #include "nuklear.h" + * + * struct nk_context ctx; + * void *last = calloc(1,64*1024); + * void *buf = calloc(1,64*1024); + * nk_init_fixed(&ctx, buf, 64*1024); + * while (1) { + * [...input...] + * [...ui...] + * + * void *cmds = nk_buffer_memory(&ctx.memory); + * if (memcmp(cmds, last, ctx.memory.allocated)) { + * memcpy(last,cmds,ctx.memory.allocated); + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * switch (cmd->type) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * } + * } + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * Finally while using draw commands makes sense for higher abstracted platforms like + * X11 and Win32 or drawing libraries it is often desirable to use graphics + * hardware directly. Therefore it is possible to just define + * `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output. + * To access the vertex output you first have to convert all draw commands into + * vertexes by calling `nk_convert` which takes in your prefered vertex format. + * After successfully converting all draw commands just iterate over and execute all + * vertex draw commands: + * + * struct nk_convert_config cfg = {}; + * static const struct nk_draw_vertex_layout_element vertex_layout[] = { + * {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)}, + * {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)}, + * {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)}, + * {NK_VERTEX_LAYOUT_END} + * }; + * cfg.shape_AA = NK_ANTI_ALIASING_ON; + * cfg.line_AA = NK_ANTI_ALIASING_ON; + * cfg.vertex_layout = vertex_layout; + * cfg.vertex_size = sizeof(struct your_vertex); + * cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex); + * cfg.circle_segment_count = 22; + * cfg.curve_segment_count = 22; + * cfg.arc_segment_count = 22; + * cfg.global_alpha = 1.0f; + * cfg.null = dev->null; + * + * struct nk_buffer cmds, verts, idx; + * nk_buffer_init_default(&cmds); + * nk_buffer_init_default(&verts); + * nk_buffer_init_default(&idx); + * nk_convert(&ctx, &cmds, &verts, &idx, &cfg); + * nk_draw_foreach(cmd, &ctx, &cmds) { + * if (!cmd->elem_count) continue; + * [...] + * } + * nk_buffer_free(&cms); + * nk_buffer_free(&verts); + * nk_buffer_free(&idx); + * + * Reference + * ------------------- + * nk__begin - Returns the first draw command in the context draw command list to be drawn + * nk__next - Increments the draw command iterator to the next command inside the context draw command list + * nk_foreach - Iteratates over each draw command inside the context draw command list + * + * nk_convert - Converts from the abstract draw commands list into a hardware accessable vertex format + * nk__draw_begin - Returns the first vertex command in the context vertex draw list to be executed + * nk__draw_next - Increments the vertex command iterator to the next command inside the context vertex command list + * nk__draw_end - Returns the end of the vertex draw list + * nk_draw_foreach - Iterates over each vertex draw command inside the vertex draw list + */ +enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON}; +enum nk_convert_result { + NK_CONVERT_SUCCESS = 0, + NK_CONVERT_INVALID_PARAM = 1, + NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1), + NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2), + NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3) +}; +struct nk_draw_null_texture { + nk_handle texture; /* texture handle to a texture with a white pixel */ + struct nk_vec2 uv; /* coordinates to a white pixel in the texture */ +}; +struct nk_convert_config { + float global_alpha; /* global alpha value */ + enum nk_anti_aliasing line_AA; /* line anti-aliasing flag can be turned off if you are tight on memory */ + enum nk_anti_aliasing shape_AA; /* shape anti-aliasing flag can be turned off if you are tight on memory */ + unsigned circle_segment_count; /* number of segments used for circles: default to 22 */ + unsigned arc_segment_count; /* number of segments used for arcs: default to 22 */ + unsigned curve_segment_count; /* number of segments used for curves: default to 22 */ + struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */ + const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */ + nk_size vertex_size; /* sizeof one vertex for vertex packing */ + nk_size vertex_alignment; /* vertex alignment: Can be optained by NK_ALIGNOF */ +}; +/* nk__begin - Returns a draw command list iterator to iterate all draw + * commands accumulated over one frame. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * Return values: + * draw command pointer pointing to the first command inside the draw command list */ +NK_API const struct nk_command* nk__begin(struct nk_context*); +/* nk__next - Returns a draw command list iterator to iterate all draw + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @cmd must point to an previously a draw command either returned by `nk__begin` or `nk__next` + * Return values: + * draw command pointer pointing to the next command inside the draw command list */ +NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); +/* nk_foreach - Iterates over each draw command inside the context draw command list + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @cmd pointer initialized to NULL */ +#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c)) +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT +/* nk_convert - converts all internal draw command into vertex draw commands and fills + * three buffers with vertexes, vertex draw commands and vertex indicies. The vertex format + * as well as some other configuration values have to be configurated by filling out a + * `nk_convert_config` struct. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @cmds must point to a previously initialized buffer to hold converted vertex draw commands + * @vertices must point to a previously initialized buffer to hold all produced verticies + * @elements must point to a previously initialized buffer to hold all procudes vertex indicies + * @config must point to a filled out `nk_config` struct to configure the conversion process + * Returns: + * returns NK_CONVERT_SUCCESS on success and a enum nk_convert_result error values if not */ +NK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*); +/* nk__draw_begin - Returns a draw vertex command buffer iterator to iterate each the vertex draw command buffer + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer + * Return values: + * vertex draw command pointer pointing to the first command inside the vertex draw command buffer */ +NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); +/* nk__draw_end - Returns the vertex draw command at the end of the vertex draw command buffer + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer + * Return values: + * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */ +NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*); +/* nk__draw_next - Increments the the vertex draw command buffer iterator + * Parameters: + * @cmd must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command + * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * Return values: + * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */ +NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); +/* nk_draw_foreach - Iterates over each vertex draw command inside a vertex draw command buffer + * Parameters: + * @cmd nk_draw_command pointer set to NULL + * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame */ +#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx)) +#endif +/* ============================================================================= + * + * WINDOW + * + * ============================================================================= + * Windows are the main persistent state used inside nuklear and are life time + * controlled by simply "retouching" (i.e. calling) each window each frame. + * All widgets inside nuklear can only be added inside function pair `nk_begin_xxx` + * and `nk_end`. Calling any widgets outside these two functions will result in an + * assert in debug or no state change in release mode. + * + * Each window holds frame persistent state like position, size, flags, state tables, + * and some garbage collected internal persistent widget state. Each window + * is linked into a window stack list which determines the drawing and overlapping + * order. The topmost window thereby is the currently active window. + * + * To change window position inside the stack occurs either automatically by + * user input by being clicked on or programatically by calling `nk_window_focus`. + * Windows by default are visible unless explicitly being defined with flag + * `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag + * `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling + * `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`. + * + * Usage + * ------------------- + * To create and keep a window you have to call one of the two `nk_begin_xxx` + * functions to start window declarations and `nk_end` at the end. Furthermore it + * is recommended to check the return value of `nk_begin_xxx` and only process + * widgets inside the window if the value is not 0. Either way you have to call + * `nk_end` at the end of window declarations. Furthmore do not attempt to + * nest `nk_begin_xxx` calls which will hopefully result in an assert or if not + * in a segmation fault. + * + * if (nk_begin_xxx(...) { + * [... widgets ...] + * } + * nk_end(ctx); + * + * In the grand concept window and widget declarations need to occur after input + * handling and before drawing to screen. Not doing so can result in higher + * latency or at worst invalid behavior. Furthermore make sure that `nk_clear` + * is called at the end of the frame. While nuklears default platform backends + * already call `nk_clear` for you if you write your own backend not calling + * `nk_clear` can cause asserts or even worse undefined behavior. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * Event evt; + * nk_input_begin(&ctx); + * while (GetEvent(&evt)) { + * if (evt.type == MOUSE_MOVE) + * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); + * else if (evt.type == [...]) { + * nk_input_xxx(...); + * } + * } + * nk_input_end(&ctx); + * + * if (nk_begin_xxx(...) { + * [...] + * } + * nk_end(ctx); + * + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * Reference + * ------------------- + * nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed + * nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title + * nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup + * + * nk_window_find - finds and returns the window with give name + * nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window. + * nk_window_get_position - returns the position of the currently processed window + * nk_window_get_size - returns the size with width and height of the currently processed window + * nk_window_get_width - returns the width of the currently processed window + * nk_window_get_height - returns the height of the currently processed window + * nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window + * nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window + * nk_window_get_content_region_min - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window + * nk_window_get_content_region_max - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window + * nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window + * nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets + * + * nk_window_has_focus - returns if the currently processed window is currently active + * nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed + * nk_window_is_closed - returns if the currently processed window was closed + * nk_window_is_hidden - returns if the currently processed window was hidden + * nk_window_is_active - same as nk_window_has_focus for some reason + * nk_window_is_hovered - returns if the currently processed window is currently being hovered by mouse + * nk_window_is_any_hovered - return if any wndow currently hovered + * nk_item_is_any_active - returns if any window or widgets is currently hovered or active + * + * nk_window_set_bounds - updates position and size of the currently processed window + * nk_window_set_position - updates position of the currently process window + * nk_window_set_size - updates the size of the currently processed window + * nk_window_set_focus - set the currently processed window as active window + * + * nk_window_close - closes the window with given window name which deletes the window at the end of the frame + * nk_window_collapse - collapses the window with given window name + * nk_window_collapse_if - collapses the window with given window name if the given condition was met + * nk_window_show - hides a visible or reshows a hidden window + * nk_window_show_if - hides/shows a window depending on condition + */ +enum nk_panel_flags { + NK_WINDOW_BORDER = NK_FLAG(0), /* Draws a border around the window to visually separate window from the background */ + NK_WINDOW_MOVABLE = NK_FLAG(1), /* The movable flag indicates that a window can be moved by user input or by dragging the window header */ + NK_WINDOW_SCALABLE = NK_FLAG(2), /* The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window */ + NK_WINDOW_CLOSABLE = NK_FLAG(3), /* adds a closable icon into the header */ + NK_WINDOW_MINIMIZABLE = NK_FLAG(4), /* adds a minimize icon into the header */ + NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5), /* Removes the scrollbar from the window */ + NK_WINDOW_TITLE = NK_FLAG(6), /* Forces a header at the top at the window showing the title */ + NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7), /* Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame */ + NK_WINDOW_BACKGROUND = NK_FLAG(8), /* Always keep window in the background */ + NK_WINDOW_SCALE_LEFT = NK_FLAG(9), /* Puts window scaler in the left-ottom corner instead right-bottom*/ + NK_WINDOW_NO_INPUT = NK_FLAG(10) /* Prevents window of scaling, moving or getting focus */ +}; +/* nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @title window title and identifier. Needs to be persitent over frames to identify the window + * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame + * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors + * Return values: + * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise for example if minimized `*/ +NK_API int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); +/* nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name window identifier. Needs to be persitent over frames to identify the window + * @title window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set + * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame + * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors + * Return values: + * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise `*/ +NK_API int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); +/* nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup. + * All widget calls after this functions will result in asserts or no state changes + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct */ +NK_API void nk_end(struct nk_context *ctx); +/* nk_window_find - finds and returns the window with give name + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name window identifier + * Return values: + * returns a `nk_window` struct pointing to the idified window or 0 if no window with given name was found */ +NK_API struct nk_window *nk_window_find(struct nk_context *ctx, const char *name); +/* nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a `nk_rect` struct with window upper left position and size */ +NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx); +/* nk_window_get_position - returns the position of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a `nk_vec2` struct with window upper left position */ +NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx); +/* nk_window_get_size - returns the size with width and height of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a `nk_vec2` struct with window size */ +NK_API struct nk_vec2 nk_window_get_size(const struct nk_context*); +/* nk_window_get_width - returns the width of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns the window width */ +NK_API float nk_window_get_width(const struct nk_context*); +/* nk_window_get_height - returns the height of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns the window height */ +NK_API float nk_window_get_height(const struct nk_context*); +/* nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a pointer to window internal `nk_panel` state. DO NOT keep this pointer around it is only valid until `nk_end` */ +NK_API struct nk_panel* nk_window_get_panel(struct nk_context*); +/* nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns `nk_rect` struct with screen position and size (no scrollbar offset) of the visible space inside the current window */ +NK_API struct nk_rect nk_window_get_content_region(struct nk_context*); +/* nk_window_get_content_region_min - returns the upper left position of the currently visible and non-clipped space inside the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns `nk_vec2` struct with upper left screen position (no scrollbar offset) of the visible space inside the current window */ +NK_API struct nk_vec2 nk_window_get_content_region_min(struct nk_context*); +/* nk_window_get_content_region_max - returns the lower right screen position of the currently visible and non-clipped space inside the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns `nk_vec2` struct with lower right screen position (no scrollbar offset) of the visible space inside the current window */ +NK_API struct nk_vec2 nk_window_get_content_region_max(struct nk_context*); +/* nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns `nk_vec2` struct with size the visible space inside the current window */ +NK_API struct nk_vec2 nk_window_get_content_region_size(struct nk_context*); +/* nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a pointer to window internal `nk_command_buffer` struct used as drawing canvas. Can be used to do custom drawing */ +NK_API struct nk_command_buffer* nk_window_get_canvas(struct nk_context*); +/* nk_window_has_focus - returns if the currently processed window is currently active + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns 0 if current window is not active or 1 if it is */ +NK_API int nk_window_has_focus(const struct nk_context*); +/* nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of window you want to check is collapsed + * Return values: + * returns 1 if current window is minimized and 0 if window not found or is not minimized */ +NK_API int nk_window_is_collapsed(struct nk_context *ctx, const char *name); +/* nk_window_is_closed - returns if the window with given name was closed by calling `nk_close` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of window you want to check is closed + * Return values: + * returns 1 if current window was closed or 0 window not found or not closed */ +NK_API int nk_window_is_closed(struct nk_context*, const char*); +/* nk_window_is_hidden - returns if the window with given name is hidden + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of window you want to check is hidden + * Return values: + * returns 1 if current window is hidden or 0 window not found or visible */ +NK_API int nk_window_is_hidden(struct nk_context*, const char*); +/* nk_window_is_active - same as nk_window_has_focus for some reason + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of window you want to check is hidden + * Return values: + * returns 1 if current window is active or 0 window not found or not active */ +NK_API int nk_window_is_active(struct nk_context*, const char*); +/* nk_window_is_hovered - return if the current window is being hovered + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns 1 if current window is hovered or 0 otherwise */ +NK_API int nk_window_is_hovered(struct nk_context*); +/* nk_window_is_any_hovered - returns if the any window is being hovered + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns 1 if any window is hovered or 0 otherwise */ +NK_API int nk_window_is_any_hovered(struct nk_context*); +/* nk_item_is_any_active - returns if the any window is being hovered or any widget is currently active. + * Can be used to decide if input should be processed by UI or your specific input handling. + * Example could be UI and 3D camera to move inside a 3D space. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns 1 if any window is hovered or any item is active or 0 otherwise */ +NK_API int nk_item_is_any_active(struct nk_context*); +/* nk_window_set_bounds - updates position and size of the currently processed window + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @bounds points to a `nk_rect` struct with the new position and size of currently active window */ +NK_API void nk_window_set_bounds(struct nk_context*, struct nk_rect bounds); +/* nk_window_set_position - updates position of the currently processed window + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @pos points to a `nk_vec2` struct with the new position of currently active window */ +NK_API void nk_window_set_position(struct nk_context*, struct nk_vec2 pos); +/* nk_window_set_size - updates size of the currently processed window + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @bounds points to a `nk_vec2` struct with the new size of currently active window */ +NK_API void nk_window_set_size(struct nk_context*, struct nk_vec2); +/* nk_window_set_focus - sets the window with given name as active + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be set active */ +NK_API void nk_window_set_focus(struct nk_context*, const char *name); +/* nk_window_close - closed a window and marks it for being freed at the end of the frame + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be closed */ +NK_API void nk_window_close(struct nk_context *ctx, const char *name); +/* nk_window_collapse - updates collapse state of a window with given name + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be either collapse or maximize */ +NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state); +/* nk_window_collapse - updates collapse state of a window with given name if given condition is met + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be either collapse or maximize + * @state the window should be put into + * @condition that has to be true to actually commit the collsage state change */ +NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); +/* nk_window_show - updates visibility state of a window with given name + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be either collapse or maximize + * @state with either visible or hidden to modify the window with */ +NK_API void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); +/* nk_window_show_if - updates visibility state of a window with given name if a given condition is met + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be either collapse or maximize + * @state with either visible or hidden to modify the window with + * @condition that has to be true to actually commit the visible state change */ +NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); +/* ============================================================================= + * + * LAYOUT + * + * ============================================================================= */ +/* Layouting in general describes placing widget inside a window with position and size. + * While in this particular implementation there are five different APIs for layouting + * each with different trade offs between control and ease of use. + * + * All layouting methodes in this library are based around the concept of a row. + * A row has a height the window content grows by and a number of columns and each + * layouting method specifies how each widget is placed inside the row. + * After a row has been allocated by calling a layouting functions and then + * filled with widgets will advance an internal pointer over the allocated row. + * + * To acually define a layout you just call the appropriate layouting function + * and each subsequnetial widget call will place the widget as specified. Important + * here is that if you define more widgets then columns defined inside the layout + * functions it will allocate the next row without you having to make another layouting + * call. + * + * Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API + * is that you have to define the row height for each. However the row height + * often depends on the height of the font. + * + * To fix that internally nuklear uses a minimum row height that is set to the + * height plus padding of currently active font and overwrites the row height + * value if zero. + * + * If you manually want to change the minimum row height then + * use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to + * reset it back to be derived from font height. + * + * Also if you change the font in nuklear it will automatically change the minimum + * row height for you and. This means if you change the font but still want + * a minimum row height smaller than the font you have to repush your value. + * + * For actually more advanced UI I would even recommend using the `nk_layout_space_xxx` + * layouting method in combination with a cassowary constraint solver (there are + * some versions on github with permissive license model) to take over all control over widget + * layouting yourself. However for quick and dirty layouting using all the other layouting + * functions should be fine. + * + * Usage + * ------------------- + * 1.) nk_layout_row_dynamic + * The easiest layouting function is `nk_layout_row_dynamic`. It provides each + * widgets with same horizontal space inside the row and dynamically grows + * if the owning window grows in width. So the number of columns dictates + * the size of each widget dynamically by formula: + * + * widget_width = (window_width - padding - spacing) * (1/colum_count) + * + * Just like all other layouting APIs if you define more widget than columns this + * library will allocate a new row and keep all layouting parameters previously + * defined. + * + * if (nk_begin_xxx(...) { + * // first row with height: 30 composed of two widgets + * nk_layout_row_dynamic(&ctx, 30, 2); + * nk_widget(...); + * nk_widget(...); + * + * // second row with same parameter as defined above + * nk_widget(...); + * nk_widget(...); + * + * // third row uses 0 for height which will use auto layouting + * nk_layout_row_dynamic(&ctx, 0, 2); + * nk_widget(...); + * nk_widget(...); + * } + * nk_end(...); + * + * 2.) nk_layout_row_static + * Another easy layouting function is `nk_layout_row_static`. It provides each + * widget with same horizontal pixel width inside the row and does not grow + * if the owning window scales smaller or bigger. + * + * if (nk_begin_xxx(...) { + * // first row with height: 30 composed of two widgets with width: 80 + * nk_layout_row_static(&ctx, 30, 80, 2); + * nk_widget(...); + * nk_widget(...); + * + * // second row with same parameter as defined above + * nk_widget(...); + * nk_widget(...); + * + * // third row uses 0 for height which will use auto layouting + * nk_layout_row_static(&ctx, 0, 80, 2); + * nk_widget(...); + * nk_widget(...); + * } + * nk_end(...); + * + * 3.) nk_layout_row_xxx + * A little bit more advanced layouting API are functions `nk_layout_row_begin`, + * `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly + * specify each column pixel or window ratio in a row. It supports either + * directly setting per column pixel width or widget window ratio but not + * both. Furthermore it is a immediate mode API so each value is directly + * pushed before calling a widget. Therefore the layout is not automatically + * repeating like the last two layouting functions. + * + * if (nk_begin_xxx(...) { + * // first row with height: 25 composed of two widgets with width 60 and 40 + * nk_layout_row_begin(ctx, NK_STATIC, 25, 2); + * nk_layout_row_push(ctx, 60); + * nk_widget(...); + * nk_layout_row_push(ctx, 40); + * nk_widget(...); + * nk_layout_row_end(ctx); + * + * // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75 + * nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2); + * nk_layout_row_push(ctx, 0.25f); + * nk_widget(...); + * nk_layout_row_push(ctx, 0.75f); + * nk_widget(...); + * nk_layout_row_end(ctx); + * + * // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75 + * nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2); + * nk_layout_row_push(ctx, 0.25f); + * nk_widget(...); + * nk_layout_row_push(ctx, 0.75f); + * nk_widget(...); + * nk_layout_row_end(ctx); + * } + * nk_end(...); + * + * 4.) nk_layout_row + * The array counterpart to API nk_layout_row_xxx is the single nk_layout_row + * functions. Instead of pushing either pixel or window ratio for every widget + * it allows to define it by array. The trade of for less control is that + * `nk_layout_row` is automatically repeating. Otherwise the behavior is the + * same. + * + * if (nk_begin_xxx(...) { + * // two rows with height: 30 composed of two widgets with width 60 and 40 + * const float size[] = {60,40}; + * nk_layout_row(ctx, NK_STATIC, 30, 2, ratio); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * + * // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75 + * const float ratio[] = {0.25, 0.75}; + * nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * + * // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75 + * const float ratio[] = {0.25, 0.75}; + * nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * } + * nk_end(...); + * + * 5.) nk_layout_row_template_xxx + * The most complex and second most flexible API is a simplified flexbox version without + * line wrapping and weights for dynamic widgets. It is an immediate mode API but + * unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called + * before calling the templated widgets. + * The row template layout has three different per widget size specifier. The first + * one is the static widget size specifier with fixed widget pixel width. They do + * not grow if the row grows and will always stay the same. The second size + * specifier is nk_layout_row_template_push_variable which defines a + * minumum widget size but it also can grow if more space is available not taken + * by other widgets. Finally there are dynamic widgets which are completly flexible + * and unlike variable widgets can even shrink to zero if not enough space + * is provided. + * + * if (nk_begin_xxx(...) { + * // two rows with height: 30 composed of three widgets + * nk_layout_row_template_begin(ctx, 30); + * nk_layout_row_template_push_dynamic(ctx); + * nk_layout_row_template_push_variable(ctx, 80); + * nk_layout_row_template_push_static(ctx, 80); + * nk_layout_row_template_end(ctx); + * + * nk_widget(...); // dynamic widget can go to zero if not enough space + * nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space + * nk_widget(...); // static widget with fixed 80 pixel width + * + * // second row same layout + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * } + * nk_end(...); + * + * 6.) nk_layout_space_xxx + * Finally the most flexible API directly allows you to place widgets inside the + * window. The space layout API is an immediate mode API which does not support + * row auto repeat and directly sets position and size of a widget. Position + * and size hereby can be either specified as ratio of alloated space or + * allocated space local position and pixel size. Since this API is quite + * powerfull there are a number of utility functions to get the available space + * and convert between local allocated space and screen space. + * + * if (nk_begin_xxx(...) { + * // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) + * nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX); + * nk_layout_space_push(ctx, nk_rect(0,0,150,200)); + * nk_widget(...); + * nk_layout_space_push(ctx, nk_rect(200,200,100,200)); + * nk_widget(...); + * nk_layout_space_end(ctx); + * + * // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) + * nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX); + * nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1)); + * nk_widget(...); + * nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1)); + * nk_widget(...); + * } + * nk_end(...); + * + * Reference + * ------------------- + * nk_layout_set_min_row_height - set the currently used minimum row height to a specified value + * nk_layout_reset_min_row_height - resets the currently used minimum row height to font height + * + * nk_layout_widget_bounds - calculates current width a static layout row can fit inside a window + * nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size + * + * nk_layout_row_dynamic - current layout is divided into n same sized gowing columns + * nk_layout_row_static - current layout is divided into n same fixed sized columns + * nk_layout_row_begin - starts a new row with given height and number of columns + * nk_layout_row_push - pushes another column with given size or window ratio + * nk_layout_row_end - finished previously started row + * nk_layout_row - specifies row columns in array as either window ratio or size + * + * nk_layout_row_template_begin - begins the row template declaration + * nk_layout_row_template_push_dynamic - adds a dynamic column that dynamically grows and can go to zero if not enough space + * nk_layout_row_template_push_variable - adds a variable column that dynamically grows but does not shrink below specified pixel width + * nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size + * nk_layout_row_template_end - marks the end of the row template + * + * nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size + * nk_layout_space_push - pushes position and size of the next widget in own coordiante space either as pixel or ratio + * nk_layout_space_end - marks the end of the layouting space + * + * nk_layout_space_bounds - callable after nk_layout_space_begin and returns total space allocated + * nk_layout_space_to_screen - convertes vector from nk_layout_space coordiant space into screen space + * nk_layout_space_to_local - convertes vector from screem space into nk_layout_space coordinates + * nk_layout_space_rect_to_screen - convertes rectangle from nk_layout_space coordiant space into screen space + * nk_layout_space_rect_to_local - convertes rectangle from screem space into nk_layout_space coordinates + */ +/* nk_layout_set_min_row_height - sets the currently used minimum row height. + * IMPORTANT: The passed height needs to include both your prefered row height + * as well as padding. No internal padding is added. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` + * @height new minimum row height to be used for auto generating the row height */ +NK_API void nk_layout_set_min_row_height(struct nk_context*, float height); +/* nk_layout_reset_min_row_height - Reset the currently used minimum row height + * back to font height + text padding + additional padding (style_window.min_row_height_padding) + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` */ +NK_API void nk_layout_reset_min_row_height(struct nk_context*); +/* nk_layout_widget_bounds - returns the width of the next row allocate by one of the layouting functions + * Parameters: + * @ctx must point to an previously initialized `nk_context` */ +NK_API struct nk_rect nk_layout_widget_bounds(struct nk_context*); +/* nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size + * Parameters: + * @ctx must point to an previously initialized `nk_context` + * @pixel_width to convert to window ratio */ +NK_API float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); +/* nk_layout_row_dynamic - Sets current row layout to share horizontal space + * between @cols number of widgets evenly. Once called all subsequent widget + * calls greater than @cols will allocate a new row with same layout. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` + * @row_height holds height of each widget in row or zero for auto layouting + * @cols number of widget inside row */ +NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols); +/* nk_layout_row_static - Sets current row layout to fill @cols number of widgets + * in row with same @item_width horizontal size. Once called all subsequent widget + * calls greater than @cols will allocate a new row with same layout. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` + * @height holds row height to allocate from panel for widget height + * @item_width holds width of each widget in row + * @cols number of widget inside row */ +NK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols); +/* nk_layout_row_begin - Starts a new dynamic or fixed row with given height and columns. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` + * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns + * @row_height holds height of each widget in row or zero for auto layouting + * @cols number of widget inside row */ +NK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols); +/* nk_layout_row_push - Specifies either window ratio or width of a single column + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_begin` + * @value either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call */ +NK_API void nk_layout_row_push(struct nk_context*, float value); +/* nk_layout_row_end - finished previously started row + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_begin` */ +NK_API void nk_layout_row_end(struct nk_context*); +/* nk_layout_row - specifies row columns in array as either window ratio or size + * Parameters: + * @ctx must point to an previously initialized `nk_context` + * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns + * @row_height holds height of each widget in row or zero for auto layouting + * @cols number of widget inside row */ +NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); +/* nk_layout_row_template_begin - Begins the row template declaration + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @row_height holds height of each widget in row or zero for auto layouting */ +NK_API void nk_layout_row_template_begin(struct nk_context*, float row_height); +/* nk_layout_row_template_push_dynamic - adds a dynamic column that dynamically grows and can go to zero if not enough space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` */ +NK_API void nk_layout_row_template_push_dynamic(struct nk_context*); +/* nk_layout_row_template_push_variable - adds a variable column that dynamically grows but does not shrink below specified pixel width + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` + * @min_width holds the minimum pixel width the next column must be */ +NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width); +/* nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` + * @width holds the absolulte pixel width value the next column must be */ +NK_API void nk_layout_row_template_push_static(struct nk_context*, float width); +/* nk_layout_row_template_end - marks the end of the row template + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` */ +NK_API void nk_layout_row_template_end(struct nk_context*); +/* nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns + * @row_height holds height of each widget in row or zero for auto layouting + * @widget_count number of widgets inside row */ +NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); +/* nk_layout_space_push - pushes position and size of the next widget in own coordiante space either as pixel or ratio + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @bounds position and size in laoyut space local coordinates */ +NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect); +/* nk_layout_space_end - marks the end of the layout space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */ +NK_API void nk_layout_space_end(struct nk_context*); +/* nk_layout_space_bounds - returns total space allocated for `nk_layout_space` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */ +NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*); +/* nk_layout_space_to_screen - convertes vector from nk_layout_space coordiant space into screen space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @vec position to convert from layout space into screen coordinate space */ +NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); +/* nk_layout_space_to_screen - convertes vector from layout space into screen space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @vec position to convert from screen space into layout coordinate space */ +NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); +/* nk_layout_space_rect_to_screen - convertes rectangle from screen space into layout space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @bounds rectangle to convert from layout space into screen space */ +NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); +/* nk_layout_space_rect_to_local - convertes rectangle from layout space into screen space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @bounds rectangle to convert from screen space into layout space */ +NK_API struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); +/* ============================================================================= + * + * GROUP + * + * ============================================================================= */ +NK_API int nk_group_begin(struct nk_context*, const char *title, nk_flags); +NK_API int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char*, nk_flags); +NK_API int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll*, const char *title, nk_flags); +NK_API void nk_group_scrolled_end(struct nk_context*); +NK_API void nk_group_end(struct nk_context*); +/* ============================================================================= + * + * LIST VIEW + * + * ============================================================================= */ +struct nk_list_view { +/* public: */ + int begin, end, count; +/* private: */ + int total_height; + struct nk_context *ctx; + nk_uint *scroll_pointer; + nk_uint scroll_value; +}; +NK_API int nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count); +NK_API void nk_list_view_end(struct nk_list_view*); +/* ============================================================================= + * + * TREE + * + * ============================================================================= */ +#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) +#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) +NK_API int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); +#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) +#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) +NK_API int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); +NK_API void nk_tree_pop(struct nk_context*); +NK_API int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); +NK_API int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); +NK_API void nk_tree_state_pop(struct nk_context*); +/* ============================================================================= + * + * WIDGET + * + * ============================================================================= */ +enum nk_widget_layout_states { + NK_WIDGET_INVALID, /* The widget cannot be seen and is completely out of view */ + NK_WIDGET_VALID, /* The widget is completely inside the window and can be updated and drawn */ + NK_WIDGET_ROM /* The widget is partially visible and cannot be updated */ +}; +enum nk_widget_states { + NK_WIDGET_STATE_MODIFIED = NK_FLAG(1), + NK_WIDGET_STATE_INACTIVE = NK_FLAG(2), /* widget is neither active nor hovered */ + NK_WIDGET_STATE_ENTERED = NK_FLAG(3), /* widget has been hovered on the current frame */ + NK_WIDGET_STATE_HOVER = NK_FLAG(4), /* widget is being hovered */ + NK_WIDGET_STATE_ACTIVED = NK_FLAG(5),/* widget is currently activated */ + NK_WIDGET_STATE_LEFT = NK_FLAG(6), /* widget is from this frame on not hovered anymore */ + NK_WIDGET_STATE_HOVERED = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /* widget is being hovered */ + NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /* widget is currently activated */ +}; +NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*); +NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, struct nk_context*, struct nk_vec2); +NK_API struct nk_rect nk_widget_bounds(struct nk_context*); +NK_API struct nk_vec2 nk_widget_position(struct nk_context*); +NK_API struct nk_vec2 nk_widget_size(struct nk_context*); +NK_API float nk_widget_width(struct nk_context*); +NK_API float nk_widget_height(struct nk_context*); +NK_API int nk_widget_is_hovered(struct nk_context*); +NK_API int nk_widget_is_mouse_clicked(struct nk_context*, enum nk_buttons); +NK_API int nk_widget_has_mouse_click_down(struct nk_context*, enum nk_buttons, int down); +NK_API void nk_spacing(struct nk_context*, int cols); +/* ============================================================================= + * + * TEXT + * + * ============================================================================= */ +enum nk_text_align { + NK_TEXT_ALIGN_LEFT = 0x01, + NK_TEXT_ALIGN_CENTERED = 0x02, + NK_TEXT_ALIGN_RIGHT = 0x04, + NK_TEXT_ALIGN_TOP = 0x08, + NK_TEXT_ALIGN_MIDDLE = 0x10, + NK_TEXT_ALIGN_BOTTOM = 0x20 +}; +enum nk_text_alignment { + NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT, + NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED, + NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT +}; +NK_API void nk_text(struct nk_context*, const char*, int, nk_flags); +NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color); +NK_API void nk_text_wrap(struct nk_context*, const char*, int); +NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color); +NK_API void nk_label(struct nk_context*, const char*, nk_flags align); +NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color); +NK_API void nk_label_wrap(struct nk_context*, const char*); +NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color); +NK_API void nk_image(struct nk_context*, struct nk_image); +#ifdef NK_INCLUDE_STANDARD_VARARGS +NK_API void nk_labelf(struct nk_context*, nk_flags, const char*, ...); +NK_API void nk_labelf_colored(struct nk_context*, nk_flags align, struct nk_color, const char*,...); +NK_API void nk_labelf_wrap(struct nk_context*, const char*,...); +NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, const char*,...); +NK_API void nk_value_bool(struct nk_context*, const char *prefix, int); +NK_API void nk_value_int(struct nk_context*, const char *prefix, int); +NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int); +NK_API void nk_value_float(struct nk_context*, const char *prefix, float); +NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color); +NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color); +NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color); +#endif +/* ============================================================================= + * + * BUTTON + * + * ============================================================================= */ +NK_API int nk_button_text(struct nk_context*, const char *title, int len); +NK_API int nk_button_label(struct nk_context*, const char *title); +NK_API int nk_button_color(struct nk_context*, struct nk_color); +NK_API int nk_button_symbol(struct nk_context*, enum nk_symbol_type); +NK_API int nk_button_image(struct nk_context*, struct nk_image img); +NK_API int nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment); +NK_API int nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API int nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment); +NK_API int nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment); +NK_API int nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len); +NK_API int nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title); +NK_API int nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type); +NK_API int nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img); +NK_API int nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align); +NK_API int nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment); +NK_API int nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment); +NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior); +NK_API int nk_button_push_behavior(struct nk_context*, enum nk_button_behavior); +NK_API int nk_button_pop_behavior(struct nk_context*); +/* ============================================================================= + * + * CHECKBOX + * + * ============================================================================= */ +NK_API int nk_check_label(struct nk_context*, const char*, int active); +NK_API int nk_check_text(struct nk_context*, const char*, int,int active); +NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value); +NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value); +NK_API int nk_checkbox_label(struct nk_context*, const char*, int *active); +NK_API int nk_checkbox_text(struct nk_context*, const char*, int, int *active); +NK_API int nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value); +NK_API int nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value); +/* ============================================================================= + * + * RADIO BUTTON + * + * ============================================================================= */ +NK_API int nk_radio_label(struct nk_context*, const char*, int *active); +NK_API int nk_radio_text(struct nk_context*, const char*, int, int *active); +NK_API int nk_option_label(struct nk_context*, const char*, int active); +NK_API int nk_option_text(struct nk_context*, const char*, int, int active); +/* ============================================================================= + * + * SELECTABLE + * + * ============================================================================= */ +NK_API int nk_selectable_label(struct nk_context*, const char*, nk_flags align, int *value); +NK_API int nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, int *value); +NK_API int nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, int *value); +NK_API int nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, int *value); +NK_API int nk_select_label(struct nk_context*, const char*, nk_flags align, int value); +NK_API int nk_select_text(struct nk_context*, const char*, int, nk_flags align, int value); +NK_API int nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, int value); +NK_API int nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, int value); +/* ============================================================================= + * + * SLIDER + * + * ============================================================================= */ +NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step); +NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step); +NK_API int nk_slider_float(struct nk_context*, float min, float *val, float max, float step); +NK_API int nk_slider_int(struct nk_context*, int min, int *val, int max, int step); +/* ============================================================================= + * + * PROGRESSBAR + * + * ============================================================================= */ +NK_API int nk_progress(struct nk_context*, nk_size *cur, nk_size max, int modifyable); +NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, int modifyable); +/* ============================================================================= + * + * COLOR PICKER + * + * ============================================================================= */ +NK_API struct nk_color nk_color_picker(struct nk_context*, struct nk_color, enum nk_color_format); +NK_API int nk_color_pick(struct nk_context*, struct nk_color*, enum nk_color_format); +/* ============================================================================= + * + * PROPERTIES + * + * ============================================================================= */ +NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel); +NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel); +NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel); +NK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel); +NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel); +NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel); +/* ============================================================================= + * + * TEXT EDIT + * + * ============================================================================= */ +enum nk_edit_flags { + NK_EDIT_DEFAULT = 0, + NK_EDIT_READ_ONLY = NK_FLAG(0), + NK_EDIT_AUTO_SELECT = NK_FLAG(1), + NK_EDIT_SIG_ENTER = NK_FLAG(2), + NK_EDIT_ALLOW_TAB = NK_FLAG(3), + NK_EDIT_NO_CURSOR = NK_FLAG(4), + NK_EDIT_SELECTABLE = NK_FLAG(5), + NK_EDIT_CLIPBOARD = NK_FLAG(6), + NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7), + NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8), + NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9), + NK_EDIT_MULTILINE = NK_FLAG(10), + NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(11) +}; +enum nk_edit_types { + NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE, + NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD, + NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD, + NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD +}; +enum nk_edit_events { + NK_EDIT_ACTIVE = NK_FLAG(0), /* edit widget is currently being modified */ + NK_EDIT_INACTIVE = NK_FLAG(1), /* edit widget is not active and is not being modified */ + NK_EDIT_ACTIVATED = NK_FLAG(2), /* edit widget went from state inactive to state active */ + NK_EDIT_DEACTIVATED = NK_FLAG(3), /* edit widget went from state active to state inactive */ + NK_EDIT_COMMITED = NK_FLAG(4) /* edit widget has received an enter and lost focus */ +}; +NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter); +NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter); +NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter); +NK_API void nk_edit_focus(struct nk_context*, nk_flags flags); +NK_API void nk_edit_unfocus(struct nk_context*); +/* ============================================================================= + * + * CHART + * + * ============================================================================= */ +NK_API int nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max); +NK_API int nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max); +NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value); +NK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value); +NK_API nk_flags nk_chart_push(struct nk_context*, float); +NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int); +NK_API void nk_chart_end(struct nk_context*); +NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset); +NK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset); +/* ============================================================================= + * + * POPUP + * + * ============================================================================= */ +NK_API int nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds); +NK_API void nk_popup_close(struct nk_context*); +NK_API void nk_popup_end(struct nk_context*); +/* ============================================================================= + * + * COMBOBOX + * + * ============================================================================= */ +NK_API int nk_combo(struct nk_context*, const char **items, int count, int selected, int item_height, struct nk_vec2 size); +NK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size); +NK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size); +NK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size); +NK_API void nk_combobox(struct nk_context*, const char **items, int count, int *selected, int item_height, struct nk_vec2 size); +NK_API void nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size); +NK_API void nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator,int *selected, int count, int item_height, struct nk_vec2 size); +NK_API void nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size); +/* ============================================================================= + * + * ABSTRACT COMBOBOX + * + * ============================================================================= */ +NK_API int nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size); +NK_API int nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size); +NK_API int nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size); +NK_API int nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size); +NK_API int nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size); +NK_API int nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size); +NK_API int nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment); +NK_API int nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment); +NK_API int nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); +NK_API int nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment); +NK_API int nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); +NK_API int nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API void nk_combo_close(struct nk_context*); +NK_API void nk_combo_end(struct nk_context*); +/* ============================================================================= + * + * CONTEXTUAL + * + * ============================================================================= */ +NK_API int nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds); +NK_API int nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align); +NK_API int nk_contextual_item_label(struct nk_context*, const char*, nk_flags align); +NK_API int nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); +NK_API int nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); +NK_API int nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); +NK_API int nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API void nk_contextual_close(struct nk_context*); +NK_API void nk_contextual_end(struct nk_context*); +/* ============================================================================= + * + * TOOLTIP + * + * ============================================================================= */ +NK_API void nk_tooltip(struct nk_context*, const char*); +NK_API int nk_tooltip_begin(struct nk_context*, float width); +NK_API void nk_tooltip_end(struct nk_context*); +/* ============================================================================= + * + * MENU + * + * ============================================================================= */ +NK_API void nk_menubar_begin(struct nk_context*); +NK_API void nk_menubar_end(struct nk_context*); +NK_API int nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size); +NK_API int nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size); +NK_API int nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size); +NK_API int nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size); +NK_API int nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size); +NK_API int nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align); +NK_API int nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment); +NK_API int nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); +NK_API int nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); +NK_API int nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API int nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); +NK_API void nk_menu_close(struct nk_context*); +NK_API void nk_menu_end(struct nk_context*); +/* ============================================================================= + * + * STYLE + * + * ============================================================================= */ enum nk_style_colors { NK_COLOR_TEXT, NK_COLOR_WINDOW, @@ -611,7 +2165,6 @@ enum nk_style_colors { NK_COLOR_TAB_HEADER, NK_COLOR_COUNT }; - enum nk_style_cursor { NK_CURSOR_ARROW, NK_CURSOR_TEXT, @@ -622,532 +2175,142 @@ enum nk_style_cursor { NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT, NK_CURSOR_COUNT }; +NK_API void nk_style_default(struct nk_context*); +NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*); +NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*); +NK_API void nk_style_load_all_cursors(struct nk_context*, struct nk_cursor*); +NK_API const char* nk_style_get_color_by_name(enum nk_style_colors); +NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*); +NK_API int nk_style_set_cursor(struct nk_context*, enum nk_style_cursor); +NK_API void nk_style_show_cursor(struct nk_context*); +NK_API void nk_style_hide_cursor(struct nk_context*); -enum nk_widget_layout_states { - NK_WIDGET_INVALID, /* The widget cannot be seen and is completely out of view */ - NK_WIDGET_VALID, /* The widget is completely inside the window and can be updated and drawn */ - NK_WIDGET_ROM /* The widget is partially visible and cannot be updated */ -}; +NK_API int nk_style_push_font(struct nk_context*, const struct nk_user_font*); +NK_API int nk_style_push_float(struct nk_context*, float*, float); +NK_API int nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2); +NK_API int nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item); +NK_API int nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags); +NK_API int nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color); -/* widget states */ -enum nk_widget_states { - NK_WIDGET_STATE_MODIFIED = NK_FLAG(1), - NK_WIDGET_STATE_INACTIVE = NK_FLAG(2), /* widget is neither active nor hovered */ - NK_WIDGET_STATE_ENTERED = NK_FLAG(3), /* widget has been hovered on the current frame */ - NK_WIDGET_STATE_HOVER = NK_FLAG(4), /* widget is being hovered */ - NK_WIDGET_STATE_ACTIVED = NK_FLAG(5),/* widget is currently activated */ - NK_WIDGET_STATE_LEFT = NK_FLAG(6), /* widget is from this frame on not hovered anymore */ - NK_WIDGET_STATE_HOVERED = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /* widget is being hovered */ - NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /* widget is currently activated */ -}; +NK_API int nk_style_pop_font(struct nk_context*); +NK_API int nk_style_pop_float(struct nk_context*); +NK_API int nk_style_pop_vec2(struct nk_context*); +NK_API int nk_style_pop_style_item(struct nk_context*); +NK_API int nk_style_pop_flags(struct nk_context*); +NK_API int nk_style_pop_color(struct nk_context*); +/* ============================================================================= + * + * COLOR + * + * ============================================================================= */ +NK_API struct nk_color nk_rgb(int r, int g, int b); +NK_API struct nk_color nk_rgb_iv(const int *rgb); +NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb); +NK_API struct nk_color nk_rgb_f(float r, float g, float b); +NK_API struct nk_color nk_rgb_fv(const float *rgb); +NK_API struct nk_color nk_rgb_hex(const char *rgb); -/* text alignment */ -enum nk_text_align { - NK_TEXT_ALIGN_LEFT = 0x01, - NK_TEXT_ALIGN_CENTERED = 0x02, - NK_TEXT_ALIGN_RIGHT = 0x04, - NK_TEXT_ALIGN_TOP = 0x08, - NK_TEXT_ALIGN_MIDDLE = 0x10, - NK_TEXT_ALIGN_BOTTOM = 0x20 -}; -enum nk_text_alignment { - NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT, - NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED, - NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT -}; +NK_API struct nk_color nk_rgba(int r, int g, int b, int a); +NK_API struct nk_color nk_rgba_u32(nk_uint); +NK_API struct nk_color nk_rgba_iv(const int *rgba); +NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba); +NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a); +NK_API struct nk_color nk_rgba_fv(const float *rgba); +NK_API struct nk_color nk_rgba_hex(const char *rgb); -/* edit flags */ -enum nk_edit_flags { - NK_EDIT_DEFAULT = 0, - NK_EDIT_READ_ONLY = NK_FLAG(0), - NK_EDIT_AUTO_SELECT = NK_FLAG(1), - NK_EDIT_SIG_ENTER = NK_FLAG(2), - NK_EDIT_ALLOW_TAB = NK_FLAG(3), - NK_EDIT_NO_CURSOR = NK_FLAG(4), - NK_EDIT_SELECTABLE = NK_FLAG(5), - NK_EDIT_CLIPBOARD = NK_FLAG(6), - NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7), - NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8), - NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9), - NK_EDIT_MULTILINE = NK_FLAG(11), - NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(12) -}; -enum nk_edit_types { - NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE, - NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD, - NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD, - NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD -}; -enum nk_edit_events { - NK_EDIT_ACTIVE = NK_FLAG(0), /* edit widget is currently being modified */ - NK_EDIT_INACTIVE = NK_FLAG(1), /* edit widget is not active and is not being modified */ - NK_EDIT_ACTIVATED = NK_FLAG(2), /* edit widget went from state inactive to state active */ - NK_EDIT_DEACTIVATED = NK_FLAG(3), /* edit widget went from state active to state inactive */ - NK_EDIT_COMMITED = NK_FLAG(4) /* edit widget has received an enter and lost focus */ -}; -enum nk_panel_flags { - NK_WINDOW_BORDER = NK_FLAG(0), /* Draws a border around the window to visually separate the window from the background */ - NK_WINDOW_MOVABLE = NK_FLAG(1), /* The movable flag indicates that a window can be moved by user input or by dragging the window header */ - NK_WINDOW_SCALABLE = NK_FLAG(2), /* The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window */ - NK_WINDOW_CLOSABLE = NK_FLAG(3), /* adds a closable icon into the header */ - NK_WINDOW_MINIMIZABLE = NK_FLAG(4), /* adds a minimize icon into the header */ - NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5), /* Removes the scrollbar from the window */ - NK_WINDOW_TITLE = NK_FLAG(6), /* Forces a header at the top at the window showing the title */ - NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7), /* Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame */ - NK_WINDOW_BACKGROUND = NK_FLAG(8), /* Always keep window in the background */ - NK_WINDOW_SCALE_LEFT = NK_FLAG(9) /* Puts window scaler in the left-ottom corner instead right-bottom*/ -}; +NK_API struct nk_color nk_hsv(int h, int s, int v); +NK_API struct nk_color nk_hsv_iv(const int *hsv); +NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv); +NK_API struct nk_color nk_hsv_f(float h, float s, float v); +NK_API struct nk_color nk_hsv_fv(const float *hsv); -/* context */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API int nk_init_default(struct nk_context*, const struct nk_user_font*); -#endif -NK_API int nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*); -NK_API int nk_init(struct nk_context*, struct nk_allocator*, const struct nk_user_font*); -NK_API int nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*); -NK_API void nk_clear(struct nk_context*); -NK_API void nk_free(struct nk_context*); -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void nk_set_user_data(struct nk_context*, nk_handle handle); -#endif - -/* window */ -NK_API int nk_begin(struct nk_context*, const char *title, struct nk_rect bounds, nk_flags flags); -NK_API int nk_begin_titled(struct nk_context*, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); -NK_API void nk_end(struct nk_context*); - -NK_API struct nk_window* nk_window_find(struct nk_context *ctx, const char *name); -NK_API struct nk_rect nk_window_get_bounds(const struct nk_context*); -NK_API struct nk_vec2 nk_window_get_position(const struct nk_context*); -NK_API struct nk_vec2 nk_window_get_size(const struct nk_context*); -NK_API float nk_window_get_width(const struct nk_context*); -NK_API float nk_window_get_height(const struct nk_context*); -NK_API struct nk_panel* nk_window_get_panel(struct nk_context*); -NK_API struct nk_rect nk_window_get_content_region(struct nk_context*); -NK_API struct nk_vec2 nk_window_get_content_region_min(struct nk_context*); -NK_API struct nk_vec2 nk_window_get_content_region_max(struct nk_context*); -NK_API struct nk_vec2 nk_window_get_content_region_size(struct nk_context*); -NK_API struct nk_command_buffer* nk_window_get_canvas(struct nk_context*); - -NK_API int nk_window_has_focus(const struct nk_context*); -NK_API int nk_window_is_collapsed(struct nk_context*, const char*); -NK_API int nk_window_is_closed(struct nk_context*, const char*); -NK_API int nk_window_is_hidden(struct nk_context*, const char*); -NK_API int nk_window_is_active(struct nk_context*, const char*); -NK_API int nk_window_is_hovered(struct nk_context*); -NK_API int nk_window_is_any_hovered(struct nk_context*); -NK_API int nk_item_is_any_active(struct nk_context*); - -NK_API void nk_window_set_bounds(struct nk_context*, struct nk_rect); -NK_API void nk_window_set_position(struct nk_context*, struct nk_vec2); -NK_API void nk_window_set_size(struct nk_context*, struct nk_vec2); -NK_API void nk_window_set_focus(struct nk_context*, const char *name); - -NK_API void nk_window_close(struct nk_context *ctx, const char *name); -NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states); -NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); -NK_API void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); -NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); - -/* Layout */ -NK_API void nk_layout_row_dynamic(struct nk_context*, float height, int cols); -NK_API void nk_layout_row_static(struct nk_context*, float height, int item_width, int cols); - -NK_API void nk_layout_row_begin(struct nk_context*, enum nk_layout_format, float row_height, int cols); -NK_API void nk_layout_row_push(struct nk_context*, float value); -NK_API void nk_layout_row_end(struct nk_context*); -NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); - -NK_API void nk_layout_row_template_begin(struct nk_context*, float height); -NK_API void nk_layout_row_template_push_dynamic(struct nk_context*); -NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width); -NK_API void nk_layout_row_template_push_static(struct nk_context*, float width); -NK_API void nk_layout_row_template_end(struct nk_context*); - -NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); -NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect); -NK_API void nk_layout_space_end(struct nk_context*); - -/* Layout: Utility */ -NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*); -NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); -NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); -NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); -NK_API struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); -NK_API float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); - -/* Layout: Group */ -NK_API int nk_group_begin(struct nk_context*, const char *title, nk_flags); -NK_API int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char*, nk_flags); -NK_API int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll*, const char *title, nk_flags); -NK_API void nk_group_scrolled_end(struct nk_context*); -NK_API void nk_group_end(struct nk_context*); - -NK_API int nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count); -NK_API void nk_list_view_end(struct nk_list_view*); - -/* Layout: Tree */ -#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -NK_API int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -NK_API int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -NK_API void nk_tree_pop(struct nk_context*); - -NK_API int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); -NK_API int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); -NK_API void nk_tree_state_pop(struct nk_context*); - -/* Widgets */ -NK_API void nk_text(struct nk_context*, const char*, int, nk_flags); -NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color); -NK_API void nk_text_wrap(struct nk_context*, const char*, int); -NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color); - -NK_API void nk_label(struct nk_context*, const char*, nk_flags align); -NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color); -NK_API void nk_label_wrap(struct nk_context*, const char*); -NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color); -NK_API void nk_image(struct nk_context*, struct nk_image); -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void nk_labelf(struct nk_context*, nk_flags, const char*, ...); -NK_API void nk_labelf_colored(struct nk_context*, nk_flags align, struct nk_color, const char*,...); -NK_API void nk_labelf_wrap(struct nk_context*, const char*,...); -NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, const char*,...); - -NK_API void nk_value_bool(struct nk_context*, const char *prefix, int); -NK_API void nk_value_int(struct nk_context*, const char *prefix, int); -NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int); -NK_API void nk_value_float(struct nk_context*, const char *prefix, float); -NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color); -NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color); -NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color); -#endif - -/* Widgets: Buttons */ -NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior); -NK_API int nk_button_push_behavior(struct nk_context*, enum nk_button_behavior); -NK_API int nk_button_pop_behavior(struct nk_context*); - -NK_API int nk_button_text(struct nk_context*, const char *title, int len); -NK_API int nk_button_label(struct nk_context*, const char *title); -NK_API int nk_button_color(struct nk_context*, struct nk_color); -NK_API int nk_button_symbol(struct nk_context*, enum nk_symbol_type); -NK_API int nk_button_image(struct nk_context*, struct nk_image img); -NK_API int nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment); -NK_API int nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment); -NK_API int nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment); - -NK_API int nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len); -NK_API int nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title); -NK_API int nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type); -NK_API int nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img); -NK_API int nk_button_symbol_label_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, nk_flags text_alignment); -NK_API int nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment); -NK_API int nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment); - -/* Widgets: Checkbox */ -NK_API int nk_check_label(struct nk_context*, const char*, int active); -NK_API int nk_check_text(struct nk_context*, const char*, int,int active); -NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value); -NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value); -NK_API int nk_checkbox_label(struct nk_context*, const char*, int *active); -NK_API int nk_checkbox_text(struct nk_context*, const char*, int, int *active); -NK_API int nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value); -NK_API int nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value); - -/* Widgets: Radio */ -NK_API int nk_radio_label(struct nk_context*, const char*, int *active); -NK_API int nk_radio_text(struct nk_context*, const char*, int, int *active); -NK_API int nk_option_label(struct nk_context*, const char*, int active); -NK_API int nk_option_text(struct nk_context*, const char*, int, int active); - -/* Widgets: Selectable */ -NK_API int nk_selectable_label(struct nk_context*, const char*, nk_flags align, int *value); -NK_API int nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, int *value); -NK_API int nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, int *value); -NK_API int nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, int *value); - -NK_API int nk_select_label(struct nk_context*, const char*, nk_flags align, int value); -NK_API int nk_select_text(struct nk_context*, const char*, int, nk_flags align, int value); -NK_API int nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, int value); -NK_API int nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, int value); - -/* Widgets: Slider */ -NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step); -NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step); -NK_API int nk_slider_float(struct nk_context*, float min, float *val, float max, float step); -NK_API int nk_slider_int(struct nk_context*, int min, int *val, int max, int step); - -/* Widgets: Progressbar */ -NK_API int nk_progress(struct nk_context*, nk_size *cur, nk_size max, int modifyable); -NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, int modifyable); - -/* Widgets: Color picker */ -NK_API struct nk_color nk_color_picker(struct nk_context*, struct nk_color, enum nk_color_format); -NK_API int nk_color_pick(struct nk_context*, struct nk_color*, enum nk_color_format); - -/* Widgets: Property */ -NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel); -NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel); -NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel); -NK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel); -NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel); -NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel); - -/* Widgets: TextEdit */ -NK_API void nk_edit_focus(struct nk_context*, nk_flags flags); -NK_API void nk_edit_unfocus(struct nk_context*); -NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter); -NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter); -NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter); - -/* Chart */ -NK_API int nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max); -NK_API int nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max); -NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value); -NK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value); -NK_API nk_flags nk_chart_push(struct nk_context*, float); -NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int); -NK_API void nk_chart_end(struct nk_context*); -NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset); -NK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset); - -/* Popups */ -NK_API int nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds); -NK_API void nk_popup_close(struct nk_context*); -NK_API void nk_popup_end(struct nk_context*); - -/* Combobox */ -NK_API int nk_combo(struct nk_context*, const char **items, int count, int selected, int item_height, struct nk_vec2 size); -NK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size); -NK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size); -NK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox(struct nk_context*, const char **items, int count, int *selected, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator,int *selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size); - -/* Combobox: abstract */ -NK_API int nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size); -NK_API int nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size); -NK_API int nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size); -NK_API int nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size); -NK_API int nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size); -NK_API int nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment); -NK_API int nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment); -NK_API int nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment); -NK_API int nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API int nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API void nk_combo_close(struct nk_context*); -NK_API void nk_combo_end(struct nk_context*); - -/* Contextual */ -NK_API int nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds); -NK_API int nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align); -NK_API int nk_contextual_item_label(struct nk_context*, const char*, nk_flags align); -NK_API int nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); -NK_API int nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API int nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API void nk_contextual_close(struct nk_context*); -NK_API void nk_contextual_end(struct nk_context*); - -/* Tooltip */ -NK_API void nk_tooltip(struct nk_context*, const char*); -NK_API int nk_tooltip_begin(struct nk_context*, float width); -NK_API void nk_tooltip_end(struct nk_context*); - -/* Menu */ -NK_API void nk_menubar_begin(struct nk_context*); -NK_API void nk_menubar_end(struct nk_context*); - -NK_API int nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size); -NK_API int nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size); -NK_API int nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align); -NK_API int nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment); -NK_API int nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); -NK_API int nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API void nk_menu_close(struct nk_context*); -NK_API void nk_menu_end(struct nk_context*); - -/* Drawing*/ -#define nk_foreach(c, ctx) for((c)=nk__begin(ctx); (c)!=0; (c)=nk__next(ctx, c)) -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -NK_API void nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*); -#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx)) -#define nk_draw_foreach_bounded(cmd,from,to) for((cmd)=(from); (cmd) && (to) && (cmd)>=to; --(cmd)) -NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); -NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*); -NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); -#endif - -/* User Input */ -NK_API void nk_input_begin(struct nk_context*); -NK_API void nk_input_motion(struct nk_context*, int x, int y); -NK_API void nk_input_key(struct nk_context*, enum nk_keys, int down); -NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, int down); -NK_API void nk_input_scroll(struct nk_context*, float y); -NK_API void nk_input_char(struct nk_context*, char); -NK_API void nk_input_glyph(struct nk_context*, const nk_glyph); -NK_API void nk_input_unicode(struct nk_context*, nk_rune); -NK_API void nk_input_end(struct nk_context*); - -/* Style */ -NK_API void nk_style_default(struct nk_context*); -NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*); -NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*); -NK_API void nk_style_load_all_cursors(struct nk_context*, struct nk_cursor*); -NK_API const char* nk_style_get_color_by_name(enum nk_style_colors); -NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*); -NK_API int nk_style_set_cursor(struct nk_context*, enum nk_style_cursor); -NK_API void nk_style_show_cursor(struct nk_context*); -NK_API void nk_style_hide_cursor(struct nk_context*); - -/* Style: stack */ -NK_API int nk_style_push_font(struct nk_context*, struct nk_user_font*); -NK_API int nk_style_push_float(struct nk_context*, float*, float); -NK_API int nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2); -NK_API int nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item); -NK_API int nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags); -NK_API int nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color); - -NK_API int nk_style_pop_font(struct nk_context*); -NK_API int nk_style_pop_float(struct nk_context*); -NK_API int nk_style_pop_vec2(struct nk_context*); -NK_API int nk_style_pop_style_item(struct nk_context*); -NK_API int nk_style_pop_flags(struct nk_context*); -NK_API int nk_style_pop_color(struct nk_context*); - -/* Utilities */ -NK_API struct nk_rect nk_widget_bounds(struct nk_context*); -NK_API struct nk_vec2 nk_widget_position(struct nk_context*); -NK_API struct nk_vec2 nk_widget_size(struct nk_context*); -NK_API float nk_widget_width(struct nk_context*); -NK_API float nk_widget_height(struct nk_context*); -NK_API int nk_widget_is_hovered(struct nk_context*); -NK_API int nk_widget_is_mouse_clicked(struct nk_context*, enum nk_buttons); -NK_API int nk_widget_has_mouse_click_down(struct nk_context*, enum nk_buttons, int down); -NK_API void nk_spacing(struct nk_context*, int cols); - -/* base widget function */ -NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*); -NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, struct nk_context*, struct nk_vec2); - -/* color (conversion user --> nuklear) */ -NK_API struct nk_color nk_rgb(int r, int g, int b); -NK_API struct nk_color nk_rgb_iv(const int *rgb); -NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb); -NK_API struct nk_color nk_rgb_f(float r, float g, float b); -NK_API struct nk_color nk_rgb_fv(const float *rgb); -NK_API struct nk_color nk_rgb_hex(const char *rgb); - -NK_API struct nk_color nk_rgba(int r, int g, int b, int a); -NK_API struct nk_color nk_rgba_u32(nk_uint); -NK_API struct nk_color nk_rgba_iv(const int *rgba); -NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba); -NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a); -NK_API struct nk_color nk_rgba_fv(const float *rgba); -NK_API struct nk_color nk_rgba_hex(const char *rgb); - -NK_API struct nk_color nk_hsv(int h, int s, int v); -NK_API struct nk_color nk_hsv_iv(const int *hsv); -NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv); -NK_API struct nk_color nk_hsv_f(float h, float s, float v); -NK_API struct nk_color nk_hsv_fv(const float *hsv); - -NK_API struct nk_color nk_hsva(int h, int s, int v, int a); -NK_API struct nk_color nk_hsva_iv(const int *hsva); -NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva); -NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a); -NK_API struct nk_color nk_hsva_fv(const float *hsva); +NK_API struct nk_color nk_hsva(int h, int s, int v, int a); +NK_API struct nk_color nk_hsva_iv(const int *hsva); +NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva); +NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a); +NK_API struct nk_color nk_hsva_fv(const float *hsva); /* color (conversion nuklear --> user) */ -NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color); -NK_API void nk_color_fv(float *rgba_out, struct nk_color); -NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color); -NK_API void nk_color_dv(double *rgba_out, struct nk_color); +NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color); +NK_API void nk_color_fv(float *rgba_out, struct nk_color); +NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color); +NK_API void nk_color_dv(double *rgba_out, struct nk_color); -NK_API nk_uint nk_color_u32(struct nk_color); -NK_API void nk_color_hex_rgba(char *output, struct nk_color); -NK_API void nk_color_hex_rgb(char *output, struct nk_color); +NK_API nk_uint nk_color_u32(struct nk_color); +NK_API void nk_color_hex_rgba(char *output, struct nk_color); +NK_API void nk_color_hex_rgb(char *output, struct nk_color); -NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color); -NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color); -NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color); -NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color); -NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color); -NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color); +NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color); +NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color); +NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color); +NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color); +NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color); +NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color); -NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color); -NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color); -NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color); -NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color); -NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color); -NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color); +NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color); +NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color); +NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color); +NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color); +NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color); +NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color); +/* ============================================================================= + * + * IMAGE + * + * ============================================================================= */ +NK_API nk_handle nk_handle_ptr(void*); +NK_API nk_handle nk_handle_id(int); +NK_API struct nk_image nk_image_handle(nk_handle); +NK_API struct nk_image nk_image_ptr(void*); +NK_API struct nk_image nk_image_id(int); +NK_API int nk_image_is_subimage(const struct nk_image* img); +NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region); +NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region); +NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region); +/* ============================================================================= + * + * MATH + * + * ============================================================================= */ +NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed); +NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading); -/* image */ -NK_API nk_handle nk_handle_ptr(void*); -NK_API nk_handle nk_handle_id(int); -NK_API struct nk_image nk_image_handle(nk_handle); -NK_API struct nk_image nk_image_ptr(void*); -NK_API struct nk_image nk_image_id(int); -NK_API int nk_image_is_subimage(const struct nk_image* img); -NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region); -NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region); -NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region); - -/* math */ -NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed); -NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading); - -NK_API struct nk_vec2 nk_vec2(float x, float y); -NK_API struct nk_vec2 nk_vec2i(int x, int y); -NK_API struct nk_vec2 nk_vec2v(const float *xy); -NK_API struct nk_vec2 nk_vec2iv(const int *xy); - -NK_API struct nk_rect nk_get_null_rect(void); -NK_API struct nk_rect nk_rect(float x, float y, float w, float h); -NK_API struct nk_rect nk_recti(int x, int y, int w, int h); -NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size); -NK_API struct nk_rect nk_rectv(const float *xywh); -NK_API struct nk_rect nk_rectiv(const int *xywh); -NK_API struct nk_vec2 nk_rect_pos(struct nk_rect); -NK_API struct nk_vec2 nk_rect_size(struct nk_rect); - -/* string*/ -NK_API int nk_strlen(const char *str); -NK_API int nk_stricmp(const char *s1, const char *s2); -NK_API int nk_stricmpn(const char *s1, const char *s2, int n); -NK_API int nk_strtoi(const char *str, char **endptr); -NK_API float nk_strtof(const char *str, char **endptr); -NK_API double nk_strtod(const char *str, char **endptr); -NK_API int nk_strfilter(const char *text, const char *regexp); -NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score); -NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score); - -/* UTF-8 */ -NK_API int nk_utf_decode(const char*, nk_rune*, int); -NK_API int nk_utf_encode(nk_rune, char*, int); -NK_API int nk_utf_len(const char*, int byte_len); -NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len); +NK_API struct nk_vec2 nk_vec2(float x, float y); +NK_API struct nk_vec2 nk_vec2i(int x, int y); +NK_API struct nk_vec2 nk_vec2v(const float *xy); +NK_API struct nk_vec2 nk_vec2iv(const int *xy); +NK_API struct nk_rect nk_get_null_rect(void); +NK_API struct nk_rect nk_rect(float x, float y, float w, float h); +NK_API struct nk_rect nk_recti(int x, int y, int w, int h); +NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size); +NK_API struct nk_rect nk_rectv(const float *xywh); +NK_API struct nk_rect nk_rectiv(const int *xywh); +NK_API struct nk_vec2 nk_rect_pos(struct nk_rect); +NK_API struct nk_vec2 nk_rect_size(struct nk_rect); +/* ============================================================================= + * + * STRING + * + * ============================================================================= */ +NK_API int nk_strlen(const char *str); +NK_API int nk_stricmp(const char *s1, const char *s2); +NK_API int nk_stricmpn(const char *s1, const char *s2, int n); +NK_API int nk_strtoi(const char *str, const char **endptr); +NK_API float nk_strtof(const char *str, const char **endptr); +NK_API double nk_strtod(const char *str, const char **endptr); +NK_API int nk_strfilter(const char *text, const char *regexp); +NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score); +NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score); +/* ============================================================================= + * + * UTF-8 + * + * ============================================================================= */ +NK_API int nk_utf_decode(const char*, nk_rune*, int); +NK_API int nk_utf_encode(nk_rune, char*, int); +NK_API int nk_utf_len(const char*, int byte_len); +NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len); /* =============================================================== * * FONT @@ -1274,7 +2437,7 @@ NK_API const char* nk_utf_at(const char *buffer, int length, int in nk_font_atlas_begin(&atlas); nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, 0); nk_font *font2 = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font2.ttf", 16, 0); - void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32, 0); + const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32); nk_font_atlas_end(&atlas, nk_handle_id(texture), 0); struct nk_context ctx; @@ -1791,7 +2954,8 @@ enum nk_command_type { NK_COMMAND_POLYGON_FILLED, NK_COMMAND_POLYLINE, NK_COMMAND_TEXT, - NK_COMMAND_IMAGE + NK_COMMAND_IMAGE, + NK_COMMAND_CUSTOM }; /* command base and header of every command inside the buffer */ @@ -1933,6 +3097,16 @@ struct nk_command_image { struct nk_color col; }; +typedef void (*nk_command_custom_callback)(void *canvas, short x,short y, + unsigned short w, unsigned short h, nk_handle callback_data); +struct nk_command_custom { + struct nk_command header; + short x, y; + unsigned short w, h; + nk_handle callback_data; + nk_command_custom_callback callback; +}; + struct nk_command_text { struct nk_command header; const struct nk_user_font *font; @@ -1977,11 +3151,10 @@ NK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, floa NK_API void nk_fill_polygon(struct nk_command_buffer*, float*, int point_count, struct nk_color); /* misc */ -NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect); NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color); NK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color); -NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); -NK_API const struct nk_command* nk__begin(struct nk_context*); +NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect); +NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr); /* =============================================================== * @@ -1998,7 +3171,7 @@ struct nk_mouse { struct nk_vec2 pos; struct nk_vec2 prev; struct nk_vec2 delta; - float scroll_delta; + struct nk_vec2 scroll_delta; unsigned char grab; unsigned char grabbed; unsigned char ungrab; @@ -2085,6 +3258,7 @@ NK_FORMAT_COLOR_BEGIN, NK_FORMAT_R32G32B32, NK_FORMAT_R8G8B8A8, + NK_FORMAT_B8G8R8A8, NK_FORMAT_R16G15B16A16, NK_FORMAT_R32G32B32A32, NK_FORMAT_R32G32B32A32_FLOAT, @@ -2132,6 +3306,9 @@ struct nk_draw_list { unsigned int path_count; unsigned int path_offset; + enum nk_anti_aliasing line_AA; + enum nk_anti_aliasing shape_AA; + #ifdef NK_INCLUDE_COMMAND_USERDATA nk_handle userdata; #endif @@ -2139,7 +3316,7 @@ struct nk_draw_list { /* draw list */ NK_API void nk_draw_list_init(struct nk_draw_list*); -NK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements); +NK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, enum nk_anti_aliasing line_aa,enum nk_anti_aliasing shape_aa); NK_API void nk_draw_list_clear(struct nk_draw_list*); /* drawing */ @@ -2579,6 +3756,7 @@ struct nk_style_window { float group_border; float tooltip_border; float popup_border; + float min_row_height_padding; float rounding; struct nk_vec2 spacing; @@ -2681,6 +3859,7 @@ struct nk_row_layout { enum nk_panel_row_layout_type type; int index; float height; + float min_height; int columns; const float *ratio; float item_width; @@ -2720,7 +3899,6 @@ struct nk_panel { struct nk_menu_state menu; struct nk_row_layout row; struct nk_chart chart; - struct nk_popup_buffer popup_buffer; struct nk_command_buffer *buffer; struct nk_panel *parent; }; @@ -2734,24 +3912,27 @@ struct nk_panel { struct nk_table; enum nk_window_flags { - NK_WINDOW_PRIVATE = NK_FLAG(10), + NK_WINDOW_PRIVATE = NK_FLAG(11), NK_WINDOW_DYNAMIC = NK_WINDOW_PRIVATE, /* special window type growing up in height while being filled to a certain maximum height */ - NK_WINDOW_ROM = NK_FLAG(11), - /* sets the window into a read only mode and does not allow input changes */ - NK_WINDOW_HIDDEN = NK_FLAG(12), - /* Hides the window and stops any window interaction and drawing */ - NK_WINDOW_CLOSED = NK_FLAG(13), + NK_WINDOW_ROM = NK_FLAG(12), + /* sets window widgets into a read only mode and does not allow input changes */ + NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT, + /* prevents all interaction caused by input to either window or widgets inside */ + NK_WINDOW_HIDDEN = NK_FLAG(13), + /* Hides window and stops any window interaction and drawing */ + NK_WINDOW_CLOSED = NK_FLAG(14), /* Directly closes and frees the window at the end of the frame */ - NK_WINDOW_MINIMIZED = NK_FLAG(14), + NK_WINDOW_MINIMIZED = NK_FLAG(15), /* marks the window as minimized */ - NK_WINDOW_REMOVE_ROM = NK_FLAG(15) - /* Removes the read only mode at the end of the window */ + NK_WINDOW_REMOVE_ROM = NK_FLAG(16) + /* Removes read only mode at the end of the window */ }; struct nk_popup_state { struct nk_window *win; enum nk_panel_type type; + struct nk_popup_buffer buf; nk_hash name; int active; unsigned combo_count; @@ -2778,6 +3959,8 @@ struct nk_property_state { char buffer[NK_MAX_NUMBER_BUFFER]; int length; int cursor; + int select_start; + int select_end; nk_hash name; unsigned int seq; unsigned int old; @@ -2803,8 +3986,7 @@ struct nk_window { unsigned int scrolled; struct nk_table *tables; - unsigned short table_count; - unsigned short table_size; + unsigned int table_count; /* window list hooks */ struct nk_window *next; @@ -2833,7 +4015,7 @@ struct nk_window { * nk_style_pop_style_item(ctx); * nk_style_pop_vec2(ctx); * - * Nuklear has a stack for style_items, float properties, vector properties, + * Nuklear has a stack for style_items, float properties, vector properties, * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack * which can be changed at compile time. */ @@ -2907,10 +4089,11 @@ struct nk_configuration_stacks { * CONTEXT * =============================================================*/ #define NK_VALUE_PAGE_CAPACITY \ - ((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint)) / 2) + (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2) struct nk_table { unsigned int seq; + unsigned int size; nk_hash keys[NK_VALUE_PAGE_CAPACITY]; nk_uint values[NK_VALUE_PAGE_CAPACITY]; struct nk_table *next, *prev; @@ -2997,7 +4180,7 @@ struct nk_context { #define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x))) #define NK_LEN(a) (sizeof(a)/sizeof(a)[0]) #define NK_ABS(a) (((a) < 0) ? -(a) : (a)) -#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b)) #define NK_INBOX(px, py, x, y, w, h)\ (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h)) #define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \ @@ -3051,7 +4234,7 @@ template struct nk_helper{enum {value = size_diff};}; template struct nk_helper{enum {value = nk_alignof::value};}; template struct nk_alignof{struct Big {T x; char c;}; enum { diff = sizeof(Big) - sizeof(T), value = nk_helper::value};}; -#define NK_ALIGNOF(t) (nk_alignof::value); +#define NK_ALIGNOF(t) (nk_alignof::value) #elif defined(_MSC_VER) #define NK_ALIGNOF(t) (__alignof(t)) #else @@ -3518,7 +4701,7 @@ nk_strlen(const char *str) } NK_API int -nk_strtoi(const char *str, char **endptr) +nk_strtoi(const char *str, const char **endptr) { int neg = 1; const char *p = str; @@ -3538,12 +4721,12 @@ nk_strtoi(const char *str, char **endptr) p++; } if (endptr) - *endptr = (char*)p; + *endptr = p; return neg*value; } NK_API double -nk_strtod(const char *str, char **endptr) +nk_strtod(const char *str, const char **endptr) { double m; double neg = 1.0; @@ -3596,12 +4779,12 @@ nk_strtod(const char *str, char **endptr) } number = value * neg; if (endptr) - *endptr = (char*)p; + *endptr = p; return number; } NK_API float -nk_strtof(const char *str, char **endptr) +nk_strtof(const char *str, const char **endptr) { float float_value; double double_value; @@ -4028,6 +5211,7 @@ nk_dtoa(char *s, double n) } #ifdef NK_INCLUDE_STANDARD_VARARGS +#ifndef NK_INCLUDE_STANDARD_IO static int nk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args) { @@ -4079,7 +5263,7 @@ nk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args) /* width argument */ width = NK_DEFAULT; if (*iter >= '1' && *iter <= '9') { - char *end; + const char *end; width = nk_strtoi(iter, &end); if (end == iter) width = -1; @@ -4097,7 +5281,7 @@ nk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args) precision = va_arg(args, int); iter++; } else { - char *end; + const char *end; precision = nk_strtoi(iter, &end); if (end == iter) precision = -1; @@ -4346,6 +5530,7 @@ nk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args) result = (len >= buf_size)?-1:len; return result; } +#endif NK_INTERN int nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args) @@ -5074,7 +6259,7 @@ nk_text_clamp(const struct nk_user_font *font, const char *text, sep_len = len; break; } - if (i == NK_MAX(sep_count,0)){ + if (i == sep_count){ last_width = sep_width = width; sep_g = g+1; } @@ -5449,11 +6634,12 @@ nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, /* check if buffer has enough memory*/ if (type == NK_BUFFER_FRONT) full = ((b->allocated + size + alignment) > b->size); - else full = ((b->size - (size + alignment)) <= b->allocated); + else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated); if (full) { nk_size capacity; - NK_ASSERT(b->type == NK_BUFFER_DYNAMIC); + if (b->type != NK_BUFFER_DYNAMIC) + return 0; NK_ASSERT(b->pool.alloc && b->pool.free); if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free) return 0; @@ -5470,7 +6656,6 @@ nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); memory = nk_buffer_align(unaligned, align, &alignment, type); } - if (type == NK_BUFFER_FRONT) b->allocated += size + alignment; else b->size -= (size + alignment); @@ -6156,7 +7341,7 @@ nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, { struct nk_command_line *cmd; NK_ASSERT(b); - if (!b) return; + if (!b || line_thickness <= 0) return; cmd = (struct nk_command_line*) nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd)); if (!cmd) return; @@ -6175,7 +7360,7 @@ nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay, { struct nk_command_curve *cmd; NK_ASSERT(b); - if (!b || col.a == 0) return; + if (!b || col.a == 0 || line_thickness <= 0) return; cmd = (struct nk_command_curve*) nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd)); @@ -6198,13 +7383,12 @@ nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect, { struct nk_command_rect *cmd; NK_ASSERT(b); - if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return; + if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return; if (b->use_clipping) { const struct nk_rect *clip = &b->clip; if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, clip->x, clip->y, clip->w, clip->h)) return; } - cmd = (struct nk_command_rect*) nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd)); if (!cmd) return; @@ -6273,7 +7457,7 @@ nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r, float line_thickness, struct nk_color c) { struct nk_command_circle *cmd; - if (!b || r.w == 0 || r.h == 0) return; + if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return; if (b->use_clipping) { const struct nk_rect *clip = &b->clip; if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) @@ -6318,7 +7502,7 @@ nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color c) { struct nk_command_arc *cmd; - if (!b || c.a == 0) return; + if (!b || c.a == 0 || line_thickness <= 0) return; cmd = (struct nk_command_arc*) nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd)); if (!cmd) return; @@ -6355,7 +7539,7 @@ nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, { struct nk_command_triangle *cmd; NK_ASSERT(b); - if (!b || c.a == 0) return; + if (!b || c.a == 0 || line_thickness <= 0) return; if (b->use_clipping) { const struct nk_rect *clip = &b->clip; if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && @@ -6414,7 +7598,7 @@ nk_stroke_polygon(struct nk_command_buffer *b, float *points, int point_count, struct nk_command_polygon *cmd; NK_ASSERT(b); - if (!b || col.a == 0) return; + if (!b || col.a == 0 || line_thickness <= 0) return; size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size); if (!cmd) return; @@ -6458,7 +7642,7 @@ nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count, struct nk_command_polyline *cmd; NK_ASSERT(b); - if (!b || col.a == 0) return; + if (!b || col.a == 0 || line_thickness <= 0) return; size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size); if (!cmd) return; @@ -6495,6 +7679,30 @@ nk_draw_image(struct nk_command_buffer *b, struct nk_rect r, cmd->col = col; } +NK_API void +nk_push_custom(struct nk_command_buffer *b, struct nk_rect r, + nk_command_custom_callback cb, nk_handle usr) +{ + struct nk_command_custom *cmd; + NK_ASSERT(b); + if (!b) return; + if (b->use_clipping) { + const struct nk_rect *c = &b->clip; + if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) + return; + } + + cmd = (struct nk_command_custom*) + nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd)); + if (!cmd) return; + cmd->x = (short)r.x; + cmd->y = (short)r.y; + cmd->w = (unsigned short)NK_MAX(0, r.w); + cmd->h = (unsigned short)NK_MAX(0, r.h); + cmd->callback_data = usr; + cmd->callback = cb; +} + NK_API void nk_draw_text(struct nk_command_buffer *b, struct nk_rect r, const char *string, int length, const struct nk_user_font *font, @@ -6559,7 +7767,8 @@ nk_draw_list_init(struct nk_draw_list *list) NK_API void nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config, - struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements) + struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, + enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa) { NK_ASSERT(canvas); NK_ASSERT(config); @@ -6573,6 +7782,8 @@ nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config * canvas->config = *config; canvas->elements = elements; canvas->vertices = vertices; + canvas->line_AA = line_aa; + canvas->shape_AA = shape_aa; canvas->clip_rect = nk_null_rect; } @@ -6799,7 +8010,7 @@ nk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count) return ids; } -static int +NK_INTERN int nk_draw_vertex_layout_element_is_end_of_layout( const struct nk_draw_vertex_layout_element *element) { @@ -6807,7 +8018,7 @@ nk_draw_vertex_layout_element_is_end_of_layout( element->format == NK_FORMAT_COUNT); } -static void +NK_INTERN void nk_draw_vertex_color(void *attribute, const float *values, enum nk_draw_vertex_layout_format format) { @@ -6823,6 +8034,11 @@ nk_draw_vertex_color(void *attribute, const float *values, struct nk_color col = nk_rgba_fv(values); NK_MEMCPY(attribute, &col.r, sizeof(col)); } break; + case NK_FORMAT_B8G8R8A8: { + struct nk_color col = nk_rgba_fv(values); + struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a); + NK_MEMCPY(attribute, &bgra, sizeof(bgra)); + } break; case NK_FORMAT_R16G15B16: { nk_ushort col[3]; col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX); @@ -6873,7 +8089,7 @@ nk_draw_vertex_color(void *attribute, const float *values, } } -static void +NK_INTERN void nk_draw_vertex_element(void *dst, const float *values, int value_count, enum nk_draw_vertex_layout_format format) { @@ -6993,7 +8209,6 @@ nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *p nk_size size; struct nk_vec2 *normals, *temp; - NK_ASSERT(vtx && ids); if (!vtx || !ids) return; /* temporary allocate normals + points */ @@ -7461,8 +8676,13 @@ nk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a, { NK_ASSERT(list); if (!list || !col.a) return; - nk_draw_list_path_line_to(list, nk_vec2_add(a, nk_vec2(0.5f, 0.5f))); - nk_draw_list_path_line_to(list, nk_vec2_add(b, nk_vec2(0.5f, 0.5f))); + if (list->line_AA == NK_ANTI_ALIASING_ON) { + nk_draw_list_path_line_to(list, a); + nk_draw_list_path_line_to(list, b); + } else { + nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f))); + nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f))); + } nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); } @@ -7472,9 +8692,14 @@ nk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect, { NK_ASSERT(list); if (!list || !col.a) return; - nk_draw_list_path_rect_to(list, nk_vec2(rect.x + 0.5f, rect.y + 0.5f), - nk_vec2(rect.x + rect.w + 0.5f, rect.y + rect.h + 0.5f), rounding); - nk_draw_list_path_fill(list, col); + + if (list->line_AA == NK_ANTI_ALIASING_ON) { + nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), + nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); + } else { + nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), + nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); + } nk_draw_list_path_fill(list, col); } NK_API void @@ -7483,9 +8708,13 @@ nk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect, { NK_ASSERT(list); if (!list || !col.a) return; - nk_draw_list_path_rect_to(list, nk_vec2(rect.x + 0.5f, rect.y + 0.5f), - nk_vec2(rect.x + rect.w + 0.5f, rect.y + rect.h + 0.5f), rounding); - nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); + if (list->line_AA == NK_ANTI_ALIASING_ON) { + nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), + nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); + } else { + nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), + nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); + } nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); } NK_API void @@ -7694,11 +8923,12 @@ nk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font } } -NK_API void +NK_API nk_flags nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config *config) { + nk_flags res = NK_CONVERT_SUCCESS; const struct nk_command *cmd; NK_ASSERT(ctx); NK_ASSERT(cmds); @@ -7708,9 +8938,10 @@ nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, NK_ASSERT(config->vertex_layout); NK_ASSERT(config->vertex_size); if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout) - return; + return NK_CONVERT_INVALID_PARAM; - nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements); + nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements, + config->line_AA, config->shape_AA); nk_foreach(cmd, ctx) { #ifdef NK_INCLUDE_COMMAND_USERDATA @@ -7822,11 +9053,18 @@ nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, const struct nk_command_image *i = (const struct nk_command_image*)cmd; nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col); } break; + case NK_COMMAND_CUSTOM: { + const struct nk_command_custom *c = (const struct nk_command_custom*)cmd; + c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data); + } break; default: break; } } + res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0; + res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0; + res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0; + return res; } - NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context *ctx, const struct nk_buffer *buffer) @@ -8166,7 +9404,7 @@ nk_rect_original_order(const void *a, const void *b) return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); } -static void +NK_INTERN void nk_rp_qsort(struct nk_rp_rect *array, unsigned int len, int(*cmp)(const void*,const void*)) { /* iterative quick sort */ @@ -10118,8 +11356,8 @@ nk_font_bake_pack(struct nk_font_baker *baker, int rect_n = 0; int char_n = 0; - /* pack custom user data first so it will be in the upper left corner*/ if (custom) { + /* pack custom user data first so it will be in the upper left corner*/ struct nk_rp_rect custom_space; nk_zero(&custom_space, sizeof(custom_space)); custom_space.w = (nk_rp_coord)((custom->w * 2) + 1); @@ -10430,10 +11668,9 @@ nk_font_find_glyph(struct nk_font *font, nk_rune unicode) glyph = font->fallback; count = nk_range_count(font->info.ranges); for (i = 0; i < count; ++i) { - int diff; nk_rune f = font->info.ranges[(i*2)+0]; nk_rune t = font->info.ranges[(i*2)+1]; - diff = (int)((t - f) + 1); + int diff = (int)((t - f) + 1); if (unicode >= f && unicode <= t) return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))]; total_glyphs += diff; @@ -10454,6 +11691,7 @@ nk_font_init(struct nk_font *font, float pixel_height, return; baked = *baked_font; + font->fallback = 0; font->info = baked; font->scale = (float)pixel_height / (float)font->info.height; font->glyphs = &glyphs[baked_font->glyph_offset]; @@ -11235,6 +12473,7 @@ nk_font_atlas_cleanup(struct nk_font_atlas *atlas) atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); atlas->permanent.free(atlas->permanent.userdata, iter); } + atlas->config = 0; } } @@ -11279,7 +12518,7 @@ nk_input_begin(struct nk_context *ctx) in->mouse.buttons[i].clicked = 0; in->keyboard.text_len = 0; - in->mouse.scroll_delta = 0; + in->mouse.scroll_delta = nk_vec2(0,0); in->mouse.prev.x = in->mouse.pos.x; in->mouse.prev.y = in->mouse.pos.y; in->mouse.delta.x = 0; @@ -11324,8 +12563,9 @@ nk_input_key(struct nk_context *ctx, enum nk_keys key, int down) NK_ASSERT(ctx); if (!ctx) return; in = &ctx->input; + if (in->keyboard.keys[key].down != down) + in->keyboard.keys[key].clicked++; in->keyboard.keys[key].down = down; - in->keyboard.keys[key].clicked++; } NK_API void @@ -11346,11 +12586,12 @@ nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, int do } NK_API void -nk_input_scroll(struct nk_context *ctx, float y) +nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val) { NK_ASSERT(ctx); if (!ctx) return; - ctx->input.mouse.scroll_delta += y; + ctx->input.mouse.scroll_delta.x += val.x; + ctx->input.mouse.scroll_delta.y += val.y; } NK_API void @@ -11918,23 +13159,14 @@ nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len) if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return; glyph_len = nk_utf_decode(text, &unicode, total_len); - if (!glyph_len) return; while ((text_len < total_len) && glyph_len) { /* don't insert a backward delete, just process the event */ - if (unicode == 127) - break; - + if (unicode == 127) goto next; /* can't add newline in single-line mode */ - if (unicode == '\n' && state->single_line) - break; - + if (unicode == '\n' && state->single_line) goto next; /* filter incoming text */ - if (state->filter && !state->filter(state, unicode)) { - glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len); - text_len += glyph_len; - continue; - } + if (state->filter && !state->filter(state, unicode)) goto next; if (!NK_TEXT_HAS_SELECTION(state) && state->cursor < state->string.len) @@ -11959,8 +13191,9 @@ nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len) state->has_preferred_x = 0; } } - glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len); + next: text_len += glyph_len; + glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len); } } @@ -12560,6 +13793,7 @@ nk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size) NK_ASSERT(state); NK_ASSERT(memory); if (!state || !memory || !size) return; + NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); nk_str_init_fixed(&state->string, memory, size); } @@ -12570,6 +13804,7 @@ nk_textedit_init(struct nk_text_edit *state, struct nk_allocator *alloc, nk_size NK_ASSERT(state); NK_ASSERT(alloc); if (!state || !alloc) return; + NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); nk_str_init(&state->string, alloc, size); } @@ -12580,6 +13815,7 @@ nk_textedit_init_default(struct nk_text_edit *state) { NK_ASSERT(state); if (!state) return; + NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); nk_str_init_default(&state->string); } @@ -13422,8 +14658,7 @@ nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, NK_INTERN float nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, struct nk_rect *visual_cursor, struct nk_input *in, - const struct nk_style_slider *style, struct nk_rect bounds, - float slider_min, float slider_max, float slider_value, + struct nk_rect bounds, float slider_min, float slider_max, float slider_value, float slider_step, float slider_steps) { int left_mouse_down; @@ -13605,7 +14840,7 @@ nk_do_slider(nk_flags *state, visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor, - in, style, bounds, slider_min, slider_max, slider_value, step, slider_steps); + in, bounds, slider_min, slider_max, slider_value, step, slider_steps); visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; /* draw slider */ @@ -13728,9 +14963,10 @@ nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, const struct nk_rect *empty1, float scroll_offset, float target, float scroll_step, enum nk_orientation o) { - nk_flags ws; + nk_flags ws = 0; int left_mouse_down; int left_mouse_click_in_cursor; + float scroll_delta; nk_widget_state_reset(state); if (!in) return scroll_offset; @@ -13741,6 +14977,7 @@ nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, if (nk_input_is_mouse_hovering_rect(in, *scroll)) *state = NK_WIDGET_STATE_HOVERED; + scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x; if (left_mouse_down && left_mouse_click_in_cursor) { /* update cursor by mouse dragging */ float pixel, delta; @@ -13773,9 +15010,9 @@ nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h); else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w); } else if (has_scrolling) { - if ((in->mouse.scroll_delta<0 || (in->mouse.scroll_delta>0))) { + if ((scroll_delta < 0 || (scroll_delta > 0))) { /* update cursor by mouse scrolling */ - scroll_offset = scroll_offset + scroll_step * (-in->mouse.scroll_delta); + scroll_offset = scroll_offset + scroll_step * (-scroll_delta); if (o == NK_VERTICAL) scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h); else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w); @@ -13851,7 +15088,7 @@ nk_do_scrollbarv(nk_flags *state, if (!out || !style) return 0; scroll.w = NK_MAX(scroll.w, 1); - scroll.h = NK_MAX(scroll.h, 2 * scroll.w); + scroll.h = NK_MAX(scroll.h, 0); if (target <= scroll.h) return 0; /* optional scrollbar buttons */ @@ -13864,7 +15101,7 @@ nk_do_scrollbarv(nk_flags *state, button.w = scroll.w; button.h = scroll.w; - scroll_h = scroll.h - 2 * button.h; + scroll_h = NK_MAX(scroll.h - 2 * button.h,0); scroll_step = NK_MIN(step, button_pixel_inc); /* decrement button */ @@ -13890,7 +15127,7 @@ nk_do_scrollbarv(nk_flags *state, scroll_off = scroll_offset / target; /* calculate scrollbar cursor bounds */ - cursor.h = (scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y); + cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0); cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y; cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x); cursor.x = scroll.x + style->border + style->padding.x; @@ -13899,12 +15136,12 @@ nk_do_scrollbarv(nk_flags *state, empty_north.x = scroll.x; empty_north.y = scroll.y; empty_north.w = scroll.w; - empty_north.h = cursor.y - scroll.y; + empty_north.h = NK_MAX(cursor.y - scroll.y, 0); empty_south.x = scroll.x; empty_south.y = cursor.y + cursor.h; empty_south.w = scroll.w; - empty_south.h = (scroll.y + scroll.h) - (cursor.y + cursor.h); + empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0); /* update scrollbar */ scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, @@ -14549,7 +15786,7 @@ nk_do_edit(nk_flags *state, struct nk_command_buffer *out, const char *begin = nk_str_get_const(&edit->string); int l = nk_str_len_char(&edit->string); nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, l, row_height, font, + area.y - edit->scrollbar.y, 0, begin, l, row_height, font, background_color, text_color, nk_false); } else { /* edit has selection so draw 1-3 text chunks */ @@ -14789,9 +16026,11 @@ nk_do_property(nk_flags *ws, struct nk_command_buffer *out, struct nk_rect property, const char *name, struct nk_property_variant *variant, float inc_per_pixel, char *buffer, int *len, - int *state, int *cursor, const struct nk_style_property *style, + int *state, int *cursor, int *select_begin, int *select_end, + const struct nk_style_property *style, enum nk_property_filter filter, struct nk_input *in, - const struct nk_user_font *font, struct nk_text_edit *text_edit) + const struct nk_user_font *font, struct nk_text_edit *text_edit, + enum nk_button_behavior behavior) { const nk_plugin_filter filters[] = { nk_filter_decimal, @@ -14880,7 +16119,7 @@ nk_do_property(nk_flags *ws, if (style->draw_end) style->draw_end(out, style->userdata); /* execute right button */ - if (nk_do_button_symbol(ws, out, left, style->sym_left, NK_BUTTON_DEFAULT, &style->dec_button, in, font)) { + if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) { switch (variant->kind) { default: break; case NK_PROPERTY_INT: @@ -14891,9 +16130,8 @@ nk_do_property(nk_flags *ws, variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break; } } - /* execute left button */ - if (nk_do_button_symbol(ws, out, right, style->sym_right, NK_BUTTON_DEFAULT, &style->inc_button, in, font)) { + if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) { switch (variant->kind) { default: break; case NK_PROPERTY_INT: @@ -14904,38 +16142,39 @@ nk_do_property(nk_flags *ws, variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break; } } - - active = (*state == NK_PROPERTY_EDIT); - if (old != NK_PROPERTY_EDIT && active) { + if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) { /* property has been activated so setup buffer */ NK_MEMCPY(buffer, dst, (nk_size)*length); *cursor = nk_utf_len(buffer, *length); *len = *length; length = len; dst = buffer; - } + active = 0; + } else active = (*state == NK_PROPERTY_EDIT); /* execute and run text edit field */ nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]); text_edit->active = (unsigned char)active; text_edit->string.len = *length; text_edit->cursor = NK_CLAMP(0, *cursor, *length); + text_edit->select_start = NK_CLAMP(0,*select_begin, *length); + text_edit->select_end = NK_CLAMP(0,*select_end, *length); text_edit->string.buffer.allocated = (nk_size)*length; text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER; text_edit->string.buffer.memory.ptr = dst; text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER; text_edit->mode = NK_TEXT_EDIT_MODE_INSERT; - nk_do_edit(ws, out, edit, NK_EDIT_ALWAYS_INSERT_MODE, filters[filter], - text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font); + nk_do_edit(ws, out, edit, NK_EDIT_FIELD|NK_EDIT_AUTO_SELECT, + filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font); *length = text_edit->string.len; - active = text_edit->active; *cursor = text_edit->cursor; + *select_begin = text_edit->select_start; + *select_end = text_edit->select_end; + if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER)) + text_edit->active = nk_false; - if (active && nk_input_is_key_pressed(in, NK_KEY_ENTER)) - active = !active; - - if (old && !active) { + if (active && !text_edit->active) { /* property is now not active so convert edit text to value*/ *state = NK_PROPERTY_DEFAULT; buffer[*len] = '\0'; @@ -15725,6 +16964,7 @@ nk_style_from_table(struct nk_context *ctx, const struct nk_color *table) win->tooltip_border = 1.0f; win->popup_border = 1.0f; win->border = 2.0f; + win->min_row_height_padding = 8; win->padding = nk_vec2(4,4); win->group_padding = nk_vec2(4,4); @@ -15740,14 +16980,17 @@ nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font) { struct nk_style *style; NK_ASSERT(ctx); + if (!ctx) return; style = &ctx->style; style->font = font; ctx->stacks.fonts.head = 0; + if (ctx->current) + nk_layout_reset_min_row_height(ctx); } NK_API int -nk_style_push_font(struct nk_context *ctx, struct nk_user_font *font) +nk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font) { struct nk_config_stack_user_font *font_stack; struct nk_config_stack_user_font_element *element; @@ -15889,7 +17132,7 @@ nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors) * ===============================================================*/ NK_INTERN void nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, - unsigned int capacity) + unsigned int capacity) { nk_zero(pool, sizeof(*pool)); pool->alloc = *alloc; @@ -15901,12 +17144,11 @@ nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, NK_INTERN void nk_pool_free(struct nk_pool *pool) { - struct nk_page *next; struct nk_page *iter = pool->pages; if (!pool) return; if (pool->type == NK_BUFFER_FIXED) return; while (iter) { - next = iter->next; + struct nk_page *next = iter->next; pool->alloc.free(pool->alloc.userdata, iter); iter = next; } @@ -16099,7 +17341,6 @@ nk_clear(struct nk_context *ctx) iter = iter->next; continue; } - /* remove hotness from hidden or closed windows*/ if (((iter->flags & NK_WINDOW_HIDDEN) || (iter->flags & NK_WINDOW_CLOSED)) && @@ -16111,7 +17352,6 @@ nk_clear(struct nk_context *ctx) nk_free_window(ctx, iter->popup.win); iter->popup.win = 0; } - /* remove unused window state tables */ {struct nk_table *n, *it = iter->tables; while (it) { @@ -16125,7 +17365,6 @@ nk_clear(struct nk_context *ctx) } it = n; }} - /* window itself is not used anymore so free */ if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) { next = iter->next; @@ -16166,18 +17405,12 @@ NK_INTERN void nk_start_popup(struct nk_context *ctx, struct nk_window *win) { struct nk_popup_buffer *buf; - struct nk_panel *iter; NK_ASSERT(ctx); NK_ASSERT(win); if (!ctx || !win) return; - /* make sure to use the correct popup buffer*/ - iter = win->layout; - while (iter->parent) - iter = iter->parent; - /* save buffer fill state for popup */ - buf = &iter->popup_buffer; + buf = &win->popup.buf; buf->begin = win->buffer.end; buf->end = win->buffer.end; buf->parent = win->buffer.last; @@ -16189,17 +17422,11 @@ NK_INTERN void nk_finish_popup(struct nk_context *ctx, struct nk_window *win) { struct nk_popup_buffer *buf; - struct nk_panel *iter; NK_ASSERT(ctx); NK_ASSERT(win); if (!ctx || !win) return; - /* make sure to use the correct popup buffer*/ - iter = win->layout; - while (iter->parent) - iter = iter->parent; - - buf = &iter->popup_buffer; + buf = &win->popup.buf; buf->last = win->buffer.last; buf->end = win->buffer.end; } @@ -16218,41 +17445,26 @@ nk_finish(struct nk_context *ctx, struct nk_window *win) { struct nk_popup_buffer *buf; struct nk_command *parent_last; - struct nk_command *sublast; - struct nk_command *last; void *memory; NK_ASSERT(ctx); NK_ASSERT(win); if (!ctx || !win) return; nk_finish_buffer(ctx, &win->buffer); - if (!win->layout->popup_buffer.active) return; + if (!win->popup.buf.active) return; - /* from here on is for popup window buffer handling */ - /*--------------------------------------------------*/ - buf = &win->layout->popup_buffer; + buf = &win->popup.buf; memory = ctx->memory.memory.ptr; - - /* redirect the sub-window buffer to the end of the window command buffer */ parent_last = nk_ptr_add(struct nk_command, memory, buf->parent); - sublast = nk_ptr_add(struct nk_command, memory, buf->last); - last = nk_ptr_add(struct nk_command, memory, win->buffer.last); - parent_last->next = buf->end; - sublast->next = last->next; - last->next = buf->begin; - win->buffer.last = buf->last; - win->buffer.end = buf->end; - buf->active = nk_false; } NK_INTERN void nk_build(struct nk_context *ctx) { - struct nk_window *iter; - struct nk_window *next; - struct nk_command *cmd; - nk_byte *buffer; + struct nk_window *iter = 0; + struct nk_command *cmd = 0; + nk_byte *buffer = 0; /* draw cursor overlay */ if (!ctx->style.cursor_active) @@ -16271,29 +17483,42 @@ nk_build(struct nk_context *ctx) nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white); nk_finish_buffer(ctx, &ctx->overlay); } - - /* build one big draw command list out of all buffers */ + /* build one big draw command list out of all window buffers */ iter = ctx->begin; buffer = (nk_byte*)ctx->memory.memory.ptr; while (iter != 0) { - next = iter->next; - if (iter->buffer.last == iter->buffer.begin || (iter->flags & NK_WINDOW_HIDDEN)) { - iter = next; - continue; - } + struct nk_window *next = iter->next; + if (iter->buffer.last == iter->buffer.begin || (iter->flags & NK_WINDOW_HIDDEN)|| + iter->seq != ctx->seq) + goto cont; + cmd = nk_ptr_add(struct nk_command, buffer, iter->buffer.last); while (next && ((next->buffer.last == next->buffer.begin) || (next->flags & NK_WINDOW_HIDDEN))) next = next->next; /* skip empty command buffers */ - if (next) { - cmd->next = next->buffer.begin; - } else { - if (ctx->overlay.end != ctx->overlay.begin) - cmd->next = ctx->overlay.begin; - else cmd->next = ctx->memory.allocated; - } - iter = next; + if (next) cmd->next = next->buffer.begin; + cont: iter = next; + } + /* append all popup draw commands into lists */ + iter = ctx->begin; + while (iter != 0) { + struct nk_window *next = iter->next; + struct nk_popup_buffer *buf; + if (!iter->popup.buf.active) + goto skip; + + buf = &iter->popup.buf; + cmd->next = buf->begin; + cmd = nk_ptr_add(struct nk_command, buffer, buf->last); + buf->active = nk_false; + skip: iter = next; + } + /* append overlay commands */ + if (cmd) { + if (ctx->overlay.end != ctx->overlay.begin) + cmd->next = ctx->overlay.begin; + else cmd->next = ctx->memory.allocated; } } @@ -16311,7 +17536,6 @@ nk__begin(struct nk_context *ctx) nk_build(ctx); ctx->build = nk_true; } - iter = ctx->begin; while (iter && ((iter->buffer.begin == iter->buffer.end) || (iter->flags & NK_WINDOW_HIDDEN))) iter = iter->next; @@ -16340,7 +17564,6 @@ nk__next(struct nk_context *ctx, const struct nk_command *cmd) static int nk_panel_has_header(nk_flags flags, const char *title) { - /* window header state */ int active = 0; active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE)); active = active || (flags & NK_WINDOW_TITLE); @@ -16425,20 +17648,21 @@ nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type pan NK_ASSERT(ctx->current->layout); if (!ctx || !ctx->current || !ctx->current->layout) return 0; nk_zero(ctx->current->layout, sizeof(*ctx->current->layout)); - if (ctx->current->flags & NK_WINDOW_HIDDEN) + if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) { + nk_zero(ctx->current->layout, sizeof(struct nk_panel)); + ctx->current->layout->type = panel_type; return 0; - + } /* pull state into local stack */ style = &ctx->style; font = style->font; - in = &ctx->input; win = ctx->current; layout = win->layout; out = &win->buffer; + in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input; #ifdef NK_INCLUDE_COMMAND_USERDATA win->buffer.userdata = ctx->userdata; #endif - /* pull style configuration into local stack */ scrollbar_size = style->window.scrollbar_size; panel_padding = nk_panel_get_padding(style, panel_type); @@ -16486,6 +17710,7 @@ nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type pan layout->max_x = 0; layout->header_height = 0; layout->footer_height = 0; + nk_layout_reset_min_row_height(ctx); layout->row.index = 0; layout->row.columns = 0; layout->row.ratio = 0; @@ -16564,7 +17789,6 @@ nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type pan &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) { layout->flags |= NK_WINDOW_HIDDEN; - layout->flags |= NK_WINDOW_CLOSED; layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED; } } @@ -16602,6 +17826,7 @@ nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type pan label.y = header.y + style->window.header.label_padding.y; label.h = font->height + 2 * style->window.header.label_padding.y; label.w = t + 2 * style->window.header.spacing.x; + label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x); nk_widget_text(out, label,(const char*)title, text_len, &text, NK_TEXT_LEFT, font);} } @@ -16649,7 +17874,7 @@ nk_panel_end(struct nk_context *ctx) layout = window->layout; style = &ctx->style; out = &window->buffer; - in = (layout->flags & NK_WINDOW_ROM) ? 0 :&ctx->input; + in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input; if (!nk_panel_is_sub(layout->type)) nk_push_scissor(out, nk_null_rect); @@ -16712,6 +17937,44 @@ nk_panel_end(struct nk_context *ctx) float scroll_offset; float scroll_step; float scroll_inc; + + /* mouse wheel scrolling */ + if (nk_panel_is_sub(layout->type)) + { + /* sub-window mouse wheel scrolling */ + struct nk_window *root_window = window; + struct nk_panel *root_panel = window->layout; + while (root_panel->parent) + root_panel = root_panel->parent; + while (root_window->parent) + root_window = root_window->parent; + + /* only allow scrolling if parent window is active */ + scroll_has_scrolling = 0; + if ((root_window == ctx->active) && layout->has_scrolling) { + /* and panel is being hovered and inside clip rect*/ + if (nk_input_is_mouse_hovering_rect(in, layout->bounds) && + NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h, + root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h)) + { + /* deactivate all parent scrolling */ + root_panel = window->layout; + while (root_panel->parent) { + root_panel->has_scrolling = nk_false; + root_panel = root_panel->parent; + } + root_panel->has_scrolling = nk_false; + scroll_has_scrolling = nk_true; + } + } + } else if (!nk_panel_is_sub(layout->type)) { + /* window mouse wheel scrolling */ + scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling; + if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling) + window->scrolled = nk_true; + else window->scrolled = nk_false; + } else scroll_has_scrolling = nk_false; + { /* vertical scrollbar */ nk_flags state = 0; @@ -16724,51 +17987,12 @@ nk_panel_end(struct nk_context *ctx) scroll_step = scroll.h * 0.10f; scroll_inc = scroll.h * 0.01f; scroll_target = (float)(int)(layout->at_y - scroll.y); - - /* scrolling by mouse wheel */ - if (nk_panel_is_sub(layout->type)) - { - /* sub-window scrollbar wheel scrolling */ - struct nk_window *root_window = window; - struct nk_panel *root_panel = window->layout; - while (root_panel->parent) - root_panel = root_panel->parent; - while (root_window->parent) - root_window = root_window->parent; - - /* only allow scrolling if parent window is active */ - scroll_has_scrolling = 0; - if ((root_window == ctx->active) && layout->has_scrolling) { - /* and panel is being hovered and inside clip rect*/ - if (nk_input_is_mouse_hovering_rect(in, layout->bounds) && - NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h, - root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h)) - { - /* deactivate all parent scrolling */ - root_panel = window->layout; - while (root_panel->parent) { - root_panel->has_scrolling = nk_false; - root_panel = root_panel->parent; - } - root_panel->has_scrolling = nk_false; - scroll_has_scrolling = nk_true; - } - } - } else if (!nk_panel_is_sub(layout->type)) { - /* window scrollbar wheel scrolling */ - scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling; - if (in && in->mouse.scroll_delta > 0 && scroll_has_scrolling) - window->scrolled = nk_true; - else window->scrolled = nk_false; - } else scroll_has_scrolling = nk_false; - - /* execute scrollbar */ scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &ctx->style.scrollv, in, style->font); + scroll_offset, scroll_target, scroll_step, scroll_inc, + &ctx->style.scrollv, in, style->font); *layout->offset_y = (nk_uint)scroll_offset; if (in && scroll_has_scrolling) - in->mouse.scroll_delta = 0; + in->mouse.scroll_delta.y = 0; } { /* horizontal scrollbar */ @@ -16782,17 +18006,16 @@ nk_panel_end(struct nk_context *ctx) scroll_target = (float)(int)(layout->max_x - scroll.x); scroll_step = layout->max_x * 0.05f; scroll_inc = layout->max_x * 0.005f; - scroll_has_scrolling = nk_false; scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &ctx->style.scrollh, in, style->font); + scroll_offset, scroll_target, scroll_step, scroll_inc, + &ctx->style.scrollh, in, style->font); *layout->offset_x = (nk_uint)scroll_offset; } } /* hide scroll if no user input */ if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) { - int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta != 0; + int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0; int is_window_hovered = nk_window_is_hovered(ctx); int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active)) @@ -16866,24 +18089,34 @@ nk_panel_end(struct nk_context *ctx) int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, scaler, nk_true); - if (nk_input_is_mouse_down(in, NK_BUTTON_LEFT) && left_mouse_down && left_mouse_click_in_scaler) { + if (left_mouse_down && left_mouse_click_in_scaler) { float delta_x = in->mouse.delta.x; if (layout->flags & NK_WINDOW_SCALE_LEFT) { delta_x = -delta_x; window->bounds.x += in->mouse.delta.x; } - window->bounds.w = NK_MAX(window_size.x, window->bounds.w + delta_x); - - /* dragging in y-direction is only possible if static window */ - if (!(layout->flags & NK_WINDOW_DYNAMIC)) - window->bounds.h = NK_MAX(window_size.y, window->bounds.h + in->mouse.delta.y); + /* dragging in x-direction */ + if (window->bounds.w + delta_x >= window_size.x) { + if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) { + window->bounds.w = window->bounds.w + delta_x; + scaler.x += in->mouse.delta.x; + } + } + /* dragging in y-direction (only possible if static window) */ + if (!(layout->flags & NK_WINDOW_DYNAMIC)) { + if (window_size.y < window->bounds.h + in->mouse.delta.y) { + if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) { + window->bounds.h = window->bounds.h + in->mouse.delta.y; + scaler.y += in->mouse.delta.y; + } + } + } ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT]; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + in->mouse.delta.x + scaler.w/2.0f; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + in->mouse.delta.y + scaler.h/2.0f; + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f; + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f; } } } - if (!nk_panel_is_sub(layout->type)) { /* window is hidden so clear command buffer */ if (layout->flags & NK_WINDOW_HIDDEN) @@ -16908,7 +18141,6 @@ nk_panel_end(struct nk_context *ctx) window->property.prev = window->property.active; window->property.seq = 0; } - /* edit garbage collector */ if (window->edit.active && window->edit.old != window->edit.seq && window->edit.active == window->edit.prev) { @@ -16918,7 +18150,6 @@ nk_panel_end(struct nk_context *ctx) window->edit.prev = window->edit.active; window->edit.seq = 0; } - /* contextual garbage collector */ if (window->popup.active_con && window->popup.con_old != window->popup.con_count) { window->popup.con_count = 0; @@ -16929,8 +18160,7 @@ nk_panel_end(struct nk_context *ctx) window->popup.con_count = 0; } window->popup.combo_count = 0; - - /* helper to make sure you have a 'nk_tree_push' * for every 'nk_tree_pop' */ + /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */ NK_ASSERT(!layout->row.tree_depth); } @@ -16953,7 +18183,7 @@ nk_create_page_element(struct nk_context *ctx) NK_ASSERT(elem); if (!elem) return 0; } else { - /* allocate new page element from the back of the fixed size memory buffer */ + /* allocate new page element from back of fixed size memory buffer */ NK_STORAGE const nk_size size = sizeof(struct nk_page_element); NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element); elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align); @@ -16987,7 +18217,6 @@ nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem) nk_link_page_element_into_freelist(ctx, elem); return; } - /* if possible remove last element from back of fixed memory buffer */ {void *elem_end = (void*)(elem + 1); void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size; @@ -17049,16 +18278,16 @@ nk_push_table(struct nk_window *win, struct nk_table *tbl) win->tables = tbl; tbl->next = 0; tbl->prev = 0; + tbl->size = 0; win->table_count = 1; - win->table_size = 0; return; } win->tables->prev = tbl; tbl->next = win->tables; tbl->prev = 0; + tbl->size = 0; win->tables = tbl; win->table_count++; - win->table_size = 0; } NK_INTERN void @@ -17081,32 +18310,31 @@ nk_add_value(struct nk_context *ctx, struct nk_window *win, NK_ASSERT(ctx); NK_ASSERT(win); if (!win || !ctx) return 0; - if (!win->tables || win->table_size >= NK_VALUE_PAGE_CAPACITY) { + if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) { struct nk_table *tbl = nk_create_table(ctx); NK_ASSERT(tbl); if (!tbl) return 0; nk_push_table(win, tbl); } win->tables->seq = win->seq; - win->tables->keys[win->table_size] = name; - win->tables->values[win->table_size] = value; - return &win->tables->values[win->table_size++]; + win->tables->keys[win->tables->size] = name; + win->tables->values[win->tables->size] = value; + return &win->tables->values[win->tables->size++]; } NK_INTERN nk_uint* nk_find_value(struct nk_window *win, nk_hash name) { - nk_ushort size = win->table_size; struct nk_table *iter = win->tables; while (iter) { - nk_ushort i = 0; + unsigned int i = 0; + unsigned int size = iter->size; for (i = 0; i < size; ++i) { if (iter->keys[i] == name) { iter->seq = win->seq; return &iter->values[i]; } - } - size = NK_VALUE_PAGE_CAPACITY; + } size = NK_VALUE_PAGE_CAPACITY; iter = iter->next; } return 0; @@ -17131,7 +18359,7 @@ NK_INTERN void nk_free_window(struct nk_context *ctx, struct nk_window *win) { /* unlink windows from list */ - struct nk_table *n, *it = win->tables; + struct nk_table *it = win->tables; if (win->popup.win) { nk_free_window(ctx, win->popup.win); win->popup.win = 0; @@ -17141,7 +18369,7 @@ nk_free_window(struct nk_context *ctx, struct nk_window *win) while (it) { /*free window state tables */ - n = it->next; + struct nk_table *n = it->next; nk_remove_table(win, it); nk_free_table(ctx, it); if (it == win->tables) @@ -17323,11 +18551,12 @@ nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, } if (win->flags & NK_WINDOW_HIDDEN) { ctx->current = win; + win->layout = 0; return 0; } /* window overlapping */ - if (!(win->flags & NK_WINDOW_HIDDEN)) + if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT)) { int inpanel, ishovered; const struct nk_window *iter = win; @@ -17408,11 +18637,11 @@ nk_end(struct nk_context *ctx) struct nk_panel *layout; NK_ASSERT(ctx); NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`"); - NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) + return; layout = ctx->current->layout; - if (!ctx || !ctx->current) return; - if (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN)) { + if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) { ctx->current = 0; return; } @@ -17844,6 +19073,42 @@ nk_menubar_end(struct nk_context *ctx) * LAYOUT * * --------------------------------------------------------------*/ +NK_API void +nk_layout_set_min_row_height(struct nk_context *ctx, float height) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + layout->row.min_height = height; +} + +NK_API void +nk_layout_reset_min_row_height(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + layout->row.min_height = ctx->style.font->height; + layout->row.min_height += ctx->style.text.padding.y*2; + layout->row.min_height += ctx->style.window.min_row_height_padding*2; +} + NK_INTERN float nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, float total_space, int columns) @@ -17902,7 +19167,10 @@ nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, layout->row.index = 0; layout->at_y += layout->row.height; layout->row.columns = cols; - layout->row.height = height + item_spacing.y; + if (height == 0.0f) + layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y; + else layout->row.height = height + item_spacing.y; + layout->row.item_offset = 0; if (layout->flags & NK_WINDOW_DYNAMIC) { /* draw background for dynamic panels */ @@ -18303,6 +19571,26 @@ nk_layout_space_bounds(struct nk_context *ctx) return ret; } +NK_API struct nk_rect +nk_layout_widget_bounds(struct nk_context *ctx) +{ + struct nk_rect ret; + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + win = ctx->current; + layout = win->layout; + + ret.x = layout->at_x; + ret.y = layout->at_y; + ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0); + ret.h = layout->row.height; + return ret; +} + NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret) { @@ -18415,7 +19703,7 @@ nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, switch (layout->row.type) { case NK_LAYOUT_DYNAMIC_FIXED: { /* scaling fixed size widgets item width */ - item_width = panel_space / (float)layout->row.columns; + item_width = NK_MAX(1.0f,panel_space-1.0f) / (float)layout->row.columns; item_offset = (float)layout->row.index * item_width; item_spacing = (float)layout->row.index * spacing.x; } break; @@ -18572,6 +19860,7 @@ nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type, const struct nk_input *in; const struct nk_style_button *button; enum nk_symbol_type symbol; + float row_height; struct nk_vec2 item_spacing; struct nk_rect header = {0,0,0,0}; @@ -18595,7 +19884,11 @@ nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type, item_spacing = style->window.spacing; /* calculate header bounds and draw background */ - nk_layout_row_dynamic(ctx, style->font->height + 2 * style->tab.padding.y, 1); + row_height = style->font->height + 2 * style->tab.padding.y; + nk_layout_set_min_row_height(ctx, row_height); + nk_layout_row_dynamic(ctx, row_height, 1); + nk_layout_reset_min_row_height(ctx); + widget_state = nk_widget(&header, ctx); if (type == NK_TREE_TAB) { const struct nk_style_item *background = &style->tab.background; @@ -18806,57 +20099,79 @@ nk_widget_height(struct nk_context *ctx) NK_API int nk_widget_is_hovered(struct nk_context *ctx) { - int ret; + struct nk_rect c, v; struct nk_rect bounds; NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) + if (!ctx || !ctx->current || ctx->active != ctx->current) return 0; + c = ctx->current->layout->clip; + c.x = (float)((int)c.x); + c.y = (float)((int)c.y); + c.w = (float)((int)c.w); + c.h = (float)((int)c.h); + nk_layout_peek(&bounds, ctx); - ret = (ctx->active == ctx->current); - ret = ret && nk_input_is_mouse_hovering_rect(&ctx->input, bounds); - return ret; + nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); + if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) + return 0; + return nk_input_is_mouse_hovering_rect(&ctx->input, bounds); } NK_API int nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn) { - int ret; + struct nk_rect c, v; struct nk_rect bounds; NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) + if (!ctx || !ctx->current || ctx->active != ctx->current) return 0; + c = ctx->current->layout->clip; + c.x = (float)((int)c.x); + c.y = (float)((int)c.y); + c.w = (float)((int)c.w); + c.h = (float)((int)c.h); + nk_layout_peek(&bounds, ctx); - ret = (ctx->active == ctx->current); - ret = ret && nk_input_mouse_clicked(&ctx->input, btn, bounds); - return ret; + nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); + if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) + return 0; + return nk_input_mouse_clicked(&ctx->input, btn, bounds); } NK_API int nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, int down) { - int ret; + struct nk_rect c, v; struct nk_rect bounds; NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) + if (!ctx || !ctx->current || ctx->active != ctx->current) return 0; + c = ctx->current->layout->clip; + c.x = (float)((int)c.x); + c.y = (float)((int)c.y); + c.w = (float)((int)c.w); + c.h = (float)((int)c.h); + nk_layout_peek(&bounds, ctx); - ret = (ctx->active == ctx->current); - ret = ret && nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down); - return ret; + nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); + if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) + return 0; + return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down); } NK_API enum nk_widget_layout_states nk_widget(struct nk_rect *bounds, const struct nk_context *ctx) { - struct nk_rect *c = 0; + struct nk_rect c, v; struct nk_window *win; struct nk_panel *layout; + const struct nk_input *in; NK_ASSERT(ctx); NK_ASSERT(ctx->current); @@ -18864,11 +20179,12 @@ nk_widget(struct nk_rect *bounds, const struct nk_context *ctx) if (!ctx || !ctx->current || !ctx->current->layout) return NK_WIDGET_INVALID; - /* allocate space and check if the widget needs to be updated and drawn */ + /* allocate space and check if the widget needs to be updated and drawn */ nk_panel_alloc_space(bounds, ctx); win = ctx->current; layout = win->layout; - c = &layout->clip; + in = &ctx->input; + c = layout->clip; /* if one of these triggers you forgot to add an `if` condition around either a window, group, popup, combobox or contextual menu `begin` and `end` block. @@ -18879,15 +20195,21 @@ nk_widget(struct nk_rect *bounds, const struct nk_context *ctx) NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); - /* need to convert to int here to remove floating point error */ + /* need to convert to int here to remove floating point errors */ bounds->x = (float)((int)bounds->x); bounds->y = (float)((int)bounds->y); bounds->w = (float)((int)bounds->w); bounds->h = (float)((int)bounds->h); - if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds->x, bounds->y, bounds->w, bounds->h)) + c.x = (float)((int)c.x); + c.y = (float)((int)c.y); + c.w = (float)((int)c.w); + c.h = (float)((int)c.h); + + nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h); + if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h)) return NK_WIDGET_INVALID; - if (!NK_CONTAINS(bounds->x, bounds->y, bounds->w, bounds->h, c->x, c->y, c->w, c->h)) + if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h)) return NK_WIDGET_ROM; return NK_WIDGET_VALID; } @@ -18955,7 +20277,6 @@ nk_spacing(struct nk_context *ctx, int cols) nk_panel_alloc_row(ctx, win); cols = index; } - /* non table layout need to allocate space */ if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED && layout->row.type != NK_LAYOUT_STATIC_FIXED) { @@ -20020,12 +21341,16 @@ nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant char *buffer = 0; int *len = 0; int *cursor = 0; + int *select_begin = 0; + int *select_end = 0; int old_state; char dummy_buffer[NK_MAX_NUMBER_BUFFER]; int dummy_state = NK_PROPERTY_DEFAULT; int dummy_length = 0; int dummy_cursor = 0; + int dummy_select_begin = 0; + int dummy_select_end = 0; NK_ASSERT(ctx); NK_ASSERT(ctx->current); @@ -20038,7 +21363,6 @@ nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant style = &ctx->style; s = nk_widget(&bounds, ctx); if (!s) return; - in = (s == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; /* calculate hash from name */ if (name[0] == '#') { @@ -20052,18 +21376,26 @@ nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant len = &win->property.length; cursor = &win->property.cursor; state = &win->property.state; + select_begin = &win->property.select_start; + select_end = &win->property.select_end; } else { buffer = dummy_buffer; len = &dummy_length; cursor = &dummy_cursor; state = &dummy_state; + select_begin = &dummy_select_begin; + select_end = &dummy_select_end; } /* execute property widget */ old_state = *state; + ctx->text_edit.clip = ctx->clip; + in = ((s == NK_WIDGET_ROM && !win->property.active) || + layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name, - variant, inc_per_pixel, buffer, len, state, cursor, - &style->property, filter, in, style->font, &ctx->text_edit); + variant, inc_per_pixel, buffer, len, state, cursor, select_begin, + select_end, &style->property, filter, in, style->font, &ctx->text_edit, + ctx->button_behavior); if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) { /* current property is now hot */ @@ -20073,12 +21405,13 @@ nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant win->property.cursor = *cursor; win->property.state = *state; win->property.name = hash; + win->property.select_start = *select_begin; + win->property.select_end = *select_end; if (*state == NK_PROPERTY_DRAG) { ctx->input.mouse.grab = nk_true; ctx->input.mouse.grabbed = nk_true; } } - /* check if previously active property is now inactive */ if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) { if (old_state == NK_PROPERTY_DRAG) { @@ -20086,6 +21419,8 @@ nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant ctx->input.mouse.grabbed = nk_false; ctx->input.mouse.ungrab = nk_true; } + win->property.select_start = 0; + win->property.select_end = 0; win->property.active = 0; } } @@ -20505,10 +21840,12 @@ nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values, min_value = NK_MIN(values[i + offset], min_value); max_value = NK_MAX(values[i + offset], max_value); } - nk_chart_begin(ctx, type, count, min_value, max_value); - for (i = 0; i < count; ++i) - nk_chart_push(ctx, values[i + offset]); - nk_chart_end(ctx); + + if (nk_chart_begin(ctx, type, count, min_value, max_value)) { + for (i = 0; i < count; ++i) + nk_chart_push(ctx, values[i + offset]); + nk_chart_end(ctx); + } } NK_API void @@ -20529,10 +21866,12 @@ nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata min_value = NK_MIN(value, min_value); max_value = NK_MAX(value, max_value); } - nk_chart_begin(ctx, type, count, min_value, max_value); - for (i = 0; i < count; ++i) - nk_chart_push(ctx, value_getter(userdata, i + offset)); - nk_chart_end(ctx); + + if (nk_chart_begin(ctx, type, count, min_value, max_value)) { + for (i = 0; i < count; ++i) + nk_chart_push(ctx, value_getter(userdata, i + offset)); + nk_chart_end(ctx); + } } /* ------------------------------------------------------------- @@ -20550,7 +21889,6 @@ nk_group_scrolled_offset_begin(struct nk_context *ctx, win = ctx->current; nk_panel_alloc_space(&bounds, ctx); - {const struct nk_rect *c = &win->layout->clip; if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) && !(flags & NK_WINDOW_MOVABLE)) { @@ -20559,7 +21897,7 @@ nk_group_scrolled_offset_begin(struct nk_context *ctx, if (win->flags & NK_WINDOW_ROM) flags |= NK_WINDOW_ROM; - /* initialize a fake window to create the layout from */ + /* initialize a fake window to create the panel from */ nk_zero(&panel, sizeof(panel)); panel.bounds = bounds; panel.flags = flags; @@ -20576,7 +21914,18 @@ nk_group_scrolled_offset_begin(struct nk_context *ctx, panel.layout->offset_y = y_offset; panel.layout->parent = win->layout; win->layout = panel.layout; + ctx->current = win; + if ((panel.layout->flags & NK_WINDOW_CLOSED) || + (panel.layout->flags & NK_WINDOW_MINIMIZED)) + { + nk_flags f = panel.layout->flags; + nk_group_scrolled_end(ctx); + if (f & NK_WINDOW_CLOSED) + return NK_WINDOW_CLOSED; + if (f & NK_WINDOW_MINIMIZED) + return NK_WINDOW_MINIMIZED; + } return 1; } @@ -20730,7 +22079,7 @@ nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view, result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); win = ctx->current; layout = win->layout; - + view->total_height = row_height * NK_MAX(row_count,1); view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f); view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height), 0); @@ -20799,7 +22148,7 @@ nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type, win->popup.type = NK_PANEL_POPUP; } - /* make sure we have to correct popup */ + /* make sure we have correct popup */ if (win->popup.name != title_hash) { if (!win->popup.active) { nk_zero(popup, sizeof(*popup)); @@ -20851,7 +22200,7 @@ nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type, root->flags |= NK_WINDOW_REMOVE_ROM; root = root->parent; } - win->layout->popup_buffer.active = 0; + win->popup.buf.active = 0; win->popup.active = 0; ctx->memory.allocated = allocated; ctx->current = win; @@ -20881,7 +22230,7 @@ nk_nonblock_begin(struct nk_context *ctx, win = ctx->current; panel = win->layout; NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP)); - (void)panel; + (void)panel; popup = win->popup.win; if (!popup) { /* create window for nonblocking popup */ @@ -20903,8 +22252,7 @@ nk_nonblock_begin(struct nk_context *ctx, if (!is_active) { /* remove read only mode from all parent panels */ - struct nk_panel *root; - root = win->layout; + struct nk_panel *root = win->layout; while (root) { root->flags |= NK_WINDOW_REMOVE_ROM; root = root->parent; @@ -21262,7 +22610,7 @@ nk_contextual_end(struct nk_context *ctx) NK_ASSERT(panel->type & NK_PANEL_SET_POPUP); if (panel->flags & NK_WINDOW_DYNAMIC) { /* Close behavior - This is a bit hack solution since we do not now before we end our popup + This is a bit of a hack solution since we do not know before we end our popup how big it will be. We therefore do not directly know when a click outside the non-blocking popup must close it at that direct frame. Instead it will be closed in the next frame.*/ @@ -21273,7 +22621,6 @@ nk_contextual_end(struct nk_context *ctx) body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height); body.h = (panel->bounds.y + panel->bounds.h) - body.y; } - {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); if (pressed && in_body) diff --git a/deps/nuklear_glfw_gl2.h b/deps/nuklear_glfw_gl2.h index 4b4e2f950..965af5fe1 100644 --- a/deps/nuklear_glfw_gl2.h +++ b/deps/nuklear_glfw_gl2.h @@ -1,7 +1,7 @@ /* * Nuklear - v1.32.0 - public domain * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke + * authored from 2015-2017 by Micha Mettke */ /* * ============================================================== @@ -24,7 +24,7 @@ NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atl NK_API void nk_glfw3_font_stash_end(void); NK_API void nk_glfw3_new_frame(void); -NK_API void nk_glfw3_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer); +NK_API void nk_glfw3_render(enum nk_anti_aliasing); NK_API void nk_glfw3_shutdown(void); NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint); @@ -44,6 +44,12 @@ NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xof #ifndef NK_GLFW_TEXT_MAX #define NK_GLFW_TEXT_MAX 256 #endif +#ifndef NK_GLFW_DOUBLE_CLICK_LO +#define NK_GLFW_DOUBLE_CLICK_LO 0.02 +#endif +#ifndef NK_GLFW_DOUBLE_CLICK_HI +#define NK_GLFW_DOUBLE_CLICK_HI 0.2 +#endif struct nk_glfw_device { struct nk_buffer cmds; @@ -67,7 +73,8 @@ static struct nk_glfw { struct nk_vec2 fb_scale; unsigned int text[NK_GLFW_TEXT_MAX]; int text_len; - float scroll; + struct nk_vec2 scroll; + double last_button_click; } glfw; NK_INTERN void @@ -83,7 +90,7 @@ nk_glfw3_device_upload_atlas(const void *image, int width, int height) } NK_API void -nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) +nk_glfw3_render(enum nk_anti_aliasing AA) { /* setup global state */ struct nk_glfw_device *dev = &glfw.ogl; @@ -200,7 +207,22 @@ NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) { (void)win; (void)xoff; - glfw.scroll += (float)yoff; + glfw.scroll.x += (float)xoff; + glfw.scroll.y += (float)yoff; +} + +NK_API void +nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + double x, y; + if (button != GLFW_MOUSE_BUTTON_LEFT) return; + glfwGetCursorPos(window, &x, &y); + if (action == GLFW_PRESS) { + double dt = glfwGetTime() - glfw.last_button_click; + if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) + nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_true); + glfw.last_button_click = glfwGetTime(); + } else nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_false); } NK_INTERN void @@ -232,8 +254,8 @@ nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { glfwSetScrollCallback(win, nk_gflw3_scroll_callback); glfwSetCharCallback(win, nk_glfw3_char_callback); + glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback); } - nk_init_default(&glfw.ctx, 0); glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; @@ -333,7 +355,7 @@ nk_glfw3_new_frame(void) nk_input_scroll(ctx, glfw.scroll); nk_input_end(&glfw.ctx); glfw.text_len = 0; - glfw.scroll = 0; + glfw.scroll = nk_vec2(0,0); } NK_API diff --git a/tests/gamma.c b/tests/gamma.c index 3599482d7..500d41c40 100644 --- a/tests/gamma.c +++ b/tests/gamma.c @@ -140,7 +140,7 @@ int main(int argc, char** argv) } nk_end(nk); - nk_glfw3_render(NK_ANTI_ALIASING_ON, 10000, 1000); + nk_glfw3_render(NK_ANTI_ALIASING_ON); glfwSwapBuffers(window); glfwWaitEventsTimeout(1.0); diff --git a/tests/joysticks.c b/tests/joysticks.c index 8a6ff7445..9425af78f 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -298,7 +298,7 @@ int main(void) nk_end(nk); } - nk_glfw3_render(NK_ANTI_ALIASING_ON, 10000, 1000); + nk_glfw3_render(NK_ANTI_ALIASING_ON); glfwSwapBuffers(window); glfwPollEvents(); From 5b7281bd41149f6d064b954a0071c25ed950154b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 23 Jul 2017 16:34:11 +0200 Subject: [PATCH 100/222] Add glfwGetJoystickGUID This function completes the first round of support for SDL_GameControllerDB. Fixes #900. --- README.md | 2 ++ docs/news.dox | 6 +++--- include/GLFW/glfw3.h | 37 +++++++++++++++++++++++++++++++++++++ src/input.c | 25 +++++++++++++++++++++++++ tests/joysticks.c | 2 ++ 5 files changed, 69 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0892b4037..3353dacc5 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,8 @@ information on what to include when reporting a bug. SDL\_GameControllerDB format (#900) - Added `glfwJoystickIsGamepad` function for querying whether a joystick has a gamepad mapping (#900) +- Added `glfwGetJoystickGUID` function for querying the SDL compatible GUID of + a joystick (#900) - Added `glfwGetGamepadName` function for querying the name provided by the gamepad mapping (#900) - Added `glfwGetGamepadState` function, `GLFW_GAMEPAD_*` and `GLFWgamepadstate` diff --git a/docs/news.dox b/docs/news.dox index 2d4b621d5..d8bb23a52 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -16,9 +16,9 @@ human-readable description with @ref glfwGetError. @subsection news_33_gamepad SDL_GameControllerDB support and gamepad input GLFW now supports remapping of gamepads and controllers to a 360-like controller -layout with @ref glfwJoystickIsGamepad, @ref glfwGetGamepadName, @ref -glfwGetGamepadState and @ref glfwUpdateGamepadMappings, and the input state -struct @ref GLFWgamepadstate. +layout with @ref glfwJoystickIsGamepad, @ref glfwGetJoystickGUID, @ref +glfwGetGamepadName, @ref glfwGetGamepadState and @ref glfwUpdateGamepadMappings, +and the input state struct @ref GLFWgamepadstate. @sa @ref gamepad diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 83fad7374..253262522 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4381,6 +4381,43 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); */ GLFWAPI const char* glfwGetJoystickName(int jid); +/*! @brief Returns the SDL comaptible GUID of the specified joystick. + * + * This function returns the SDL compatible GUID, as a UTF-8 encoded + * hexadecimal string, of the specified joystick. The returned string is + * allocated and freed by GLFW. You should not free it yourself. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. Call @ref glfwJoystickPresent to check + * device presence. + * + * The GUID uses the format introduced in SDL 2.0.5. This GUID tries to + * uniquely identify the make and model of a joystick but does not identify + * a specific unit, e.g. all wired Xbox 360 controllers will have the same + * GUID on that platform. The GUID for a unit may vary between platforms + * depending on what hardware information the platform specific APIs provide. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded GUID of the joystick, or `NULL` if the joystick + * is not present or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetJoystickGUID(int jid); + /*! @brief Returns whether the specified joystick has a gamepad mapping. * * This function returns whether the specified joystick is both present and has diff --git a/src/input.c b/src/input.c index 2a5dfef07..101b6859b 100644 --- a/src/input.c +++ b/src/input.c @@ -896,6 +896,31 @@ GLFWAPI const char* glfwGetJoystickName(int jid) return js->name; } +GLFWAPI const char* glfwGetJoystickGUID(int jid) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return NULL; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return NULL; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return NULL; + + return js->guid; +} + GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); diff --git a/tests/joysticks.c b/tests/joysticks.c index 9425af78f..88489d4e6 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -228,6 +228,8 @@ int main(void) GLFWgamepadstate state; nk_layout_row_dynamic(nk, 30, 1); + nk_labelf(nk, NK_TEXT_LEFT, "Hardware GUID %s", + glfwGetJoystickGUID(joysticks[i])); nk_label(nk, "Joystick state", NK_TEXT_LEFT); axes = glfwGetJoystickAxes(joysticks[i], &axis_count); From ab2247f8f38198b97c43b0d9a51cbe1e8ce4ea99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 6 Aug 2017 23:04:19 +0200 Subject: [PATCH 101/222] Cocoa: Fix string object being updated incorrectly Fixes #1050. --- README.md | 1 + src/cocoa_window.m | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3353dacc5..260818c89 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Value range was ignored for joystick hats and buttons (#888) - [Cocoa] Bugfix: Full screen framebuffer was incorrectly sized for some video modes (#682) +- [Cocoa] Bugfix: A string object for IME was updated non-idiomatically (#1050) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 2acfa98b9..4c27c517b 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -698,10 +698,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange { + [markedText release]; if ([string isKindOfClass:[NSAttributedString class]]) - [markedText initWithAttributedString:string]; + markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string]; else - [markedText initWithString:string]; + markedText = [[NSMutableAttributedString alloc] initWithString:string]; } - (void)unmarkText From a397195d3fd14b3e94026bce684e6b5f392f5015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 9 Aug 2017 12:04:38 +0200 Subject: [PATCH 102/222] Linux: Make joystick init always fail silently Related to #833. --- README.md | 1 + src/linux_joystick.c | 39 +++++++++++++-------------------------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 260818c89..62dc98bde 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,7 @@ information on what to include when reporting a bug. - [Linux] Moved to evdev for joystick input (#906,#1005) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Linux] Bugfix: The joystick device path could be truncated (#1025) +- [Linux] Bugfix: `glfwInit` would fail if inotify creation failed (#833) - [Cocoa] Added support for Vulkan window surface creation via [MoltenVK](https://moltengl.com/moltenvk/) (#870) - [Cocoa] Added support for loading a `MainMenu.nib` when available diff --git a/src/linux_joystick.c b/src/linux_joystick.c index a16f208c8..3283d1eaf 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -266,28 +266,17 @@ GLFWbool _glfwInitJoysticksLinux(void) const char* dirname = "/dev/input"; _glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - if (_glfw.linjs.inotify == -1) + if (_glfw.linjs.inotify > 0) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Linux: Failed to initialize inotify: %s", - strerror(errno)); - return GLFW_FALSE; + // HACK: Register for IN_ATTRIB to get notified when udev is done + // This works well in practice but the true way is libudev + + _glfw.linjs.watch = inotify_add_watch(_glfw.linjs.inotify, + dirname, + IN_CREATE | IN_ATTRIB | IN_DELETE); } - // HACK: Register for IN_ATTRIB as well to get notified when udev is done - // This works well in practice but the true way is libudev - - _glfw.linjs.watch = inotify_add_watch(_glfw.linjs.inotify, - dirname, - IN_CREATE | IN_ATTRIB | IN_DELETE); - if (_glfw.linjs.watch == -1) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Linux: Failed to watch for joystick connections in %s: %s", - dirname, - strerror(errno)); - // Continue without device connection notifications - } + // Continue without device connection notifications if inotify fails if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0) { @@ -318,13 +307,8 @@ GLFWbool _glfwInitJoysticksLinux(void) closedir(dir); } else - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Linux: Failed to open joystick device directory %s: %s", - dirname, - strerror(errno)); - // Continue with no joysticks detected - } + + // Continue with no joysticks if enumeration fails qsort(_glfw.joysticks, count, sizeof(_GLFWjoystick), compareJoysticks); return GLFW_TRUE; @@ -359,6 +343,9 @@ void _glfwDetectJoystickConnectionLinux(void) ssize_t offset = 0; char buffer[16384]; + if (_glfw.linjs.inotify <= 0) + return; + const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer)); while (size > offset) From 75e44abf09621180b6c67dc44aaf60a2309f1253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 3 Aug 2017 02:11:32 +0200 Subject: [PATCH 103/222] Win32: Remove deadzone logic from XInput path Related to #1021. Related to #1045. --- README.md | 1 + src/win32_joystick.c | 33 ++++++--------------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 62dc98bde..7fe97897a 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ information on what to include when reporting a bug. - Bugfix: The scancode for synthetic key release events was always zero - [Win32] Added system error strings to relevant GLFW error descriptions (#733) - [Win32] Moved to `WM_INPUT` for disabled cursor mode motion input (#125) +- [Win32] Removed XInput circular deadzone from joystick axis data (#1045) - [Win32] Bugfix: Undecorated windows could not be iconified by the user (#861) - [Win32] Bugfix: Deadzone logic could underflow with some controllers (#910) - [Win32] Bugfix: Bitness test in `FindVulkan.cmake` was VS specific (#928) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 6db08467b..c3a7c7672 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -675,7 +675,6 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) int i, dpad = 0; DWORD result; XINPUT_STATE xis; - float axes[6] = { 0.f, 0.f, 0.f, 0.f, -1.f, -1.f }; const WORD buttons[10] = { XINPUT_GAMEPAD_A, @@ -702,32 +701,12 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) if (mode == _GLFW_POLL_PRESENCE) return GLFW_TRUE; - if ((float) xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX + - (float) xis.Gamepad.sThumbLY * xis.Gamepad.sThumbLY > - (float) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) - { - axes[0] = (xis.Gamepad.sThumbLX + 0.5f) / 32767.f; - axes[1] = (xis.Gamepad.sThumbLY + 0.5f) / 32767.f; - } - - if ((float) xis.Gamepad.sThumbRX * xis.Gamepad.sThumbRX + - (float) xis.Gamepad.sThumbRY * xis.Gamepad.sThumbRY > - (float) XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) - { - axes[2] = (xis.Gamepad.sThumbRX + 0.5f) / 32767.f; - axes[3] = (xis.Gamepad.sThumbRY + 0.5f) / 32767.f; - } - - if (xis.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) - axes[4] = xis.Gamepad.bLeftTrigger / 127.5f - 1.f; - - if (xis.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) - axes[5] = xis.Gamepad.bRightTrigger / 127.5f - 1.f; - - for (i = 0; i < 6; i++) - _glfwInputJoystickAxis(js, i, axes[i]); + _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.f); + _glfwInputJoystickAxis(js, 1, (xis.Gamepad.sThumbLY + 0.5f) / 32767.f); + _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.f); + _glfwInputJoystickAxis(js, 3, (xis.Gamepad.sThumbRY + 0.5f) / 32767.f); + _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f); + _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f); for (i = 0; i < 10; i++) { From f95c9d1bf3849f98f18f86e2eceb24f10d06b2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 4 Aug 2017 02:05:08 +0200 Subject: [PATCH 104/222] Win32: Fix XInput axis normalization Fixes #1045. --- README.md | 1 + src/win32_joystick.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7fe97897a..0954d1065 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ information on what to include when reporting a bug. - [Win32] Bugfix: Monitors with no display devices were not enumerated (#960) - [Win32] Bugfix: Monitor events were not emitted (#784) - [Win32] Bugfix: The Cygwin DLL was installed to the wrong directory (#1035) +- [Win32] Bugfix: Normalization of axis data via XInput was incorrect (#1045) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X diff --git a/src/win32_joystick.c b/src/win32_joystick.c index c3a7c7672..394d371a5 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -701,10 +701,10 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) if (mode == _GLFW_POLL_PRESENCE) return GLFW_TRUE; - _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.f); - _glfwInputJoystickAxis(js, 1, (xis.Gamepad.sThumbLY + 0.5f) / 32767.f); - _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.f); - _glfwInputJoystickAxis(js, 3, (xis.Gamepad.sThumbRY + 0.5f) / 32767.f); + _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 1, (xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 3, (xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f); _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f); From 5bc1c381592d124a6bac6b03132c8f7065a3318e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 4 Aug 2017 01:00:36 +0200 Subject: [PATCH 105/222] Documentation work [ci skip] --- docs/intro.dox | 7 ++++--- include/GLFW/glfw3.h | 44 +++++++++++++++++++++++++++----------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/docs/intro.dox b/docs/intro.dox index 88245d9b0..e0e7e8aeb 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -112,7 +112,7 @@ Set this with @ref glfwInitHintString. @subsubsection init_hints_values Supported and default values -Init hint | Default value | Supported values +Initialization hint | Default value | Supported values ------------------------------- | ------------- | ---------------- @ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @@ -388,8 +388,9 @@ Undocumented behavior, i.e. behavior that is not described in the documentation, may change at any time until it is documented. If the reference documentation and the implementation differ, the reference -documentation is correct and the implementation will be fixed in the next -release. +documentation will almost always take precedence and the implementation will be +fixed in the next release. The reference documentation will also take +precedence over anything stated in a guide. @subsection event_order Event order diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 253262522..1eb5131c7 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4203,6 +4203,10 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); * * This function returns whether the specified joystick is present. * + * There is no need to call this function before other functions that accept + * a joystick ID, as they all check for presence before performing any other + * work. + * * @param[in] jid The [joystick](@ref joysticks) to query. * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. * @@ -4225,8 +4229,8 @@ GLFWAPI int glfwJoystickPresent(int jid); * Each element in the array is a value between -1.0 and 1.0. * * If the specified joystick is not present this function will return `NULL` - * but will not generate an error. Call @ref glfwJoystickPresent to check - * device presence. + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of axis values in the returned @@ -4265,8 +4269,8 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count); * GLFW_JOYSTICK_HAT_BUTTONS init hint before initialization. * * If the specified joystick is not present this function will return `NULL` - * but will not generate an error. Call @ref glfwJoystickPresent to check - * device presence. + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of button states in the returned @@ -4322,8 +4326,8 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); * @endcode * * If the specified joystick is not present this function will return `NULL` - * but will not generate an error. Call @ref glfwJoystickPresent to check - * device presence. + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of hat states in the returned @@ -4357,8 +4361,8 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); * yourself. * * If the specified joystick is not present this function will return `NULL` - * but will not generate an error. Call @ref glfwJoystickPresent to check - * device presence. + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick @@ -4387,9 +4391,13 @@ GLFWAPI const char* glfwGetJoystickName(int jid); * hexadecimal string, of the specified joystick. The returned string is * allocated and freed by GLFW. You should not free it yourself. * + * The GUID is what connects a joystick to a gamepad mapping. A connected + * joystick will always have a GUID even if there is no gamepad mapping + * assigned to it. + * * If the specified joystick is not present this function will return `NULL` - * but will not generate an error. Call @ref glfwJoystickPresent to check - * device presence. + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. * * The GUID uses the format introduced in SDL 2.0.5. This GUID tries to * uniquely identify the make and model of a joystick but does not identify @@ -4425,7 +4433,8 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid); * * If the specified joystick is present but does not have a gamepad mapping * this function will return `GLFW_FALSE` but will not generate an error. Call - * @ref glfwJoystickPresent to only check device presence. + * @ref glfwJoystickPresent to check if a joystick is present regardless of + * whether it has a mapping. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return `GLFW_TRUE` if a joystick is both present and has a gamepad mapping, @@ -4514,8 +4523,9 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string); * gamepad mapping assigned to the specified joystick. * * If the specified joystick is not present or does not have a gamepad mapping - * this function will return `NULL` but will not generate an error. Call @ref - * glfwJoystickIsGamepad to check whether it is present and has a gamepad mapping. + * this function will return `NULL` but will not generate an error. Call + * @ref glfwJoystickPresent to check whether it is present regardless of + * whether it has a mapping. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the gamepad, or `NULL` if the @@ -4542,10 +4552,10 @@ GLFWAPI const char* glfwGetGamepadName(int jid); * This function retrives the state of the specified joystick remapped to * an Xbox-like gamepad. * - * If the specified joystick is not present this function will return - * `GLFW_FALSE` but will not generate an error. Call @ref - * glfwJoystickIsGamepad to check whether it is present and has a gamepad - * mapping. + * If the specified joystick is not present or does not have a gamepad mapping + * this function will return `GLFW_FALSE` but will not generate an error. Call + * @ref glfwJoystickPresent to check whether it is present regardless of + * whether it has a mapping. * * The Guide button may not be available for input as it is often hooked by the * system or the Steam client. From 549308051dcf4bca8889045a8cb619619a5059b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 7 Aug 2017 11:34:06 +0200 Subject: [PATCH 106/222] Linux: Update joystick API in version strings --- src/mir_init.c | 2 +- src/wl_init.c | 2 +- src/x11_init.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mir_init.c b/src/mir_init.c index cf3dcf1ec..5f9ed3731 100644 --- a/src/mir_init.c +++ b/src/mir_init.c @@ -231,7 +231,7 @@ const char* _glfwPlatformGetVersionString(void) #else " gettimeofday" #endif - " /dev/js" + " evdev" #if defined(_GLFW_BUILD_DLL) " shared" #endif diff --git a/src/wl_init.c b/src/wl_init.c index 0927a98a8..40e6e43a0 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -737,7 +737,7 @@ const char* _glfwPlatformGetVersionString(void) #else " gettimeofday" #endif - " /dev/js" + " evdev" #if defined(_GLFW_BUILD_DLL) " shared" #endif diff --git a/src/x11_init.c b/src/x11_init.c index a52216f07..402552bba 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -887,7 +887,7 @@ const char* _glfwPlatformGetVersionString(void) " gettimeofday" #endif #if defined(__linux__) - " /dev/js" + " evdev" #endif #if defined(_GLFW_BUILD_DLL) " shared" From 079518617cdefc4c5b676224b82abb871473a95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 9 Aug 2017 16:15:59 +0200 Subject: [PATCH 107/222] Linux: Fix missing feature macro for using strdup This adds _XOPEN_SOURCE = 500. Fixes #1055. --- README.md | 1 + src/CMakeLists.txt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0954d1065..41173f0ff 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ information on what to include when reporting a bug. - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Linux] Bugfix: The joystick device path could be truncated (#1025) - [Linux] Bugfix: `glfwInit` would fail if inotify creation failed (#833) +- [Linux] Bugfix: `strdup` was used without any required feature macro (#1055) - [Cocoa] Added support for Vulkan window surface creation via [MoltenVK](https://moltengl.com/moltenvk/) (#870) - [Cocoa] Added support for loading a `MainMenu.nib` when available diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 87bd72073..c5af0ec37 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,7 +74,9 @@ set_target_properties(glfw PROPERTIES POSITION_INDEPENDENT_CODE ON FOLDER "GLFW3") -target_compile_definitions(glfw PRIVATE -D_GLFW_USE_CONFIG_H) +target_compile_definitions(glfw PRIVATE + -D_GLFW_USE_CONFIG_H + $<$:_XOPEN_SOURCE=500>) target_include_directories(glfw PUBLIC $ $/include>) From e376404d38e800523301e624834496923d931d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 9 Aug 2017 16:26:29 +0200 Subject: [PATCH 108/222] Cleanup --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5af0ec37..31d73fec6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,7 +75,7 @@ set_target_properties(glfw PROPERTIES FOLDER "GLFW3") target_compile_definitions(glfw PRIVATE - -D_GLFW_USE_CONFIG_H + _GLFW_USE_CONFIG_H $<$:_XOPEN_SOURCE=500>) target_include_directories(glfw PUBLIC $ @@ -120,7 +120,7 @@ if (BUILD_SHARED_LIBS) target_compile_options(glfw PRIVATE "-fvisibility=hidden") endif() - target_compile_definitions(glfw INTERFACE -DGLFW_DLL) + target_compile_definitions(glfw INTERFACE GLFW_DLL) target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES}) else() target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES}) From 3ee7f8f6954e7693051b2ee80c5367ee5e846a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 10 Aug 2017 22:24:44 +0200 Subject: [PATCH 109/222] Cocoa: Fix warnings caused by _XOPEN_SOURCE --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31d73fec6..8e9d17f27 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -76,7 +76,7 @@ set_target_properties(glfw PROPERTIES target_compile_definitions(glfw PRIVATE _GLFW_USE_CONFIG_H - $<$:_XOPEN_SOURCE=500>) + $<$:_XOPEN_SOURCE=600>) target_include_directories(glfw PUBLIC $ $/include>) From 29a75ab09dab1984e7da19f6d4ce36c00a1d61ff Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Wed, 2 Aug 2017 16:10:13 +0200 Subject: [PATCH 110/222] X11: Add native access to primary selection This adds the native access functions glfwSetX11SelectionString and glfwGetX11SelectionString under GLFW_EXPOSE_NATIVE_X11. They are similar to glfwSetClipboardString and glfwGetClipboardString but operate on the PRIMARY selection. The primary selection is widely used in X11, and so seems important to support. Primary selection is mostly an X11-specific thing, hence it's exposed as an X11 native interface. Fixes #894. Closes #1056. Signed-off-by: Kristian Nielsen --- README.md | 3 + docs/news.dox | 9 ++ include/GLFW/glfw3native.h | 50 ++++++++++ src/x11_init.c | 2 + src/x11_platform.h | 3 + src/x11_window.c | 185 ++++++++++++++++++++++--------------- 6 files changed, 180 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 41173f0ff..e24293b5c 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,9 @@ information on what to include when reporting a bug. ## Changelog +- Added `glfwSetX11SelectionString` and `glfwGetX11SelectionString` + native functions for accessing X11 primary selection as a supplement to + the clipboard on the X11 platform (#894) - Added `glfwGetError` function for querying the last error code and its description (#970) - Added `glfwUpdateGamepadMappings` function for importing gamepad mappings in diff --git a/docs/news.dox b/docs/news.dox index d8bb23a52..0fdb5a73a 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -5,6 +5,15 @@ @section news_33 Release notes for 3.3 +@subsection news_33_native_x11_selection X11 native Primary Selection access + +GLFW now supports X11 platform specific native functions for accessing +the X11 primary selection, as a supplement to the clipboard on this +platform. See @ref clipboard. + +@see @ref error_handling + + @subsection news_33_geterror Error query GLFW now supports querying the last error code for the calling thread and its diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index 982eaa656..ad7ccb57b 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -289,6 +289,56 @@ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); * @ingroup native */ GLFWAPI Window glfwGetX11Window(GLFWwindow* window); + +/*! @brief Sets the current primary selection to the specified string. + * + * @param[in] string A UTF-8 encoded string. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified string is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa glfwGetX11SelectionString + * @sa glfwSetClipboardString + * + * @since Added in version 3.3. + * + * @ingroup native + */ +GLFWAPI void glfwSetX11SelectionString(const char* string); + +/*! @brief Returns the contents of the current primary selection as a string. + * + * If the selection is empty or if its contents cannot be converted, `NULL` + * is returned and a @ref GLFW_FORMAT_UNAVAILABLE error is generated. + * + * @return The contents of the selection as a UTF-8 encoded string, or `NULL` + * if an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetX11SelectionString or @ref glfwSetX11SelectionString, or until the + * library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa glfwSetX11SelectionString + * @sa glfwGetClipboardString + * + * @since Added in version 3.3. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetX11SelectionString(void); #endif #if defined(GLFW_EXPOSE_NATIVE_GLX) diff --git a/src/x11_init.c b/src/x11_init.c index 402552bba..7acea7079 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -611,6 +611,7 @@ static GLFWbool initExtensions(void) // ICCCM standard clipboard atoms _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); + _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False); _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); // Clipboard manager atoms @@ -853,6 +854,7 @@ void _glfwPlatformTerminate(void) _glfw.x11.hiddenCursorHandle = (Cursor) 0; } + free(_glfw.x11.primarySelectionString); free(_glfw.x11.clipboardString); if (_glfw.x11.im) diff --git a/src/x11_platform.h b/src/x11_platform.h index e56630cfb..e28127bc0 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -161,6 +161,8 @@ typedef struct _GLFWlibraryX11 XIM im; // Most recent error code received by X error handler int errorCode; + // Primary selection string (while the primary selection is owned) + char* primarySelectionString; // Clipboard string (while the selection is owned) char* clipboardString; // Key name string @@ -214,6 +216,7 @@ typedef struct _GLFWlibraryX11 Atom TARGETS; Atom MULTIPLE; Atom CLIPBOARD; + Atom PRIMARY; Atom CLIPBOARD_MANAGER; Atom SAVE_TARGETS; Atom NULL_; diff --git a/src/x11_window.c b/src/x11_window.c index cdaac5f8d..eacb74677 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -675,6 +675,8 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) _glfw.x11.COMPOUND_STRING, XA_STRING }; const int formatCount = sizeof(formats) / sizeof(formats[0]); + char *selectionString = request->selection == _glfw.x11.PRIMARY ? + _glfw.x11.primarySelectionString : _glfw.x11.clipboardString; if (request->property == None) { @@ -735,8 +737,8 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) targets[i], 8, PropModeReplace, - (unsigned char*) _glfw.x11.clipboardString, - strlen(_glfw.x11.clipboardString)); + (unsigned char *) selectionString, + strlen(selectionString)); } else targets[i + 1] = None; @@ -787,8 +789,8 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) request->target, 8, PropModeReplace, - (unsigned char*) _glfw.x11.clipboardString, - strlen(_glfw.x11.clipboardString)); + (unsigned char *) selectionString, + strlen(selectionString)); return request->property; } @@ -801,8 +803,17 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) static void handleSelectionClear(XEvent* event) { - free(_glfw.x11.clipboardString); - _glfw.x11.clipboardString = NULL; + const XSelectionClearEvent* request = &event->xselectionclear; + if (request->selection == _glfw.x11.PRIMARY) + { + free(_glfw.x11.primarySelectionString); + _glfw.x11.primarySelectionString = NULL; + } + else if (request->selection == _glfw.x11.CLIPBOARD) + { + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = NULL; + } } static void handleSelectionRequest(XEvent* event) @@ -823,6 +834,76 @@ static void handleSelectionRequest(XEvent* event) XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply); } +static const char *getSelection(Atom selection, char **ptr) +{ + size_t i; + const Atom formats[] = { _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + const size_t formatCount = sizeof(formats) / sizeof(formats[0]); + + if (XGetSelectionOwner(_glfw.x11.display, selection) == + _glfw.x11.helperWindowHandle) + { + // Instead of doing a large number of X round-trips just to put this + // string into a window property and then read it back, just return it + return *ptr; + } + + free(*ptr); + *ptr = NULL; + + for (i = 0; i < formatCount; i++) + { + char* data; + XEvent event; + + XConvertSelection(_glfw.x11.display, + selection, + formats[i], + _glfw.x11.GLFW_SELECTION, + _glfw.x11.helperWindowHandle, + CurrentTime); + + while (!XCheckTypedWindowEvent(_glfw.x11.display, + _glfw.x11.helperWindowHandle, + SelectionNotify, + &event)) + { + waitForEvent(NULL); + } + + if (event.xselection.property == None) + continue; + + if (_glfwGetWindowPropertyX11(event.xselection.requestor, + event.xselection.property, + event.xselection.target, + (unsigned char**) &data)) + { + *ptr = strdup(data); + } + + if (data) + XFree(data); + + XDeleteProperty(_glfw.x11.display, + event.xselection.requestor, + event.xselection.property); + + if (*ptr) + break; + } + + if (*ptr == NULL) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "X11: Failed to convert clipboard to string"); + } + + return *ptr; +} + // Make the specified window and its video mode active on its monitor // static GLFWbool acquireMonitor(_GLFWwindow* window) @@ -2572,72 +2653,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) { - size_t i; - const Atom formats[] = { _glfw.x11.UTF8_STRING, - _glfw.x11.COMPOUND_STRING, - XA_STRING }; - const size_t formatCount = sizeof(formats) / sizeof(formats[0]); - - if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == - _glfw.x11.helperWindowHandle) - { - // Instead of doing a large number of X round-trips just to put this - // string into a window property and then read it back, just return it - return _glfw.x11.clipboardString; - } - - free(_glfw.x11.clipboardString); - _glfw.x11.clipboardString = NULL; - - for (i = 0; i < formatCount; i++) - { - char* data; - XEvent event; - - XConvertSelection(_glfw.x11.display, - _glfw.x11.CLIPBOARD, - formats[i], - _glfw.x11.GLFW_SELECTION, - _glfw.x11.helperWindowHandle, - CurrentTime); - - while (!XCheckTypedWindowEvent(_glfw.x11.display, - _glfw.x11.helperWindowHandle, - SelectionNotify, - &event)) - { - waitForEvent(NULL); - } - - if (event.xselection.property == None) - continue; - - if (_glfwGetWindowPropertyX11(event.xselection.requestor, - event.xselection.property, - event.xselection.target, - (unsigned char**) &data)) - { - _glfw.x11.clipboardString = strdup(data); - } - - if (data) - XFree(data); - - XDeleteProperty(_glfw.x11.display, - event.xselection.requestor, - event.xselection.property); - - if (_glfw.x11.clipboardString) - break; - } - - if (_glfw.x11.clipboardString == NULL) - { - _glfwInputError(GLFW_FORMAT_UNAVAILABLE, - "X11: Failed to convert clipboard to string"); - } - - return _glfw.x11.clipboardString; + return getSelection(_glfw.x11.CLIPBOARD, &_glfw.x11.clipboardString); } void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) @@ -2807,3 +2823,28 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* handle) return window->x11.handle; } +GLFWAPI void glfwSetX11SelectionString(const char* string) +{ + _GLFW_REQUIRE_INIT(); + + free(_glfw.x11.primarySelectionString); + _glfw.x11.primarySelectionString = strdup(string); + + XSetSelectionOwner(_glfw.x11.display, + _glfw.x11.PRIMARY, + _glfw.x11.helperWindowHandle, + CurrentTime); + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.PRIMARY) != + _glfw.x11.helperWindowHandle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to become owner of primary selection"); + } +} + +GLFWAPI const char* glfwGetX11SelectionString(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return getSelection(_glfw.x11.PRIMARY, &_glfw.x11.primarySelectionString); +} From b7a0f225ea964c62bf4b0e21f9149cba08edad00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 13 Aug 2017 18:11:35 +0200 Subject: [PATCH 111/222] Cleanup Don't advertise native functions in public API guides. Don't list primary selection access as most notable new feature. Don't have different levels of abstraction among selection helper functions. Don't forget to take credit. Related to #1056. --- README.md | 6 +++--- docs/news.dox | 16 +++++++--------- src/x11_window.c | 40 +++++++++++++++++++++++++--------------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index e24293b5c..b4eb3b83d 100644 --- a/README.md +++ b/README.md @@ -124,9 +124,6 @@ information on what to include when reporting a bug. ## Changelog -- Added `glfwSetX11SelectionString` and `glfwGetX11SelectionString` - native functions for accessing X11 primary selection as a supplement to - the clipboard on the X11 platform (#894) - Added `glfwGetError` function for querying the last error code and its description (#970) - Added `glfwUpdateGamepadMappings` function for importing gamepad mappings in @@ -149,6 +146,8 @@ information on what to include when reporting a bug. - Added `glfwGetJoystickHats` function for querying joystick hats (#889,#906,#934) - Added `glfwInitHint` and `glfwInitHintString` for setting initialization hints +- Added `glfwGetX11SelectionString` and `glfwSetX11SelectionString` + functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering @@ -333,6 +332,7 @@ skills. - Jon Morton - Pierre Moulon - Julian Møller + - Kristian Nielsen - Kamil Nowakowski - Ozzy - Andri Pálsson diff --git a/docs/news.dox b/docs/news.dox index 0fdb5a73a..042468f16 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -5,15 +5,6 @@ @section news_33 Release notes for 3.3 -@subsection news_33_native_x11_selection X11 native Primary Selection access - -GLFW now supports X11 platform specific native functions for accessing -the X11 primary selection, as a supplement to the clipboard on this -platform. See @ref clipboard. - -@see @ref error_handling - - @subsection news_33_geterror Error query GLFW now supports querying the last error code for the calling thread and its @@ -127,6 +118,13 @@ creation API, intended for automated testing. This backend does not provide input. +@subsection news_33_primary X11 primary selection access + +GLFW now supports querying and setting the X11 primary selection via the native +access functions @ref glfwGetX11SelectionString and @ref +glfwSetX11SelectionString. + + @section news_32 Release notes for 3.2 diff --git a/src/x11_window.c b/src/x11_window.c index eacb74677..da83fcf98 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -671,12 +671,16 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, static Atom writeTargetToProperty(const XSelectionRequestEvent* request) { int i; + char* selectionString = NULL; const Atom formats[] = { _glfw.x11.UTF8_STRING, _glfw.x11.COMPOUND_STRING, XA_STRING }; const int formatCount = sizeof(formats) / sizeof(formats[0]); - char *selectionString = request->selection == _glfw.x11.PRIMARY ? - _glfw.x11.primarySelectionString : _glfw.x11.clipboardString; + + if (request->selection == _glfw.x11.PRIMARY) + selectionString = _glfw.x11.primarySelectionString; + else + selectionString = _glfw.x11.clipboardString; if (request->property == None) { @@ -803,13 +807,12 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) static void handleSelectionClear(XEvent* event) { - const XSelectionClearEvent* request = &event->xselectionclear; - if (request->selection == _glfw.x11.PRIMARY) + if (event->xselectionclear.selection == _glfw.x11.PRIMARY) { free(_glfw.x11.primarySelectionString); _glfw.x11.primarySelectionString = NULL; } - else if (request->selection == _glfw.x11.CLIPBOARD) + else { free(_glfw.x11.clipboardString); _glfw.x11.clipboardString = NULL; @@ -834,24 +837,30 @@ static void handleSelectionRequest(XEvent* event) XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply); } -static const char *getSelection(Atom selection, char **ptr) +static const char* getSelectionString(Atom selection) { size_t i; + char** selectionString = NULL; const Atom formats[] = { _glfw.x11.UTF8_STRING, _glfw.x11.COMPOUND_STRING, XA_STRING }; const size_t formatCount = sizeof(formats) / sizeof(formats[0]); + if (selection == _glfw.x11.PRIMARY) + selectionString = &_glfw.x11.primarySelectionString; + else + selectionString = &_glfw.x11.clipboardString; + if (XGetSelectionOwner(_glfw.x11.display, selection) == _glfw.x11.helperWindowHandle) { // Instead of doing a large number of X round-trips just to put this // string into a window property and then read it back, just return it - return *ptr; + return *selectionString; } - free(*ptr); - *ptr = NULL; + free(*selectionString); + *selectionString = NULL; for (i = 0; i < formatCount; i++) { @@ -881,7 +890,7 @@ static const char *getSelection(Atom selection, char **ptr) event.xselection.target, (unsigned char**) &data)) { - *ptr = strdup(data); + *selectionString = strdup(data); } if (data) @@ -891,17 +900,17 @@ static const char *getSelection(Atom selection, char **ptr) event.xselection.requestor, event.xselection.property); - if (*ptr) + if (*selectionString) break; } - if (*ptr == NULL) + if (!*selectionString) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "X11: Failed to convert clipboard to string"); } - return *ptr; + return *selectionString; } // Make the specified window and its video mode active on its monitor @@ -2653,7 +2662,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) { - return getSelection(_glfw.x11.CLIPBOARD, &_glfw.x11.clipboardString); + return getSelectionString(_glfw.x11.CLIPBOARD); } void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) @@ -2846,5 +2855,6 @@ GLFWAPI void glfwSetX11SelectionString(const char* string) GLFWAPI const char* glfwGetX11SelectionString(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return getSelection(_glfw.x11.PRIMARY, &_glfw.x11.primarySelectionString); + return getSelectionString(_glfw.x11.PRIMARY); } + From e27dc50689885736b0b79fde22c9d24046264f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 13 Aug 2017 20:03:12 +0200 Subject: [PATCH 112/222] Add non-VS warning about C99 declarations This adds a warning in GCC and Clang about using intermingled variable declarations in source files that will be built by VS. This currently excludes egl_context.c and osmesa_context.c. It will be addressed by a separate commit. Related to #1026. --- src/CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e9d17f27..5c8f33e67 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,6 +66,18 @@ if (APPLE) set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) endif() +# Make GCC and Clang warn about declarations that VS 2010 and 2012 won't accept +# for all source files that VS will build +if (${CMAKE_C_COMPILER_ID} STREQUAL GNU OR ${CMAKE_C_COMPILER_ID} STREQUAL Clang) + if (WIN32) + set(windows_SOURCES ${glfw_SOURCES}) + else() + set(windows_SOURCES ${common_SOURCES}) + endif() + set_source_files_properties(${windows_SOURCES} PROPERTIES + COMPILE_FLAGS -Wdeclaration-after-statement) +endif() + add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) set_target_properties(glfw PROPERTIES OUTPUT_NAME ${GLFW_LIB_NAME} From 2d0ffd788b7ecd5e525684e9f9e895d0fcfd7110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 13 Aug 2017 20:06:40 +0200 Subject: [PATCH 113/222] Fix type in filename --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5c8f33e67..0d7139d50 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,7 @@ set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c) if (_GLFW_COCOA) set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h - posix_thread.h nsgl_context.h egl_context.h osmesa_context.c) + posix_thread.h nsgl_context.h egl_context.h osmesa_context.h) set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m cocoa_monitor.m cocoa_window.m cocoa_time.c posix_thread.c nsgl_context.m egl_context.c osmesa_context.c) From 0019f7a45e74a1f11e49c75435e8cc2fa325d2ba Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 8 Aug 2017 01:33:20 +0200 Subject: [PATCH 114/222] Wayland: Stop crashing when Compose is unavailable There was a missing check for when no Compose key was configured in the xkb file, making _glfw.wl.xkb.composeState NULL and crashing on key press. Closes #1059. --- src/wl_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wl_init.c b/src/wl_init.c index 40e6e43a0..8e42ce6e3 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -294,7 +294,7 @@ static int toGLFWKeyCode(uint32_t key) static xkb_keysym_t composeSymbol(xkb_keysym_t sym) { - if (sym == XKB_KEY_NoSymbol) + if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) return sym; if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED) From 15d102b75efc2b0944b4aa133ff25ad8f28776d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 16 Aug 2017 19:46:09 +0200 Subject: [PATCH 115/222] X11: Add dynamic loading of libXrandr --- CMakeLists.txt | 4 +-- src/x11_init.c | 75 +++++++++++++++++++++++++++++++++++++--------- src/x11_platform.h | 53 ++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f3bedfd4..be886bb84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -245,12 +245,10 @@ if (_GLFW_X11) # Check for XRandR (modern resolution switching and gamma control) if (NOT X11_Xrandr_FOUND) - message(FATAL_ERROR "The RandR library and headers were not found") + message(FATAL_ERROR "The RandR headers were not found") endif() list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}") - list(APPEND glfw_LIBRARIES "${X11_Xrandr_LIB}") - list(APPEND glfw_PKG_DEPS "xrandr") # Check for Xinerama (legacy multi-monitor support) if (NOT X11_Xinerama_FOUND) diff --git a/src/x11_init.c b/src/x11_init.c index 7acea7079..6e06fb2ea 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -505,22 +505,63 @@ static GLFWbool initExtensions(void) } } - if (XRRQueryExtension(_glfw.x11.display, - &_glfw.x11.randr.eventBase, - &_glfw.x11.randr.errorBase)) + _glfw.x11.randr.handle = dlopen("libXrandr.so.2", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.randr.handle) { - if (XRRQueryVersion(_glfw.x11.display, - &_glfw.x11.randr.major, - &_glfw.x11.randr.minor)) + _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) + dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); + _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) + dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) + dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); + _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) + dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) + dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); + _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) + dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); + _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); + _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); + _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); + _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) + dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); + _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) + dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); + _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) + dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); + _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) + dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); + _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) + dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); + _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) + dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); + _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) + dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); + _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) + dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); + _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) + dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); + + if (XRRQueryExtension(_glfw.x11.display, + &_glfw.x11.randr.eventBase, + &_glfw.x11.randr.errorBase)) { - // The GLFW RandR path requires at least version 1.3 - if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) - _glfw.x11.randr.available = GLFW_TRUE; - } - else - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to query RandR version"); + if (XRRQueryVersion(_glfw.x11.display, + &_glfw.x11.randr.major, + &_glfw.x11.randr.minor)) + { + // The GLFW RandR path requires at least version 1.3 + if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) + _glfw.x11.randr.available = GLFW_TRUE; + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to query RandR version"); + } } } @@ -836,6 +877,12 @@ void _glfwPlatformTerminate(void) _glfw.x11.x11xcb.handle = NULL; } + if (_glfw.x11.randr.handle) + { + dlclose(_glfw.x11.randr.handle); + _glfw.x11.randr.handle = NULL; + } + if (_glfw.x11.helperWindowHandle) { if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == diff --git a/src/x11_platform.h b/src/x11_platform.h index e28127bc0..c0efb41d4 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -47,6 +47,41 @@ // The XInput extension provides raw mouse motion input #include +typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int); +typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*); +typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*); +typedef void (* PFN_XRRFreeOutputInfo)(XRROutputInfo*); +typedef void (* PFN_XRRFreeScreenResources)(XRRScreenResources*); +typedef XRRCrtcGamma* (* PFN_XRRGetCrtcGamma)(Display*,RRCrtc); +typedef int (* PFN_XRRGetCrtcGammaSize)(Display*,RRCrtc); +typedef XRRCrtcInfo* (* PFN_XRRGetCrtcInfo) (Display*,XRRScreenResources*,RRCrtc); +typedef XRROutputInfo* (* PFN_XRRGetOutputInfo)(Display*,XRRScreenResources*,RROutput); +typedef RROutput (* PFN_XRRGetOutputPrimary)(Display*,Window); +typedef XRRScreenResources* (* PFN_XRRGetScreenResourcesCurrent)(Display*,Window); +typedef Bool (* PFN_XRRQueryExtension)(Display*,int*,int*); +typedef Status (* PFN_XRRQueryVersion)(Display*,int*,int*); +typedef void (* PFN_XRRSelectInput)(Display*,Window,int); +typedef Status (* PFN_XRRSetCrtcConfig)(Display*,XRRScreenResources*,RRCrtc,Time,int,int,RRMode,Rotation,RROutput*,int); +typedef void (* PFN_XRRSetCrtcGamma)(Display*,RRCrtc,XRRCrtcGamma*); +typedef int (* PFN_XRRUpdateConfiguration)(XEvent*); +#define XRRAllocGamma _glfw.x11.randr.AllocGamma +#define XRRFreeCrtcInfo _glfw.x11.randr.FreeCrtcInfo +#define XRRFreeGamma _glfw.x11.randr.FreeGamma +#define XRRFreeOutputInfo _glfw.x11.randr.FreeOutputInfo +#define XRRFreeScreenResources _glfw.x11.randr.FreeScreenResources +#define XRRGetCrtcGamma _glfw.x11.randr.GetCrtcGamma +#define XRRGetCrtcGammaSize _glfw.x11.randr.GetCrtcGammaSize +#define XRRGetCrtcInfo _glfw.x11.randr.GetCrtcInfo +#define XRRGetOutputInfo _glfw.x11.randr.GetOutputInfo +#define XRRGetOutputPrimary _glfw.x11.randr.GetOutputPrimary +#define XRRGetScreenResourcesCurrent _glfw.x11.randr.GetScreenResourcesCurrent +#define XRRQueryExtension _glfw.x11.randr.QueryExtension +#define XRRQueryVersion _glfw.x11.randr.QueryVersion +#define XRRSelectInput _glfw.x11.randr.SelectInput +#define XRRSetCrtcConfig _glfw.x11.randr.SetCrtcConfig +#define XRRSetCrtcGamma _glfw.x11.randr.SetCrtcGamma +#define XRRUpdateConfiguration _glfw.x11.randr.UpdateConfiguration + typedef XID xcb_window_t; typedef XID xcb_visualid_t; typedef struct xcb_connection_t xcb_connection_t; @@ -227,12 +262,30 @@ typedef struct _GLFWlibraryX11 struct { GLFWbool available; + void* handle; int eventBase; int errorBase; int major; int minor; GLFWbool gammaBroken; GLFWbool monitorBroken; + PFN_XRRAllocGamma AllocGamma; + PFN_XRRFreeCrtcInfo FreeCrtcInfo; + PFN_XRRFreeGamma FreeGamma; + PFN_XRRFreeOutputInfo FreeOutputInfo; + PFN_XRRFreeScreenResources FreeScreenResources; + PFN_XRRGetCrtcGamma GetCrtcGamma; + PFN_XRRGetCrtcGammaSize GetCrtcGammaSize; + PFN_XRRGetCrtcInfo GetCrtcInfo; + PFN_XRRGetOutputInfo GetOutputInfo; + PFN_XRRGetOutputPrimary GetOutputPrimary; + PFN_XRRGetScreenResourcesCurrent GetScreenResourcesCurrent; + PFN_XRRQueryExtension QueryExtension; + PFN_XRRQueryVersion QueryVersion; + PFN_XRRSelectInput SelectInput; + PFN_XRRSetCrtcConfig SetCrtcConfig; + PFN_XRRSetCrtcGamma SetCrtcGamma; + PFN_XRRUpdateConfiguration UpdateConfiguration; } randr; struct { From 3f852c321f325ec6dbb2179a1e8b25dbb5783870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 16 Aug 2017 19:55:32 +0200 Subject: [PATCH 116/222] X11: Add dynamic loading of libXinerama --- CMakeLists.txt | 4 +--- src/x11_init.c | 27 ++++++++++++++++++++++----- src/x11_platform.h | 11 +++++++++++ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be886bb84..fa543418b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -252,12 +252,10 @@ if (_GLFW_X11) # Check for Xinerama (legacy multi-monitor support) if (NOT X11_Xinerama_FOUND) - message(FATAL_ERROR "The Xinerama library and headers were not found") + message(FATAL_ERROR "The Xinerama headers were not found") endif() list(APPEND glfw_INCLUDE_DIRS "${X11_Xinerama_INCLUDE_PATH}") - list(APPEND glfw_LIBRARIES "${X11_Xinerama_LIB}") - list(APPEND glfw_PKG_DEPS "xinerama") # Check for Xkb (X keyboard extension) if (NOT X11_Xkb_FOUND) diff --git a/src/x11_init.c b/src/x11_init.c index 6e06fb2ea..90f5e34cb 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -593,12 +593,23 @@ static GLFWbool initExtensions(void) RROutputChangeNotifyMask); } - if (XineramaQueryExtension(_glfw.x11.display, - &_glfw.x11.xinerama.major, - &_glfw.x11.xinerama.minor)) + _glfw.x11.xinerama.handle = dlopen("libXinerama.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.xinerama.handle) { - if (XineramaIsActive(_glfw.x11.display)) - _glfw.x11.xinerama.available = GLFW_TRUE; + _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive) + dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); + _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension) + dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); + _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens) + dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); + + if (XineramaQueryExtension(_glfw.x11.display, + &_glfw.x11.xinerama.major, + &_glfw.x11.xinerama.minor)) + { + if (XineramaIsActive(_glfw.x11.display)) + _glfw.x11.xinerama.available = GLFW_TRUE; + } } _glfw.x11.xkb.major = 1; @@ -883,6 +894,12 @@ void _glfwPlatformTerminate(void) _glfw.x11.randr.handle = NULL; } + if (_glfw.x11.xinerama.handle) + { + dlclose(_glfw.x11.xinerama.handle); + _glfw.x11.xinerama.handle = NULL; + } + if (_glfw.x11.helperWindowHandle) { if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == diff --git a/src/x11_platform.h b/src/x11_platform.h index c0efb41d4..05a6def81 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -82,6 +82,13 @@ typedef int (* PFN_XRRUpdateConfiguration)(XEvent*); #define XRRSetCrtcGamma _glfw.x11.randr.SetCrtcGamma #define XRRUpdateConfiguration _glfw.x11.randr.UpdateConfiguration +typedef Bool (* PFN_XineramaIsActive)(Display*); +typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*); +typedef XineramaScreenInfo* (* PFN_XineramaQueryScreens)(Display*,int*); +#define XineramaIsActive _glfw.x11.xinerama.IsActive +#define XineramaQueryExtension _glfw.x11.xinerama.QueryExtension +#define XineramaQueryScreens _glfw.x11.xinerama.QueryScreens + typedef XID xcb_window_t; typedef XID xcb_visualid_t; typedef struct xcb_connection_t xcb_connection_t; @@ -314,8 +321,12 @@ typedef struct _GLFWlibraryX11 struct { GLFWbool available; + void* handle; int major; int minor; + PFN_XineramaIsActive IsActive; + PFN_XineramaQueryExtension QueryExtension; + PFN_XineramaQueryScreens QueryScreens; } xinerama; struct { From 99e72830eaa956dacf614b4ac0f53a1046832b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 16 Aug 2017 20:54:14 +0200 Subject: [PATCH 117/222] X11: Add dynamic loading of libXcursor --- CMakeLists.txt | 4 +--- src/x11_init.c | 20 ++++++++++++++++++++ src/x11_platform.h | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa543418b..91becda9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,12 +266,10 @@ if (_GLFW_X11) # Check for Xcursor if (NOT X11_Xcursor_FOUND) - message(FATAL_ERROR "The Xcursor libraries and headers were not found") + message(FATAL_ERROR "The Xcursor headers were not found") endif() list(APPEND glfw_INCLUDE_DIR "${X11_Xcursor_INCLUDE_PATH}") - list(APPEND glfw_LIBRARIES "${X11_Xcursor_LIB}") - list(APPEND glfw_PKG_DEPS "xcursor") endif() diff --git a/src/x11_init.c b/src/x11_init.c index 90f5e34cb..d6e58bb56 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -593,6 +593,17 @@ static GLFWbool initExtensions(void) RROutputChangeNotifyMask); } + _glfw.x11.xcursor.handle = dlopen("libXcursor.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.xcursor.handle) + { + _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate) + dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); + _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy) + dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); + _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) + dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); + } + _glfw.x11.xinerama.handle = dlopen("libXinerama.so.1", RTLD_LAZY | RTLD_GLOBAL); if (_glfw.x11.xinerama.handle) { @@ -782,6 +793,9 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) int i; Cursor cursor; + if (!_glfw.x11.xcursor.handle) + return None; + XcursorImage* native = XcursorImageCreate(image->width, image->height); if (native == NULL) return None; @@ -894,6 +908,12 @@ void _glfwPlatformTerminate(void) _glfw.x11.randr.handle = NULL; } + if (_glfw.x11.xcursor.handle) + { + dlclose(_glfw.x11.xcursor.handle); + _glfw.x11.xcursor.handle = NULL; + } + if (_glfw.x11.xinerama.handle) { dlclose(_glfw.x11.xinerama.handle); diff --git a/src/x11_platform.h b/src/x11_platform.h index 05a6def81..50cba3461 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -82,6 +82,13 @@ typedef int (* PFN_XRRUpdateConfiguration)(XEvent*); #define XRRSetCrtcGamma _glfw.x11.randr.SetCrtcGamma #define XRRUpdateConfiguration _glfw.x11.randr.UpdateConfiguration +typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int); +typedef void (* PFN_XcursorImageDestroy)(XcursorImage*); +typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*); +#define XcursorImageCreate _glfw.x11.xcursor.ImageCreate +#define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy +#define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor + typedef Bool (* PFN_XineramaIsActive)(Display*); typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*); typedef XineramaScreenInfo* (* PFN_XineramaQueryScreens)(Display*,int*); @@ -319,6 +326,13 @@ typedef struct _GLFWlibraryX11 Atom format; } xdnd; + struct { + void* handle; + PFN_XcursorImageCreate ImageCreate; + PFN_XcursorImageDestroy ImageDestroy; + PFN_XcursorImageLoadCursor ImageLoadCursor; + } xcursor; + struct { GLFWbool available; void* handle; From ac01da6953aef5e37715492623bbd6c9f48f719c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 16 Aug 2017 21:00:10 +0200 Subject: [PATCH 118/222] Cleanup --- CMakeLists.txt | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91becda9f..a1f994dbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,29 +248,25 @@ if (_GLFW_X11) message(FATAL_ERROR "The RandR headers were not found") endif() - list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}") - # Check for Xinerama (legacy multi-monitor support) if (NOT X11_Xinerama_FOUND) message(FATAL_ERROR "The Xinerama headers were not found") endif() - list(APPEND glfw_INCLUDE_DIRS "${X11_Xinerama_INCLUDE_PATH}") - # Check for Xkb (X keyboard extension) if (NOT X11_Xkb_FOUND) message(FATAL_ERROR "The X keyboard extension headers were not found") endif() - list(APPEND glfw_INCLUDE_DIR "${X11_Xkb_INCLUDE_PATH}") - - # Check for Xcursor + # Check for Xcursor (cursor creation from RGBA images) if (NOT X11_Xcursor_FOUND) message(FATAL_ERROR "The Xcursor headers were not found") endif() - list(APPEND glfw_INCLUDE_DIR "${X11_Xcursor_INCLUDE_PATH}") - + list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}" + "${X11_Xinerama_INCLUDE_PATH}" + "${X11_Xkb_INCLUDE_PATH}" + "${X11_Xcursor_INCLUDE_PATH}") endif() #-------------------------------------------------------------------- From 0d9e71fe811500d0006c32f38cd27ca582ba237c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 16 Aug 2017 21:03:10 +0200 Subject: [PATCH 119/222] Cleanup --- src/x11_init.c | 2 +- src/x11_platform.h | 3 ++- src/x11_window.c | 6 ++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index d6e58bb56..f2c6ae067 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -647,7 +647,7 @@ static GLFWbool initExtensions(void) _glfw.x11.x11xcb.handle = dlopen("libX11-xcb.so.1", RTLD_LAZY | RTLD_GLOBAL); if (_glfw.x11.x11xcb.handle) { - _glfw.x11.x11xcb.XGetXCBConnection = (PFN_XGetXCBConnection) + _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); } diff --git a/src/x11_platform.h b/src/x11_platform.h index 50cba3461..48d15bc92 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -100,6 +100,7 @@ typedef XID xcb_window_t; typedef XID xcb_visualid_t; typedef struct xcb_connection_t xcb_connection_t; typedef xcb_connection_t* (* PFN_XGetXCBConnection)(Display*); +#define XGetXCBConnection _glfw.x11.x11xcb.GetXCBConnection typedef Bool (* PFN_XF86VidModeQueryExtension)(Display*,int*,int*); typedef Bool (* PFN_XF86VidModeGetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*); @@ -345,7 +346,7 @@ typedef struct _GLFWlibraryX11 struct { void* handle; - PFN_XGetXCBConnection XGetXCBConnection; + PFN_XGetXCBConnection GetXCBConnection; } x11xcb; struct { diff --git a/src/x11_window.c b/src/x11_window.c index da83fcf98..aee89d402 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2705,8 +2705,7 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, return GLFW_FALSE; } - xcb_connection_t* connection = - _glfw.x11.x11xcb.XGetXCBConnection(_glfw.x11.display); + xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); if (!connection) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -2749,8 +2748,7 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, VkXcbSurfaceCreateInfoKHR sci; PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; - xcb_connection_t* connection = - _glfw.x11.x11xcb.XGetXCBConnection(_glfw.x11.display); + xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); if (!connection) { _glfwInputError(GLFW_PLATFORM_ERROR, From 08737bdc023f2cd7e8b11a0437ad6fc92f9f99c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 16 Aug 2017 21:12:48 +0200 Subject: [PATCH 120/222] X11: Close extension libraries after XCloseDisplay --- src/x11_init.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index f2c6ae067..3bae1fa3e 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -896,30 +896,6 @@ int _glfwPlatformInit(void) void _glfwPlatformTerminate(void) { - if (_glfw.x11.x11xcb.handle) - { - dlclose(_glfw.x11.x11xcb.handle); - _glfw.x11.x11xcb.handle = NULL; - } - - if (_glfw.x11.randr.handle) - { - dlclose(_glfw.x11.randr.handle); - _glfw.x11.randr.handle = NULL; - } - - if (_glfw.x11.xcursor.handle) - { - dlclose(_glfw.x11.xcursor.handle); - _glfw.x11.xcursor.handle = NULL; - } - - if (_glfw.x11.xinerama.handle) - { - dlclose(_glfw.x11.xinerama.handle); - _glfw.x11.xinerama.handle = NULL; - } - if (_glfw.x11.helperWindowHandle) { if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == @@ -955,6 +931,30 @@ void _glfwPlatformTerminate(void) _glfw.x11.display = NULL; } + if (_glfw.x11.x11xcb.handle) + { + dlclose(_glfw.x11.x11xcb.handle); + _glfw.x11.x11xcb.handle = NULL; + } + + if (_glfw.x11.xcursor.handle) + { + dlclose(_glfw.x11.xcursor.handle); + _glfw.x11.xcursor.handle = NULL; + } + + if (_glfw.x11.randr.handle) + { + dlclose(_glfw.x11.randr.handle); + _glfw.x11.randr.handle = NULL; + } + + if (_glfw.x11.xinerama.handle) + { + dlclose(_glfw.x11.xinerama.handle); + _glfw.x11.xinerama.handle = NULL; + } + // NOTE: This needs to be done after XCloseDisplay, as libGL registers // cleanup callbacks that get called by it _glfwTerminateGLX(); From 0c70eb8d5c7090e0293a192239796d1a0933b3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 17 Aug 2017 14:25:10 +0200 Subject: [PATCH 121/222] Unify error message buffer lengths --- src/init.c | 2 +- src/internal.h | 4 +++- src/win32_init.c | 4 ++-- src/x11_init.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/init.c b/src/init.c index fd86c5be5..7d3678fac 100644 --- a/src/init.c +++ b/src/init.c @@ -148,7 +148,7 @@ static void terminate(void) void _glfwInputError(int code, const char* format, ...) { _GLFWerror* error; - char description[1024]; + char description[_GLFW_MESSAGE_SIZE]; if (format) { diff --git a/src/internal.h b/src/internal.h index fdff84d01..a95d1f867 100644 --- a/src/internal.h +++ b/src/internal.h @@ -54,6 +54,8 @@ #define _GLFW_POLL_BUTTONS 2 #define _GLFW_POLL_ALL (_GLFW_POLL_AXES | _GLFW_POLL_BUTTONS) +#define _GLFW_MESSAGE_SIZE 1024 + typedef int GLFWbool; typedef struct _GLFWerror _GLFWerror; @@ -263,7 +265,7 @@ struct _GLFWerror { _GLFWerror* next; int code; - char description[1024]; + char description[_GLFW_MESSAGE_SIZE]; }; /*! @brief Initialization configuration. diff --git a/src/win32_init.c b/src/win32_init.c index 231b0a28b..06eb44cb1 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -412,8 +412,8 @@ char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source) // void _glfwInputErrorWin32(int error, const char* description) { - WCHAR buffer[1024] = L""; - char message[2048] = ""; + WCHAR buffer[_GLFW_MESSAGE_SIZE] = L""; + char message[_GLFW_MESSAGE_SIZE] = ""; FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | diff --git a/src/x11_init.c b/src/x11_init.c index 3bae1fa3e..c4e84474f 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -779,7 +779,7 @@ void _glfwReleaseErrorHandlerX11(void) // void _glfwInputErrorX11(int error, const char* message) { - char buffer[8192]; + char buffer[_GLFW_MESSAGE_SIZE]; XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode, buffer, sizeof(buffer)); From b4ea2d32e6fd5de1b3d48f699508e839441fd7cb Mon Sep 17 00:00:00 2001 From: Andrey Zholos Date: Sat, 18 Mar 2017 10:12:49 +0000 Subject: [PATCH 122/222] Add input lag test Closes #973. --- tests/CMakeLists.txt | 6 +- tests/inputlag.c | 305 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 tests/inputlag.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 56d871b8f..1a39d59d4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(cursor cursor.c ${GLAD}) add_executable(empty WIN32 MACOSX_BUNDLE empty.c ${TINYCTHREAD} ${GLAD}) add_executable(gamma WIN32 MACOSX_BUNDLE gamma.c ${GLAD}) add_executable(icon WIN32 MACOSX_BUNDLE icon.c ${GLAD}) +add_executable(inputlag WIN32 MACOSX_BUNDLE inputlag.c ${GETOPT} ${GLAD}) add_executable(joysticks WIN32 MACOSX_BUNDLE joysticks.c ${GLAD}) add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c ${GETOPT} ${GLAD}) add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT} ${GLAD}) @@ -45,8 +46,8 @@ if (RT_LIBRARY) target_link_libraries(threads "${RT_LIBRARY}") endif() -set(WINDOWS_BINARIES empty gamma icon joysticks sharing tearing threads timeout - title windows) +set(WINDOWS_BINARIES empty gamma icon inputlag joysticks sharing tearing threads + timeout title windows) set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen cursor) @@ -73,6 +74,7 @@ endif() if (APPLE) set_target_properties(empty PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Empty Event") set_target_properties(gamma PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gamma") + set_target_properties(inputlag PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Input Lag") set_target_properties(joysticks PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Joysticks") set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing") set_target_properties(tearing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Tearing") diff --git a/tests/inputlag.c b/tests/inputlag.c new file mode 100644 index 000000000..eee4544c9 --- /dev/null +++ b/tests/inputlag.c @@ -0,0 +1,305 @@ +//======================================================================== +// Input lag test +// Copyright (c) Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test renders a marker at the cursor position reported by GLFW to +// check how much it lags behind the hardware mouse cursor +// +//======================================================================== + +#include +#include + +#define NK_IMPLEMENTATION +#define NK_INCLUDE_FIXED_TYPES +#define NK_INCLUDE_FONT_BAKING +#define NK_INCLUDE_DEFAULT_FONT +#define NK_INCLUDE_DEFAULT_ALLOCATOR +#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT +#define NK_INCLUDE_STANDARD_VARARGS +#include + +#define NK_GLFW_GL2_IMPLEMENTATION +#include + +#include +#include +#include + +#include "getopt.h" + +void usage(void) +{ + printf("Usage: inputlag [-h] [-f]\n"); + printf("Options:\n"); + printf(" -f create full screen window\n"); + printf(" -h show this help\n"); +} + +struct nk_vec2 cursor_new, cursor_pos, cursor_vel; +enum { cursor_sync_query, cursor_input_message } cursor_method = cursor_sync_query; + +void sample_input(GLFWwindow* window) +{ + float a = .25; // exponential smoothing factor + + if (cursor_method == cursor_sync_query) { + double x, y; + glfwGetCursorPos(window, &x, &y); + cursor_new.x = (float) x; + cursor_new.y = (float) y; + } + + cursor_vel.x = (cursor_new.x - cursor_pos.x) * a + cursor_vel.x * (1 - a); + cursor_vel.y = (cursor_new.y - cursor_pos.y) * a + cursor_vel.y * (1 - a); + cursor_pos = cursor_new; +} + +void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) +{ + cursor_new.x = (float) xpos; + cursor_new.y = (float) ypos; +} + +int enable_vsync = nk_true; + +void update_vsync() +{ + glfwSwapInterval(enable_vsync == nk_true ? 1 : 0); +} + +int swap_clear = nk_false; +int swap_finish = nk_true; +int swap_occlusion_query = nk_false; +int swap_read_pixels = nk_false; +GLuint occlusion_query; + +void swap_buffers(GLFWwindow* window) +{ + glfwSwapBuffers(window); + + if (swap_clear) + glClear(GL_COLOR_BUFFER_BIT); + + if (swap_finish) + glFinish(); + + if (swap_occlusion_query) { + GLint occlusion_result; + if (!occlusion_query) + glGenQueries(1, &occlusion_query); + glBeginQuery(GL_SAMPLES_PASSED, occlusion_query); + glBegin(GL_POINTS); + glVertex2f(0, 0); + glEnd(); + glEndQuery(GL_SAMPLES_PASSED); + glGetQueryObjectiv(occlusion_query, GL_QUERY_RESULT, &occlusion_result); + } + + if (swap_read_pixels) { + unsigned char rgba[4]; + glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + } +} + +void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, 1); + break; + } +} + +void draw_marker(struct nk_command_buffer* canvas, int lead, struct nk_vec2 pos) +{ + struct nk_color colors[4] = { nk_rgb(255,0,0), nk_rgb(255,255,0), nk_rgb(0,255,0), nk_rgb(0,96,255) }; + struct nk_rect rect = { -5 + pos.x, -5 + pos.y, 10, 10 }; + nk_fill_circle(canvas, rect, colors[lead]); +} + +int main(int argc, char** argv) +{ + int ch, width, height; + unsigned long frame_count = 0; + double last_time, current_time; + double frame_rate = 0; + int fullscreen = GLFW_FALSE; + GLFWmonitor* monitor = NULL; + GLFWwindow* window; + struct nk_context* nk; + struct nk_font_atlas* atlas; + + int show_forecasts = nk_true; + + while ((ch = getopt(argc, argv, "fh")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + + case 'f': + fullscreen = GLFW_TRUE; + break; + } + } + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + if (fullscreen) + { + const GLFWvidmode* mode; + + monitor = glfwGetPrimaryMonitor(); + mode = glfwGetVideoMode(monitor); + + width = mode->width; + height = mode->height; + } + else + { + width = 640; + height = 480; + } + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + + window = glfwCreateWindow(width, height, "Input lag test", monitor, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + update_vsync(); + + last_time = glfwGetTime(); + + nk = nk_glfw3_init(window, NK_GLFW3_INSTALL_CALLBACKS); + nk_glfw3_font_stash_begin(&atlas); + nk_glfw3_font_stash_end(); + + glfwSetKeyCallback(window, key_callback); + glfwSetCursorPosCallback(window, cursor_pos_callback); + + while (!glfwWindowShouldClose(window)) + { + int width, height; + struct nk_rect area; + + glfwPollEvents(); + sample_input(window); + + glfwGetWindowSize(window, &width, &height); + area = nk_rect(0.f, 0.f, (float) width, (float) height); + + glClear(GL_COLOR_BUFFER_BIT); + nk_glfw3_new_frame(); + if (nk_begin(nk, "", area, 0)) + { + nk_flags align_left = NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE; + struct nk_command_buffer *canvas = nk_window_get_canvas(nk); + int lead; + + for (lead = show_forecasts ? 3 : 0; lead >= 0; lead--) + draw_marker(canvas, lead, nk_vec2(cursor_pos.x + cursor_vel.x * lead, + cursor_pos.y + cursor_vel.y * lead)); + + // print instructions + nk_layout_row_dynamic(nk, 20, 1); + nk_label(nk, "Move mouse uniformly and check marker under cursor:", align_left); + for (lead = 0; lead <= 3; lead++) { + nk_layout_row_begin(nk, NK_STATIC, 12, 2); + nk_layout_row_push(nk, 25); + draw_marker(canvas, lead, nk_layout_space_to_screen(nk, nk_vec2(20, 5))); + nk_label(nk, "", 0); + nk_layout_row_push(nk, 500); + if (lead == 0) + nk_label(nk, "- current cursor position (no input lag)", align_left); + else + nk_labelf(nk, align_left, "- %d-frame forecast (input lag is %d frame)", lead, lead); + nk_layout_row_end(nk); + } + + nk_layout_row_dynamic(nk, 20, 1); + + nk_checkbox_label(nk, "Show forecasts", &show_forecasts); + nk_label(nk, "Input method:", align_left); + if (nk_option_label(nk, "glfwGetCursorPos (sync query)", cursor_method == cursor_sync_query)) + cursor_method = cursor_sync_query; + if (nk_option_label(nk, "glfwSetCursorPosCallback (latest input message)", cursor_method == cursor_input_message)) + cursor_method = cursor_input_message; + + nk_label(nk, "", 0); // separator + + nk_value_float(nk, "FPS", (float) frame_rate); + if (nk_checkbox_label(nk, "Enable vsync", &enable_vsync)) + update_vsync(); + + nk_label(nk, "", 0); // separator + + nk_label(nk, "After swap:", align_left); + nk_checkbox_label(nk, "glClear", &swap_clear); + nk_checkbox_label(nk, "glFinish", &swap_finish); + nk_checkbox_label(nk, "draw with occlusion query", &swap_occlusion_query); + nk_checkbox_label(nk, "glReadPixels", &swap_read_pixels); + } + + nk_end(nk); + nk_glfw3_render(NK_ANTI_ALIASING_ON); + + swap_buffers(window); + + frame_count++; + + current_time = glfwGetTime(); + if (current_time - last_time > 1.0) + { + frame_rate = frame_count / (current_time - last_time); + frame_count = 0; + last_time = current_time; + } + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + From af866e05d20068be149e0cc410d64490fb0b7a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 18 Aug 2017 13:02:35 +0200 Subject: [PATCH 123/222] Cleanup Related to #973. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b4eb3b83d..a7aa04fa8 100644 --- a/README.md +++ b/README.md @@ -385,6 +385,7 @@ skills. - Frank Wille - yuriks - Ryogo Yoshimura + - Andrey Zholos - Santi Zupancic - Jonas Ådahl - Lasse Öörni From 0d6937b33b52935fb9b082bf703d20915147a1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 20 Aug 2017 14:41:49 +0200 Subject: [PATCH 124/222] Cleanup --- src/wgl_context.c | 16 ++++++++-------- src/win32_init.c | 4 ++-- src/win32_platform.h | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/wgl_context.c b/src/wgl_context.c index f209dbf6c..1f2b12a50 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -233,15 +233,15 @@ static int choosePixelFormat(_GLFWwindow* window, // static GLFWbool isCompositionEnabled(void) { - BOOL enabled; + if (_glfw.win32.dwmapi.instance) + { + BOOL enabled; - if (!_glfw_DwmIsCompositionEnabled) - return FALSE; + if (DwmIsCompositionEnabled(&enabled) == S_OK) + return enabled; + } - if (_glfw_DwmIsCompositionEnabled(&enabled) != S_OK) - return FALSE; - - return enabled; + return FALSE; } static void makeContextCurrentWGL(_GLFWwindow* window) @@ -276,7 +276,7 @@ static void swapBuffersWGL(_GLFWwindow* window) { int count = abs(window->context.wgl.interval); while (count--) - _glfw_DwmFlush(); + DwmFlush(); } SwapBuffers(window->context.wgl.dc); diff --git a/src/win32_init.c b/src/win32_init.c index 06eb44cb1..732ee8677 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -124,9 +124,9 @@ static GLFWbool loadLibraries(void) _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); if (_glfw.win32.dwmapi.instance) { - _glfw.win32.dwmapi.DwmIsCompositionEnabled = (PFN_DwmIsCompositionEnabled) + _glfw.win32.dwmapi.IsCompositionEnabled = (PFN_DwmIsCompositionEnabled) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); - _glfw.win32.dwmapi.DwmFlush = (PFN_DwmFlush) + _glfw.win32.dwmapi.Flush = (PFN_DwmFlush) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); } diff --git a/src/win32_platform.h b/src/win32_platform.h index c21d5ce3a..340b1ebbe 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -180,8 +180,8 @@ typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEF // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); -#define _glfw_DwmIsCompositionEnabled _glfw.win32.dwmapi.DwmIsCompositionEnabled -#define _glfw_DwmFlush _glfw.win32.dwmapi.DwmFlush +#define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled +#define DwmFlush _glfw.win32.dwmapi.Flush // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); @@ -284,8 +284,8 @@ typedef struct _GLFWlibraryWin32 struct { HINSTANCE instance; - PFN_DwmIsCompositionEnabled DwmIsCompositionEnabled; - PFN_DwmFlush DwmFlush; + PFN_DwmIsCompositionEnabled IsCompositionEnabled; + PFN_DwmFlush Flush; } dwmapi; struct { From ad9458a14c7754c43c8a7c69fced44950c045cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 20 Aug 2017 14:42:39 +0200 Subject: [PATCH 125/222] Clarify what glfwVulkanSupported means --- tests/glfwinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index 47e220773..da2e56ecf 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -806,7 +806,7 @@ int main(int argc, char** argv) if (list_extensions) list_context_extensions(client, major, minor); - printf("Vulkan support: %s\n", + printf("Vulkan loader: %s\n", glfwVulkanSupported() ? "available" : "missing"); if (glfwVulkanSupported()) From 0882fffc37bbaeed08030df22fb03abef00ebb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 20 Aug 2017 14:47:44 +0200 Subject: [PATCH 126/222] Fix missing CMake file path quoting --- CMakeLists.txt | 4 ++-- src/CMakeLists.txt | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1f994dbd..56c1f386d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,7 +181,7 @@ endif() #-------------------------------------------------------------------- if (GLFW_VULKAN_STATIC) if (VULKAN_FOUND AND VULKAN_STATIC_LIBRARY) - list(APPEND glfw_LIBRARIES ${VULKAN_STATIC_LIBRARY} ${GLFW_VULKAN_DEPS}) + list(APPEND glfw_LIBRARIES "${VULKAN_STATIC_LIBRARY}" ${GLFW_VULKAN_DEPS}) if (BUILD_SHARED_LIBS) message(WARNING "Linking Vulkan loader static library into GLFW") endif() @@ -274,7 +274,7 @@ endif() #-------------------------------------------------------------------- if (_GLFW_WAYLAND) find_package(ECM REQUIRED NO_MODULE) - list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}") find_package(Wayland REQUIRED) find_package(WaylandScanner REQUIRED) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0d7139d50..b14512cc5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,11 +41,11 @@ elseif (_GLFW_WAYLAND) ecm_add_wayland_client_protocol(glfw_SOURCES PROTOCOL - ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" BASENAME relative-pointer-unstable-v1) ecm_add_wayland_client_protocol(glfw_SOURCES PROTOCOL - ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" BASENAME pointer-constraints-unstable-v1) elseif (_GLFW_MIR) set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h @@ -90,8 +90,8 @@ target_compile_definitions(glfw PRIVATE _GLFW_USE_CONFIG_H $<$:_XOPEN_SOURCE=600>) target_include_directories(glfw PUBLIC - $ - $/include>) + "$" + "$/include>") target_include_directories(glfw PRIVATE "${GLFW_SOURCE_DIR}/src" "${GLFW_BINARY_DIR}/src" From c23fca63439f2456f5aa0b99a724bbd7177e0167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 21 Aug 2017 14:37:38 +0200 Subject: [PATCH 127/222] Fix APIENTRY from windows.h being undefined Some extension loader headers include windows.h. If they were included before glfw3.h, glfw3native.h would leave APIENTRY undefined. This adds the GLFW_APIENTRY_DEFINED macro to signal when GLFW "owns" APIENTRY and may undefine it. Fixes #1062. --- README.md | 1 + include/GLFW/glfw3.h | 1 + include/GLFW/glfw3native.h | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a7aa04fa8..982399204 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,7 @@ information on what to include when reporting a bug. - [Win32] Bugfix: Monitor events were not emitted (#784) - [Win32] Bugfix: The Cygwin DLL was installed to the wrong directory (#1035) - [Win32] Bugfix: Normalization of axis data via XInput was incorrect (#1045) +- [Win32] Bugfix: `glfw3native.h` would undefine a foreign `APIENTRY` (#1062) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 1eb5131c7..05e76a9ae 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -105,6 +105,7 @@ extern "C" { #else #define APIENTRY #endif + #define GLFW_APIENTRY_DEFINED #endif /* APIENTRY */ /* Some Windows OpenGL headers need this. diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index ad7ccb57b..4372cb766 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -86,7 +86,10 @@ extern "C" { // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for // example to allow applications to correctly declare a GL_ARB_debug_output // callback) but windows.h assumes no one will define APIENTRY before it does - #undef APIENTRY + #if defined(GLFW_APIENTRY_DEFINED) + #undef APIENTRY + #undef GLFW_APIENTRY_DEFINED + #endif #include #elif defined(GLFW_EXPOSE_NATIVE_COCOA) #include From 80e4922b5e78f8ce4ca5d98ffeeb4aea9ebf8dec Mon Sep 17 00:00:00 2001 From: Sergey Tikhomirov Date: Mon, 5 Jun 2017 00:26:55 +0300 Subject: [PATCH 128/222] Cocoa: Hide cursor instead of using blank image When cursor isn't in normal mode and should be hidden, use [NSCursor hide] method instead of setting it to blank image. This should prevent situations when hidden cursor becomes visible after system notification was shown. Fixes #971. Closes #1028. --- src/cocoa_init.m | 3 --- src/cocoa_platform.h | 1 - src/cocoa_window.m | 38 +++++++++++++++++++++++--------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/cocoa_init.m b/src/cocoa_init.m index ba5ddb629..dfc35b6ff 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -352,9 +352,6 @@ void _glfwPlatformTerminate(void) _glfw.ns.listener = nil; } - [_glfw.ns.cursor release]; - _glfw.ns.cursor = nil; - free(_glfw.ns.clipboardString); _glfwTerminateNSGL(); diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index b8e0bc983..95223f34a 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -102,7 +102,6 @@ typedef struct _GLFWlibraryNS CGEventSourceRef eventSource; id delegate; id autoreleasePool; - id cursor; TISInputSourceRef inputSource; IOHIDManagerRef hidManager; id unicodeData; diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 4c27c517b..41fdb4c8a 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -88,19 +88,35 @@ static GLFWbool cursorInClientArea(_GLFWwindow* window) return [window->ns.view mouse:pos inRect:[window->ns.view frame]]; } +// Updates cursor visibility +// +static void setCursorVisibility(_GLFWwindow* window, BOOL makeVisible) +{ + static BOOL isCursorVisible = YES; + + if (makeVisible && !isCursorVisible) + [NSCursor unhide]; + else if (!makeVisible && isCursorVisible) + [NSCursor hide]; + + isCursorVisible = makeVisible; +} + // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window) { if (window->cursorMode == GLFW_CURSOR_NORMAL) { + setCursorVisibility(window, YES); + if (window->cursor) [(NSCursor*) window->cursor->ns.object set]; else [[NSCursor arrowCursor] set]; } else - [(NSCursor*) _glfw.ns.cursor set]; + setCursorVisibility(window, NO); } // Transforms the specified y-coordinate between the CG display and NS screen @@ -363,20 +379,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; @implementation GLFWContentView -+ (void)initialize -{ - if (self == [GLFWContentView class]) - { - if (_glfw.ns.cursor == nil) - { - NSImage* data = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)]; - _glfw.ns.cursor = [[NSCursor alloc] initWithImage:data - hotSpot:NSZeroPoint]; - [data release]; - } - } -} - - (id)initWithGlfwWindow:(_GLFWwindow *)initWindow { self = [super init]; @@ -522,11 +524,17 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)mouseExited:(NSEvent *)event { + if (window->cursorMode == GLFW_CURSOR_HIDDEN) + setCursorVisibility(window, YES); + _glfwInputCursorEnter(window, GLFW_FALSE); } - (void)mouseEntered:(NSEvent *)event { + if (window->cursorMode == GLFW_CURSOR_HIDDEN) + setCursorVisibility(window, NO); + _glfwInputCursorEnter(window, GLFW_TRUE); } From ce5e649d3b4718f8d226d55b35397f8df5c47927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 22 Aug 2017 20:40:07 +0200 Subject: [PATCH 129/222] Cleanup Move global data to library struct. Simplify semantics. Update changelog. Related to #1028. --- README.md | 2 ++ src/cocoa_platform.h | 1 + src/cocoa_window.m | 32 ++++++++++++++++++++------------ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 982399204..ba98864d2 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,8 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Full screen framebuffer was incorrectly sized for some video modes (#682) - [Cocoa] Bugfix: A string object for IME was updated non-idiomatically (#1050) +- [Cocoa] Bugfix: A hidden or disabled cursor would become visible when a user + notification was shown (#971,#1028) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 95223f34a..f0ba4e857 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -102,6 +102,7 @@ typedef struct _GLFWlibraryNS CGEventSourceRef eventSource; id delegate; id autoreleasePool; + GLFWbool cursorHidden; TISInputSourceRef inputSource; IOHIDManagerRef hidManager; id unicodeData; diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 41fdb4c8a..7b5939f64 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -88,18 +88,26 @@ static GLFWbool cursorInClientArea(_GLFWwindow* window) return [window->ns.view mouse:pos inRect:[window->ns.view frame]]; } -// Updates cursor visibility +// Hides the cursor if not already hidden // -static void setCursorVisibility(_GLFWwindow* window, BOOL makeVisible) +static void hideCursor(_GLFWwindow* window) { - static BOOL isCursorVisible = YES; - - if (makeVisible && !isCursorVisible) - [NSCursor unhide]; - else if (!makeVisible && isCursorVisible) + if (!_glfw.ns.cursorHidden) + { [NSCursor hide]; + _glfw.ns.cursorHidden = GLFW_TRUE; + } +} - isCursorVisible = makeVisible; +// Shows the cursor if not already shown +// +static void showCursor(_GLFWwindow* window) +{ + if (_glfw.ns.cursorHidden) + { + [NSCursor unhide]; + _glfw.ns.cursorHidden = GLFW_FALSE; + } } // Updates the cursor image according to its cursor mode @@ -108,7 +116,7 @@ static void updateCursorImage(_GLFWwindow* window) { if (window->cursorMode == GLFW_CURSOR_NORMAL) { - setCursorVisibility(window, YES); + showCursor(window); if (window->cursor) [(NSCursor*) window->cursor->ns.object set]; @@ -116,7 +124,7 @@ static void updateCursorImage(_GLFWwindow* window) [[NSCursor arrowCursor] set]; } else - setCursorVisibility(window, NO); + hideCursor(window); } // Transforms the specified y-coordinate between the CG display and NS screen @@ -525,7 +533,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)mouseExited:(NSEvent *)event { if (window->cursorMode == GLFW_CURSOR_HIDDEN) - setCursorVisibility(window, YES); + showCursor(window); _glfwInputCursorEnter(window, GLFW_FALSE); } @@ -533,7 +541,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)mouseEntered:(NSEvent *)event { if (window->cursorMode == GLFW_CURSOR_HIDDEN) - setCursorVisibility(window, NO); + hideCursor(window); _glfwInputCursorEnter(window, GLFW_TRUE); } From 2f8b71d7a157f21fbf832b5ce128093f5b9615e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 23 Aug 2017 15:04:09 +0200 Subject: [PATCH 130/222] Add and update credits --- README.md | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ba98864d2..57fc49697 100644 --- a/README.md +++ b/README.md @@ -259,9 +259,8 @@ GLFW exists because people around the world donated their time and lent their skills. - Bobyshev Alexander - - artblanc - - arturo - Matt Arsenault + - David Avedissian - Keith Bauer - John Bartholomew - Niklas Behrens @@ -270,11 +269,16 @@ skills. - Doug Binks - blanco - Kyle Brenneman + - Rok Breulj - Martin Capitanio - David Carlier + - Arturo Castro - Chi-kwan Chan + - Ian Clarkson - Michał Cichoń - Lambert Clara + - Yaron Cohen-Tal + - Omar Cornut - Andrew Corrigan - Noel Cower - Jason Daly @@ -286,6 +290,8 @@ skills. - Mario Dorn - Jonathan Dummer - Ralph Eastwood + - Fredrik Ehnbom + - Robin Eklind - Siavash Eliasi - Felipe Ferreira - Michael Fogleman @@ -295,6 +301,7 @@ skills. - Marcus Geelnard - Eloi Marín Gratacós - Stefan Gustavson + - Jonathan Hale - Sylvain Hellegouarch - Matthew Henry - heromyth @@ -307,20 +314,22 @@ skills. - Toni Jovanoski - Arseny Kapoulkine - Osman Keskin + - Josh Kilmer - Cameron King - Peter Knut - Christoph Kubisch + - Yuri Kunde Schlesner - Konstantin Käfer - Eric Larson - Robin Leffmann - Glenn Lewis - Shane Liesegang - Eyal Lotem - - Дмитри Малышев - - Martins Mozeiko - Tristam MacDonald - Hans Mackowiak + - Дмитри Малышев - Zbigniew Mandziejewicz + - Célestin Marot - Kyle McDonald - David Medlock - Bryce Mehring @@ -332,11 +341,15 @@ skills. - Bruce Mitchener - Jack Moffitt - Jeff Molofee + - Pierre Morel - Jon Morton - Pierre Moulon + - Martins Mozeiko - Julian Møller + - ndogxj - Kristian Nielsen - Kamil Nowakowski + - Denis Ovod - Ozzy - Andri Pálsson - Peoro @@ -346,28 +359,34 @@ skills. - Orson Peters - Emmanuel Gil Peyrot - Cyril Pichard - - Pieroman + - Keith Pitt + - Stanislav Podgorskiy + - Alexandre Pretyman - Philip Rideout + - Eddie Ringle - Jorge Rodriguez - Ed Ropple - Aleksey Rybalkin - Riku Salminen - Brandon Schaefer - Sebastian Schuberth + - Christian Sdunek - Matt Sealey - - SephiRok - Steve Sexton - - Systemcluster + - Arkady Shapkin - Yoshiki Shibukawa - Dmitri Shuralyov - Daniel Skorupski - Bradley Smith - Patrick Snape + - Erlend Sogge Heggen - Julian Squires - Johannes Stein + - Pontus Stenetorp - Michael Stocker - Justin Stoecker - Elviss Strazdins + - Paul Sultana - Nathan Sweet - TTK-Bandit - Sergey Tikhomirov @@ -377,6 +396,7 @@ skills. - Matthew Turner - urraka - Elias Vanderstuyft + - Stef Velzel - Jari Vetoniemi - Ricardo Vieira - Nicholas Vitovitch @@ -386,7 +406,6 @@ skills. - Xo Wang - Jay Weisskopf - Frank Wille - - yuriks - Ryogo Yoshimura - Andrey Zholos - Santi Zupancic From 58a247b26d283c40078426443d375d4c126d69e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 23 Aug 2017 18:24:29 +0200 Subject: [PATCH 131/222] Cocoa: Fix some characters not repeating Fixes #1010. --- README.md | 1 + src/cocoa_window.m | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/README.md b/README.md index 57fc49697..a93c60ae1 100644 --- a/README.md +++ b/README.md @@ -226,6 +226,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: A string object for IME was updated non-idiomatically (#1050) - [Cocoa] Bugfix: A hidden or disabled cursor would become visible when a user notification was shown (#971,#1028) +- [Cocoa] Bugfix: Some characters did not repeat due to Press and Hold (#1010) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 7b5939f64..cd4f3f894 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -999,6 +999,13 @@ static GLFWbool initializeAppKit(void) [NSApp setDelegate:_glfw.ns.delegate]; [NSApp run]; + // Press and Hold prevents some keys from emitting repeated characters + NSDictionary* defaults = + [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], + @"ApplePressAndHoldEnabled", + nil]; + [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; + return GLFW_TRUE; } From 45ca8b8d196338ff9c96b3269bc4b7115d35b91b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 27 Aug 2017 22:42:23 +0200 Subject: [PATCH 132/222] Win32: Add HMONITOR to monitor data --- src/win32_monitor.c | 33 +++++++++++++++++++++++++++++++++ src/win32_platform.h | 1 + 2 files changed, 34 insertions(+) diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 06e0e0cf3..2aaec4827 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -33,6 +33,27 @@ #include +// Callback for EnumDisplayMonitors in createMonitor +// +static BOOL CALLBACK monitorCallback(HMONITOR handle, + HDC dc, + RECT* rect, + LPARAM data) +{ + MONITORINFOEXW mi; + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + + if (GetMonitorInfoW(handle, (MONITORINFO*) &mi)) + { + _GLFWmonitor* monitor = (_GLFWmonitor*) data; + if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0) + monitor->win32.handle = handle; + } + + return TRUE; +} + // Create monitor from an adapter and (optionally) a display // static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, @@ -41,6 +62,8 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, _GLFWmonitor* monitor; char* name; HDC dc; + DEVMODEW dm; + RECT rect; if (display) name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString); @@ -78,6 +101,16 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, NULL, NULL); } + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm); + + rect.left = dm.dmPosition.x; + rect.top = dm.dmPosition.y; + rect.right = dm.dmPosition.x + dm.dmPelsWidth; + rect.bottom = dm.dmPosition.y + dm.dmPelsHeight; + + EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor); return monitor; } diff --git a/src/win32_platform.h b/src/win32_platform.h index 340b1ebbe..0cc524d6d 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -299,6 +299,7 @@ typedef struct _GLFWlibraryWin32 // typedef struct _GLFWmonitorWin32 { + HMONITOR handle; // This size matches the static size of DISPLAY_DEVICE.DeviceName WCHAR adapterName[32]; WCHAR displayName[32]; From d8551b73f6065ab353b508d6d22b8c80eff1a333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 27 Aug 2017 23:09:08 +0200 Subject: [PATCH 133/222] Cleanup --- src/win32_monitor.c | 31 +++++++++++++++---------------- src/win32_window.c | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 2aaec4827..76fbc0d8a 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -142,8 +142,8 @@ void _glfwPollMonitorsWin32(void) { int type = _GLFW_INSERT_LAST; - ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); - adapter.cb = sizeof(DISPLAY_DEVICEW); + ZeroMemory(&adapter, sizeof(adapter)); + adapter.cb = sizeof(adapter); if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) break; @@ -156,8 +156,8 @@ void _glfwPollMonitorsWin32(void) for (displayIndex = 0; ; displayIndex++) { - ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); - display.cb = sizeof(DISPLAY_DEVICEW); + ZeroMemory(&display, sizeof(display)); + display.cb = sizeof(display); if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) break; @@ -244,7 +244,7 @@ GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desire return GLFW_TRUE; ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(DEVMODEW); + dm.dmSize = sizeof(dm); dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; dm.dmPelsWidth = best->width; @@ -309,19 +309,19 @@ void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { - DEVMODEW settings; - ZeroMemory(&settings, sizeof(DEVMODEW)); - settings.dmSize = sizeof(DEVMODEW); + DEVMODEW dm; + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); EnumDisplaySettingsExW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, - &settings, + &dm, EDS_ROTATEDMODE); if (xpos) - *xpos = settings.dmPosition.x; + *xpos = dm.dmPosition.x; if (ypos) - *ypos = settings.dmPosition.y; + *ypos = dm.dmPosition.y; } GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) @@ -337,8 +337,8 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) GLFWvidmode mode; DEVMODEW dm; - ZeroMemory(&dm, sizeof(DEVMODEW)); - dm.dmSize = sizeof(DEVMODEW); + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm)) break; @@ -404,9 +404,8 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { DEVMODEW dm; - - ZeroMemory(&dm, sizeof(DEVMODEW)); - dm.dmSize = sizeof(DEVMODEW); + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm); diff --git a/src/win32_window.c b/src/win32_window.c index ef05898a6..092ce5e05 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -111,7 +111,7 @@ static HICON createIcon(const GLFWimage* image, unsigned char* source = image->pixels; ZeroMemory(&bi, sizeof(bi)); - bi.bV5Size = sizeof(BITMAPV5HEADER); + bi.bV5Size = sizeof(bi); bi.bV5Width = image->width; bi.bV5Height = -image->height; bi.bV5Planes = 1; From d80d4be0307d52d7add69f9a995a34325a9dfe1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 28 Aug 2017 19:01:41 +0200 Subject: [PATCH 134/222] Fix .appveyor.yml provider settings syntax --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index cde766645..4a002500c 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,5 +19,5 @@ notifications: - provider: Email to: - ci@glfw.org - - on_build_failure: true - - on_build_success: false + on_build_failure: true + on_build_success: false From a368d89c947db11afb97bc4788022929fcd71493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 8 Sep 2017 16:15:57 +0200 Subject: [PATCH 135/222] Win32: Fix disabled cursor mode vs caption buttons This postpones disabling the cursor until the user is done interacting with a caption button. Related to #650. Fixes #1071. --- README.md | 2 ++ src/win32_platform.h | 1 + src/win32_window.c | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/README.md b/README.md index a93c60ae1..f7d5d67fb 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,8 @@ information on what to include when reporting a bug. - [Win32] Bugfix: The Cygwin DLL was installed to the wrong directory (#1035) - [Win32] Bugfix: Normalization of axis data via XInput was incorrect (#1045) - [Win32] Bugfix: `glfw3native.h` would undefine a foreign `APIENTRY` (#1062) +- [Win32] Bugfix: Disabled cursor mode prevented use of caption buttons + (#650,#1071) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X diff --git a/src/win32_platform.h b/src/win32_platform.h index 0cc524d6d..233510efe 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -233,6 +233,7 @@ typedef struct _GLFWwindowWin32 HICON smallIcon; GLFWbool cursorTracked; + GLFWbool frameAction; GLFWbool iconified; GLFWbool maximized; diff --git a/src/win32_window.c b/src/win32_window.c index 092ce5e05..2b4ddeded 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -495,10 +495,47 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, switch (uMsg) { + case WM_MOUSEACTIVATE: + { + // HACK: Postpone cursor disabling when the window was activated by + // clicking a caption button + if (HIWORD(lParam) == WM_LBUTTONDOWN) + { + if (LOWORD(lParam) == HTCLOSE || + LOWORD(lParam) == HTMINBUTTON || + LOWORD(lParam) == HTMAXBUTTON) + { + window->win32.frameAction = GLFW_TRUE; + } + } + + break; + } + + case WM_CAPTURECHANGED: + { + // HACK: Disable the cursor once the caption button action has been + // completed or cancelled + if (lParam == 0 && window->win32.frameAction) + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + + window->win32.frameAction = GLFW_FALSE; + } + + break; + } + case WM_SETFOCUS: { _glfwInputWindowFocus(window, GLFW_TRUE); + // HACK: Do not disable cursor while the user is interacting with + // a caption button + if (window->win32.frameAction) + break; + if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); @@ -758,6 +795,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: { + // HACK: Postpone cursor disabling while the user is moving or + // resizing the window or using the menu if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); @@ -767,6 +806,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_EXITSIZEMOVE: case WM_EXITMENULOOP: { + // HACK: Disable the cursor once the user is done moving or + // resizing the window or using the menu if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); From b97039f3f58521ff84e67cfc2dd18b2c0e238ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 10 Sep 2017 02:55:29 +0200 Subject: [PATCH 136/222] Cleanup --- src/input.c | 123 ++++++++++++++++++++++------------------------ src/window.c | 135 +++++++++++++++++++++++++-------------------------- 2 files changed, 123 insertions(+), 135 deletions(-) diff --git a/src/input.c b/src/input.c index 101b6859b..7d9ff7741 100644 --- a/src/input.c +++ b/src/input.c @@ -354,10 +354,10 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) return window->stickyKeys; case GLFW_STICKY_MOUSE_BUTTONS: return window->stickyMouseButtons; - default: - _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); - return 0; } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); + return 0; } GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) @@ -367,79 +367,72 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) _GLFW_REQUIRE_INIT(); - switch (mode) + if (mode == GLFW_CURSOR) { - case GLFW_CURSOR: + if (value != GLFW_CURSOR_NORMAL && + value != GLFW_CURSOR_HIDDEN && + value != GLFW_CURSOR_DISABLED) { - if (value != GLFW_CURSOR_NORMAL && - value != GLFW_CURSOR_HIDDEN && - value != GLFW_CURSOR_DISABLED) - { - _glfwInputError(GLFW_INVALID_ENUM, - "Invalid cursor mode 0x%08X", - value); - return; - } - - if (window->cursorMode == value) - return; - - window->cursorMode = value; - - _glfwPlatformGetCursorPos(window, - &window->virtualCursorPosX, - &window->virtualCursorPosY); - - if (_glfwPlatformWindowFocused(window)) - _glfwPlatformSetCursorMode(window, value); - + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid cursor mode 0x%08X", + value); return; } - case GLFW_STICKY_KEYS: - { - if (window->stickyKeys == value) - return; - - if (!value) - { - int i; - - // Release all sticky keys - for (i = 0; i <= GLFW_KEY_LAST; i++) - { - if (window->keys[i] == _GLFW_STICK) - window->keys[i] = GLFW_RELEASE; - } - } - - window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE; + if (window->cursorMode == value) return; - } - case GLFW_STICKY_MOUSE_BUTTONS: - { - if (window->stickyMouseButtons == value) - return; + window->cursorMode = value; - if (!value) - { - int i; + _glfwPlatformGetCursorPos(window, + &window->virtualCursorPosX, + &window->virtualCursorPosY); - // Release all sticky mouse buttons - for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) - { - if (window->mouseButtons[i] == _GLFW_STICK) - window->mouseButtons[i] = GLFW_RELEASE; - } - } - - window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE; - return; - } + if (_glfwPlatformWindowFocused(window)) + _glfwPlatformSetCursorMode(window, value); } + else if (mode == GLFW_STICKY_KEYS) + { + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->stickyKeys == value) + return; - _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); + if (!value) + { + int i; + + // Release all sticky keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window->keys[i] == _GLFW_STICK) + window->keys[i] = GLFW_RELEASE; + } + } + + window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE; + } + else if (mode == GLFW_STICKY_MOUSE_BUTTONS) + { + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->stickyMouseButtons == value) + return; + + if (!value) + { + int i; + + // Release all sticky mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == _GLFW_STICK) + window->mouseButtons[i] = GLFW_RELEASE; + } + } + + window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE; + } + else + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); } GLFWAPI const char* glfwGetKeyName(int key, int scancode) diff --git a/src/window.c b/src/window.c index b7498e1be..5c33217de 100644 --- a/src/window.c +++ b/src/window.c @@ -278,119 +278,118 @@ GLFWAPI void glfwWindowHint(int hint, int value) { case GLFW_RED_BITS: _glfw.hints.framebuffer.redBits = value; - break; + return; case GLFW_GREEN_BITS: _glfw.hints.framebuffer.greenBits = value; - break; + return; case GLFW_BLUE_BITS: _glfw.hints.framebuffer.blueBits = value; - break; + return; case GLFW_ALPHA_BITS: _glfw.hints.framebuffer.alphaBits = value; - break; + return; case GLFW_DEPTH_BITS: _glfw.hints.framebuffer.depthBits = value; - break; + return; case GLFW_STENCIL_BITS: _glfw.hints.framebuffer.stencilBits = value; - break; + return; case GLFW_ACCUM_RED_BITS: _glfw.hints.framebuffer.accumRedBits = value; - break; + return; case GLFW_ACCUM_GREEN_BITS: _glfw.hints.framebuffer.accumGreenBits = value; - break; + return; case GLFW_ACCUM_BLUE_BITS: _glfw.hints.framebuffer.accumBlueBits = value; - break; + return; case GLFW_ACCUM_ALPHA_BITS: _glfw.hints.framebuffer.accumAlphaBits = value; - break; + return; case GLFW_AUX_BUFFERS: _glfw.hints.framebuffer.auxBuffers = value; - break; + return; case GLFW_STEREO: _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_DOUBLEBUFFER: _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_SAMPLES: _glfw.hints.framebuffer.samples = value; - break; + return; case GLFW_SRGB_CAPABLE: _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_RESIZABLE: _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_DECORATED: _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_FOCUSED: _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_AUTO_ICONIFY: _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_FLOATING: _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_MAXIMIZED: _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_VISIBLE: _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_COCOA_RETINA_FRAMEBUFFER: _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_COCOA_FRAME_AUTOSAVE: _glfw.hints.window.ns.frame = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_COCOA_GRAPHICS_SWITCHING: _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_CENTER_CURSOR: _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_CLIENT_API: _glfw.hints.context.client = value; - break; + return; case GLFW_CONTEXT_CREATION_API: _glfw.hints.context.source = value; - break; + return; case GLFW_CONTEXT_VERSION_MAJOR: _glfw.hints.context.major = value; - break; + return; case GLFW_CONTEXT_VERSION_MINOR: _glfw.hints.context.minor = value; - break; + return; case GLFW_CONTEXT_ROBUSTNESS: _glfw.hints.context.robustness = value; - break; + return; case GLFW_OPENGL_FORWARD_COMPAT: _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_OPENGL_DEBUG_CONTEXT: _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_CONTEXT_NO_ERROR: _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE; - break; + return; case GLFW_OPENGL_PROFILE: _glfw.hints.context.profile = value; - break; + return; case GLFW_CONTEXT_RELEASE_BEHAVIOR: _glfw.hints.context.release = value; - break; + return; case GLFW_REFRESH_RATE: _glfw.hints.refreshRate = value; - break; - default: - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); - break; + return; } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); } GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) @@ -770,41 +769,37 @@ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) value = value ? GLFW_TRUE : GLFW_FALSE; - switch (attrib) + if (attrib == GLFW_AUTO_ICONIFY) + window->autoIconify = value; + else if (attrib == GLFW_RESIZABLE) { - case GLFW_RESIZABLE: - if (window->resizable != value) - { - window->resizable = value; - if (!window->monitor) - _glfwPlatformSetWindowResizable(window, value); - } + if (window->resizable == value) return; - case GLFW_DECORATED: - if (window->decorated != value) - { - window->decorated = value; - if (!window->monitor) - _glfwPlatformSetWindowDecorated(window, value); - } - return; - - case GLFW_FLOATING: - if (window->floating != value) - { - window->floating = value; - if (!window->monitor) - _glfwPlatformSetWindowFloating(window, value); - } - return; - - case GLFW_AUTO_ICONIFY: - window->autoIconify = value; - return; + window->resizable = value; + if (!window->monitor) + _glfwPlatformSetWindowResizable(window, value); } + else if (attrib == GLFW_DECORATED) + { + if (window->decorated == value) + return; - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); + window->decorated = value; + if (!window->monitor) + _glfwPlatformSetWindowDecorated(window, value); + } + else if (attrib == GLFW_FLOATING) + { + if (window->floating == value) + return; + + window->floating = value; + if (!window->monitor) + _glfwPlatformSetWindowFloating(window, value); + } + else + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); } GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) From d099181307253a22a57b7932ab32df02e196035f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 10 Sep 2017 21:02:26 +0200 Subject: [PATCH 137/222] Add library name override macros --- docs/compile.dox | 6 ++++++ src/egl_context.c | 16 ++++++++++++---- src/glx_context.c | 4 +++- src/osmesa_context.c | 4 +++- src/vulkan.c | 4 +++- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/docs/compile.dox b/docs/compile.dox index 75f938cac..35d657324 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -265,6 +265,12 @@ If you are linking the Vulkan loader statically into your application then you must also define @b _GLFW_VULKAN_STATIC. Otherwise, GLFW will attempt to use the external version. +If you are using a custom name for the Vulkan, EGL, GLX, OSMesa, OpenGL, GLESv1 +or GLESv2 library, you can override the default names by defining those you need +of @b _GLFW_VULKAN_LIBRARY, @b _GLFW_EGL_LIBRARY, @b _GLFW_GLX_LIBRARY, @b +_GLFW_OSMESA_LIBRARY, @b _GLFW_OPENGL_LIBRARY, @b _GLFW_GLESV1_LIBRARY and @b +_GLFW_GLESV2_LIBRARY. Otherwise, GLFW will use the built-in default names. + For the EGL context creation API, the following options are available: - @b _GLFW_USE_EGLPLATFORM_H to use `EGL/eglplatform.h` for native handle diff --git a/src/egl_context.c b/src/egl_context.c index d1bbbf08d..54257f25d 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -286,7 +286,9 @@ GLFWbool _glfwInitEGL(void) int i; const char* sonames[] = { -#if defined(_GLFW_WIN32) +#if defined(_GLFW_EGL_LIBRARY) + _GLFW_EGL_LIBRARY, +#elif defined(_GLFW_WIN32) "libEGL.dll", "EGL.dll", #elif defined(_GLFW_COCOA) @@ -601,7 +603,9 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const char** sonames; const char* es1sonames[] = { -#if defined(_GLFW_WIN32) +#if defined(_GLFW_GLESV1_LIBRARY) + _GLFW_GLESV1_LIBRARY, +#elif defined(_GLFW_WIN32) "GLESv1_CM.dll", "libGLES_CM.dll", #elif defined(_GLFW_COCOA) @@ -614,7 +618,9 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, }; const char* es2sonames[] = { -#if defined(_GLFW_WIN32) +#if defined(_GLFW_GLESV2_LIBRARY) + _GLFW_GLESV2_LIBRARY, +#elif defined(_GLFW_WIN32) "GLESv2.dll", "libGLESv2.dll", #elif defined(_GLFW_COCOA) @@ -628,7 +634,9 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, }; const char* glsonames[] = { -#if defined(_GLFW_WIN32) +#if defined(_GLFW_OPENGL_LIBRARY) + _GLFW_OPENGL_LIBRARY, +#elif defined(_GLFW_WIN32) #elif defined(_GLFW_COCOA) #else "libGL.so.1", diff --git a/src/glx_context.c b/src/glx_context.c index dbac4ea77..e545fa0fe 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -244,7 +244,9 @@ GLFWbool _glfwInitGLX(void) int i; const char* sonames[] = { -#if defined(__CYGWIN__) +#if defined(_GLFW_GLX_LIBRARY) + _GLFW_GLX_LIBRARY, +#elif defined(__CYGWIN__) "libGL-1.so", #else "libGL.so.1", diff --git a/src/osmesa_context.c b/src/osmesa_context.c index 46102fbab..a7de33f26 100644 --- a/src/osmesa_context.c +++ b/src/osmesa_context.c @@ -113,7 +113,9 @@ GLFWbool _glfwInitOSMesa(void) int i; const char* sonames[] = { -#if defined(_WIN32) +#if defined(_GLFW_OSMESA_LIBRARY) + _GLFW_OSMESA_LIBRARY, +#elif defined(_WIN32) "libOSMesa.dll", "OSMesa.dll", #elif defined(__APPLE__) diff --git a/src/vulkan.c b/src/vulkan.c index f2473cf6e..1fd15fad2 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -49,7 +49,9 @@ GLFWbool _glfwInitVulkan(int mode) return GLFW_TRUE; #if !defined(_GLFW_VULKAN_STATIC) -#if defined(_GLFW_WIN32) +#if defined(_GLFW_VULKAN_LIBRARY) + _glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY); +#elif defined(_GLFW_WIN32) _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); #elif defined(_GLFW_COCOA) _glfw.vk.handle = _glfw_dlopen("libMoltenVK.dylib"); From 1955c37c48105836e30257ec21f56b33c4a88ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 10 Sep 2017 21:03:17 +0200 Subject: [PATCH 138/222] Documentation work --- docs/header.html | 1 - docs/intro.dox | 53 +++++++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/docs/header.html b/docs/header.html index 9759d8b02..16b09a721 100644 --- a/docs/header.html +++ b/docs/header.html @@ -25,7 +25,6 @@ $extrastylesheet diff --git a/docs/intro.dox b/docs/intro.dox index e0e7e8aeb..65aeef68b 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -82,6 +82,9 @@ Some hints are platform specific. These may be set on any platform but they will only affect their specific platform. Other platforms will simply ignore them. Setting these hints requires no platform specific headers or functions. + +@subsubsection init_hints_shared Shared init hints + @anchor GLFW_JOYSTICK_HAT_BUTTONS __GLFW_JOYSTICK_HAT_BUTTONS__ specifies whether to also expose joystick hats as buttons, for compatibility with earlier versions of GLFW that did not have @ref @@ -299,35 +302,39 @@ functions not on this list will not be made non-reentrant. @subsection thread_safety Thread safety -Most GLFW functions must only be called from the main thread, but some may be -called from any thread. However, no GLFW function may be called from any thread -but the main thread until GLFW has been successfully initialized, including -functions that may called before initialization. +Most GLFW functions must only be called from the main thread (the thread that +calls main), but some may be called from any thread once the library has been +initialized. Before initialization the whole library is thread-unsafe. The reference documentation for every GLFW function states whether it is limited to the main thread. -Initialization and termination, event processing and the creation and -destruction of windows, contexts and cursors are all limited to the main thread -due to limitations of one or several platforms. +Initialization, termination, event processing and the creation and +destruction of windows, cursors and OpenGL and OpenGL ES contexts are all +restricted to the main thread due to limitations of one or several platforms. Because event processing must be performed on the main thread, all callbacks except for the error callback will only be called on that thread. The error callback may be called on any thread, as any GLFW function may generate errors. -The posting of empty events may be done from any thread. The window user -pointer and close flag may also be accessed and modified from any thread, but -this is not synchronized by GLFW. The following window related functions may -be called from any thread: +The error code and description may be queried from any thread. + + - @ref glfwGetError + +Empty events may be posted from any thread. - @ref glfwPostEmptyEvent + +The window user pointer and close flag may be read and written from any thread, +but this is not synchronized by GLFW. + - @ref glfwGetWindowUserPointer - @ref glfwSetWindowUserPointer - @ref glfwWindowShouldClose - @ref glfwSetWindowShouldClose -Rendering may be done on any thread. The following context related functions -may be called from any thread: +These functions for working with OpenGL and OpenGL ES contexts may be called +from any thread, but the window object is not synchronized by GLFW. - @ref glfwMakeContextCurrent - @ref glfwGetCurrentContext @@ -336,27 +343,23 @@ may be called from any thread: - @ref glfwExtensionSupported - @ref glfwGetProcAddress -The raw timer may be queried from any thread. The following raw timer related -functions may be called from any thread: +The raw timer functions may be called from any thread. - @ref glfwGetTimerFrequency - @ref glfwGetTimerValue -The regular timer may be used from any thread, but the reading and writing of -the timer offset is not synchronized by GLFW. The following timer related -functions may be called from any thread: +The regular timer may be used from any thread, but reading and writing the timer +offset is not synchronized by GLFW. - @ref glfwGetTime - @ref glfwSetTime -Library version information may be queried from any thread. The following -version related functions may be called from any thread: +Library version information may be queried from any thread. - @ref glfwGetVersion - @ref glfwGetVersionString -Vulkan objects may be created and information queried from any thread. The -following Vulkan related functions may be called from any thread: +All Vulkan related functions may be called from any thread. - @ref glfwVulkanSupported - @ref glfwGetRequiredInstanceExtensions @@ -364,9 +367,9 @@ following Vulkan related functions may be called from any thread: - @ref glfwGetPhysicalDevicePresentationSupport - @ref glfwCreateWindowSurface -GLFW uses no synchronization objects internally except for thread-local storage -to keep track of the current context for each thread. Synchronization is left -to the application. +GLFW uses synchronization objects internally only to manage the per-thread +context and error states. Additional synchronization is left to the +application. Functions that may currently be called from any thread will always remain so, but functions that are currently limited to the main thread may be updated to From f8668c5a9fcec29adbfc6c2e096c88f1c985ce09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 7 Feb 2017 03:29:57 +0100 Subject: [PATCH 139/222] Win32: Fix key names not matching other platforms This brings printable key names more in line with the results provided on other platforms. Fixes #943. --- README.md | 1 + src/win32_init.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ src/win32_platform.h | 3 ++- src/win32_window.c | 21 ++++++----------- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index f7d5d67fb..52349e486 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,7 @@ information on what to include when reporting a bug. - [Win32] Bugfix: `glfw3native.h` would undefine a foreign `APIENTRY` (#1062) - [Win32] Bugfix: Disabled cursor mode prevented use of caption buttons (#650,#1071) +- [Win32] Bugfix: Returned key names did not match other platforms (#943) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X diff --git a/src/win32_init.c b/src/win32_init.c index 732ee8677..392114d00 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -429,6 +429,60 @@ void _glfwInputErrorWin32(int error, const char* description) _glfwInputError(error, "%s: %s", description, message); } +// Updates key names according to the current keyboard layout +// +void _glfwUpdateKeyNamesWin32(void) +{ + int key; + BYTE state[256] = {0}; + + memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames)); + + for (key = GLFW_KEY_SPACE; key <= GLFW_KEY_LAST; key++) + { + UINT vk; + int scancode, length; + WCHAR chars[16]; + + scancode = _glfw.win32.scancodes[key]; + if (scancode == -1) + continue; + + if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) + { + const UINT vks[] = { + VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, + VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, + VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE, + VK_MULTIPLY, VK_SUBTRACT, VK_ADD + }; + + vk = vks[key - GLFW_KEY_KP_0]; + } + else + vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK); + + length = ToUnicode(vk, scancode, state, + chars, sizeof(chars) / sizeof(WCHAR), + 0); + + if (length == -1) + { + length = ToUnicode(vk, scancode, state, + chars, sizeof(chars) / sizeof(WCHAR), + 0); + } + + if (length < 1) + continue; + + WideCharToMultiByte(CP_UTF8, 0, chars, 1, + _glfw.win32.keynames[key], + sizeof(_glfw.win32.keynames[key]), + NULL, NULL); + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -448,6 +502,7 @@ int _glfwPlatformInit(void) return GLFW_FALSE; createKeyTables(); + _glfwUpdateKeyNamesWin32(); if (_glfw_SetProcessDpiAwareness) _glfw_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); diff --git a/src/win32_platform.h b/src/win32_platform.h index 233510efe..d05722267 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -250,9 +250,9 @@ typedef struct _GLFWlibraryWin32 DWORD foregroundLockTimeout; int acquiredMonitorCount; char* clipboardString; - char keyName[64]; short int keycodes[512]; short int scancodes[GLFW_KEY_LAST + 1]; + char keynames[GLFW_KEY_LAST + 1][5]; // Where to place the cursor when re-enabled double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active @@ -353,6 +353,7 @@ void _glfwUnregisterWindowClassWin32(void); WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); void _glfwInputErrorWin32(int error, const char* description); +void _glfwUpdateKeyNamesWin32(void); void _glfwInitTimerWin32(void); diff --git a/src/win32_window.c b/src/win32_window.c index 2b4ddeded..aa7efc843 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -584,6 +584,12 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, return 0; } + case WM_INPUTLANGCHANGE: + { + _glfwUpdateKeyNamesWin32(); + break; + } + case WM_CHAR: case WM_SYSCHAR: case WM_UNICHAR: @@ -1652,20 +1658,7 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) const char* _glfwPlatformGetScancodeName(int scancode) { - WCHAR name[16]; - - if (!GetKeyNameTextW(scancode << 16, name, sizeof(name) / sizeof(WCHAR))) - return NULL; - - if (!WideCharToMultiByte(CP_UTF8, 0, name, -1, - _glfw.win32.keyName, - sizeof(_glfw.win32.keyName), - NULL, NULL)) - { - return NULL; - } - - return _glfw.win32.keyName; + return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]]; } int _glfwPlatformGetKeyScancode(int key) From 7f0d5e0a0305d94278f19782d1ba0b49aaafdfd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 13 Sep 2017 17:47:49 +0200 Subject: [PATCH 140/222] Win32: Fix text conversion size semantics --- src/win32_init.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/win32_init.c b/src/win32_init.c index 392114d00..5a287076c 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -357,19 +357,19 @@ static HWND createHelperWindow(void) WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source) { WCHAR* target; - int length; + int count; - length = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0); - if (!length) + count = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0); + if (!count) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string from UTF-8"); return NULL; } - target = calloc(length, sizeof(WCHAR)); + target = calloc(count, sizeof(WCHAR)); - if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, length)) + if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string from UTF-8"); @@ -385,19 +385,19 @@ WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source) char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source) { char* target; - int length; + int size; - length = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); - if (!length) + size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); + if (!size) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string to UTF-8"); return NULL; } - target = calloc(length, 1); + target = calloc(size, 1); - if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length, NULL, NULL)) + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string to UTF-8"); From 4637c31d822c5ced34c8550488e2555054284721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 13 Sep 2017 23:19:29 +0200 Subject: [PATCH 141/222] Win32: Remove unused header --- src/win32_platform.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/win32_platform.h b/src/win32_platform.h index d05722267..63aaa94dc 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -63,7 +63,6 @@ #include #include -#include #include #include #include From 16ae02ab85fc184c20e536b3f8e33be07dd6e39c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 14 Sep 2017 20:16:25 +0200 Subject: [PATCH 142/222] Add CMake target for updating gamepad mappings This adds the 'mappings' build target that downloads the upstream gamecontrollerdb.txt file and regenerates the mappings.h header. Related to #900. --- CMake/GenerateMappings.cmake | 33 +++++++++++++++++ README.md | 1 + src/mappings.h | 11 ++++++ src/mappings.h.in | 70 ++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 CMake/GenerateMappings.cmake create mode 100644 src/mappings.h.in diff --git a/CMake/GenerateMappings.cmake b/CMake/GenerateMappings.cmake new file mode 100644 index 000000000..9fb304e87 --- /dev/null +++ b/CMake/GenerateMappings.cmake @@ -0,0 +1,33 @@ +# Usage: +# cmake -P GenerateMappings.cmake + +set(source_url "https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt") +set(source_path "${CMAKE_CURRENT_BINARY_DIR}/gamecontrollerdb.txt") +set(template_path "${CMAKE_ARGV3}") +set(target_path "${CMAKE_ARGV4}") + +if (NOT EXISTS "${template_path}") + message(FATAL_ERROR "Failed to find template file ${template_path}") +endif() + +file(DOWNLOAD "${source_url}" "${source_path}" + STATUS download_status + TLS_VERIFY on) + +list(GET download_status 0 status_code) +list(GET download_status 1 status_message) + +if (status_code) + message(FATAL_ERROR "Failed to download ${source_url}: ${status_message}") +endif() + +file(STRINGS "${source_path}" lines) +foreach(line ${lines}) + if ("${line}" MATCHES "^[0-9a-fA-F].*$") + set(GLFW_GAMEPAD_MAPPINGS "${GLFW_GAMEPAD_MAPPINGS}\"${line}\\n\"\n") + endif() +endforeach() + +configure_file("${template_path}" "${target_path}" @ONLY NEWLINE_STYLE UNIX) +file(REMOVE "${source_path}") + diff --git a/README.md b/README.md index 52349e486..5c5fe4737 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ information on what to include when reporting a bug. - Added `GLFW_INCLUDE_ES32` for including the OpenGL ES 3.2 header - Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with [OSMesa](https://www.mesa3d.org/osmesa.html) (#281) +- Added `GenerateMappings.cmake` script for updating gamepad mappings - Removed `GLFW_USE_RETINA` compile-time option - Removed `GLFW_USE_CHDIR` compile-time option - Removed `GLFW_USE_MENUBAR` compile-time option diff --git a/src/mappings.h b/src/mappings.h index 2141e520d..6c1b800d7 100644 --- a/src/mappings.h +++ b/src/mappings.h @@ -23,6 +23,16 @@ // distribution. // //======================================================================== +// As mappings.h.in, this file is used by CMake to produce the mappings.h +// header file. If you are adding a GLFW specific gamepad mapping, this is +// where to put it. +//======================================================================== +// As mappings.h, this provides all pre-defined gamepad mappings, including +// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad +// mappings not specific to GLFW should be submitted to SDL_GameControllerDB. +// This file can be re-generated from mappings.h.in and the upstream +// gamecontrollerdb.txt with the GenerateMappings.cmake script. +//======================================================================== // All gamepad mappings not labeled GLFW are copied from the // SDL_GameControllerDB project under the following license: @@ -220,6 +230,7 @@ const char* _glfwDefaultMappings = "03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" "05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" "03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,\n" + "78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" "78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" "78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" diff --git a/src/mappings.h.in b/src/mappings.h.in new file mode 100644 index 000000000..bf7206701 --- /dev/null +++ b/src/mappings.h.in @@ -0,0 +1,70 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// As mappings.h.in, this file is used by CMake to produce the mappings.h +// header file. If you are adding a GLFW specific gamepad mapping, this is +// where to put it. +//======================================================================== +// As mappings.h, this provides all pre-defined gamepad mappings, including +// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad +// mappings not specific to GLFW should be submitted to SDL_GameControllerDB. +// This file can be re-generated from mappings.h.in and the upstream +// gamecontrollerdb.txt with the GenerateMappings.cmake script. +//======================================================================== + +// All gamepad mappings not labeled GLFW are copied from the +// SDL_GameControllerDB project under the following license: +// +// Simple DirectMedia Layer +// Copyright (C) 1997-2013 Sam Lantinga +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +const char* _glfwDefaultMappings = +@GLFW_GAMEPAD_MAPPINGS@ +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n"; + From f30acd8f74adf0b26b18bbbf627b87d20c8c9b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 6 Sep 2017 04:30:18 +0200 Subject: [PATCH 143/222] Add OSMesa to context API list --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5c5fe4737..bc28c6987 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ guide](http://www.glfw.org/docs/latest/moving.html) for moving to the GLFW ## Compiling GLFW GLFW itself requires only the headers and libraries for your window system. It -does not need the headers for any context creation API (WGL, GLX, EGL, NSGL) or -rendering API (OpenGL, OpenGL ES, Vulkan) to enable support for them. +does not need the headers for any context creation API (WGL, GLX, EGL, NSGL, +OSMesa) or rendering API (OpenGL, OpenGL ES, Vulkan) to enable support for them. GLFW supports compilation on Windows with Visual C++ 2010 and later, MinGW and MinGW-w64, on macOS with Clang and on Linux and other Unix-like systems with GCC From f7dc6df02c9769e6d1c5cf7926481e7a831ce1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 7 Aug 2017 23:23:37 +0200 Subject: [PATCH 144/222] X11: Add support for reading clipboard via INCR This allows glfwGetClipboardString to retrieve clipboard contents larger than (typically) 2^18 bytes. Related to #275. --- README.md | 1 + src/x11_init.c | 1 + src/x11_platform.h | 1 + src/x11_window.c | 98 +++++++++++++++++++++++++++++++++++++--------- 4 files changed, 83 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index bc28c6987..93c5c2c85 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747) - [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size - [X11] Bugfix: Key name string encoding depended on current locale (#981,#983) +- [X11] Bugfix: Incremental reading of selections was not supported (#275) - [Linux] Moved to evdev for joystick input (#906,#1005) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Linux] Bugfix: The joystick device path could be truncated (#1025) diff --git a/src/x11_init.c b/src/x11_init.c index c4e84474f..baf76fa40 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -675,6 +675,7 @@ static GLFWbool initExtensions(void) _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False); + _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False); _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); // Clipboard manager atoms diff --git a/src/x11_platform.h b/src/x11_platform.h index 48d15bc92..39eaec056 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -265,6 +265,7 @@ typedef struct _GLFWlibraryX11 // Selection (clipboard) atoms Atom TARGETS; Atom MULTIPLE; + Atom INCR; Atom CLIPBOARD; Atom PRIMARY; Atom CLIPBOARD_MANAGER; diff --git a/src/x11_window.c b/src/x11_window.c index aee89d402..592a8eb75 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -164,6 +164,17 @@ static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointe event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS; } +// Returns whether it is a property event for the specified selection transfer +// +static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer pointer) +{ + XEvent* notification = (XEvent*) pointer; + return event->type == PropertyNotify && + event->xproperty.state == PropertyNewValue && + event->xproperty.window == notification->xselection.requestor && + event->xproperty.atom == notification->xselection.property; +} + // Translates a GLFW standard cursor to a font cursor shape // static int translateCursorShape(int shape) @@ -841,10 +852,10 @@ static const char* getSelectionString(Atom selection) { size_t i; char** selectionString = NULL; - const Atom formats[] = { _glfw.x11.UTF8_STRING, + const Atom targets[] = { _glfw.x11.UTF8_STRING, _glfw.x11.COMPOUND_STRING, XA_STRING }; - const size_t formatCount = sizeof(formats) / sizeof(formats[0]); + const size_t targetCount = sizeof(targets) / sizeof(targets[0]); if (selection == _glfw.x11.PRIMARY) selectionString = &_glfw.x11.primarySelectionString; @@ -862,14 +873,17 @@ static const char* getSelectionString(Atom selection) free(*selectionString); *selectionString = NULL; - for (i = 0; i < formatCount; i++) + for (i = 0; i < targetCount; i++) { char* data; - XEvent event; + Atom actualType; + int actualFormat; + unsigned long itemCount, bytesAfter; + XEvent notification, dummy; XConvertSelection(_glfw.x11.display, selection, - formats[i], + targets[i], _glfw.x11.GLFW_SELECTION, _glfw.x11.helperWindowHandle, CurrentTime); @@ -877,28 +891,76 @@ static const char* getSelectionString(Atom selection) while (!XCheckTypedWindowEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, SelectionNotify, - &event)) + ¬ification)) { waitForEvent(NULL); } - if (event.xselection.property == None) + if (notification.xselection.property == None) continue; - if (_glfwGetWindowPropertyX11(event.xselection.requestor, - event.xselection.property, - event.xselection.target, - (unsigned char**) &data)) + XCheckIfEvent(_glfw.x11.display, + &dummy, + isSelPropNewValueNotify, + (XPointer) ¬ification); + + XGetWindowProperty(_glfw.x11.display, + notification.xselection.requestor, + notification.xselection.property, + 0, + LONG_MAX, + True, + AnyPropertyType, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + (unsigned char**) &data); + + if (actualType == _glfw.x11.INCR) { - *selectionString = strdup(data); + size_t size = 1; + + for (;;) + { + while (!XCheckIfEvent(_glfw.x11.display, + &dummy, + isSelPropNewValueNotify, + (XPointer) ¬ification)) + { + waitForEvent(NULL); + } + + XFree(data); + XGetWindowProperty(_glfw.x11.display, + notification.xselection.requestor, + notification.xselection.property, + 0, + LONG_MAX, + True, + AnyPropertyType, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + (unsigned char**) &data); + + if (itemCount) + { + size += itemCount; + *selectionString = realloc(*selectionString, size); + (*selectionString)[size - itemCount - 1] = '\0'; + strcat(*selectionString, data); + } + + if (!itemCount) + break; + } } + else if (actualType == targets[i]) + *selectionString = strdup(data); - if (data) - XFree(data); - - XDeleteProperty(_glfw.x11.display, - event.xselection.requestor, - event.xselection.property); + XFree(data); if (*selectionString) break; From 9dbc935afb5b9fa8977e1d6f5c844038ece7fa73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 8 Aug 2017 14:04:51 +0200 Subject: [PATCH 145/222] X11: Stop reporting support for COMPOUND_TEXT --- README.md | 1 + src/x11_init.c | 5 +---- src/x11_window.c | 9 ++------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 93c5c2c85..4ca7a0bec 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size - [X11] Bugfix: Key name string encoding depended on current locale (#981,#983) - [X11] Bugfix: Incremental reading of selections was not supported (#275) +- [X11] Bugfix: Selection I/O reported but did not support `COMPOUND_TEXT` - [Linux] Moved to evdev for joystick input (#906,#1005) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Linux] Bugfix: The joystick device path could be truncated (#1025) diff --git a/src/x11_init.c b/src/x11_init.c index baf76fa40..6a8ba6597 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -661,10 +661,7 @@ static GLFWbool initExtensions(void) // String format atoms _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); - _glfw.x11.UTF8_STRING = - XInternAtom(_glfw.x11.display, "UTF8_STRING", False); - _glfw.x11.COMPOUND_STRING = - XInternAtom(_glfw.x11.display, "COMPOUND_STRING", False); + _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False); _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); // Custom selection property atom diff --git a/src/x11_window.c b/src/x11_window.c index 592a8eb75..a0dd81be7 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -683,9 +683,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) { int i; char* selectionString = NULL; - const Atom formats[] = { _glfw.x11.UTF8_STRING, - _glfw.x11.COMPOUND_STRING, - XA_STRING }; + const Atom formats[] = { _glfw.x11.UTF8_STRING, XA_STRING }; const int formatCount = sizeof(formats) / sizeof(formats[0]); if (request->selection == _glfw.x11.PRIMARY) @@ -707,7 +705,6 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) const Atom targets[] = { _glfw.x11.TARGETS, _glfw.x11.MULTIPLE, _glfw.x11.UTF8_STRING, - _glfw.x11.COMPOUND_STRING, XA_STRING }; XChangeProperty(_glfw.x11.display, @@ -852,9 +849,7 @@ static const char* getSelectionString(Atom selection) { size_t i; char** selectionString = NULL; - const Atom targets[] = { _glfw.x11.UTF8_STRING, - _glfw.x11.COMPOUND_STRING, - XA_STRING }; + const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING }; const size_t targetCount = sizeof(targets) / sizeof(targets[0]); if (selection == _glfw.x11.PRIMARY) From 0b5023bc6269fbca6507f246f28ad37d7d1d040e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 8 Aug 2017 16:25:13 +0200 Subject: [PATCH 146/222] X11: Fix Latin-1 text not being converted to UTF-8 --- README.md | 1 + src/x11_window.c | 155 +++++++++++++++++++++++++++++------------------ 2 files changed, 96 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 4ca7a0bec..40e9544f4 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Key name string encoding depended on current locale (#981,#983) - [X11] Bugfix: Incremental reading of selections was not supported (#275) - [X11] Bugfix: Selection I/O reported but did not support `COMPOUND_TEXT` +- [X11] Bugfix: Latin-1 text read from selections was not converted to UTF-8 - [Linux] Moved to evdev for joystick input (#906,#1005) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Linux] Bugfix: The joystick device path could be truncated (#1025) diff --git a/src/x11_window.c b/src/x11_window.c index a0dd81be7..ea49e55d0 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -460,6 +460,81 @@ static char** parseUriList(char* text, int* count) return paths; } +// Encode a Unicode code point to a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +static size_t encodeUTF8(char* s, unsigned int ch) +{ + size_t count = 0; + + if (ch < 0x80) + s[count++] = (char) ch; + else if (ch < 0x800) + { + s[count++] = (ch >> 6) | 0xc0; + s[count++] = (ch & 0x3f) | 0x80; + } + else if (ch < 0x10000) + { + s[count++] = (ch >> 12) | 0xe0; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; + } + else if (ch < 0x110000) + { + s[count++] = (ch >> 18) | 0xf0; + s[count++] = ((ch >> 12) & 0x3f) | 0x80; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; + } + + return count; +} + +// Decode a Unicode code point from a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +#if defined(X_HAVE_UTF8_STRING) +static unsigned int decodeUTF8(const char** s) +{ + unsigned int ch = 0, count = 0; + static const unsigned int offsets[] = + { + 0x00000000u, 0x00003080u, 0x000e2080u, + 0x03c82080u, 0xfa082080u, 0x82082080u + }; + + do + { + ch = (ch << 6) + (unsigned char) **s; + (*s)++; + count++; + } while ((**s & 0xc0) == 0x80); + + assert(count <= 6); + return ch - offsets[count - 1]; +} +#endif /*X_HAVE_UTF8_STRING*/ + +// Convert the specified Latin-1 string to UTF-8 +// +static char* convertLatin1toUTF8(const char* source) +{ + size_t size = 1; + const char* sp; + + for (sp = source; *sp; sp++) + size += (*sp & 0x80) ? 2 : 1; + + char* target = calloc(size, 1); + char* tp = target; + + for (sp = source; *sp; sp++) + tp += encodeUTF8(tp, *sp); + + return target; +} + // Centers the cursor over the window client area // static void centerCursor(_GLFWwindow* window) @@ -915,6 +990,7 @@ static const char* getSelectionString(Atom selection) if (actualType == _glfw.x11.INCR) { size_t size = 1; + char* string = NULL; for (;;) { @@ -943,17 +1019,32 @@ static const char* getSelectionString(Atom selection) if (itemCount) { size += itemCount; - *selectionString = realloc(*selectionString, size); - (*selectionString)[size - itemCount - 1] = '\0'; - strcat(*selectionString, data); + string = realloc(string, size); + string[size - itemCount - 1] = '\0'; + strcat(string, data); } if (!itemCount) + { + if (targets[i] == XA_STRING) + { + *selectionString = convertLatin1toUTF8(string); + free(string); + } + else + *selectionString = string; + break; + } } } else if (actualType == targets[i]) - *selectionString = strdup(data); + { + if (targets[i] == XA_STRING) + *selectionString = convertLatin1toUTF8(data); + else + *selectionString = strdup(data); + } XFree(data); @@ -1035,62 +1126,6 @@ static void releaseMonitor(_GLFWwindow* window) } } -// Encode a Unicode code point to a UTF-8 stream -// Based on cutef8 by Jeff Bezanson (Public Domain) -// -static size_t encodeUTF8(char* s, unsigned int ch) -{ - size_t count = 0; - - if (ch < 0x80) - s[count++] = (char) ch; - else if (ch < 0x800) - { - s[count++] = (ch >> 6) | 0xc0; - s[count++] = (ch & 0x3f) | 0x80; - } - else if (ch < 0x10000) - { - s[count++] = (ch >> 12) | 0xe0; - s[count++] = ((ch >> 6) & 0x3f) | 0x80; - s[count++] = (ch & 0x3f) | 0x80; - } - else if (ch < 0x110000) - { - s[count++] = (ch >> 18) | 0xf0; - s[count++] = ((ch >> 12) & 0x3f) | 0x80; - s[count++] = ((ch >> 6) & 0x3f) | 0x80; - s[count++] = (ch & 0x3f) | 0x80; - } - - return count; -} - -// Decode a Unicode code point from a UTF-8 stream -// Based on cutef8 by Jeff Bezanson (Public Domain) -// -#if defined(X_HAVE_UTF8_STRING) -static unsigned int decodeUTF8(const char** s) -{ - unsigned int ch = 0, count = 0; - static const unsigned int offsets[] = - { - 0x00000000u, 0x00003080u, 0x000e2080u, - 0x03c82080u, 0xfa082080u, 0x82082080u - }; - - do - { - ch = (ch << 6) + (unsigned char) **s; - (*s)++; - count++; - } while ((**s & 0xc0) == 0x80); - - assert(count <= 6); - return ch - offsets[count - 1]; -} -#endif /*X_HAVE_UTF8_STRING*/ - // Process the specified X event // static void processEvent(XEvent *event) From 3d110d2e1bc5994b90531feada3bd8552959d1c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 17 Sep 2017 13:54:17 +0200 Subject: [PATCH 147/222] X11: Fix selection error nomenclature [ci skip] --- src/x11_window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11_window.c b/src/x11_window.c index ea49e55d0..e07fea779 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1055,7 +1055,7 @@ static const char* getSelectionString(Atom selection) if (!*selectionString) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, - "X11: Failed to convert clipboard to string"); + "X11: Failed to convert selection to string"); } return *selectionString; From e3be6b8ae0d8b1701f00288c1b3db9959e2dc168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 17 Sep 2017 14:39:17 +0200 Subject: [PATCH 148/222] Cleanup Break up some overly long lines. --- src/cocoa_init.m | 8 +++++--- src/cocoa_joystick.m | 7 +++++-- src/cocoa_monitor.m | 17 ++++++++++++++--- src/mir_window.c | 3 ++- src/win32_init.c | 9 ++++++--- src/win32_joystick.c | 40 ++++++++++++++++++++++++++-------------- src/win32_window.c | 3 ++- src/wl_window.c | 3 ++- src/x11_init.c | 4 ++-- src/x11_window.c | 31 +++++++++++++++++++------------ 10 files changed, 83 insertions(+), 42 deletions(-) diff --git a/src/cocoa_init.m b/src/cocoa_init.m index dfc35b6ff..01a746bae 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -215,8 +215,9 @@ static GLFWbool updateUnicodeDataNS(void) return GLFW_FALSE; } - _glfw.ns.unicodeData = TISGetInputSourceProperty(_glfw.ns.inputSource, - kTISPropertyUnicodeKeyLayoutData); + _glfw.ns.unicodeData = + TISGetInputSourceProperty(_glfw.ns.inputSource, + kTISPropertyUnicodeKeyLayoutData); if (!_glfw.ns.unicodeData) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -232,7 +233,8 @@ static GLFWbool updateUnicodeDataNS(void) static GLFWbool initializeTIS(void) { // This works only because Cocoa has already loaded it properly - _glfw.ns.tis.bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); + _glfw.ns.tis.bundle = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); if (!_glfw.ns.tis.bundle) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 05745720e..3a5751ef0 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -73,7 +73,9 @@ static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element) // Comparison function for matching the SDL element order // -static CFComparisonResult compareElements(const void* fp, const void* sp, void* user) +static CFComparisonResult compareElements(const void* fp, + const void* sp, + void* user) { const _GLFWjoyelementNS* fe = fp; const _GLFWjoyelementNS* se = sp; @@ -183,7 +185,8 @@ static void matchCallback(void* context, for (i = 0; i < CFArrayGetCount(elements); i++) { - IOHIDElementRef native = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i); + IOHIDElementRef native = (IOHIDElementRef) + CFArrayGetValueAtIndex(elements, i); if (CFGetTypeID(native) != IOHIDElementGetTypeID()) continue; diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index 41a6cff07..6020599fd 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -54,7 +54,8 @@ static char* getDisplayName(CGDirectDisplayID displayID) while ((service = IOIteratorNext(it)) != 0) { - info = IODisplayCreateInfoDictionary(service, kIODisplayOnlyPreferredName); + info = IODisplayCreateInfoDictionary(service, + kIODisplayOnlyPreferredName); CFNumberRef vendorIDRef = CFDictionaryGetValue(info, CFSTR(kDisplayVendorID)); @@ -185,7 +186,13 @@ static CGDisplayFadeReservationToken beginFadeReservation(void) CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess) - CGDisplayFade(token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE); + { + CGDisplayFade(token, 0.3, + kCGDisplayBlendNormal, + kCGDisplayBlendSolidColor, + 0.0, 0.0, 0.0, + TRUE); + } return token; } @@ -196,7 +203,11 @@ static void endFadeReservation(CGDisplayFadeReservationToken token) { if (token != kCGDisplayFadeReservationInvalidToken) { - CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE); + CGDisplayFade(token, 0.5, + kCGDisplayBlendSolidColor, + kCGDisplayBlendNormal, + 0.0, 0.0, 0.0, + FALSE); CGReleaseDisplayFadeReservation(token); } } diff --git a/src/mir_window.c b/src/mir_window.c index 3e8d5c5bf..4ed71f971 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -869,7 +869,8 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { - PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR = + PFN_vkGetPhysicalDeviceMirPresentationSupportKHR + vkGetPhysicalDeviceMirPresentationSupportKHR = (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"); if (!vkGetPhysicalDeviceMirPresentationSupportKHR) diff --git a/src/win32_init.c b/src/win32_init.c index 5a287076c..60c974224 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -30,7 +30,8 @@ #include #include -static const GUID _glfw_GUID_DEVINTERFACE_HID = {0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}}; +static const GUID _glfw_GUID_DEVINTERFACE_HID = + {0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}}; #define GUID_DEVINTERFACE_HID _glfw_GUID_DEVINTERFACE_HID @@ -68,7 +69,8 @@ static GLFWbool loadLibraries(void) _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll"); if (!_glfw.win32.winmm.instance) { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to load winmm.dll"); + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to load winmm.dll"); return GLFW_FALSE; } @@ -78,7 +80,8 @@ static GLFWbool loadLibraries(void) _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); if (!_glfw.win32.user32.instance) { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to load user32.dll"); + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to load user32.dll"); return GLFW_FALSE; } diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 394d371a5..6da81f7ad 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -50,16 +50,26 @@ typedef struct _GLFWobjenumWin32 // Define local copies of the necessary GUIDs // -static const GUID _glfw_IID_IDirectInput8W = {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}}; -static const GUID _glfw_GUID_XAxis = {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_YAxis = {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_ZAxis = {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_RxAxis = {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_RyAxis = {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_RzAxis = {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_Slider = {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_Button = {0xa36d02f0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_POV = {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_IID_IDirectInput8W = + {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}}; +static const GUID _glfw_GUID_XAxis = + {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_YAxis = + {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_ZAxis = + {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RxAxis = + {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RyAxis = + {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RzAxis = + {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_Slider = + {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_Button = + {0xa36d02f0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_POV = + {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; #define IID_IDirectInput8W _glfw_IID_IDirectInput8W #define GUID_XAxis _glfw_GUID_XAxis @@ -345,10 +355,12 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (!_glfw.joysticks[jid].present) - continue; - if (memcmp(&_glfw.joysticks[jid].win32.guid, &di->guidInstance, sizeof(GUID)) == 0) - return DIENUM_CONTINUE; + _GLFWjoystick* js = _glfw.joysticks + jid; + if (js->present) + { + if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0) + return DIENUM_CONTINUE; + } } if (supportsXInput(&di->guidProduct)) diff --git a/src/win32_window.c b/src/win32_window.c index aa7efc843..30d1932a9 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1798,7 +1798,8 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { - PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR + vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); if (!vkGetPhysicalDeviceWin32PresentationSupportKHR) diff --git a/src/wl_window.c b/src/wl_window.c index fbd58ffbe..6c974dfd3 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1019,7 +1019,8 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { - PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = + PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR + vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR) diff --git a/src/x11_init.c b/src/x11_init.c index 6a8ba6597..9f94cc5f6 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -237,8 +237,8 @@ static void createKeyTables(void) if (_glfw.x11.xkb.available) { - // Use XKB to determine physical key locations independently of the current - // keyboard layout + // Use XKB to determine physical key locations independently of the + // current keyboard layout char name[XkbKeyNameLength + 1]; XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); diff --git a/src/x11_window.c b/src/x11_window.c index e07fea779..26ea0897f 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1263,8 +1263,10 @@ static void processEvent(XEvent *event) count = XwcLookupString(window->x11.ic, &event->xkey, - buffer, sizeof(buffer) / sizeof(wchar_t), - NULL, &status); + buffer, + sizeof(buffer) / sizeof(wchar_t), + NULL, + &status); if (status == XBufferOverflow) { @@ -1437,7 +1439,8 @@ static void processEvent(XEvent *event) const int x = event->xmotion.x; const int y = event->xmotion.y; - if (x != window->x11.warpCursorPosX || y != window->x11.warpCursorPosY) + if (x != window->x11.warpCursorPosX || + y != window->x11.warpCursorPosY) { // The cursor was moved by something other than GLFW @@ -1516,14 +1519,15 @@ static void processEvent(XEvent *event) if (protocol == _glfw.x11.WM_DELETE_WINDOW) { - // The window manager was asked to close the window, for example by - // the user pressing a 'close' window decoration button + // The window manager was asked to close the window, for + // example by the user pressing a 'close' window decoration + // button _glfwInputWindowCloseRequest(window); } else if (protocol == _glfw.x11.NET_WM_PING) { - // The window manager is pinging the application to ensure it's - // still responding to events + // The window manager is pinging the application to ensure + // it's still responding to events XEvent reply = *event; reply.xclient.window = _glfw.x11.root; @@ -1865,9 +1869,10 @@ void _glfwPushSelectionToManagerX11(void) { if (event.xselection.target == _glfw.x11.SAVE_TARGETS) { - // This means one of two things; either the selection was - // not owned, which means there is no clipboard manager, or - // the transfer to the clipboard manager has completed + // This means one of two things; either the selection + // was not owned, which means there is no clipboard + // manager, or the transfer to the clipboard manager has + // completed // In either case, it means we are done here return; } @@ -2787,7 +2792,8 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) { - PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = + PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR + vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); if (!vkGetPhysicalDeviceXcbPresentationSupportKHR) @@ -2812,7 +2818,8 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, } else { - PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = + PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR + vkGetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) From f4fb25b63df16c8a6d87077d176e7fe1c80c04d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 17 Sep 2017 16:06:02 +0200 Subject: [PATCH 149/222] X11: Fix init order breaking cursor hiding The hidden cursor was created before Xcursor was loaded. --- src/x11_init.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 9f94cc5f6..3bf07d2d5 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -860,12 +860,13 @@ int _glfwPlatformInit(void) _glfw.x11.screen = DefaultScreen(_glfw.x11.display); _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); _glfw.x11.context = XUniqueContext(); - _glfw.x11.helperWindowHandle = createHelperWindow(); - _glfw.x11.hiddenCursorHandle = createHiddenCursor(); if (!initExtensions()) return GLFW_FALSE; + _glfw.x11.helperWindowHandle = createHelperWindow(); + _glfw.x11.hiddenCursorHandle = createHiddenCursor(); + if (XSupportsLocale()) { XSetLocaleModifiers(""); From 176ab9a5d273e117bd2b9301430c67fd2125e942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 24 Sep 2017 17:04:47 +0200 Subject: [PATCH 150/222] Fix Doxyfile gen not handling paths with spaces Fixes #1081. --- README.md | 1 + docs/CMakeLists.txt | 2 +- docs/Doxyfile.in | 14 +++++++------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 40e9544f4..dbdafe007 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,7 @@ information on what to include when reporting a bug. `vkGetInstanceProcAddr` when `_GLFW_VULKAN_STATIC` was enabled - Bugfix: Invalid library paths were used in test and example CMake files (#930) - Bugfix: The scancode for synthetic key release events was always zero +- Bugfix: The generated Doxyfile did not handle paths with spaces (#1081) - [Win32] Added system error strings to relevant GLFW error descriptions (#733) - [Win32] Moved to `WM_INPUT` for disabled cursor mode motion input (#125) - [Win32] Removed XInput circular deadzone from joystick axis data (#1045) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index b3034dfb3..20d85ae9c 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -23,7 +23,7 @@ if (GLFW_DOCUMENT_INTERNALS) endif() foreach(arg ${glfw_DOCS_SOURCES}) - set(GLFW_DOCS_SOURCES "${GLFW_DOCS_SOURCES} ${arg}") + set(GLFW_DOCS_SOURCES "${GLFW_DOCS_SOURCES} \\\n\"${arg}\"") endforeach() configure_file(Doxyfile.in Doxyfile @ONLY) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 9bbd9245f..c2069c5ca 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -52,7 +52,7 @@ PROJECT_LOGO = # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. -OUTPUT_DIRECTORY = @GLFW_BINARY_DIR@/docs +OUTPUT_DIRECTORY = "@GLFW_BINARY_DIR@/docs" # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output @@ -651,7 +651,7 @@ WARN_FORMAT = "$file:$line: $text" # and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = @GLFW_BINARY_DIR@/docs/warnings.txt +WARN_LOGFILE = "@GLFW_BINARY_DIR@/docs/warnings.txt" #--------------------------------------------------------------------------- # configuration options related to the input files @@ -722,7 +722,7 @@ EXCLUDE_SYMBOLS = APIENTRY GLFWAPI # directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = @GLFW_SOURCE_DIR@/examples +EXAMPLE_PATH = "@GLFW_SOURCE_DIR@/examples" # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp @@ -898,13 +898,13 @@ HTML_FILE_EXTENSION = .html # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! -HTML_HEADER = @GLFW_SOURCE_DIR@/docs/header.html +HTML_HEADER = "@GLFW_SOURCE_DIR@/docs/header.html" # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. -HTML_FOOTER = @GLFW_SOURCE_DIR@/docs/footer.html +HTML_FOOTER = "@GLFW_SOURCE_DIR@/docs/footer.html" # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to @@ -923,7 +923,7 @@ HTML_STYLESHEET = # robust against future updates. Doxygen will copy the style sheet file to # the output directory. -HTML_EXTRA_STYLESHEET = @GLFW_SOURCE_DIR@/docs/extra.css +HTML_EXTRA_STYLESHEET = "@GLFW_SOURCE_DIR@/docs/extra.css" # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -932,7 +932,7 @@ HTML_EXTRA_STYLESHEET = @GLFW_SOURCE_DIR@/docs/extra.css # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. -HTML_EXTRA_FILES = @GLFW_SOURCE_DIR@/docs/spaces.svg +HTML_EXTRA_FILES = "@GLFW_SOURCE_DIR@/docs/spaces.svg" # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images From 25b7eba4a02ec15883d82e370a7479c4f8de6da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 29 Aug 2017 20:05:44 +0200 Subject: [PATCH 151/222] Win32: Clean up dynamic loading and version checks --- src/win32_init.c | 14 +++++++------- src/win32_platform.h | 36 ++++++++++++++++++++++++++++++------ src/win32_window.c | 14 +++++++------- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/win32_init.c b/src/win32_init.c index 60c974224..7a8ee2086 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -85,9 +85,9 @@ static GLFWbool loadLibraries(void) return GLFW_FALSE; } - _glfw.win32.user32.SetProcessDPIAware = (PFN_SetProcessDPIAware) + _glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware) GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); - _glfw.win32.user32.ChangeWindowMessageFilterEx = (PFN_ChangeWindowMessageFilterEx) + _glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx) GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); @@ -136,7 +136,7 @@ static GLFWbool loadLibraries(void) _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); if (_glfw.win32.shcore.instance) { - _glfw.win32.shcore.SetProcessDpiAwareness = (PFN_SetProcessDpiAwareness) + _glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness) GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); } @@ -507,10 +507,10 @@ int _glfwPlatformInit(void) createKeyTables(); _glfwUpdateKeyNamesWin32(); - if (_glfw_SetProcessDpiAwareness) - _glfw_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); - else if (_glfw_SetProcessDPIAware) - _glfw_SetProcessDPIAware(); + if (IsWindows8Point1OrGreater()) + SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + else if (IsWindowsVistaOrGreater()) + SetProcessDPIAware(); if (!_glfwRegisterWindowClassWin32()) return GLFW_FALSE; diff --git a/src/win32_platform.h b/src/win32_platform.h index 63aaa94dc..e829799d7 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -122,6 +122,30 @@ typedef enum PROCESS_DPI_AWARENESS } PROCESS_DPI_AWARENESS; #endif /*DPI_ENUMS_DECLARED*/ +// HACK: Define versionhelpers.h functions manually as MinGW lacks the header +FORCEINLINE BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp }; + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; + ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + return VerifyVersionInfoW(&osvi, mask, cond); +} + +#define IsWindowsVistaOrGreater() \ + IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), \ + LOBYTE(_WIN32_WINNT_VISTA), 0) +#define IsWindows7OrGreater() \ + IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), \ + LOBYTE(_WIN32_WINNT_WIN7), 0) +#define IsWindows8OrGreater() \ + IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), \ + LOBYTE(_WIN32_WINNT_WIN8), 0) +#define IsWindows8Point1OrGreater() \ + IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), \ + LOBYTE(_WIN32_WINNT_WINBLUE), 0) + // HACK: Define macros that some xinput.h variants don't #ifndef XINPUT_CAPS_WIRELESS #define XINPUT_CAPS_WIRELESS 0x0002 @@ -173,8 +197,8 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID* // user32.dll function pointer typedefs typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); -#define _glfw_SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware -#define _glfw_ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx +#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ +#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); @@ -184,7 +208,7 @@ typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); -#define _glfw_SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness +#define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_ typedef VkFlags VkWin32SurfaceCreateFlagsKHR; @@ -278,8 +302,8 @@ typedef struct _GLFWlibraryWin32 struct { HINSTANCE instance; - PFN_SetProcessDPIAware SetProcessDPIAware; - PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx; + PFN_SetProcessDPIAware SetProcessDPIAware_; + PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_; } user32; struct { @@ -290,7 +314,7 @@ typedef struct _GLFWlibraryWin32 struct { HINSTANCE instance; - PFN_SetProcessDpiAwareness SetProcessDpiAwareness; + PFN_SetProcessDpiAwareness SetProcessDpiAwareness_; } shcore; } _GLFWlibraryWin32; diff --git a/src/win32_window.c b/src/win32_window.c index 30d1932a9..9ce9e4361 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1039,14 +1039,14 @@ static int createNativeWindow(_GLFWwindow* window, SetPropW(window->win32.handle, L"GLFW", window); - if (_glfw_ChangeWindowMessageFilterEx) + if (IsWindows7OrGreater()) { - _glfw_ChangeWindowMessageFilterEx(window->win32.handle, - WM_DROPFILES, MSGFLT_ALLOW, NULL); - _glfw_ChangeWindowMessageFilterEx(window->win32.handle, - WM_COPYDATA, MSGFLT_ALLOW, NULL); - _glfw_ChangeWindowMessageFilterEx(window->win32.handle, - WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); + ChangeWindowMessageFilterEx(window->win32.handle, + WM_DROPFILES, MSGFLT_ALLOW, NULL); + ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYDATA, MSGFLT_ALLOW, NULL); + ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } DragAcceptFiles(window->win32.handle, TRUE); From eed94448fde4da0b494865163b9e9eda5361e031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 19 Sep 2017 14:12:15 +0200 Subject: [PATCH 152/222] Win32: Remove unused GUID --- src/win32_joystick.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 6da81f7ad..ad2dbb2f1 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -66,8 +66,6 @@ static const GUID _glfw_GUID_RzAxis = {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_Slider = {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; -static const GUID _glfw_GUID_Button = - {0xa36d02f0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_POV = {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; @@ -79,7 +77,6 @@ static const GUID _glfw_GUID_POV = #define GUID_RyAxis _glfw_GUID_RyAxis #define GUID_RzAxis _glfw_GUID_RzAxis #define GUID_Slider _glfw_GUID_Slider -#define GUID_Button _glfw_GUID_Button #define GUID_POV _glfw_GUID_POV // Object data array for our clone of c_dfDIJoystick From 019609b6cdf3e92aa10c368c8351df958415987e Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Mon, 22 Feb 2016 18:08:15 +0100 Subject: [PATCH 153/222] Add GLFW_TRANSPARENT and X11 implementation This is a squashed extract of several commits, minimally edited to ensure it compiles. Related to #197. Related to #715. --- examples/gears.c | 3 +++ include/GLFW/glfw3.h | 1 + src/egl_context.c | 49 +++++++++++++++++++++++++++++++++++++++----- src/egl_context.h | 3 ++- src/glx_context.c | 46 ++++++++++++++++++++++++++++++++++++----- src/glx_context.h | 4 ++-- src/internal.h | 2 ++ src/window.c | 7 +++++++ src/x11_init.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ src/x11_platform.h | 28 ++++++++++++++++++++++++- src/x11_window.c | 4 ++-- 11 files changed, 180 insertions(+), 16 deletions(-) diff --git a/examples/gears.c b/examples/gears.c index a787baedf..f7526e05f 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -172,6 +172,7 @@ static GLfloat angle = 0.f; /* OpenGL draw function & timing */ static void draw(void) { + glClearColor(0., 0., 0., 0.); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); @@ -311,6 +312,8 @@ int main(int argc, char *argv[]) } glfwWindowHint(GLFW_DEPTH_BITS, 16); + glfwWindowHint(GLFW_ALPHA_BITS, 8); + glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); if (!window) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 05e76a9ae..58b7d7b91 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -787,6 +787,7 @@ extern "C" { * Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint). */ #define GLFW_CENTER_CURSOR 0x00020009 +#define GLFW_TRANSPARENT 0x0002000A /*! @brief Framebuffer bit depth hint. * diff --git a/src/egl_context.c b/src/egl_context.c index 54257f25d..e5435468c 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -87,13 +87,21 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib) // static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* desired, - EGLConfig* result) + EGLConfig* result, + GLFWbool findTransparent) { EGLConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; int i, nativeCount, usableCount; +#if defined(_GLFW_X11) + XVisualInfo visualTemplate = {0}; + if ( !(_glfw.xrender.major || _glfw.xrender.minor) ) { + findTransparent = GLFW_FALSE; + } +#endif // _GLFW_X11 + eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); if (!nativeCount) { @@ -107,6 +115,7 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; +selectionloop: for (i = 0; i < nativeCount; i++) { const EGLConfig n = nativeConfigs[i]; @@ -122,8 +131,31 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, #if defined(_GLFW_X11) // Only consider EGLConfigs with associated Visuals - if (!getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID)) + visualTemplate.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!visualTemplate.visualid) continue; + + if( findTransparent ) { + int n_vi; + XVisualInfo *visualinfo; + XRenderPictFormat *pictFormat; + + visualinfo = XGetVisualInfo(_glfw.x11.display, VisualIDMask, &visualTemplate, &n_vi); + if (!visualinfo) + continue; + + pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); + if( !pictFormat ) { + XFree( visualinfo ); + continue; + } + + if( !pictFormat->direct.alphaMask ) { + XFree( visualinfo ); + continue; + } + XFree( visualinfo ); + } #endif // _GLFW_X11 if (ctxconfig->client == GLFW_OPENGL_ES_API) @@ -159,6 +191,12 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, u->handle = (uintptr_t) n; usableCount++; } + // reiterate the selection loop without looking for transparency supporting + // formats if no matchig FB configs for a transparent window were found. + if( findTransparent && !usableCount ) { + findTransparent = GLFW_FALSE; + goto selectionloop; + } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) @@ -455,7 +493,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.egl.handle; - if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &config, window->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); @@ -689,7 +727,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, // Returns the Visual and depth of the chosen EGLConfig // #if defined(_GLFW_X11) -GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, +GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { @@ -699,7 +738,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, EGLint visualID = 0, count = 0; const long vimask = VisualScreenMask | VisualIDMask; - if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &native, wndconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); diff --git a/src/egl_context.h b/src/egl_context.h index bfab5111f..aa339baac 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -211,7 +211,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #if defined(_GLFW_X11) -GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, +GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); #endif /*_GLFW_X11*/ diff --git a/src/glx_context.c b/src/glx_context.c index e545fa0fe..9d02a6fab 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -47,7 +47,10 @@ static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) // Return the GLXFBConfig most closely matching the specified hints // -static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result) +static GLFWbool chooseGLXFBConfig( + const _GLFWfbconfig* desired, + GLXFBConfig* result, + GLFWbool findTransparent) { GLXFBConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; @@ -56,6 +59,10 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; + if ( !(_glfw.xrender.major || _glfw.xrender.minor) ) { + findTransparent = GLFW_FALSE; + } + // HACK: This is a (hopefully temporary) workaround for Chromium // (VirtualBox GL) not setting the window bit on any GLXFBConfigs vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); @@ -73,6 +80,7 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; +selectionloop: for (i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; @@ -89,6 +97,27 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res continue; } + if( findTransparent ) { + XVisualInfo *visualinfo; + XRenderPictFormat *pictFormat; + + visualinfo = glXGetVisualFromFBConfig(_glfw.x11.display, n); + if (!visualinfo) + continue; + + pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); + if( !pictFormat ) { + XFree( visualinfo ); + continue; + } + + if( !pictFormat->direct.alphaMask ) { + XFree( visualinfo ); + continue; + } + XFree( visualinfo ); + } + u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); @@ -118,6 +147,12 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res u->handle = (uintptr_t) n; usableCount++; } + // reiterate the selection loop without looking for transparency supporting + // formats if no matchig FB configs for a transparent window were found. + if( findTransparent && !usableCount ) { + findTransparent = GLFW_FALSE; + goto selectionloop; + } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) @@ -442,7 +477,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.glx.handle; - if (!chooseGLXFBConfig(fbconfig, &native)) + if (!chooseGLXFBConfig(fbconfig, &native, window->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -622,14 +657,15 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, // Returns the Visual and depth of the chosen GLXFBConfig // -GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, +GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { GLXFBConfig native; XVisualInfo* result; - if (!chooseGLXFBConfig(fbconfig, &native)) + if (!chooseGLXFBConfig(fbconfig, &native, wndconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -645,7 +681,7 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, } *visual = result->visual; - *depth = result->depth; + *depth = result->depth; XFree(result); return GLFW_TRUE; diff --git a/src/glx_context.h b/src/glx_context.h index 30743c112..f767cb141 100644 --- a/src/glx_context.h +++ b/src/glx_context.h @@ -168,14 +168,14 @@ typedef struct _GLFWlibraryGLX } _GLFWlibraryGLX; - GLFWbool _glfwInitGLX(void); void _glfwTerminateGLX(void); GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextGLX(_GLFWwindow* window); -GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, +GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); diff --git a/src/internal.h b/src/internal.h index a95d1f867..01517ec16 100644 --- a/src/internal.h +++ b/src/internal.h @@ -299,6 +299,7 @@ struct _GLFWwndconfig GLFWbool resizable; GLFWbool visible; GLFWbool decorated; + GLFWbool transparent; GLFWbool focused; GLFWbool autoIconify; GLFWbool floating; @@ -402,6 +403,7 @@ struct _GLFWwindow // Window settings and state GLFWbool resizable; GLFWbool decorated; + GLFWbool transparent; GLFWbool autoIconify; GLFWbool floating; GLFWbool shouldClose; diff --git a/src/window.c b/src/window.c index 5c33217de..e8a68b61a 100644 --- a/src/window.c +++ b/src/window.c @@ -180,6 +180,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->monitor = (_GLFWmonitor*) monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; + window->transparent = wndconfig.transparent; window->autoIconify = wndconfig.autoIconify; window->floating = wndconfig.floating; window->cursorMode = GLFW_CURSOR_NORMAL; @@ -249,6 +250,7 @@ void glfwDefaultWindowHints(void) _glfw.hints.window.resizable = GLFW_TRUE; _glfw.hints.window.visible = GLFW_TRUE; _glfw.hints.window.decorated = GLFW_TRUE; + _glfw.hints.window.transparent = GLFW_FALSE; _glfw.hints.window.focused = GLFW_TRUE; _glfw.hints.window.autoIconify = GLFW_TRUE; @@ -327,6 +329,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_DECORATED: _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; return; + case GLFW_TRANSPARENT: + _glfw.hints.window.transparent = value ? GLFW_TRUE : GLFW_FALSE; + return; case GLFW_FOCUSED: _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; return; @@ -728,6 +733,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->resizable; case GLFW_DECORATED: return window->decorated; + case GLFW_TRANSPARENT: + return window->transparent; case GLFW_FLOATING: return window->floating; case GLFW_AUTO_ICONIFY: diff --git a/src/x11_init.c b/src/x11_init.c index 3bf07d2d5..195c8ce4f 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -717,6 +717,55 @@ static GLFWbool initExtensions(void) _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + int i; + const char* sonames_xrender[] = + { +#if defined(__CYGWIN__) + "libXrender-1.so", +#else + "libXrender.so.1", + "libXrender.so", +#endif + NULL + }; + + // Xrender support is optional and not a requirement for GLX/EGL + // to work. Xrender is required for selecting a FB config that + // supports a picture format with an alpha mask, which in turn + // is required for transparent windows. I Xrender is not supported + // the GLFW_TRANSPARENT window hint is ignored. + for (i = 0; sonames_xrender[i]; i++) + { + _glfw.xrender.handle = dlopen(sonames_xrender[i], RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.xrender.handle) + break; + } + _glfw.xrender.errorBase = 0; + _glfw.xrender.eventBase = 0; + _glfw.xrender.major = 0; + _glfw.xrender.minor = 0; + if (_glfw.xrender.handle) do { + int errorBase, eventBase, major, minor; + _glfw.xrender.QueryExtension = + dlsym(_glfw.xrender.handle, "XRenderQueryExtension"); + _glfw.xrender.QueryVersion = + dlsym(_glfw.xrender.handle, "XRenderQueryVersion"); + _glfw.xrender.FindVisualFormat = + dlsym(_glfw.xrender.handle, "XRenderFindVisualFormat"); + + if ( !XRenderQueryExtension(_glfw.x11.display, &errorBase, &eventBase)) { + break; + } + if ( !XRenderQueryVersion(_glfw.x11.display, &major, &minor)) { + break; + } + + _glfw.xrender.errorBase = errorBase; + _glfw.xrender.eventBase = eventBase; + _glfw.xrender.major = major; + _glfw.xrender.minor = minor; + } while(0); + return GLFW_TRUE; } diff --git a/src/x11_platform.h b/src/x11_platform.h index 39eaec056..9890f7034 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -162,10 +162,20 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 -#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 ; _GLFWlibraryXrender xrender #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11 +// libXrender.so function pointer typedefs +typedef Bool (*PFNXRENDERQUERYEXTENSIONPROC)(Display*,int*,int*); +typedef Status (*PFNXRENDERQUERYVERSIONPROC)(Display*dpy,int*,int*); +typedef XRenderPictFormat* (*PFNXRENDERFINDVISUALFORMATPROC)(Display*,Visual const *); + +// libXrender.so function identifier overlays +#define XRenderQueryExtension _glfw.xrender.QueryExtension +#define XRenderQueryVersion _glfw.xrender.QueryVersion +#define XRenderFindVisualFormat _glfw.xrender.FindVisualFormat + // X11-specific per-window data // @@ -375,6 +385,22 @@ typedef struct _GLFWlibraryX11 } _GLFWlibraryX11; +// Xrender-specific global data +typedef struct _GLFWlibraryXrender +{ + int major, minor; + int eventBase; + int errorBase; + + // dlopen handle for libGL.so.1 + void* handle; + + // Xrender functions (subset required for transparent window) + PFNXRENDERQUERYEXTENSIONPROC QueryExtension; + PFNXRENDERQUERYVERSIONPROC QueryVersion; + PFNXRENDERFINDVISUALFORMATPROC FindVisualFormat; +} _GLFWlibraryXrender; + // X11-specific per-monitor data // typedef struct _GLFWmonitorX11 diff --git a/src/x11_window.c b/src/x11_window.c index 26ea0897f..3addee6ca 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1905,14 +1905,14 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, { if (!_glfwInitGLX()) return GLFW_FALSE; - if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth)) + if (!_glfwChooseVisualGLX(wndconfig, ctxconfig, fbconfig, &visual, &depth)) return GLFW_FALSE; } else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) { if (!_glfwInitEGL()) return GLFW_FALSE; - if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) + if (!_glfwChooseVisualEGL(wndconfig, ctxconfig, fbconfig, &visual, &depth)) return GLFW_FALSE; } else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) From 51f0cd3b510b90237236dfc46a9afe61b8713925 Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Tue, 23 Feb 2016 23:40:22 -0500 Subject: [PATCH 154/222] Win32: Implement GLFW_TRANSPARENT This is a squashed extract of several commits, minimally edited to ensure it compiles. Related to #197. Related to #723. --- src/wgl_context.c | 102 +++++++++++++++++++++++++++++++++++++++++-- src/win32_init.c | 2 + src/win32_platform.h | 16 +++++++ 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/src/wgl_context.c b/src/wgl_context.c index 1f2b12a50..990eb2992 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -83,6 +83,20 @@ static int choosePixelFormat(_GLFWwindow* window, { const int n = i + 1; _GLFWfbconfig* u = usableConfigs + usableCount; + PIXELFORMATDESCRIPTOR pfd; + + if (window->transparent) { + if (!DescribePixelFormat(window->context.wgl.dc, + n, + sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) + continue; + } if (_glfw.wgl.ARB_pixel_format) { @@ -152,11 +166,9 @@ static int choosePixelFormat(_GLFWwindow* window, } else { - PIXELFORMATDESCRIPTOR pfd; - // Get pixel format attributes through legacy PFDs - if (!DescribePixelFormat(window->context.wgl.dc, + if (!window->transparent && DescribePixelFormat(window->context.wgl.dc, n, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) @@ -203,6 +215,15 @@ static int choosePixelFormat(_GLFWwindow* window, u->handle = n; usableCount++; } + // Reiterate the selection loop without looking for transparency supporting + // formats if no matching pixelformat for a transparent window were found. + if (window->transparent && !usableCount) { + window->transparent = GLFW_FALSE; + free(usableConfigs); + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: No pixel format found for transparent window. Ignoring transparency."); + return choosePixelFormat(window, ctxconfig, fbconfig); + } if (!usableCount) { @@ -484,6 +505,75 @@ void _glfwTerminateWGL(void) attribs[index++] = v; \ } +static GLFWbool setupTransparentWindow(_GLFWwindow* window) +{ + if (!isCompositionEnabled) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Composition needed for transparent window is disabled"); + } + if (!_glfw_DwmEnableBlurBehindWindow) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Unable to load DwmEnableBlurBehindWindow required for transparent window"); + return GLFW_FALSE; + } + + HRESULT hr = S_OK; + HWND handle = window->win32.handle; + + DWM_BLURBEHIND bb = { 0 }; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); // makes the window transparent + bb.fEnable = TRUE; + hr = _glfw_DwmEnableBlurBehindWindow(handle, &bb); + + if (!SUCCEEDED(hr)) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to enable blur behind window required for transparent window"); + return GLFW_FALSE; + } + + // Decorated windows on Windows 8+ don't repaint the transparent background + // leaving a trail behind animations. + // Hack: making the window layered with a transparency color key seems to fix this. + // Normally, when specifying a transparency color key to be used when composing + // the layered window, all pixels painted by the window in this color will be transparent. + // That doesn't seem to be the case anymore on Windows 8+, at least when used with + // DwmEnableBlurBehindWindow + negative region. + if (window->decorated && IsWindows8OrGreater()) + { + long style = GetWindowLong(handle, GWL_EXSTYLE); + if (!style) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve extended styles. GetLastError: %d", + GetLastError()); + return GLFW_FALSE; + } + style |= WS_EX_LAYERED; + if (!SetWindowLongPtr(handle, GWL_EXSTYLE, style)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to add layered style. GetLastError: %d", + GetLastError()); + return GLFW_FALSE; + } + if (!SetLayeredWindowAttributes(handle, + // Using a color key not equal to black to fix the trailing issue. + // When set to black, something is making the hit test not resize with the + // window frame. + RGB(0, 193, 48), + 255, + LWA_COLORKEY)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to set layered window. GetLastError: %d", + GetLastError()); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + // Create the OpenGL or OpenGL ES context // GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, @@ -713,6 +803,12 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } } + if (window->transparent) + { + if (!setupTransparentWindow(window)) + window->transparent = GLFW_FALSE; + } + window->context.makeCurrent = makeContextCurrentWGL; window->context.swapBuffers = swapBuffersWGL; window->context.swapInterval = swapIntervalWGL; diff --git a/src/win32_init.c b/src/win32_init.c index 7a8ee2086..619fcfb14 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -131,6 +131,8 @@ static GLFWbool loadLibraries(void) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); _glfw.win32.dwmapi.Flush = (PFN_DwmFlush) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); + _glfw.win32.dwmapi.DwmEnableBlurBehindWindow = (DWMENABLEBLURBEHINDWINDOW_T) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); } _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); diff --git a/src/win32_platform.h b/src/win32_platform.h index e829799d7..bfed50514 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -122,6 +122,19 @@ typedef enum PROCESS_DPI_AWARENESS } PROCESS_DPI_AWARENESS; #endif /*DPI_ENUMS_DECLARED*/ +#if !defined(_DWMAPI_H_) +#define DWM_BB_ENABLE 0x00000001 +#define DWM_BB_BLURREGION 0x00000002 + +typedef struct +{ + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; +} DWM_BLURBEHIND; +#endif + // HACK: Define versionhelpers.h functions manually as MinGW lacks the header FORCEINLINE BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) { @@ -203,8 +216,10 @@ typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEF // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); +typedef HRESULT(WINAPI * DWMENABLEBLURBEHINDWINDOW_T)(HWND, const DWM_BLURBEHIND*); #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled #define DwmFlush _glfw.win32.dwmapi.Flush +#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); @@ -310,6 +325,7 @@ typedef struct _GLFWlibraryWin32 HINSTANCE instance; PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmFlush Flush; + DWMENABLEBLURBEHINDWINDOW_T DwmEnableBlurBehindWindow; } dwmapi; struct { From ac009a5f5c41f9a78d19cd6cf0c72a0700bafc14 Mon Sep 17 00:00:00 2001 From: Cem Karan Date: Wed, 16 Dec 2015 16:28:20 -0500 Subject: [PATCH 155/222] Cocoa: Implement GLFW_TRANSPARENT This is an extract of a commit, minimally edited to ensure it compiles. Closes #663. Related to #197. --- src/cocoa_window.m | 12 +++++++++++- src/nsgl_context.m | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index cd4f3f894..4b5cd3c1f 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -413,7 +413,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (BOOL)isOpaque { - return YES; + // Set to NO even if alphaMask is not used; + // The NSView/GLFWContentView does not need to be opaque anyway, + // and to avoid keeping track of alphaMask inside the NSView we + // just return NO here instead. + return NO; } - (BOOL)canBecomeKeyView @@ -1081,6 +1085,12 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, if (wndconfig->ns.retina) [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; + if (window->transparent) + { + [window->ns.object setOpaque:NO]; + [window->ns.object setBackgroundColor:[NSColor clearColor]]; + } + [window->ns.object setContentView:window->ns.view]; [window->ns.object makeFirstResponder:window->ns.view]; [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 8504f0b97..ef247ca7d 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -296,6 +296,12 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, return GLFW_FALSE; } + if (window->transparent) + { + GLint opaque = 0; + [window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; + } + [window->context.nsgl.object setView:window->ns.view]; window->context.makeCurrent = makeContextCurrentNSGL; From 93e66661d3f087ba38b8e157a9661cf747142bc5 Mon Sep 17 00:00:00 2001 From: Bailey Cosier Date: Tue, 19 Sep 2017 18:27:45 +0200 Subject: [PATCH 156/222] Cleanup This is an extract of a commit, minimally edited to ensure it compiles. Closes #1078. Related to #197. --- docs/window.dox | 4 ++++ include/GLFW/glfw3.h | 7 ++++++- src/cocoa_window.m | 2 +- src/egl_context.c | 4 ++-- src/glx_context.c | 4 ++-- src/internal.h | 3 +-- src/nsgl_context.m | 2 +- src/wgl_context.c | 13 +++++++------ src/window.c | 11 ++++------- 9 files changed, 28 insertions(+), 22 deletions(-) diff --git a/docs/window.dox b/docs/window.dox index d9a837f63..17fa3002b 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -287,6 +287,10 @@ __GLFW_DOUBLEBUFFER__ specifies whether the framebuffer should be double buffered. You nearly always want to use double buffering. This is a hard constraint. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. +@anchor GLFW_TRANSPARENT_hint +__GLFW_TRANSPARENT__ specifies whether the framebuffer will support transparency +in the background. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. + @subsubsection window_hints_mtr Monitor related hints diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 58b7d7b91..5e9eac6f2 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -787,7 +787,6 @@ extern "C" { * Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint). */ #define GLFW_CENTER_CURSOR 0x00020009 -#define GLFW_TRANSPARENT 0x0002000A /*! @brief Framebuffer bit depth hint. * @@ -869,6 +868,12 @@ extern "C" { * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER). */ #define GLFW_DOUBLEBUFFER 0x00021010 +/*! @brief Framebuffer transparency hint. + * + * Framebuffer transparency [hint](@ref GLFW_TRANSPARENT_hint). + */ +#define GLFW_TRANSPARENT 0x00021011 + /*! @brief Context client API hint and attribute. * * Context client API [hint](@ref GLFW_CLIENT_API_hint) and diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 4b5cd3c1f..5b2736b40 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1085,7 +1085,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, if (wndconfig->ns.retina) [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; - if (window->transparent) + if (_glfw.hints.framebuffer.transparent) { [window->ns.object setOpaque:NO]; [window->ns.object setBackgroundColor:[NSColor clearColor]]; diff --git a/src/egl_context.c b/src/egl_context.c index e5435468c..bba1efb7e 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -493,7 +493,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.egl.handle; - if (!chooseEGLConfig(ctxconfig, fbconfig, &config, window->transparent)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &config, fbconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); @@ -738,7 +738,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, EGLint visualID = 0, count = 0; const long vimask = VisualScreenMask | VisualIDMask; - if (!chooseEGLConfig(ctxconfig, fbconfig, &native, wndconfig->transparent)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &native, fbconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); diff --git a/src/glx_context.c b/src/glx_context.c index 9d02a6fab..712e8c78e 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -477,7 +477,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.glx.handle; - if (!chooseGLXFBConfig(fbconfig, &native, window->transparent)) + if (!chooseGLXFBConfig(fbconfig, &native, fbconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -665,7 +665,7 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, GLXFBConfig native; XVisualInfo* result; - if (!chooseGLXFBConfig(fbconfig, &native, wndconfig->transparent)) + if (!chooseGLXFBConfig(fbconfig, &native, fbconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); diff --git a/src/internal.h b/src/internal.h index 01517ec16..2e4e0150d 100644 --- a/src/internal.h +++ b/src/internal.h @@ -299,7 +299,6 @@ struct _GLFWwndconfig GLFWbool resizable; GLFWbool visible; GLFWbool decorated; - GLFWbool transparent; GLFWbool focused; GLFWbool autoIconify; GLFWbool floating; @@ -360,6 +359,7 @@ struct _GLFWfbconfig int samples; GLFWbool sRGB; GLFWbool doublebuffer; + GLFWbool transparent; uintptr_t handle; }; @@ -403,7 +403,6 @@ struct _GLFWwindow // Window settings and state GLFWbool resizable; GLFWbool decorated; - GLFWbool transparent; GLFWbool autoIconify; GLFWbool floating; GLFWbool shouldClose; diff --git a/src/nsgl_context.m b/src/nsgl_context.m index ef247ca7d..a7cbf00f3 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -296,7 +296,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, return GLFW_FALSE; } - if (window->transparent) + if (fbconfig->transparent) { GLint opaque = 0; [window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; diff --git a/src/wgl_context.c b/src/wgl_context.c index 990eb2992..0834e0a89 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -85,7 +85,7 @@ static int choosePixelFormat(_GLFWwindow* window, _GLFWfbconfig* u = usableConfigs + usableCount; PIXELFORMATDESCRIPTOR pfd; - if (window->transparent) { + if (fbconfig->transparent) { if (!DescribePixelFormat(window->context.wgl.dc, n, sizeof(PIXELFORMATDESCRIPTOR), @@ -168,7 +168,7 @@ static int choosePixelFormat(_GLFWwindow* window, { // Get pixel format attributes through legacy PFDs - if (!window->transparent && DescribePixelFormat(window->context.wgl.dc, + if (!fbconfig->transparent && DescribePixelFormat(window->context.wgl.dc, n, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) @@ -217,8 +217,7 @@ static int choosePixelFormat(_GLFWwindow* window, } // Reiterate the selection loop without looking for transparency supporting // formats if no matching pixelformat for a transparent window were found. - if (window->transparent && !usableCount) { - window->transparent = GLFW_FALSE; + if (fbconfig->transparent && !usableCount) { free(usableConfigs); _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: No pixel format found for transparent window. Ignoring transparency."); @@ -803,10 +802,12 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } } - if (window->transparent) + if (fbconfig->transparent) { if (!setupTransparentWindow(window)) - window->transparent = GLFW_FALSE; + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to setup window as transparent as requested"); + } window->context.makeCurrent = makeContextCurrentWGL; diff --git a/src/window.c b/src/window.c index e8a68b61a..863f0ed23 100644 --- a/src/window.c +++ b/src/window.c @@ -147,6 +147,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, fbconfig = _glfw.hints.framebuffer; ctxconfig = _glfw.hints.context; wndconfig = _glfw.hints.window; + fbconfig.transparent = _glfw.hints.framebuffer.transparent ? GLFW_TRUE : GLFW_FALSE; wndconfig.width = width; wndconfig.height = height; @@ -180,7 +181,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->monitor = (_GLFWmonitor*) monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; - window->transparent = wndconfig.transparent; window->autoIconify = wndconfig.autoIconify; window->floating = wndconfig.floating; window->cursorMode = GLFW_CURSOR_NORMAL; @@ -250,7 +250,6 @@ void glfwDefaultWindowHints(void) _glfw.hints.window.resizable = GLFW_TRUE; _glfw.hints.window.visible = GLFW_TRUE; _glfw.hints.window.decorated = GLFW_TRUE; - _glfw.hints.window.transparent = GLFW_FALSE; _glfw.hints.window.focused = GLFW_TRUE; _glfw.hints.window.autoIconify = GLFW_TRUE; @@ -317,6 +316,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_DOUBLEBUFFER: _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; return; + case GLFW_TRANSPARENT: + _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE; + return; case GLFW_SAMPLES: _glfw.hints.framebuffer.samples = value; return; @@ -329,9 +331,6 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_DECORATED: _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_TRANSPARENT: - _glfw.hints.window.transparent = value ? GLFW_TRUE : GLFW_FALSE; - return; case GLFW_FOCUSED: _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; return; @@ -733,8 +732,6 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->resizable; case GLFW_DECORATED: return window->decorated; - case GLFW_TRANSPARENT: - return window->transparent; case GLFW_FLOATING: return window->floating; case GLFW_AUTO_ICONIFY: From 32e78aeb2edb5cb5add36ae575fc914f6c4fc7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 18 Sep 2017 18:10:57 +0200 Subject: [PATCH 157/222] Add GLFW_TRANSPARENT attribute and documentation This completes support for window framebuffer transparency on Windows, macOS and X11. Note that the hint/attribute may be renamed before release to clarify its relationship to GLFW_OPACITY. Fixes #197. Closes #1079. Related to #663. Related to #715. Related to #723. Related to #1078. --- README.md | 6 +++ docs/compat.dox | 5 ++ docs/news.dox | 7 +++ docs/window.dox | 41 +++++++++++++-- examples/gears.c | 3 +- include/GLFW/glfw3.h | 11 ++-- src/cocoa_window.m | 18 ++++--- src/context.c | 3 ++ src/egl_context.c | 58 +++++++------------- src/glx_context.c | 48 +++++------------ src/internal.h | 1 + src/mir_window.c | 7 +++ src/null_window.c | 5 ++ src/wgl_context.c | 122 ++----------------------------------------- src/win32_init.c | 13 ++++- src/win32_platform.h | 48 ++++++++--------- src/win32_window.c | 86 +++++++++++++++++++++++++++++- src/window.c | 3 +- src/wl_window.c | 7 +++ src/x11_init.c | 72 ++++++++----------------- src/x11_platform.h | 51 +++++++++--------- src/x11_window.c | 25 +++++++++ 22 files changed, 322 insertions(+), 318 deletions(-) diff --git a/README.md b/README.md index dbdafe007..ff753270b 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,8 @@ information on what to include when reporting a bug. functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header +- Added `GLFW_TRANSPARENT` window hint for enabling window framebuffer + transparency (#197,#663,#715,#723,#1078) - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) @@ -289,6 +291,7 @@ skills. - Yaron Cohen-Tal - Omar Cornut - Andrew Corrigan + - Bailey Cosier - Noel Cower - Jason Daly - Jarrod Davis @@ -297,6 +300,7 @@ skills. - Michael Dickens - Роман Донченко - Mario Dorn + - Wolfgang Draxinger - Jonathan Dummer - Ralph Eastwood - Fredrik Ehnbom @@ -322,6 +326,7 @@ skills. - Erik S. V. Jansson - Toni Jovanoski - Arseny Kapoulkine + - Cem Karan - Osman Keskin - Josh Kilmer - Cameron King @@ -363,6 +368,7 @@ skills. - Andri Pálsson - Peoro - Braden Pellett + - Christopher Pelloux - Arturo J. Pérez - Anthony Pesch - Orson Peters diff --git a/docs/compat.dox b/docs/compat.dox index cabe18c33..a27f58f3d 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -80,6 +80,11 @@ GLFW uses the XInput2 extension to provide raw, non-accelerated mouse motion when the cursor is disabled. If the running X server does not support this extension, regular accelerated mouse motion will be used. +GLFW uses both the XRender extension and the compositing manager to support +transparent window framebuffers. If the running X server does not support this +extension or there is no running compositing manager, the `GLFW_TRANSPARENT` +framebuffer hint will have no effect. + @section compat_glx GLX extensions diff --git a/docs/news.dox b/docs/news.dox index 042468f16..86b68c41f 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -85,6 +85,13 @@ be disabled with the @ref GLFW_JOYSTICK_HAT_BUTTONS init hint. @see @ref joystick_hat +@subsection news_33_transparent Support for transparent window framebuffer + +GLFW now supports the creation of windows with transparent framebuffers on +systems with desktop compositing enabled with the @ref GLFW_TRANSPARENT window +hint and attribute. Any window decorations will still be opaque. + + @subsection news_33_centercursor Cursor centering window hint GLFW now supports controlling whether the cursor is centered over newly created diff --git a/docs/window.dox b/docs/window.dox index 17fa3002b..5dbf15bfa 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -225,6 +225,13 @@ __GLFW_CENTER_CURSOR__ specifies whether the cursor should be centered over newly created full screen windows. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. This hint is ignored for windowed mode windows. +@anchor GLFW_TRANSPARENT_hint +__GLFW_TRANSPARENT__ specifies whether the window framebuffer will be +transparent. If enabled and supported by the system, the window framebuffer +alpha channel will be used to combine the framebuffer with the background. This +does not affect window decorations. Possible values are `GLFW_TRUE` and +`GLFW_FALSE`. + @subsubsection window_hints_fb Framebuffer related hints @@ -287,10 +294,6 @@ __GLFW_DOUBLEBUFFER__ specifies whether the framebuffer should be double buffered. You nearly always want to use double buffering. This is a hard constraint. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. -@anchor GLFW_TRANSPARENT_hint -__GLFW_TRANSPARENT__ specifies whether the framebuffer will support transparency -in the background. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. - @subsubsection window_hints_mtr Monitor related hints @@ -474,6 +477,7 @@ GLFW_AUTO_ICONIFY | `GLFW_TRUE` | `GLFW_TRUE` or `GL GLFW_FLOATING | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_MAXIMIZED | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_CENTER_CURSOR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` +GLFW_TRANSPARENT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_RED_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_GREEN_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_BLUE_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` @@ -1065,6 +1069,30 @@ window contents are saved off-screen, this callback might only be called when the window or framebuffer is resized. +@subsection window_transparency Window transparency + +Window framebuffers can be made transparent on a per-pixel per-frame basis with +the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT_hint) window hint. + +@code +glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); +@endcode + +If supported by the system, the window framebuffer will be composited with the +background using the framebuffer per-pixel alpha channel. This requires desktop +compositing to be enabled on the system. It does not affect window decorations. + +You can check whether the window framebuffer was successfully made transparent +with the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT_attrib) window attribute. + +@code +if (glfwGetWindowAttrib(window, GLFW_TRANSPARENT)) +{ + // window framebuffer is currently transparent +} +@endcode + + @subsection window_attribs Window attributes Windows have a number of attributes that can be returned using @ref @@ -1134,6 +1162,11 @@ called topmost or always-on-top. This can be set before creation with the [GLFW_FLOATING](@ref GLFW_FLOATING_hint) window hint or after with @ref glfwSetWindowAttrib. +@anchor GLFW_TRANSPARENT_attrib +__GLFW_TRANSPARENT__ indicates whether the specified window has a transparent +framebuffer, i.e. the window contents is composited with the background using +the window framebuffer alpha channel. See @ref window_transparency for details. + @subsubsection window_attribs_ctx Context related attributes diff --git a/examples/gears.c b/examples/gears.c index f7526e05f..f14b300a7 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -172,7 +172,7 @@ static GLfloat angle = 0.f; /* OpenGL draw function & timing */ static void draw(void) { - glClearColor(0., 0., 0., 0.); + glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); @@ -312,7 +312,6 @@ int main(int argc, char *argv[]) } glfwWindowHint(GLFW_DEPTH_BITS, 16); - glfwWindowHint(GLFW_ALPHA_BITS, 8); glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 5e9eac6f2..819d2cd6a 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -787,6 +787,12 @@ extern "C" { * Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint). */ #define GLFW_CENTER_CURSOR 0x00020009 +/*! @brief Window framebuffer transparency hint and attribute + * + * Window framebuffer transparency [window hint](@ref GLFW_TRANSPARENT_hint) + * and [window attribute](@ref GLFW_TRANSPARENT_attrib). + */ +#define GLFW_TRANSPARENT 0x0002000A /*! @brief Framebuffer bit depth hint. * @@ -868,11 +874,6 @@ extern "C" { * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER). */ #define GLFW_DOUBLEBUFFER 0x00021010 -/*! @brief Framebuffer transparency hint. - * - * Framebuffer transparency [hint](@ref GLFW_TRANSPARENT_hint). - */ -#define GLFW_TRANSPARENT 0x00021011 /*! @brief Context client API hint and attribute. * diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 5b2736b40..9d9476623 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -413,11 +413,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (BOOL)isOpaque { - // Set to NO even if alphaMask is not used; - // The NSView/GLFWContentView does not need to be opaque anyway, - // and to avoid keeping track of alphaMask inside the NSView we - // just return NO here instead. - return NO; + return [window->ns.object isOpaque]; } - (BOOL)canBecomeKeyView @@ -1016,7 +1012,8 @@ static GLFWbool initializeAppKit(void) // Create the Cocoa window // static GLFWbool createNativeWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig) + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) { window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; if (window->ns.delegate == nil) @@ -1085,7 +1082,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, if (wndconfig->ns.retina) [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; - if (_glfw.hints.framebuffer.transparent) + if (fbconfig->transparent) { [window->ns.object setOpaque:NO]; [window->ns.object setBackgroundColor:[NSColor clearColor]]; @@ -1114,7 +1111,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!initializeAppKit()) return GLFW_FALSE; - if (!createNativeWindow(window, wndconfig)) + if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) @@ -1453,6 +1450,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return [window->ns.object isZoomed]; } +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + return ![window->ns.object isOpaque] && ![window->ns.view isOpaque]; +} + void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { [window->ns.object setStyleMask:getStyleMask(window)]; diff --git a/src/context.c b/src/context.c index 1a26356e1..3842f0a37 100644 --- a/src/context.c +++ b/src/context.c @@ -208,6 +208,9 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, // not important to us here, so we count them as one missing++; } + + if (desired->transparent != current->transparent) + missing++; } // These polynomials make many small channel size differences matter diff --git a/src/egl_context.c b/src/egl_context.c index bba1efb7e..b2d11a471 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -87,21 +87,13 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib) // static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* desired, - EGLConfig* result, - GLFWbool findTransparent) + EGLConfig* result) { EGLConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; int i, nativeCount, usableCount; -#if defined(_GLFW_X11) - XVisualInfo visualTemplate = {0}; - if ( !(_glfw.xrender.major || _glfw.xrender.minor) ) { - findTransparent = GLFW_FALSE; - } -#endif // _GLFW_X11 - eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); if (!nativeCount) { @@ -115,7 +107,6 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; -selectionloop: for (i = 0; i < nativeCount; i++) { const EGLConfig n = nativeConfigs[i]; @@ -130,31 +121,24 @@ selectionloop: continue; #if defined(_GLFW_X11) + XVisualInfo vi = {0}; + // Only consider EGLConfigs with associated Visuals - visualTemplate.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); - if (!visualTemplate.visualid) + vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!vi.visualid) continue; - if( findTransparent ) { - int n_vi; - XVisualInfo *visualinfo; - XRenderPictFormat *pictFormat; - - visualinfo = XGetVisualInfo(_glfw.x11.display, VisualIDMask, &visualTemplate, &n_vi); - if (!visualinfo) - continue; - - pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); - if( !pictFormat ) { - XFree( visualinfo ); - continue; - } - - if( !pictFormat->direct.alphaMask ) { - XFree( visualinfo ); - continue; - } - XFree( visualinfo ); + if (desired->transparent) + { + int count; + XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display, + VisualIDMask, &vi, + &count); + if (vis) + { + u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); + XFree(vis); + } } #endif // _GLFW_X11 @@ -191,12 +175,6 @@ selectionloop: u->handle = (uintptr_t) n; usableCount++; } - // reiterate the selection loop without looking for transparency supporting - // formats if no matchig FB configs for a transparent window were found. - if( findTransparent && !usableCount ) { - findTransparent = GLFW_FALSE; - goto selectionloop; - } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) @@ -493,7 +471,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.egl.handle; - if (!chooseEGLConfig(ctxconfig, fbconfig, &config, fbconfig->transparent)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); @@ -738,7 +716,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, EGLint visualID = 0, count = 0; const long vimask = VisualScreenMask | VisualIDMask; - if (!chooseEGLConfig(ctxconfig, fbconfig, &native, fbconfig->transparent)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); diff --git a/src/glx_context.c b/src/glx_context.c index 712e8c78e..708663a9e 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -47,10 +47,8 @@ static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) // Return the GLXFBConfig most closely matching the specified hints // -static GLFWbool chooseGLXFBConfig( - const _GLFWfbconfig* desired, - GLXFBConfig* result, - GLFWbool findTransparent) +static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, + GLXFBConfig* result) { GLXFBConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; @@ -59,10 +57,6 @@ static GLFWbool chooseGLXFBConfig( const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; - if ( !(_glfw.xrender.major || _glfw.xrender.minor) ) { - findTransparent = GLFW_FALSE; - } - // HACK: This is a (hopefully temporary) workaround for Chromium // (VirtualBox GL) not setting the window bit on any GLXFBConfigs vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); @@ -80,7 +74,6 @@ static GLFWbool chooseGLXFBConfig( usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; -selectionloop: for (i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; @@ -97,25 +90,14 @@ selectionloop: continue; } - if( findTransparent ) { - XVisualInfo *visualinfo; - XRenderPictFormat *pictFormat; - - visualinfo = glXGetVisualFromFBConfig(_glfw.x11.display, n); - if (!visualinfo) - continue; - - pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); - if( !pictFormat ) { - XFree( visualinfo ); - continue; - } - - if( !pictFormat->direct.alphaMask ) { - XFree( visualinfo ); - continue; - } - XFree( visualinfo ); + if (desired->transparent) + { + XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n); + if (vi) + { + u->transparent = _glfwIsVisualTransparentX11(vi->visual); + XFree(vi); + } } u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); @@ -147,12 +129,6 @@ selectionloop: u->handle = (uintptr_t) n; usableCount++; } - // reiterate the selection loop without looking for transparency supporting - // formats if no matchig FB configs for a transparent window were found. - if( findTransparent && !usableCount ) { - findTransparent = GLFW_FALSE; - goto selectionloop; - } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) @@ -477,7 +453,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.glx.handle; - if (!chooseGLXFBConfig(fbconfig, &native, fbconfig->transparent)) + if (!chooseGLXFBConfig(fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -665,7 +641,7 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, GLXFBConfig native; XVisualInfo* result; - if (!chooseGLXFBConfig(fbconfig, &native, fbconfig->transparent)) + if (!chooseGLXFBConfig(fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); diff --git a/src/internal.h b/src/internal.h index 2e4e0150d..b9f55da7c 100644 --- a/src/internal.h +++ b/src/internal.h @@ -682,6 +682,7 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window); int _glfwPlatformWindowIconified(_GLFWwindow* window); int _glfwPlatformWindowVisible(_GLFWwindow* window); int _glfwPlatformWindowMaximized(_GLFWwindow* window); +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled); diff --git a/src/mir_window.c b/src/mir_window.c index 4ed71f971..8b763de10 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -614,6 +614,13 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return mir_window_get_state(window->mir.window) == mir_window_state_maximized; } +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return GLFW_FALSE; +} + void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/null_window.c b/src/null_window.c index 2e627672c..33ff6c333 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -156,6 +156,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return GLFW_FALSE; } +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + return GLFW_FALSE; +} + void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { } diff --git a/src/wgl_context.c b/src/wgl_context.c index 0834e0a89..d864a47cc 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -83,20 +83,6 @@ static int choosePixelFormat(_GLFWwindow* window, { const int n = i + 1; _GLFWfbconfig* u = usableConfigs + usableCount; - PIXELFORMATDESCRIPTOR pfd; - - if (fbconfig->transparent) { - if (!DescribePixelFormat(window->context.wgl.dc, - n, - sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - continue; - } - - if (!(pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) - continue; - } if (_glfw.wgl.ARB_pixel_format) { @@ -168,7 +154,9 @@ static int choosePixelFormat(_GLFWwindow* window, { // Get pixel format attributes through legacy PFDs - if (!fbconfig->transparent && DescribePixelFormat(window->context.wgl.dc, + PIXELFORMATDESCRIPTOR pfd; + + if (!DescribePixelFormat(window->context.wgl.dc, n, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) @@ -215,14 +203,6 @@ static int choosePixelFormat(_GLFWwindow* window, u->handle = n; usableCount++; } - // Reiterate the selection loop without looking for transparency supporting - // formats if no matching pixelformat for a transparent window were found. - if (fbconfig->transparent && !usableCount) { - free(usableConfigs); - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: No pixel format found for transparent window. Ignoring transparency."); - return choosePixelFormat(window, ctxconfig, fbconfig); - } if (!usableCount) { @@ -249,21 +229,6 @@ static int choosePixelFormat(_GLFWwindow* window, return pixelFormat; } -// Returns whether desktop compositing is enabled -// -static GLFWbool isCompositionEnabled(void) -{ - if (_glfw.win32.dwmapi.instance) - { - BOOL enabled; - - if (DwmIsCompositionEnabled(&enabled) == S_OK) - return enabled; - } - - return FALSE; -} - static void makeContextCurrentWGL(_GLFWwindow* window) { if (window) @@ -292,7 +257,7 @@ static void makeContextCurrentWGL(_GLFWwindow* window) static void swapBuffersWGL(_GLFWwindow* window) { // HACK: Use DwmFlush when desktop composition is enabled - if (isCompositionEnabled() && !window->monitor) + if (_glfwIsCompositionEnabledWin32() && !window->monitor) { int count = abs(window->context.wgl.interval); while (count--) @@ -310,7 +275,7 @@ static void swapIntervalWGL(int interval) // HACK: Disable WGL swap interval when desktop composition is enabled to // avoid interfering with DWM vsync - if (isCompositionEnabled() && !window->monitor) + if (_glfwIsCompositionEnabledWin32() && !window->monitor) interval = 0; if (_glfw.wgl.EXT_swap_control) @@ -504,75 +469,6 @@ void _glfwTerminateWGL(void) attribs[index++] = v; \ } -static GLFWbool setupTransparentWindow(_GLFWwindow* window) -{ - if (!isCompositionEnabled) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Composition needed for transparent window is disabled"); - } - if (!_glfw_DwmEnableBlurBehindWindow) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Unable to load DwmEnableBlurBehindWindow required for transparent window"); - return GLFW_FALSE; - } - - HRESULT hr = S_OK; - HWND handle = window->win32.handle; - - DWM_BLURBEHIND bb = { 0 }; - bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; - bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); // makes the window transparent - bb.fEnable = TRUE; - hr = _glfw_DwmEnableBlurBehindWindow(handle, &bb); - - if (!SUCCEEDED(hr)) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to enable blur behind window required for transparent window"); - return GLFW_FALSE; - } - - // Decorated windows on Windows 8+ don't repaint the transparent background - // leaving a trail behind animations. - // Hack: making the window layered with a transparency color key seems to fix this. - // Normally, when specifying a transparency color key to be used when composing - // the layered window, all pixels painted by the window in this color will be transparent. - // That doesn't seem to be the case anymore on Windows 8+, at least when used with - // DwmEnableBlurBehindWindow + negative region. - if (window->decorated && IsWindows8OrGreater()) - { - long style = GetWindowLong(handle, GWL_EXSTYLE); - if (!style) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to retrieve extended styles. GetLastError: %d", - GetLastError()); - return GLFW_FALSE; - } - style |= WS_EX_LAYERED; - if (!SetWindowLongPtr(handle, GWL_EXSTYLE, style)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to add layered style. GetLastError: %d", - GetLastError()); - return GLFW_FALSE; - } - if (!SetLayeredWindowAttributes(handle, - // Using a color key not equal to black to fix the trailing issue. - // When set to black, something is making the hit test not resize with the - // window frame. - RGB(0, 193, 48), - 255, - LWA_COLORKEY)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to set layered window. GetLastError: %d", - GetLastError()); - return GLFW_FALSE; - } - } - - return GLFW_TRUE; -} - // Create the OpenGL or OpenGL ES context // GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, @@ -802,14 +698,6 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } } - if (fbconfig->transparent) - { - if (!setupTransparentWindow(window)) - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "WGL: Failed to setup window as transparent as requested"); - - } - window->context.makeCurrent = makeContextCurrentWGL; window->context.swapBuffers = swapBuffersWGL; window->context.swapInterval = swapIntervalWGL; diff --git a/src/win32_init.c b/src/win32_init.c index 619fcfb14..0531ff13e 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -62,6 +62,17 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) #endif // _GLFW_BUILD_DLL +// HACK: Define versionhelpers.h functions manually as MinGW lacks the header +BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp }; + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; + ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + return VerifyVersionInfoW(&osvi, mask, cond); +} + // Load necessary libraries (DLLs) // static GLFWbool loadLibraries(void) @@ -131,7 +142,7 @@ static GLFWbool loadLibraries(void) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); _glfw.win32.dwmapi.Flush = (PFN_DwmFlush) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); - _glfw.win32.dwmapi.DwmEnableBlurBehindWindow = (DWMENABLEBLURBEHINDWINDOW_T) + _glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); } diff --git a/src/win32_platform.h b/src/win32_platform.h index bfed50514..acbb5ca2a 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -100,6 +100,9 @@ #ifndef DISPLAY_DEVICE_ACTIVE #define DISPLAY_DEVICE_ACTIVE 0x00000001 #endif +#ifndef _WIN32_WINNT_WINBLUE + #define _WIN32_WINNT_WINBLUE 0x0602 +#endif #if WINVER < 0x0601 typedef struct tagCHANGEFILTERSTRUCT @@ -113,6 +116,18 @@ typedef struct tagCHANGEFILTERSTRUCT #endif #endif /*Windows 7*/ +#if WINVER < 0x0600 +#define DWM_BB_ENABLE 0x00000001 +#define DWM_BB_BLURREGION 0x00000002 +typedef struct +{ + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; +} DWM_BLURBEHIND; +#endif /*Windows Vista*/ + #ifndef DPI_ENUMS_DECLARED typedef enum PROCESS_DPI_AWARENESS { @@ -122,30 +137,8 @@ typedef enum PROCESS_DPI_AWARENESS } PROCESS_DPI_AWARENESS; #endif /*DPI_ENUMS_DECLARED*/ -#if !defined(_DWMAPI_H_) -#define DWM_BB_ENABLE 0x00000001 -#define DWM_BB_BLURREGION 0x00000002 - -typedef struct -{ - DWORD dwFlags; - BOOL fEnable; - HRGN hRgnBlur; - BOOL fTransitionOnMaximized; -} DWM_BLURBEHIND; -#endif - // HACK: Define versionhelpers.h functions manually as MinGW lacks the header -FORCEINLINE BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) -{ - OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp }; - DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; - ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); - cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); - cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - return VerifyVersionInfoW(&osvi, mask, cond); -} - +BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp); #define IsWindowsVistaOrGreater() \ IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), \ LOBYTE(_WIN32_WINNT_VISTA), 0) @@ -216,10 +209,10 @@ typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEF // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); -typedef HRESULT(WINAPI * DWMENABLEBLURBEHINDWINDOW_T)(HWND, const DWM_BLURBEHIND*); +typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*); #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled #define DwmFlush _glfw.win32.dwmapi.Flush -#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow +#define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); @@ -274,6 +267,8 @@ typedef struct _GLFWwindowWin32 GLFWbool frameAction; GLFWbool iconified; GLFWbool maximized; + // Whether to enable framebuffer transparency on DWM + GLFWbool transparent; // The last received cursor position, regardless of source int lastCursorPosX, lastCursorPosY; @@ -325,7 +320,7 @@ typedef struct _GLFWlibraryWin32 HINSTANCE instance; PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmFlush Flush; - DWMENABLEBLURBEHINDWINDOW_T DwmEnableBlurBehindWindow; + PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; } dwmapi; struct { @@ -388,6 +383,7 @@ typedef struct _GLFWmutexWin32 GLFWbool _glfwRegisterWindowClassWin32(void); void _glfwUnregisterWindowClassWin32(void); +GLFWbool _glfwIsCompositionEnabledWin32(void); WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); diff --git a/src/win32_window.c b/src/win32_window.c index 9ce9e4361..6bebb19bd 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -306,6 +306,55 @@ static void updateWindowStyles(const _GLFWwindow* window) SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER); } +// Update window framebuffer transparency +// +static void updateFramebufferTransparency(const _GLFWwindow* window) +{ + if (!IsWindowsVistaOrGreater()) + return; + + if (_glfwIsCompositionEnabledWin32()) + { + HRGN region = CreateRectRgn(0, 0, -1, -1); + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = region; + bb.fEnable = TRUE; + + if (SUCCEEDED(DwmEnableBlurBehindWindow(window->win32.handle, &bb))) + { + // Decorated windows don't repaint the transparent background + // leaving a trail behind animations + // HACK: Making the window layered with a transparency color key + // seems to fix this. Normally, when specifying + // a transparency color key to be used when composing the + // layered window, all pixels painted by the window in this + // color will be transparent. That doesn't seem to be the + // case anymore, at least when used with blur behind window + // plus negative region. + LONG style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + style |= WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + + // Using a color key not equal to black to fix the trailing + // issue. When set to black, something is making the hit test + // not resize with the window frame. + SetLayeredWindowAttributes(window->win32.handle, + RGB(0, 193, 48), 255, LWA_COLORKEY); + } + + DeleteObject(region); + } + else + { + LONG style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + style &= ~WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + RedrawWindow(window->win32.handle, NULL, NULL, + RDW_ERASE | RDW_INVALIDATE | RDW_FRAME); + } +} + // Translates a GLFW standard cursor to a resource ID // static LPWSTR translateCursorShape(int shape) @@ -916,6 +965,13 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, return TRUE; } + case WM_DWMCOMPOSITIONCHANGED: + { + if (window->win32.transparent) + updateFramebufferTransparency(window); + return 0; + } + case WM_SETCURSOR: { if (LOWORD(lParam) == HTCLIENT) @@ -981,7 +1037,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // Creates the GLFW window // static int createNativeWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig) + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) { int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; @@ -1051,6 +1108,12 @@ static int createNativeWindow(_GLFWwindow* window, DragAcceptFiles(window->win32.handle, TRUE); + if (fbconfig->transparent) + { + updateFramebufferTransparency(window); + window->win32.transparent = GLFW_TRUE; + } + return GLFW_TRUE; } @@ -1102,6 +1165,20 @@ void _glfwUnregisterWindowClassWin32(void) UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); } +// Returns whether desktop compositing is enabled +// +GLFWbool _glfwIsCompositionEnabledWin32(void) +{ + if (IsWindowsVistaOrGreater()) + { + BOOL enabled; + if (SUCCEEDED(DwmIsCompositionEnabled(&enabled))) + return enabled; + } + + return FALSE; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -1112,7 +1189,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) @@ -1481,6 +1558,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return IsZoomed(window->win32.handle); } +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + return window->win32.transparent && _glfwIsCompositionEnabledWin32(); +} + void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { updateWindowStyles(window); diff --git a/src/window.c b/src/window.c index 863f0ed23..57845579f 100644 --- a/src/window.c +++ b/src/window.c @@ -147,7 +147,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, fbconfig = _glfw.hints.framebuffer; ctxconfig = _glfw.hints.context; wndconfig = _glfw.hints.window; - fbconfig.transparent = _glfw.hints.framebuffer.transparent ? GLFW_TRUE : GLFW_FALSE; wndconfig.width = width; wndconfig.height = height; @@ -728,6 +727,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return _glfwPlatformWindowVisible(window); case GLFW_MAXIMIZED: return _glfwPlatformWindowMaximized(window); + case GLFW_TRANSPARENT: + return _glfwPlatformFramebufferTransparent(window); case GLFW_RESIZABLE: return window->resizable; case GLFW_DECORATED: diff --git a/src/wl_window.c b/src/wl_window.c index 6c974dfd3..caa51d3a9 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -654,6 +654,13 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return window->wl.maximized; } +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Framebuffer transparency attribute not implemented yet"); + return GLFW_FALSE; +} + void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { // TODO diff --git a/src/x11_init.c b/src/x11_init.c index 195c8ce4f..526d9ca25 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -651,6 +651,29 @@ static GLFWbool initExtensions(void) dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); } + _glfw.x11.xrender.handle = dlopen("libXrender.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.xrender.handle) + { + _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension) + dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); + _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion) + dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); + _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat) + dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); + + if (XRenderQueryExtension(_glfw.x11.display, + &_glfw.x11.xrender.errorBase, + &_glfw.x11.xrender.eventBase)) + { + if (XRenderQueryVersion(_glfw.x11.display, + &_glfw.x11.xrender.major, + &_glfw.x11.xrender.minor)) + { + _glfw.x11.xrender.available = GLFW_TRUE; + } + } + } + // Update the key code LUT // FIXME: We should listen to XkbMapNotify events to track changes to // the keyboard mapping. @@ -717,55 +740,6 @@ static GLFWbool initExtensions(void) _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); - int i; - const char* sonames_xrender[] = - { -#if defined(__CYGWIN__) - "libXrender-1.so", -#else - "libXrender.so.1", - "libXrender.so", -#endif - NULL - }; - - // Xrender support is optional and not a requirement for GLX/EGL - // to work. Xrender is required for selecting a FB config that - // supports a picture format with an alpha mask, which in turn - // is required for transparent windows. I Xrender is not supported - // the GLFW_TRANSPARENT window hint is ignored. - for (i = 0; sonames_xrender[i]; i++) - { - _glfw.xrender.handle = dlopen(sonames_xrender[i], RTLD_LAZY | RTLD_GLOBAL); - if (_glfw.xrender.handle) - break; - } - _glfw.xrender.errorBase = 0; - _glfw.xrender.eventBase = 0; - _glfw.xrender.major = 0; - _glfw.xrender.minor = 0; - if (_glfw.xrender.handle) do { - int errorBase, eventBase, major, minor; - _glfw.xrender.QueryExtension = - dlsym(_glfw.xrender.handle, "XRenderQueryExtension"); - _glfw.xrender.QueryVersion = - dlsym(_glfw.xrender.handle, "XRenderQueryVersion"); - _glfw.xrender.FindVisualFormat = - dlsym(_glfw.xrender.handle, "XRenderFindVisualFormat"); - - if ( !XRenderQueryExtension(_glfw.x11.display, &errorBase, &eventBase)) { - break; - } - if ( !XRenderQueryVersion(_glfw.x11.display, &major, &minor)) { - break; - } - - _glfw.xrender.errorBase = errorBase; - _glfw.xrender.eventBase = eventBase; - _glfw.xrender.major = major; - _glfw.xrender.minor = minor; - } while(0); - return GLFW_TRUE; } diff --git a/src/x11_platform.h b/src/x11_platform.h index 9890f7034..2b1c0c622 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -116,6 +116,13 @@ typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); #define XIQueryVersion _glfw.x11.xi.QueryVersion #define XISelectEvents _glfw.x11.xi.SelectEvents +typedef Bool (* PFN_XRenderQueryExtension)(Display*,int*,int*); +typedef Status (* PFN_XRenderQueryVersion)(Display*dpy,int*,int*); +typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const*); +#define XRenderQueryExtension _glfw.x11.xrender.QueryExtension +#define XRenderQueryVersion _glfw.x11.xrender.QueryVersion +#define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat + typedef VkFlags VkXlibSurfaceCreateFlagsKHR; typedef VkFlags VkXcbSurfaceCreateFlagsKHR; @@ -162,20 +169,10 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 -#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 ; _GLFWlibraryXrender xrender +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11 -// libXrender.so function pointer typedefs -typedef Bool (*PFNXRENDERQUERYEXTENSIONPROC)(Display*,int*,int*); -typedef Status (*PFNXRENDERQUERYVERSIONPROC)(Display*dpy,int*,int*); -typedef XRenderPictFormat* (*PFNXRENDERFINDVISUALFORMATPROC)(Display*,Visual const *); - -// libXrender.so function identifier overlays -#define XRenderQueryExtension _glfw.xrender.QueryExtension -#define XRenderQueryVersion _glfw.xrender.QueryVersion -#define XRenderFindVisualFormat _glfw.xrender.FindVisualFormat - // X11-specific per-window data // @@ -189,6 +186,9 @@ typedef struct _GLFWwindowX11 GLFWbool iconified; GLFWbool maximized; + // Whether the visual supports framebuffer transparency + GLFWbool transparent; + // Cached position and size used to filter out duplicate events int width, height; int xpos, ypos; @@ -383,24 +383,20 @@ typedef struct _GLFWlibraryX11 PFN_XISelectEvents SelectEvents; } xi; + struct { + GLFWbool available; + void* handle; + int major; + int minor; + int eventBase; + int errorBase; + PFN_XRenderQueryExtension QueryExtension; + PFN_XRenderQueryVersion QueryVersion; + PFN_XRenderFindVisualFormat FindVisualFormat; + } xrender; + } _GLFWlibraryX11; -// Xrender-specific global data -typedef struct _GLFWlibraryXrender -{ - int major, minor; - int eventBase; - int errorBase; - - // dlopen handle for libGL.so.1 - void* handle; - - // Xrender functions (subset required for transparent window) - PFNXRENDERQUERYEXTENSIONPROC QueryExtension; - PFNXRENDERQUERYVERSIONPROC QueryVersion; - PFNXRENDERFINDVISUALFORMATPROC FindVisualFormat; -} _GLFWlibraryXrender; - // X11-specific per-monitor data // typedef struct _GLFWmonitorX11 @@ -434,6 +430,7 @@ unsigned long _glfwGetWindowPropertyX11(Window window, Atom property, Atom type, unsigned char** value); +GLFWbool _glfwIsVisualTransparentX11(Visual* visual); void _glfwGrabErrorHandlerX11(void); void _glfwReleaseErrorHandlerX11(void); diff --git a/src/x11_window.c b/src/x11_window.c index 3addee6ca..cf5483b0d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -364,6 +364,7 @@ static void updateWindowMode(_GLFWwindow* window) } // Enable compositor bypass + if (!window->x11.transparent) { const unsigned long value = 1; @@ -402,6 +403,7 @@ static void updateWindowMode(_GLFWwindow* window) } // Disable compositor bypass + if (!window->x11.transparent) { XDeleteProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_BYPASS_COMPOSITOR); @@ -577,6 +579,8 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, visual, AllocNone); + window->x11.transparent = _glfwIsVisualTransparentX11(visual); + // Create the actual window { XSetWindowAttributes wa; @@ -1838,6 +1842,15 @@ unsigned long _glfwGetWindowPropertyX11(Window window, return itemCount; } +GLFWbool _glfwIsVisualTransparentX11(Visual* visual) +{ + if (!_glfw.x11.xrender.available) + return GLFW_FALSE; + + XRenderPictFormat* pf = XRenderFindVisualFormat(_glfw.x11.display, visual); + return pf && pf->direct.alphaMask; +} + // Push contents of our selection to clipboard manager // void _glfwPushSelectionToManagerX11(void) @@ -2422,6 +2435,18 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return maximized; } +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + if (!window->x11.transparent) + return GLFW_FALSE; + + // Check whether a compositing manager is running + char name[32]; + snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); + const Atom selection = XInternAtom(_glfw.x11.display, name, False); + return XGetSelectionOwner(_glfw.x11.display, selection) != None; +} + void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { int width, height; From 5d0d30db38e6a7dd648ea58eac6129bfdc4c9c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 28 Sep 2017 17:32:15 +0200 Subject: [PATCH 158/222] Cleanup --- src/win32_window.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/win32_window.c b/src/win32_window.c index 6bebb19bd..490a75d2c 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -332,9 +332,9 @@ static void updateFramebufferTransparency(const _GLFWwindow* window) // color will be transparent. That doesn't seem to be the // case anymore, at least when used with blur behind window // plus negative region. - LONG style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - style |= WS_EX_LAYERED; - SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + exStyle |= WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); // Using a color key not equal to black to fix the trailing // issue. When set to black, something is making the hit test @@ -347,9 +347,9 @@ static void updateFramebufferTransparency(const _GLFWwindow* window) } else { - LONG style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - style &= ~WS_EX_LAYERED; - SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + exStyle &= ~WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); RedrawWindow(window->win32.handle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME); } From da68ec56c3e00f290ed2407eb9624792f9c46b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 27 Sep 2017 23:01:14 +0200 Subject: [PATCH 159/222] Cocoa: Start using instancetype The first tiny step towards using more modern Objective-C. --- src/cocoa_window.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 9d9476623..c8efb0d76 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -228,13 +228,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; _GLFWwindow* window; } -- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow; +- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow; @end @implementation GLFWWindowDelegate -- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow +- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow { self = [super init]; if (self != nil) @@ -381,13 +381,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; NSMutableAttributedString* markedText; } -- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow; +- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow; @end @implementation GLFWContentView -- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow +- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow { self = [super init]; if (self != nil) From 5aeb37d1b89a566d70c86c72aec1f11ce5b15c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 28 Sep 2017 18:44:04 +0200 Subject: [PATCH 160/222] Cocoa: Fix window title being lost when untitled The window title was lost and could not be updated while the window did not have NSWindowStyleMaskTitled set. Fixes #1082. --- README.md | 1 + src/cocoa_window.m | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ff753270b..01b159c93 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: A hidden or disabled cursor would become visible when a user notification was shown (#971,#1028) - [Cocoa] Bugfix: Some characters did not repeat due to Press and Hold (#1010) +- [Cocoa] Bugfix: Window title was lost when full screen or undecorated (#1082) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` diff --git a/src/cocoa_window.m b/src/cocoa_window.m index c8efb0d76..0a3bcd540 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1182,7 +1182,11 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) { - [window->ns.object setTitle:[NSString stringWithUTF8String:title]]; + NSString* string = [NSString stringWithUTF8String:title]; + [window->ns.object setTitle:string]; + // HACK: Set the miniwindow title explicitly as setTitle: doesn't update it + // if the window lacks NSWindowStyleMaskTitled + [window->ns.object setMiniwindowTitle:string]; } void _glfwPlatformSetWindowIcon(_GLFWwindow* window, @@ -1427,6 +1431,9 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, [window->ns.object setLevel:NSNormalWindowLevel]; [window->ns.object setHasShadow:YES]; + // HACK: Clearing NSWindowStyleMaskTitled resets and disables the window + // title property but the miniwindow title property is unaffected + [window->ns.object setTitle:[window->ns.object miniwindowTitle]]; } } From 95e282d5a0f20939b73dd436a8cfcb2601fdaf25 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sun, 1 Oct 2017 01:38:00 +0100 Subject: [PATCH 161/222] Wayland: Add transparency support Closes #788. --- src/wl_platform.h | 1 + src/wl_window.c | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index c543d82c4..656f0ef1f 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -76,6 +76,7 @@ typedef struct _GLFWwindowWayland int width, height; GLFWbool visible; GLFWbool maximized; + GLFWbool transparent; struct wl_surface* surface; struct wl_egl_window* native; struct wl_shell_surface* shellSurface; diff --git a/src/wl_window.c b/src/wl_window.c index caa51d3a9..32d5f4040 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -212,8 +212,8 @@ static GLFWbool createSurface(_GLFWwindow* window, window->wl.height = wndconfig->height; window->wl.scale = 1; - // TODO: make this optional once issue #197 is fixed. - setOpaqueRegion(window); + if (!window->wl.transparent) + setOpaqueRegion(window); return GLFW_TRUE; } @@ -390,6 +390,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { + window->wl.transparent = fbconfig->transparent; + if (!createSurface(window, wndconfig)) return GLFW_FALSE; @@ -514,7 +516,8 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) window->wl.width = width; window->wl.height = height; wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); - setOpaqueRegion(window); + if (!window->wl.transparent) + setOpaqueRegion(window); _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); } @@ -656,9 +659,7 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Framebuffer transparency attribute not implemented yet"); - return GLFW_FALSE; + return window->wl.transparent; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) From 6d463d36fade96c1a455a6a1549b49f31d6527af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 2 Oct 2017 17:31:39 +0200 Subject: [PATCH 162/222] Cleanup --- src/init.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/init.c b/src/init.c index 7d3678fac..19a13e0df 100644 --- a/src/init.c +++ b/src/init.c @@ -152,15 +152,13 @@ void _glfwInputError(int code, const char* format, ...) if (format) { - int count; va_list vl; va_start(vl, format); - count = vsnprintf(description, sizeof(description), format, vl); + vsnprintf(description, sizeof(description), format, vl); va_end(vl); - if (count < 0) - description[sizeof(description) - 1] = '\0'; + description[sizeof(description) - 1] = '\0'; } else strcpy(description, getErrorString(code)); From 07cc6e00da51ade97a240cf8cc1768be4046f1c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 2 Oct 2017 17:32:21 +0200 Subject: [PATCH 163/222] Add gamepad name to joysticks test --- tests/joysticks.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/joysticks.c b/tests/joysticks.c index 88489d4e6..d039a761c 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -269,7 +269,9 @@ int main(void) "LT", "RT", }; - nk_label(nk, "Gamepad state", NK_TEXT_LEFT); + nk_labelf(nk, NK_TEXT_LEFT, + "Gamepad state: %s", + glfwGetGamepadName(joysticks[i])); nk_layout_row_dynamic(nk, 30, 2); From 94ee10e655cf0f1c82882ec2efe30f4195a5cf50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 3 Oct 2017 00:41:19 +0200 Subject: [PATCH 164/222] Remove trailing else --- src/linux_joystick.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 3283d1eaf..d73961fb6 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -306,7 +306,6 @@ GLFWbool _glfwInitJoysticksLinux(void) closedir(dir); } - else // Continue with no joysticks if enumeration fails From 56ecd62f58f0c988c017050a75c46953a30a7512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 3 Oct 2017 00:41:55 +0200 Subject: [PATCH 165/222] Fix joystick test hat drawing --- tests/joysticks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/joysticks.c b/tests/joysticks.c index d039a761c..d2be6475d 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -98,7 +98,7 @@ static void hat_widget(struct nk_context* nk, unsigned char state) struct nk_rect area; struct nk_vec2 center; - if (nk_widget(&area, nk) != NK_WIDGET_VALID) + if (nk_widget(&area, nk) == NK_WIDGET_INVALID) return; center = nk_vec2(area.x + area.w / 2.f, area.y + area.h / 2.f); From f308228a19fe26fa83d56cbb62500818bfccea6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 11 Oct 2017 02:08:09 +0200 Subject: [PATCH 166/222] Documentation work Remove sentence describing GLFW-specific behavior. This describes the behavior of glfwUpdateGamepadMappings, whose behavior is a mix between the two related SDL functions, but is not part of the format. --- docs/input.dox | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/input.dox b/docs/input.dox index 6d444656d..0eaa8ef84 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -786,7 +786,6 @@ functions. There is also the special `platform` field that specifies which platform the mapping is valid for. Possible values are `Windows`, `Mac OS X` and `Linux`. -Mappings without this field will always be considered valid. Below is an example of what a gamepad mapping might look like. It is the one built into GLFW for Xbox controllers accessed via the XInput API on Windows. From 66c0394ae19c24483a5228eeaa179945206768ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 18 Oct 2017 16:48:21 +0200 Subject: [PATCH 167/222] Fix typo in window guide Fixes #1099. --- docs/window.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/window.dox b/docs/window.dox index 5dbf15bfa..39420804f 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -87,7 +87,7 @@ By default, the original video mode of the monitor will be restored and the window iconified if it loses input focus, to allow the user to switch back to the desktop. This behavior can be disabled with the [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_hint) window hint, for example if you -wish to simultaneously cover multiple windows with full screen windows. +wish to simultaneously cover multiple monitors with full screen windows. If a monitor is disconnected, any window that is full screen on that monitor will be forced into windowed mode. See @ref monitor_event for more information. From 81963967e576e703df486df16c287aef21b40b1d Mon Sep 17 00:00:00 2001 From: siavashserver Date: Sat, 21 Oct 2017 18:55:03 +0330 Subject: [PATCH 168/222] Fix Doxygen navigation bar The Doxygen CSS changed significantly in a recent release. Closes #1100. --- docs/extra.css | 2 +- docs/extra.less | 40 +++++++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/docs/extra.css b/docs/extra.css index df978c0cb..42091cd10 100644 --- a/docs/extra.css +++ b/docs/extra.css @@ -1 +1 @@ -.sm-dox,.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted,.sm-dox ul a:hover{background:none;text-shadow:none}.sm-dox ul a:hover{background:#666;text-shadow:none}#main-nav,#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code{background:none}#titlearea,.footer,.contents,div.header,.memdoc,table.doxtable td,table.doxtable th,hr,.memSeparator{border:none}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.reflist dt a.el,.levels span,.directory .levels span{text-shadow:none}.memdoc,dl.reflist dd{box-shadow:none}div.headertitle,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,table.doxtable code{padding:0}#nav-path,.directory .levels,span.lineno{display:none}html,#titlearea,.footer,tr.even,.directory tr.even,.doxtable tr:nth-child(even),.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,code{background:#f2f2f2}body{color:#4d4d4d}h1,h2,h2.groupheader,h3,div.toc h3,h4,h5,h6,strong,em{color:#1a1a1a;border-bottom:none}h1{padding-top:0.5em;font-size:180%}h2{padding-top:0.5em;margin-bottom:0;font-size:140%}h3{padding-top:0.5em;margin-bottom:0;font-size:110%}.glfwheader{font-size:16px;height:64px;max-width:920px;min-width:800px;padding:0 32px;margin:0 auto}#glfwhome{line-height:64px;padding-right:48px;color:#666;font-size:2.5em;background:url("http://www.glfw.org/css/arrow.png") no-repeat right}.glfwnavbar{list-style-type:none;margin:0 auto;float:right}#glfwhome,.glfwnavbar li{float:left}.glfwnavbar a,.glfwnavbar a:visited{line-height:64px;margin-left:2em;display:block;color:#666}#glfwhome,.glfwnavbar a,.glfwnavbar a:visited{transition:.35s ease}#titlearea,.footer{color:#666}address.footer{text-align:center;padding:2em;margin-top:3em}#top{background:#666}#main-nav{max-width:960px;min-width:800px;margin:0 auto;font-size:13px}#navrow1,#navrow2,#navrow3,#navrow4{max-width:920px;min-width:800px;margin:0 auto;font-size:13px}.memtitle{display:none}.memproto,.memname{font-weight:bold;text-shadow:none}.tablist{height:36px;display:block;position:relative}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a{color:#f2f2f2}.tablist li.current a{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}.contents{min-height:590px}div.contents,div.header{max-width:920px;margin:0 auto;padding:0 32px;background:#fff none}table.doxtable th,dl.reflist dt{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;text-align:left;color:#fff}dl.reflist dt a.el{color:#f60;padding:.2em;border-radius:4px;background-color:#ffe0cc}div.toc{float:none;width:auto}div.toc h3{font-size:1.17em}div.toc ul{padding-left:1.5em}div.toc li{font-size:1em;padding-left:0;list-style-type:disc}div.toc,.memproto,div.qindex,div.ah{background:linear-gradient(to bottom, #f2f2f2 0, #e6e6e6 100%);box-shadow:inset 0 0 32px #e6e6e6;text-shadow:0 1px 1px #fff;color:#1a1a1a;border:2px solid #e6e6e6;border-radius:4px}.paramname{color:#803300}dl.reflist dt{border:2px solid #f60;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:none}dl.reflist dd{border:2px solid #f60;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:none}table.doxtable{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,.tablist a:hover,span.lineno a:hover{color:#f60;text-decoration:none}div.directory{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}hr,.memSeparator{height:2px;background:linear-gradient(to right, #f2f2f2 0, #d9d9d9 50%, #f2f2f2 100%)}dl.note,dl.pre,dl.post,dl.invariant{background:linear-gradient(to bottom, #ddfad1 0, #cbf7ba 100%);box-shadow:inset 0 0 32px #baf5a3;color:#1e5309;border:2px solid #afe599}dl.warning,dl.attention{background:linear-gradient(to bottom, #fae8d1 0, #f7ddba 100%);box-shadow:inset 0 0 32px #f5d1a3;color:#533309;border:2px solid #e5c499}dl.deprecated,dl.bug{background:linear-gradient(to bottom, #fad1e3 0, #f7bad6 100%);box-shadow:inset 0 0 32px #f5a3c8;color:#53092a;border:2px solid #e599bb}dl.todo,dl.test{background:linear-gradient(to bottom, #d1ecfa 0, #bae3f7 100%);box-shadow:inset 0 0 32px #a3daf5;color:#093a53;border:2px solid #99cce5}dl.note,dl.pre,dl.post,dl.invariant,dl.warning,dl.attention,dl.deprecated,dl.bug,dl.todo,dl.test{border-radius:4px;padding:1em;text-shadow:0 1px 1px #fff;margin:1em 0}.note a,.pre a,.post a,.invariant a,.warning a,.attention a,.deprecated a,.bug a,.todo a,.test a,.note a:visited,.pre a:visited,.post a:visited,.invariant a:visited,.warning a:visited,.attention a:visited,.deprecated a:visited,.bug a:visited,.todo a:visited,.test a:visited{color:inherit}div.line{line-height:inherit}div.fragment,pre.fragment{background:#f2f2f2;border-radius:4px;border:none;padding:1em;overflow:auto;border-left:4px solid #ccc;margin:1em 0}.lineno a,.lineno a:visited,.line,pre.fragment{color:#4d4d4d}span.preprocessor,span.comment{color:#007899}a.code,a.code:visited{color:#e64500}span.keyword,span.keywordtype,span.keywordflow{color:#404040;font-weight:bold}span.stringliteral{color:#360099}code{padding:.1em;border-radius:4px} +.sm-dox,.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted,.sm-dox ul a:hover{background:none;text-shadow:none}.sm-dox a span.sub-arrow{border-color:#f2f2f2 transparent transparent transparent}.sm-dox a span.sub-arrow:active,.sm-dox a span.sub-arrow:focus,.sm-dox a span.sub-arrow:hover,.sm-dox a:hover span.sub-arrow{border-color:#f60 transparent transparent transparent}.sm-dox ul a span.sub-arrow:active,.sm-dox ul a span.sub-arrow:focus,.sm-dox ul a span.sub-arrow:hover,.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent #f60}.sm-dox ul a:hover{background:#666;text-shadow:none}.sm-dox ul.sm-nowrap a{color:#4d4d4d;text-shadow:none}#main-nav,#main-menu,#main-menu a,#main-menu a:visited,#main-menu a:hover,#main-menu li,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code{background:none}#titlearea,.footer,.contents,div.header,.memdoc,table.doxtable td,table.doxtable th,hr,.memSeparator{border:none}#main-menu a,#main-menu a:visited,#main-menu a:hover,#main-menu li,.reflist dt a.el,.levels span,.directory .levels span{text-shadow:none}.memdoc,dl.reflist dd{box-shadow:none}div.headertitle,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,table.doxtable code{padding:0}#nav-path,.directory .levels,span.lineno{display:none}html,#titlearea,.footer,tr.even,.directory tr.even,.doxtable tr:nth-child(even),.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,code{background:#f2f2f2}body{color:#4d4d4d}h1,h2,h2.groupheader,h3,div.toc h3,h4,h5,h6,strong,em{color:#1a1a1a;border-bottom:none}h1{padding-top:.5em;font-size:180%}h2{padding-top:.5em;margin-bottom:0;font-size:140%}h3{padding-top:.5em;margin-bottom:0;font-size:110%}.glfwheader{font-size:16px;height:64px;max-width:920px;min-width:800px;padding:0 32px;margin:0 auto}#glfwhome{line-height:64px;padding-right:48px;color:#666;font-size:2.5em;background:url("http://www.glfw.org/css/arrow.png") no-repeat right}.glfwnavbar{list-style-type:none;margin:0 auto;float:right}#glfwhome,.glfwnavbar li{float:left}.glfwnavbar a,.glfwnavbar a:visited{line-height:64px;margin-left:2em;display:block;color:#666}#glfwhome,.glfwnavbar a,.glfwnavbar a:visited{transition:.35s ease}#titlearea,.footer{color:#666}address.footer{text-align:center;padding:2em;margin-top:3em}#top{background:#666}#main-nav{max-width:960px;min-width:800px;margin:0 auto;font-size:13px}#main-menu{max-width:920px;min-width:800px;margin:0 auto;font-size:13px}.memtitle{display:none}.memproto,.memname{font-weight:bold;text-shadow:none}#main-menu{height:36px;display:block;position:relative}#main-menu a,#main-menu a:visited,#main-menu a:hover,#main-menu li{color:#f2f2f2}#main-menu li ul.sm-nowrap li a{color:#4d4d4d}#main-menu li ul.sm-nowrap li a:hover{color:#f60}.contents{min-height:590px}div.contents,div.header{max-width:920px;margin:0 auto;padding:0 32px;background:#fff none}table.doxtable th,dl.reflist dt{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;text-align:left;color:#fff}dl.reflist dt a.el{color:#f60;padding:.2em;border-radius:4px;background-color:#ffe0cc}div.toc{float:none;width:auto}div.toc h3{font-size:1.17em}div.toc ul{padding-left:1.5em}div.toc li{font-size:1em;padding-left:0;list-style-type:disc}div.toc,.memproto,div.qindex,div.ah{background:linear-gradient(to bottom, #f2f2f2 0, #e6e6e6 100%);box-shadow:inset 0 0 32px #e6e6e6;text-shadow:0 1px 1px #fff;color:#1a1a1a;border:2px solid #e6e6e6;border-radius:4px}.paramname{color:#803300}dl.reflist dt{border:2px solid #f60;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:none}dl.reflist dd{border:2px solid #f60;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:none}table.doxtable{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,#main-menu a:hover,span.lineno a:hover{color:#f60;text-decoration:none}div.directory{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}hr,.memSeparator{height:2px;background:linear-gradient(to right, #f2f2f2 0, #d9d9d9 50%, #f2f2f2 100%)}dl.note,dl.pre,dl.post,dl.invariant{background:linear-gradient(to bottom, #ddfad1 0, #cbf7ba 100%);box-shadow:inset 0 0 32px #baf5a3;color:#1e5309;border:2px solid #afe599}dl.warning,dl.attention{background:linear-gradient(to bottom, #fae8d1 0, #f7ddba 100%);box-shadow:inset 0 0 32px #f5d1a3;color:#533309;border:2px solid #e5c499}dl.deprecated,dl.bug{background:linear-gradient(to bottom, #fad1e3 0, #f7bad6 100%);box-shadow:inset 0 0 32px #f5a3c8;color:#53092a;border:2px solid #e599bb}dl.todo,dl.test{background:linear-gradient(to bottom, #d1ecfa 0, #bae3f7 100%);box-shadow:inset 0 0 32px #a3daf5;color:#093a53;border:2px solid #99cce5}dl.note,dl.pre,dl.post,dl.invariant,dl.warning,dl.attention,dl.deprecated,dl.bug,dl.todo,dl.test{border-radius:4px;padding:1em;text-shadow:0 1px 1px #fff;margin:1em 0}.note a,.pre a,.post a,.invariant a,.warning a,.attention a,.deprecated a,.bug a,.todo a,.test a,.note a:visited,.pre a:visited,.post a:visited,.invariant a:visited,.warning a:visited,.attention a:visited,.deprecated a:visited,.bug a:visited,.todo a:visited,.test a:visited{color:inherit}div.line{line-height:inherit}div.fragment,pre.fragment{background:#f2f2f2;border-radius:4px;border:none;padding:1em;overflow:auto;border-left:4px solid #ccc;margin:1em 0}.lineno a,.lineno a:visited,.line,pre.fragment{color:#4d4d4d}span.preprocessor,span.comment{color:#007899}a.code,a.code:visited{color:#e64500}span.keyword,span.keywordtype,span.keywordflow{color:#404040;font-weight:bold}span.stringliteral{color:#360099}code{padding:.1em;border-radius:4px} diff --git a/docs/extra.less b/docs/extra.less index 9221459a5..53e94f751 100644 --- a/docs/extra.less +++ b/docs/extra.less @@ -81,12 +81,29 @@ text-shadow:none; } +.sm-dox a span.sub-arrow { + border-color:@navbar-link-color transparent transparent transparent; +} + +.sm-dox a span.sub-arrow:active,.sm-dox a span.sub-arrow:focus,.sm-dox a span.sub-arrow:hover,.sm-dox a:hover span.sub-arrow { + border-color:@default-link-color transparent transparent transparent; +} + +.sm-dox ul a span.sub-arrow:active,.sm-dox ul a span.sub-arrow:focus,.sm-dox ul a span.sub-arrow:hover,.sm-dox ul a:hover span.sub-arrow { + border-color:transparent transparent transparent @default-link-color; +} + .sm-dox ul a:hover { background:@header-footer-link-color; text-shadow:none; } -#main-nav,#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code { +.sm-dox ul.sm-nowrap a { + color:@default-text-color; + text-shadow:none; +} + +#main-nav,#main-menu,#main-menu a,#main-menu a:visited,#main-menu a:hover,#main-menu li,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code { background:none; } @@ -94,7 +111,7 @@ border:none; } -.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.reflist dt a.el,.levels span,.directory .levels span { +#main-menu a,#main-menu a:visited,#main-menu a:hover,#main-menu li,.reflist dt a.el,.levels span,.directory .levels span { text-shadow:none; } @@ -199,7 +216,7 @@ address.footer { font-size:13px; } -#navrow1,#navrow2,#navrow3,#navrow4 { +#main-menu { max-width:920px; min-width:800px; margin:0 auto; @@ -215,21 +232,22 @@ address.footer { text-shadow:none; } -.tablist { +#main-menu { height:36px; display:block; position:relative; } -.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a { +#main-menu a,#main-menu a:visited,#main-menu a:hover,#main-menu li { color:@navbar-link-color; } -.tablist li.current a { - background:linear-gradient(to bottom,@tab-background-color2 0%,@tab-background-color1 100%); - box-shadow:inset 0 0 32px @tab-background-color1; - text-shadow:0 -1px 1px darken(@tab-background-color1, 15%); - color:@tab-text-color; +#main-menu li ul.sm-nowrap li a { + color:@default-text-color; +} + +#main-menu li ul.sm-nowrap li a:hover { + color:@default-link-color; } .contents { @@ -311,7 +329,7 @@ table.doxtable { border-radius:4px; } -a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,.tablist a:hover,span.lineno a:hover { +a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,#main-menu a:hover,span.lineno a:hover { color:@default-link-color; text-decoration:none; } From 1be81a15409ab5a485ce71cade96ff22e7e698fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 22 Oct 2017 16:27:17 +0200 Subject: [PATCH 169/222] Documentation work --- docs/build.dox | 14 +++++++------- docs/compile.dox | 8 ++++---- docs/context.dox | 2 +- docs/input.dox | 12 ++++++------ docs/intro.dox | 10 +++++----- docs/moving.dox | 2 +- docs/quick.dox | 12 +++++------- docs/window.dox | 10 +++++----- include/GLFW/glfw3.h | 14 ++++++-------- 9 files changed, 40 insertions(+), 44 deletions(-) diff --git a/docs/build.dox b/docs/build.dox index e428594e3..18ce13ce2 100644 --- a/docs/build.dox +++ b/docs/build.dox @@ -183,8 +183,8 @@ This section is about using CMake to compile and link GLFW along with your application. If you want to use an installed binary instead, see @ref build_link_cmake_package. -With just a few changes to your `CMakeLists.txt` you can have the GLFW source -tree built along with your application. +With a few changes to your `CMakeLists.txt` you can have the GLFW source tree +built along with your application. When including GLFW as part of your build, you probably don't want to build the GLFW tests, examples and documentation. To disable these, set the corresponding @@ -249,7 +249,7 @@ This section is about using CMake to link GLFW after it has been built and installed. If you want to build it along with your application instead, see @ref build_link_cmake_source. -With just a few changes to your `CMakeLists.txt`, you can locate the package and +With a few changes to your `CMakeLists.txt` you can locate the package and target files generated when GLFW is installed. @code{.cmake} @@ -312,8 +312,8 @@ GLFW library may look like this: cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --static --libs glfw3` @endcode -If you are using the shared version of the GLFW library, simply omit the -`--static` flag. +If you are using the shared version of the GLFW library, omit the `--static` +flag. @code{.sh} cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --libs glfw3` @@ -350,8 +350,8 @@ cc `pkg-config --cflags glfw3 glu` -o myprog myprog.c `pkg-config --static --lib @subsection build_link_xcode With Xcode on macOS -If you are using the dynamic library version of GLFW, simply add it to the -project dependencies. +If you are using the dynamic library version of GLFW, add it to the project +dependencies. If you are using the static library version of GLFW, add it and the Cocoa, OpenGL, IOKit and CoreVideo frameworks to the project as dependencies. They can diff --git a/docs/compile.dox b/docs/compile.dox index 35d657324..4486156ec 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -13,7 +13,7 @@ build applications that use GLFW, see @ref build_guide. GLFW uses [CMake](http://www.cmake.org/) to generate project files or makefiles for a particular development environment. If you are on a Unix-like system such as Linux or FreeBSD or have a package system like Fink, MacPorts, Cygwin or -Homebrew, you can simply install its CMake package. If not, you can download +Homebrew, you can install its CMake package. If not, you can download installers for Windows and macOS from the [CMake website](http://www.cmake.org/). @@ -33,9 +33,9 @@ below. @subsubsection compile_deps_msvc Dependencies for Visual C++ on Windows -The Microsoft Platform SDK that is installed along with Visual C++ already -contains all the necessary headers, link libraries and tools except for CMake. -Move on to @ref compile_generate. +The Windows SDK bundled with Visual C++ already contains all the necessary +headers, link libraries and tools except for CMake. Move on to @ref +compile_generate. @subsubsection compile_deps_mingw Dependencies for MinGW or MinGW-w64 on Windows diff --git a/docs/context.dox b/docs/context.dox index 9aa72a5c8..61292849d 100644 --- a/docs/context.dox +++ b/docs/context.dox @@ -61,7 +61,7 @@ information. The name and number of this chapter unfortunately varies between versions and APIs, but has at times been named _Shared Objects and Multiple Contexts_. -GLFW comes with a simple object sharing test program called `sharing`. +GLFW comes with a barebones object sharing test program called `sharing`. @subsection context_offscreen Offscreen contexts diff --git a/docs/input.dox b/docs/input.dox index 0eaa8ef84..318d48d5c 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -203,9 +203,9 @@ void character_callback(GLFWwindow* window, unsigned int codepoint) } @endcode -If you wish to receive even those Unicode code points generated with modifier -key combinations that a plain text field would ignore, or just want to know -exactly what modifier keys were used, set a character with modifiers callback. +If you also wish to receive those Unicode code points generated with modifier +key combinations that a plain text field would ignore, or want to know exactly +what modifier keys were used, set a character with modifiers callback. @code glfwSetCharModsCallback(window, charmods_callback); @@ -297,8 +297,8 @@ is provided normally via both the cursor position callback and through polling. other features of GLFW. It is not supported and will not work as robustly as `GLFW_CURSOR_DISABLED`. -If you just wish the cursor to become hidden when it is over a window, set -the cursor mode to `GLFW_CURSOR_HIDDEN`. +If you only wish the cursor to become hidden when it is over a window but still +want it to behave normally, set the cursor mode to `GLFW_CURSOR_HIDDEN`. @code glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); @@ -501,7 +501,7 @@ void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) } @endcode -A simple mouse wheel, being vertical, provides offsets along the Y-axis. +A normal mouse wheel, being vertical, provides offsets along the Y-axis. @section joystick Joystick input diff --git a/docs/intro.dox b/docs/intro.dox index 65aeef68b..46a445aa2 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -55,13 +55,13 @@ if (!glfwInit()) If any part of initialization fails, any parts that succeeded are terminated as if @ref glfwTerminate had been called. The library only needs to be initialized -once and additional calls to an already initialized library will simply return +once and additional calls to an already initialized library will return `GLFW_TRUE` immediately. Once the library has been successfully initialized, it should be terminated before the application exits. Modern systems are very good at freeing resources -allocated by programs that simply exit, but GLFW sometimes has to change global -system settings and these might not be restored without termination. +allocated by programs that exit, but GLFW sometimes has to change global system +settings and these might not be restored without termination. @subsection init_hints Initialization hints @@ -79,8 +79,8 @@ during initialization. Once GLFW has been initialized, any values you set will be ignored until the library is terminated and initialized again. Some hints are platform specific. These may be set on any platform but they -will only affect their specific platform. Other platforms will simply ignore -them. Setting these hints requires no platform specific headers or functions. +will only affect their specific platform. Other platforms will ignore them. +Setting these hints requires no platform specific headers or functions. @subsubsection init_hints_shared Shared init hints diff --git a/docs/moving.dox b/docs/moving.dox index af3da61cb..0f33a7e54 100644 --- a/docs/moving.dox +++ b/docs/moving.dox @@ -221,7 +221,7 @@ GLFW 2, windows and contexts created with GLFW 3 will never be destroyed unless you choose them to be. Each window now has a close flag that is set to `GLFW_TRUE` when the user attempts to close that window. By default, nothing else happens and the window stays visible. It is then up to you to either destroy -the window, take some other action or simply ignore the request. +the window, take some other action or ignore the request. You can query the close flag at any time with @ref glfwWindowShouldClose and set it at any time with @ref glfwSetWindowShouldClose. diff --git a/docs/quick.dox b/docs/quick.dox index dc1a2f8d9..ff2c6f06f 100644 --- a/docs/quick.dox +++ b/docs/quick.dox @@ -69,7 +69,7 @@ if (!glfwInit()) } @endcode -Note that `GLFW_TRUE` and `GLFW_FALSE` are and will always be just one and zero. +Note that `GLFW_TRUE` and `GLFW_FALSE` are and will always be one and zero. When you are done using GLFW, typically just before the application exits, you need to terminate GLFW. @@ -86,14 +86,12 @@ functions that require it. @subsection quick_capture_error Setting an error callback Most events are reported through callbacks, whether it's a key being pressed, -a GLFW window being moved, or an error occurring. Callbacks are simply -C functions (or C++ static methods) that are called by GLFW with arguments -describing the event. +a GLFW window being moved, or an error occurring. Callbacks are C functions (or +C++ static methods) that are called by GLFW with arguments describing the event. In case a GLFW function fails, an error is reported to the GLFW error callback. You can receive these reports with an error callback. This function must have -the signature below. This simple error callback just prints the error -description to `stderr`. +the signature below but may do anything permitted in other callbacks. @code void error_callback(int error, const char* description) @@ -249,7 +247,7 @@ You can also set a framebuffer size callback using @ref glfwSetFramebufferSizeCallback and be notified when the size changes. Actual rendering with OpenGL is outside the scope of this tutorial, but there -are [many](https://open.gl/) [excellent](http://learnopengl.com/) +are [many](https://open.gl/) [excellent](https://learnopengl.com/) [tutorial](http://openglbook.com/) [sites](http://ogldev.atspace.co.uk/) that teach modern OpenGL. Some of them use GLFW to create the context and window while others use GLUT or SDL, but remember that OpenGL itself always works the diff --git a/docs/window.dox b/docs/window.dox index 39420804f..85663e770 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -77,7 +77,7 @@ GLFWvidmode.blueBits | @ref GLFW_BLUE_BITS hint GLFWvidmode.refreshRate | @ref GLFW_REFRESH_RATE hint Once you have a full screen window, you can change its resolution, refresh rate -and monitor with @ref glfwSetWindowMonitor. If you just need change its +and monitor with @ref glfwSetWindowMonitor. If you only need change its resolution you can also call @ref glfwSetWindowSize. In all cases, the new video mode will be selected the same way as the video mode chosen by @ref glfwCreateWindow. If the window has an OpenGL or OpenGL ES context, it will be @@ -99,7 +99,7 @@ If the closest match for the desired video mode is the current one, the video mode will not be changed, making window creation faster and application switching much smoother. This is sometimes called _windowed full screen_ or _borderless full screen_ window and counts as a full screen window. To create -such a window, simply request the current video mode. +such a window, request the current video mode. @code const GLFWvidmode* mode = glfwGetVideoMode(monitor); @@ -151,8 +151,8 @@ and reset all at once to their defaults with @ref glfwDefaultWindowHints. Some hints are platform specific. These are always valid to set on any platform but they will only affect their specific platform. Other platforms -will simply ignore them. Setting these hints requires no platform specific -headers or calls. +will ignore them. Setting these hints requires no platform specific headers or +calls. Note that hints need to be set _before_ the creation of the window and context you wish to have the specified attributes. @@ -694,7 +694,7 @@ glfwSetWindowAspectRatio(window, 16, 9); The aspect ratio is specified as a numerator and denominator, corresponding to the width and height, respectively. If you want a window to maintain its -current aspect ratio, simply use its current size as the ratio. +current aspect ratio, use its current size as the ratio. @code int width, height; diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 819d2cd6a..8e6bc42cf 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -274,14 +274,14 @@ extern "C" { /*! @brief One. * * One. Seriously. You don't _need_ to use this symbol in your code. It's - * just semantic sugar for the number 1. You can use `1` or `true` or `_True` + * semantic sugar for the number 1. You can also use `1` or `true` or `_True` * or `GL_TRUE` or whatever you want. */ #define GLFW_TRUE 1 /*! @brief Zero. * * Zero. Seriously. You don't _need_ to use this symbol in your code. It's - * just just semantic sugar for the number 0. You can use `0` or `false` or + * semantic sugar for the number 0. You can also use `0` or `false` or * `_False` or `GL_FALSE` or whatever you want. */ #define GLFW_FALSE 0 @@ -1629,9 +1629,8 @@ GLFWAPI void glfwTerminate(void); * again. * * Some hints are platform specific. These may be set on any platform but they - * will only affect their specific platform. Other platforms will simply - * ignore them. Setting these hints requires no platform specific headers or - * functions. + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. * * @param[in] hint The [init hint](@ref init_hints) to set. * @param[in] value The new value of the init hint. @@ -1664,9 +1663,8 @@ GLFWAPI void glfwInitHint(int hint, int value); * again. * * Some hints are platform specific. These may be set on any platform but they - * will only affect their specific platform. Other platforms will simply - * ignore them. Setting these hints requires no platform specific headers or - * functions. + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. * * @param[in] hint The [init hint](@ref init_hints) to set. * @param[in] value The new value of the init hint. From 16bf872117896fb88493403157fcd367303fd1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 29 Aug 2017 19:19:00 +0200 Subject: [PATCH 170/222] Add content scale queries This adds glfwGetWindowContentScale and glfwGetMonitorContentScale for querying the recommended drawing scale factor for DPI-aware rendering. Parts of this patch are based on code by @ferreiradaselva. Fixes #235. Fixes #439. Fixes #677. Fixes #845. Fixes #898. --- README.md | 2 ++ docs/monitor.dox | 27 ++++++++++++++++---- docs/news.dox | 9 +++++++ docs/window.dox | 20 +++++++++++++++ include/GLFW/glfw3.h | 60 ++++++++++++++++++++++++++++++++++++++++++++ src/cocoa_monitor.m | 45 +++++++++++++++++++++++++++++++++ src/cocoa_platform.h | 1 + src/cocoa_window.m | 12 +++++++++ src/internal.h | 2 ++ src/mir_monitor.c | 9 +++++++ src/mir_window.c | 9 +++++++ src/monitor.c | 15 +++++++++++ src/null_monitor.c | 9 +++++++ src/null_window.c | 9 +++++++ src/win32_init.c | 2 ++ src/win32_monitor.c | 50 ++++++++++++++++++++++++++++++------ src/win32_platform.h | 11 ++++++++ src/win32_window.c | 21 ++++++---------- src/window.c | 15 +++++++++++ src/wl_monitor.c | 9 +++++++ src/wl_window.c | 9 +++++++ src/x11_init.c | 40 +++++++++++++++++++++++++++++ src/x11_monitor.c | 9 +++++++ src/x11_platform.h | 2 ++ src/x11_window.c | 9 +++++++ tests/monitors.c | 9 ++++--- 26 files changed, 387 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 01b159c93..a890ac09e 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,8 @@ information on what to include when reporting a bug. gamepad mapping (#900) - Added `glfwGetGamepadState` function, `GLFW_GAMEPAD_*` and `GLFWgamepadstate` for retrieving gamepad input state (#900) +- Added `glfwGetWindowContentScale` and `glfwGetMonitorContentScale` for + DPI-aware rendering (#235,#439,#677,#845,#898) - Added `glfwRequestWindowAttention` function for requesting attention from the user (#732,#988) - Added `glfwGetKeyScancode` function that allows retrieving platform dependent diff --git a/docs/monitor.dox b/docs/monitor.dox index 708461f58..7245f70cd 100644 --- a/docs/monitor.dox +++ b/docs/monitor.dox @@ -131,17 +131,34 @@ current _resolution_, i.e. the width and height of its current [video mode](@ref monitor_modes). @code -int widthMM, heightMM; -glfwGetMonitorPhysicalSize(monitor, &widthMM, &heightMM); +int width_mm, height_mm; +glfwGetMonitorPhysicalSize(monitor, &width_mm, &height_mm); @endcode -This can, for example, be used together with the current video mode to calculate -the DPI of a monitor. +While this can be used to calculate the raw DPI of a monitor, this is often not +useful. Instead use the [monitor content scale](@ref monitor_scale) and +[window content scale](@ref window_scale) to scale your content. + + +@subsection monitor_scale Content scale + +The content scale for a monitor can be retrieved with @ref +glfwGetMonitorContentScale. @code -const double dpi = mode->width / (widthMM / 25.4); +float xscale, yscale; +glfwGetMonitorContentScale(monitor, &xscale, &yscale); @endcode +The content scale is the ratio between the current DPI and the platform's +default DPI. If you scale all pixel dimensions by this scale then your content +should appear at an appropriate size. This is especially important for text and +any UI elements. + +The content scale may depend on both the monitor resolution and pixel density +and on user settings. It may be very different from the raw DPI calculated from +the physical size and current resolution. + @subsection monitor_pos Virtual position diff --git a/docs/news.dox b/docs/news.dox index 86b68c41f..03a9c8dc5 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -58,6 +58,15 @@ windows with @ref glfwSetWindowAttrib. @see @ref window_attribs +@subsection news_33_contentscale Content scale queries for DPI-aware rendering + +GLFW now supports querying the window and monitor content scale, i.e. the ratio +between the current DPI and the platform's default DPI, with @ref +glfwGetWindowContentScale and @ref glfwGetMonitorContentScale. + +@see @ref window_scale + + @subsection news_33_inithint Support for initialization hints GLFW now supports setting library initialization hints with @ref glfwInitHint diff --git a/docs/window.dox b/docs/window.dox index 85663e770..7961e0288 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -663,6 +663,26 @@ The size of a framebuffer may change independently of the size of a window, for example if the window is dragged between a regular monitor and a high-DPI one. +@subsection window_scale Window content scale + +The content scale for a window can be retrieved with @ref +glfwGetWindowContentScale. + +@code +float xscale, yscale; +glfwGetWindowContentScale(window, &xscale, &yscale); +@endcode + +The content scale of a window is the ratio between the current DPI and the +platform's default DPI. If you scale all pixel dimensions by this scale then +your content should appear at an appropriate size. This is especially important +for text and any UI elements. + +On systems where each monitors can have its own content scale, the window +content scale will depend on which monitor the system considers the window to be +on. + + @subsection window_sizelimits Window size limits The minimum and maximum size of the client area of a windowed mode window can be diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 8e6bc42cf..0ba409b0b 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1926,6 +1926,36 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); */ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); +/*! @brief Retrieves the content scale for the specified monitor. + * + * This function retrieves the content scale for the specified monitor. The + * content scale is the ratio between the current DPI and the platform's + * default DPI. If you scale all pixel dimensions by this scale then your + * content should appear at an appropriate size. This is especially important + * for text and any UI elements. + * + * The content scale may depend on both the monitor resolution and pixel + * density and on user settings. It may be very different from the raw DPI + * calculated from the physical size and current resolution. + * + * @param[in] monitor The monitor to query. + * @param[out] xscale Where to store the x-axis content scale, or `NULL`. + * @param[out] yscale Where to store the y-axis content scale, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_scale + * @sa @ref glfwGetWindowContentScale + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, float* yscale); + /*! @brief Returns the name of the specified monitor. * * This function returns a human-readable name, encoded as UTF-8, of the @@ -2774,6 +2804,36 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height) */ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); +/*! @brief Retrieves the content scale for the specified window. + * + * This function retrieves the content scale for the specified window. The + * content scale is the ratio between the current DPI and the platform's + * default DPI. If you scale all pixel dimensions by this scale then your + * content should appear at an appropriate size. This is especially important + * for text and any UI elements. + * + * On systems where each monitors can have its own content scale, the window + * content scale will depend on which monitor the system considers the window + * to be on. + * + * @param[in] window The window to query. + * @param[out] xscale Where to store the x-axis content scale, or `NULL`. + * @param[out] yscale Where to store the y-axis content scale, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_scale + * @sa @ref glfwGetMonitorContentScale + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* yscale); + /*! @brief Iconifies the specified window. * * This function iconifies (minimizes) the specified window if it was diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index 6020599fd..6108342c0 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -229,6 +229,9 @@ void _glfwPollMonitorsNS(void) displays = calloc(displayCount, sizeof(CGDirectDisplayID)); CGGetOnlineDisplayList(displayCount, displays, &displayCount); + for (i = 0; i < _glfw.monitorCount; i++) + _glfw.monitors[i]->ns.screen = nil; + disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { @@ -371,6 +374,48 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = (int) bounds.origin.y; } +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (!monitor->ns.screen) + { + NSUInteger i; + NSArray* screens = [NSScreen screens]; + + for (i = 0; i < [screens count]; i++) + { + NSScreen* screen = [screens objectAtIndex:i]; + NSNumber* displayID = + [[screen deviceDescription] objectForKey:@"NSScreenNumber"]; + + // HACK: Compare unit numbers instead of display IDs to work around + // display replacement on machines with automatic graphics + // switching + if (monitor->ns.unitNumber == + CGDisplayUnitNumber([displayID unsignedIntValue])) + { + monitor->ns.screen = screen; + break; + } + } + + if (i == [screens count]) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to find a screen for monitor"); + return; + } + } + + const NSRect points = [monitor->ns.screen frame]; + const NSRect pixels = [monitor->ns.screen convertRectToBacking:points]; + + if (xscale) + *xscale = (float) (pixels.size.width / points.size.width); + if (yscale) + *yscale = (float) (pixels.size.height / points.size.height); +} + GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { CFArrayRef modes; diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index f0ba4e857..61d0ee916 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -135,6 +135,7 @@ typedef struct _GLFWmonitorNS CGDirectDisplayID displayID; CGDisplayModeRef previousMode; uint32_t unitNumber; + id screen; } _GLFWmonitorNS; diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 0a3bcd540..4c9dea903 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1288,6 +1288,18 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, *bottom = contentRect.origin.y - frameRect.origin.y; } +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + const NSRect points = [window->ns.view frame]; + const NSRect pixels = [window->ns.view convertRectToBacking:points]; + + if (xscale) + *xscale = (float) (pixels.size.width / points.size.width); + if (yscale) + *yscale = (float) (pixels.size.height / points.size.height); +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { [window->ns.object miniaturize:nil]; diff --git a/src/internal.h b/src/internal.h index b9f55da7c..39494340b 100644 --- a/src/internal.h +++ b/src/internal.h @@ -641,6 +641,7 @@ const char* _glfwPlatformGetScancodeName(int scancode); int _glfwPlatformGetKeyScancode(int key); void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale); GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); @@ -670,6 +671,7 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int min void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom); void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale); void _glfwPlatformIconifyWindow(_GLFWwindow* window); void _glfwPlatformRestoreWindow(_GLFWwindow* window); void _glfwPlatformMaximizeWindow(_GLFWwindow* window); diff --git a/src/mir_monitor.c b/src/mir_monitor.c index 268485064..b300cac03 100644 --- a/src/mir_monitor.c +++ b/src/mir_monitor.c @@ -88,6 +88,15 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = monitor->mir.y; } +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = 1.f; + if (yscale) + *yscale = 1.f; +} + static void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf) { switch (pf) diff --git a/src/mir_window.c b/src/mir_window.c index 8b763de10..c752cdb47 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -515,6 +515,15 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) *height = window->mir.height; } +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = 1.f; + if (yscale) + *yscale = 1.f; +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { MirWindowSpec* spec; diff --git a/src/monitor.c b/src/monitor.c index 4acecd588..40b241323 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -314,6 +314,21 @@ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* *heightMM = monitor->heightMM; } +GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle, + float* xscale, float* yscale) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + if (xscale) + *xscale = 0.f; + if (yscale) + *yscale = 0.f; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale); +} + GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; diff --git a/src/null_monitor.c b/src/null_monitor.c index f5678bbc3..007dd1aac 100644 --- a/src/null_monitor.c +++ b/src/null_monitor.c @@ -36,6 +36,15 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { } +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = 1.f; + if (yscale) + *yscale = 1.f; +} + GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { return NULL; diff --git a/src/null_window.c b/src/null_window.c index 33ff6c333..3cc3905d1 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -139,6 +139,15 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, { } +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = 1.f; + if (yscale) + *yscale = 1.f; +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { } diff --git a/src/win32_init.c b/src/win32_init.c index 0531ff13e..ee7ccfdaa 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -151,6 +151,8 @@ static GLFWbool loadLibraries(void) { _glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness) GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); + _glfw.win32.shcore.GetDpiForMonitor_ = (PFN_GetDpiForMonitor) + GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor"); } return GLFW_TRUE; diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 76fbc0d8a..74dd82523 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -60,6 +60,7 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* display) { _GLFWmonitor* monitor; + int widthMM, heightMM; char* name; HDC dc; DEVMODEW dm; @@ -72,13 +73,26 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, if (!name) return NULL; + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm); + dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL); - monitor = _glfwAllocMonitor(name, - GetDeviceCaps(dc, HORZSIZE), - GetDeviceCaps(dc, VERTSIZE)); + if (IsWindows8Point1OrGreater()) + { + widthMM = GetDeviceCaps(dc, HORZSIZE); + heightMM = GetDeviceCaps(dc, VERTSIZE); + } + else + { + widthMM = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX)); + heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY)); + } DeleteDC(dc); + + monitor = _glfwAllocMonitor(name, widthMM, heightMM); free(name); if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED) @@ -101,10 +115,6 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, NULL, NULL); } - ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(dm); - EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm); - rect.left = dm.dmPosition.x; rect.top = dm.dmPosition.y; rect.right = dm.dmPosition.x + dm.dmPelsWidth; @@ -302,6 +312,26 @@ void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) } } +void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) +{ + UINT xdpi, ydpi; + + if (IsWindows8Point1OrGreater()) + GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + else + { + const HDC dc = GetDC(NULL); + xdpi = GetDeviceCaps(dc, LOGPIXELSX); + ydpi = GetDeviceCaps(dc, LOGPIXELSY); + ReleaseDC(NULL, dc); + } + + if (xscale) + *xscale = xdpi / 96.f; + if (yscale) + *yscale = ydpi / 96.f; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -324,6 +354,12 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = dm.dmPosition.y; } +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale); +} + GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { int modeIndex = 0, size = 0; diff --git a/src/win32_platform.h b/src/win32_platform.h index acbb5ca2a..1bfc638f4 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -135,6 +135,13 @@ typedef enum PROCESS_DPI_AWARENESS PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; +typedef enum MONITOR_DPI_TYPE +{ + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; #endif /*DPI_ENUMS_DECLARED*/ // HACK: Define versionhelpers.h functions manually as MinGW lacks the header @@ -216,7 +223,9 @@ typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIN // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); +typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); #define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_ +#define GetDpiForMonitor _glfw.win32.shcore.GetDpiForMonitor_ typedef VkFlags VkWin32SurfaceCreateFlagsKHR; @@ -326,6 +335,7 @@ typedef struct _GLFWlibraryWin32 struct { HINSTANCE instance; PFN_SetProcessDpiAwareness SetProcessDpiAwareness_; + PFN_GetDpiForMonitor GetDpiForMonitor_; } shcore; } _GLFWlibraryWin32; @@ -395,4 +405,5 @@ void _glfwInitTimerWin32(void); void _glfwPollMonitorsWin32(void); GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor); +void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale); diff --git a/src/win32_window.c b/src/win32_window.c index 490a75d2c..394a24dac 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -983,19 +983,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, break; } - case WM_DPICHANGED: - { - RECT* rect = (RECT*) lParam; - SetWindowPos(window->win32.handle, - HWND_TOP, - rect->left, - rect->top, - rect->right - rect->left, - rect->bottom - rect->top, - SWP_NOACTIVATE | SWP_NOZORDER); - break; - } - case WM_DROPFILES: { HDROP drop = (HDROP) wParam; @@ -1415,6 +1402,14 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, *bottom = rect.bottom - height; } +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + const HANDLE handle = MonitorFromWindow(window->win32.handle, + MONITOR_DEFAULTTONEAREST); + _glfwGetMonitorContentScaleWin32(handle, xscale, yscale); +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_MINIMIZE); diff --git a/src/window.c b/src/window.c index 57845579f..c91ef0058 100644 --- a/src/window.c +++ b/src/window.c @@ -632,6 +632,21 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); } +GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, + float* xscale, float* yscale) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (xscale) + *xscale = 0.f; + if (yscale) + *yscale = 0.f; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowContentScale(window, xscale, yscale); +} + GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_monitor.c b/src/wl_monitor.c index 24b0b39a7..10ef0e128 100644 --- a/src/wl_monitor.c +++ b/src/wl_monitor.c @@ -153,6 +153,15 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = monitor->wl.y; } +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = (float) monitor->wl.scale; + if (yscale) + *yscale = (float) monitor->wl.scale; +} + GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { *found = monitor->modeCount; diff --git a/src/wl_window.c b/src/wl_window.c index 32d5f4040..649ed7e94 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -550,6 +550,15 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, // implemented, but for now just leave everything as 0. } +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = (float) window->wl.scale; + if (yscale) + *yscale = (float) window->wl.scale; +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { // TODO: move to xdg_shell instead of wl_shell. diff --git a/src/x11_init.c b/src/x11_init.c index 526d9ca25..b603a15f2 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -743,6 +743,43 @@ static GLFWbool initExtensions(void) return GLFW_TRUE; } +// Retrieve system content scale via folklore heuristics +// +static void getSystemContentScale(float* xscale, float* yscale) +{ + // NOTE: Default to the display-wide DPI as we don't currently have a policy + // for which monitor a window is considered to be on + float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) * + 25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); + float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) * + 25.4f / DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); + + // NOTE: Basing the scale on Xft.dpi where available should provide the most + // consistent user experience (matches Qt, Gtk, etc), although not + // always the most accurate one + char* rms = XResourceManagerString(_glfw.x11.display); + if (rms) + { + XrmDatabase db = XrmGetStringDatabase(rms); + if (db) + { + XrmValue value; + char* type = NULL; + + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) + { + if (type && strcmp(type, "String") == 0) + xdpi = ydpi = atof(value.addr); + } + + XrmDestroyDatabase(db); + } + } + + *xscale = xdpi / 96.f; + *yscale = ydpi / 96.f; +} + // Create a blank cursor for hidden and disabled cursor modes // static Cursor createHiddenCursor(void) @@ -861,6 +898,7 @@ int _glfwPlatformInit(void) #endif XInitThreads(); + XrmInitialize(); _glfw.x11.display = XOpenDisplay(NULL); if (!_glfw.x11.display) @@ -884,6 +922,8 @@ int _glfwPlatformInit(void) _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); _glfw.x11.context = XUniqueContext(); + getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); + if (!initExtensions()) return GLFW_FALSE; diff --git a/src/x11_monitor.c b/src/x11_monitor.c index 5c0516e67..d68c58886 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -338,6 +338,15 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) } } +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = _glfw.x11.contentScaleX; + if (yscale) + *yscale = _glfw.x11.contentScaleY; +} + GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { GLFWvidmode* result; diff --git a/src/x11_platform.h b/src/x11_platform.h index 2b1c0c622..7eba441d5 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -211,6 +211,8 @@ typedef struct _GLFWlibraryX11 int screen; Window root; + // System content scale + float contentScaleX, contentScaleY; // Helper window for IPC Window helperWindowHandle; // Invisible cursor for hidden cursor mode diff --git a/src/x11_window.c b/src/x11_window.c index cf5483b0d..7c407cc5a 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2240,6 +2240,15 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, XFree(extents); } +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = _glfw.x11.contentScaleX; + if (yscale) + *yscale = _glfw.x11.contentScaleY; +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { if (window->x11.overrideRedirect) diff --git a/tests/monitors.c b/tests/monitors.c index fc54c3194..c7fd5c5cc 100644 --- a/tests/monitors.c +++ b/tests/monitors.c @@ -92,21 +92,24 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, static void list_modes(GLFWmonitor* monitor) { - int count, x, y, widthMM, heightMM, i; + int count, x, y, width_mm, height_mm, i; + float xscale, yscale; const GLFWvidmode* mode = glfwGetVideoMode(monitor); const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); glfwGetMonitorPos(monitor, &x, &y); - glfwGetMonitorPhysicalSize(monitor, &widthMM, &heightMM); + glfwGetMonitorPhysicalSize(monitor, &width_mm, &height_mm); + glfwGetMonitorContentScale(monitor, &xscale, &yscale); printf("Name: %s (%s)\n", glfwGetMonitorName(monitor), glfwGetPrimaryMonitor() == monitor ? "primary" : "secondary"); printf("Current mode: %s\n", format_mode(mode)); printf("Virtual position: %i %i\n", x, y); + printf("Content scale: %f %f\n", xscale, yscale); printf("Physical size: %i x %i mm (%0.2f dpi)\n", - widthMM, heightMM, mode->width * 25.4f / widthMM); + width_mm, height_mm, mode->width * 25.4f / width_mm); printf("Modes:\n"); From bf09dba95b92637795ef6f13ad87f1c9a2e5b0be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 26 Oct 2017 18:05:56 +0200 Subject: [PATCH 171/222] Cleanup --- src/cocoa_window.m | 2 +- src/internal.h | 2 +- src/win32_window.c | 2 +- src/window.c | 2 +- src/wl_window.c | 2 +- src/x11_window.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 4c9dea903..1ee85bc60 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1375,7 +1375,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, if (window->monitor) releaseMonitor(window); - _glfwInputWindowMonitorChange(window, monitor); + _glfwInputWindowMonitor(window, monitor); // HACK: Allow the state cached in Cocoa to catch up to reality // TODO: Solve this in a less terrible way diff --git a/src/internal.h b/src/internal.h index 39494340b..1bfdb8598 100644 --- a/src/internal.h +++ b/src/internal.h @@ -779,7 +779,7 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window); * @param[in] monitor The new desired monitor, or `NULL`. * @ingroup event */ -void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor); +void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); /*! @brief Notifies shared code of a physical key event. * @param[in] window The window that received the event. diff --git a/src/win32_window.c b/src/win32_window.c index 394a24dac..71738d140 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1477,7 +1477,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, if (window->monitor) releaseMonitor(window); - _glfwInputWindowMonitorChange(window, monitor); + _glfwInputWindowMonitor(window, monitor); if (monitor) { diff --git a/src/window.c b/src/window.c index c91ef0058..0e1c24847 100644 --- a/src/window.c +++ b/src/window.c @@ -108,7 +108,7 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window) window->callbacks.close((GLFWwindow*) window); } -void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor) +void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor) { window->monitor = monitor; } diff --git a/src/wl_window.c b/src/wl_window.c index 649ed7e94..f0f2637e4 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -642,7 +642,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, { wl_shell_surface_set_toplevel(window->wl.shellSurface); } - _glfwInputWindowMonitorChange(window, monitor); + _glfwInputWindowMonitor(window, monitor); } int _glfwPlatformWindowFocused(_GLFWwindow* window) diff --git a/src/x11_window.c b/src/x11_window.c index 7c407cc5a..c89d2ec51 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2377,7 +2377,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, if (window->monitor) releaseMonitor(window); - _glfwInputWindowMonitorChange(window, monitor); + _glfwInputWindowMonitor(window, monitor); updateNormalHints(window, width, height); updateWindowMode(window); From fcedb0be325425a6ad16d53349f2008ac4fc05d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 26 Oct 2017 18:52:43 +0200 Subject: [PATCH 172/222] Fix windows not detaching on monitor disconnect Regression introduced by 04f559e28d02f621187a0631490f26527cee8b81. Related to #1106. --- src/monitor.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/monitor.c b/src/monitor.c index 40b241323..0dfb19584 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -107,6 +107,17 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) else if (action == GLFW_DISCONNECTED) { int i; + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if (window->monitor == monitor) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + } + } for (i = 0; i < _glfw.monitorCount; i++) { From a1154247fad6ebd1e109e4cdbc32b93266646835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 29 Oct 2017 15:52:22 +0100 Subject: [PATCH 173/222] Fix default value of GLFW_CENTER_CURSOR Regression introduced by 72ac5badb0a188b0d912b1e4fa79a5e143253474. Fixes #1105. --- src/window.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/window.c b/src/window.c index 0e1c24847..303217338 100644 --- a/src/window.c +++ b/src/window.c @@ -246,11 +246,12 @@ void glfwDefaultWindowHints(void) // The default is a focused, visible, resizable window with decorations memset(&_glfw.hints.window, 0, sizeof(_glfw.hints.window)); - _glfw.hints.window.resizable = GLFW_TRUE; - _glfw.hints.window.visible = GLFW_TRUE; - _glfw.hints.window.decorated = GLFW_TRUE; - _glfw.hints.window.focused = GLFW_TRUE; - _glfw.hints.window.autoIconify = GLFW_TRUE; + _glfw.hints.window.resizable = GLFW_TRUE; + _glfw.hints.window.visible = GLFW_TRUE; + _glfw.hints.window.decorated = GLFW_TRUE; + _glfw.hints.window.focused = GLFW_TRUE; + _glfw.hints.window.autoIconify = GLFW_TRUE; + _glfw.hints.window.centerCursor = GLFW_TRUE; // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, // double buffered From 2867ca1e5b003b167fac33e8136a4698bb3aa074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 29 Oct 2017 16:27:15 +0100 Subject: [PATCH 174/222] Documentation work Fixes #1104. --- docs/window.dox | 14 +++++++------- include/GLFW/glfw3.h | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/window.dox b/docs/window.dox index 7961e0288..f21465021 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -582,15 +582,15 @@ window's desired video mode. The video mode most closely matching the new desired video mode is set immediately. The window is resized to fit the resolution of the set video mode. -If you wish to be notified when a window is resized, whether by the user or -the system, set a size callback. +If you wish to be notified when a window is resized, whether by the user, the +system or your own code, set a size callback. @code glfwSetWindowSizeCallback(window, window_size_callback); @endcode The callback function receives the new size, in screen coordinates, of the -client area of the window when it is resized. +client area of the window when the window is resized. @code void window_size_callback(GLFWwindow* window, int width, int height) @@ -740,15 +740,15 @@ The window system may put limitations on window placement. glfwSetWindowPos(window, 100, 100); @endcode -If you wish to be notified when a window is moved, whether by the user, system -or your own code, set a position callback. +If you wish to be notified when a window is moved, whether by the user, the +system or your own code, set a position callback. @code glfwSetWindowPosCallback(window, window_pos_callback); @endcode -The callback function receives the new position of the upper-left corner of the -client area when the window is moved. +The callback function receives the new position, in screen coordinates, of the +upper-left corner of the client area when the window is moved. @code void window_pos_callback(GLFWwindow* window, int xpos, int ypos) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 0ba409b0b..6923ba685 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3220,8 +3220,9 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); /*! @brief Sets the position callback for the specified window. * * This function sets the position callback of the specified window, which is - * called when the window is moved. The callback is provided with the screen - * position of the upper-left corner of the client area of the window. + * called when the window is moved. The callback is provided with the + * position, in screen coordinates, of the upper-left corner of the client area + * of the window. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set From a7a70cf34de16b8a0395551f69d429a7b6148ba4 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 26 Aug 2017 19:25:24 +0100 Subject: [PATCH 175/222] Wayland: Add dynamic loading of libxkbcommon --- CMakeLists.txt | 2 -- src/wl_init.c | 46 ++++++++++++++++++++++++++++++++++++++++ src/wl_platform.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56c1f386d..239a8bfce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,9 +286,7 @@ if (_GLFW_WAYLAND) list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") find_package(XKBCommon REQUIRED) - list(APPEND glfw_PKG_DEPS "xkbcommon") list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") - list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}") endif() #-------------------------------------------------------------------- diff --git a/src/wl_init.c b/src/wl_init.c index 8e42ce6e3..3841636f2 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -642,6 +642,49 @@ static void createKeyTables(void) int _glfwPlatformInit(void) { + _glfw.wl.xkb.handle = dlopen("libxkbcommon.so.0", RTLD_LAZY | RTLD_GLOBAL); + if (!_glfw.wl.xkb.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to open libxkbcommon."); + return GLFW_FALSE; + } + + _glfw.wl.xkb.context_new = (PFN_xkb_context_new) + dlsym(_glfw.wl.xkb.handle, "xkb_context_new"); + _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_context_unref"); + _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string) + dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); + _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref"); + _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index) + dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); + _glfw.wl.xkb.state_new = (PFN_xkb_state_new) + dlsym(_glfw.wl.xkb.handle, "xkb_state_new"); + _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_state_unref"); + _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms) + dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); + _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask) + dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); + _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods) + dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); + _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); + _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); + _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new"); + _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref"); + _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed"); + _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); + _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); + _glfw.wl.display = wl_display_connect(NULL); if (!_glfw.wl.display) { @@ -700,6 +743,9 @@ void _glfwPlatformTerminate(void) xkb_state_unref(_glfw.wl.xkb.state); xkb_context_unref(_glfw.wl.xkb.context); + dlclose(_glfw.wl.xkb.handle); + _glfw.wl.xkb.handle = NULL; + if (_glfw.wl.cursorTheme) wl_cursor_theme_destroy(_glfw.wl.cursorTheme); if (_glfw.wl.cursorSurface) diff --git a/src/wl_platform.h b/src/wl_platform.h index 656f0ef1f..059ea2eee 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -68,6 +68,41 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #define _GLFW_PLATFORM_CONTEXT_STATE #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE +typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags); +typedef void (* PFN_xkb_context_unref)(struct xkb_context*); +typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags); +typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*); +typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*); +typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*); +typedef void (* PFN_xkb_state_unref)(struct xkb_state*); +typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**); +typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t); +typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component); +typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); +typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); +typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags); +typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*); +typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t); +typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*); +typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*); +#define xkb_context_new _glfw.wl.xkb.context_new +#define xkb_context_unref _glfw.wl.xkb.context_unref +#define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string +#define xkb_keymap_unref _glfw.wl.xkb.keymap_unref +#define xkb_keymap_mod_get_index _glfw.wl.xkb.keymap_mod_get_index +#define xkb_state_new _glfw.wl.xkb.state_new +#define xkb_state_unref _glfw.wl.xkb.state_unref +#define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms +#define xkb_state_update_mask _glfw.wl.xkb.state_update_mask +#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods +#define xkb_compose_table_new_from_locale _glfw.wl.xkb.compose_table_new_from_locale +#define xkb_compose_table_unref _glfw.wl.xkb.compose_table_unref +#define xkb_compose_state_new _glfw.wl.xkb.compose_state_new +#define xkb_compose_state_unref _glfw.wl.xkb.compose_state_unref +#define xkb_compose_state_feed _glfw.wl.xkb.compose_state_feed +#define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status +#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym + // Wayland-specific per-window data // @@ -125,6 +160,7 @@ typedef struct _GLFWlibraryWayland short int scancodes[GLFW_KEY_LAST + 1]; struct { + void* handle; struct xkb_context* context; struct xkb_keymap* keymap; struct xkb_state* state; @@ -134,6 +170,24 @@ typedef struct _GLFWlibraryWayland xkb_mod_mask_t shiftMask; xkb_mod_mask_t superMask; unsigned int modifiers; + + PFN_xkb_context_new context_new; + PFN_xkb_context_unref context_unref; + PFN_xkb_keymap_new_from_string keymap_new_from_string; + PFN_xkb_keymap_unref keymap_unref; + PFN_xkb_keymap_mod_get_index keymap_mod_get_index; + PFN_xkb_state_new state_new; + PFN_xkb_state_unref state_unref; + PFN_xkb_state_key_get_syms state_key_get_syms; + PFN_xkb_state_update_mask state_update_mask; + PFN_xkb_state_serialize_mods state_serialize_mods; + PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; + PFN_xkb_compose_table_unref compose_table_unref; + PFN_xkb_compose_state_new compose_state_new; + PFN_xkb_compose_state_unref compose_state_unref; + PFN_xkb_compose_state_feed compose_state_feed; + PFN_xkb_compose_state_get_status compose_state_get_status; + PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym; } xkb; _GLFWwindow* pointerFocus; From 80d181f12dbb3b19fa649638252fa90eacf3d6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 31 Oct 2017 15:47:01 +0100 Subject: [PATCH 176/222] Win32: Fix maximization of undecorated windows Fixes #899. --- README.md | 1 + src/win32_window.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/README.md b/README.md index a890ac09e..4048baf10 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,7 @@ information on what to include when reporting a bug. - [Win32] Bugfix: Disabled cursor mode prevented use of caption buttons (#650,#1071) - [Win32] Bugfix: Returned key names did not match other platforms (#943) +- [Win32] Bugfix: Undecorated windows did not maximize to workarea (#899) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X diff --git a/src/win32_window.c b/src/win32_window.c index 71738d140..6d3e76cc3 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -951,6 +951,22 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, mmi->ptMaxTrackSize.y = window->maxheight + yoff; } + if (!window->decorated) + { + MONITORINFO mi; + const HMONITOR mh = MonitorFromWindow(window->win32.handle, + MONITOR_DEFAULTTONEAREST); + + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + GetMonitorInfo(mh, &mi); + + mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; + mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; + mmi->ptMaxSize.x = mi.rcWork.right - mi.rcWork.left; + mmi->ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top; + } + return 0; } From 9718675d86fe2013c7b5965ff394391f24df02ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 1 Nov 2017 21:32:50 +0100 Subject: [PATCH 177/222] Documentation work Related to #1106. --- docs/monitor.dox | 4 ++-- docs/window.dox | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/monitor.dox b/docs/monitor.dox index 7245f70cd..620646d56 100644 --- a/docs/monitor.dox +++ b/docs/monitor.dox @@ -85,8 +85,8 @@ void monitor_callback(GLFWmonitor* monitor, int event) } @endcode -If a monitor is disconnected, any windows that are full screen on it get forced -into windowed mode. +If a monitor is disconnected, all windows that are full screen on it will be +switched to windowed mode. @section monitor_properties Monitor properties diff --git a/docs/window.dox b/docs/window.dox index f21465021..3e8c748f0 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -89,8 +89,8 @@ the desktop. This behavior can be disabled with the [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_hint) window hint, for example if you wish to simultaneously cover multiple monitors with full screen windows. -If a monitor is disconnected, any window that is full screen on that monitor -will be forced into windowed mode. See @ref monitor_event for more information. +If a monitor is disconnected, all windows that are full screen on that monitor +will be switched to windowed mode. See @ref monitor_event for more information. @subsubsection window_windowed_full_screen "Windowed full screen" windows From f2756d0b3f357c7ea160445d91bc9e6169932124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 2 Nov 2017 19:30:12 +0100 Subject: [PATCH 178/222] Documentation work Related to #1065. --- docs/context.dox | 3 +++ include/GLFW/glfw3.h | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/context.dox b/docs/context.dox index 61292849d..08aa1a985 100644 --- a/docs/context.dox +++ b/docs/context.dox @@ -103,6 +103,9 @@ Before you can make OpenGL or OpenGL ES calls, you need to have a current context of the correct type. A context can only be current for a single thread at a time, and a thread can only have a single context current at a time. +When moving a context between threads, you must make it non-current on the old +thread before making it current on the new one. + The context of a window is made current with @ref glfwMakeContextCurrent. @code diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 6923ba685..bd20d9afa 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4809,10 +4809,13 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void); * thread. * * This function makes the OpenGL or OpenGL ES context of the specified window - * current on the calling thread. A context can only be made current on + * current on the calling thread. A context must only be made current on * a single thread at a time and each thread can have only a single current * context at a time. * + * When moving a context between threads, you must make it non-current on the + * old thread before making it current on the new one. + * * By default, making a context non-current implicitly forces a pipeline flush. * On machines that support `GL_KHR_context_flush_control`, you can control * whether a context performs this flush by setting the From 31cbb20ba276af45f7d5dffcb91fd231e597f6ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sat, 4 Nov 2017 21:11:58 +0100 Subject: [PATCH 179/222] Deprecate window parameter of clipboard functions --- README.md | 1 + docs/input.dox | 8 ++------ include/GLFW/glfw3.h | 4 ++-- src/cocoa_window.m | 4 ++-- src/input.c | 9 ++------- src/internal.h | 4 ++-- src/mir_window.c | 4 ++-- src/null_window.c | 4 ++-- src/win32_window.c | 4 ++-- src/wl_window.c | 4 ++-- src/x11_window.c | 4 ++-- tests/clipboard.c | 4 ++-- 12 files changed, 23 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 4048baf10..fe6a73259 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,7 @@ information on what to include when reporting a bug. - Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with [OSMesa](https://www.mesa3d.org/osmesa.html) (#281) - Added `GenerateMappings.cmake` script for updating gamepad mappings +- Deprecated window parameter of clipboard string functions - Removed `GLFW_USE_RETINA` compile-time option - Removed `GLFW_USE_CHDIR` compile-time option - Removed `GLFW_USE_MENUBAR` compile-time option diff --git a/docs/input.dox b/docs/input.dox index 318d48d5c..89ff98320 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -846,7 +846,7 @@ converted to one, you can retrieve it with @ref glfwGetClipboardString. See the reference documentation for the lifetime of the returned string. @code -const char* text = glfwGetClipboardString(window); +const char* text = glfwGetClipboardString(NULL); if (text) { insert_text(text); @@ -860,13 +860,9 @@ The contents of the system clipboard can be set to a UTF-8 encoded string with @ref glfwSetClipboardString. @code -glfwSetClipboardString(window, "A string with words in it"); +glfwSetClipboardString(NULL, "A string with words in it"); @endcode -The clipboard functions take a window handle argument because some window -systems require a window to communicate with the system clipboard. Any valid -window may be used. - @section path_drop Path drop input diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index bd20d9afa..fc7d3cb3b 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4655,7 +4655,7 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); * This function sets the system clipboard to the specified, UTF-8 encoded * string. * - * @param[in] window The window that will own the clipboard contents. + * @param[in] window Deprecated. Any valid window or `NULL`. * @param[in] string A UTF-8 encoded string. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref @@ -4684,7 +4684,7 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); * if its contents cannot be converted, `NULL` is returned and a @ref * GLFW_FORMAT_UNAVAILABLE error is generated. * - * @param[in] window The window that will request the clipboard contents. + * @param[in] window Deprecated. Any valid window or `NULL`. * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` * if an [error](@ref error_handling) occurred. * diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 1ee85bc60..5f2686b29 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1740,7 +1740,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) updateCursorImage(window); } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; @@ -1750,7 +1750,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) forType:NSStringPboardType]; } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; diff --git a/src/input.c b/src/input.c index 7d9ff7741..c06715aa4 100644 --- a/src/input.c +++ b/src/input.c @@ -1099,21 +1099,16 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) { - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); assert(string != NULL); _GLFW_REQUIRE_INIT(); - _glfwPlatformSetClipboardString(window, string); + _glfwPlatformSetClipboardString(string); } GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) { - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetClipboardString(window); + return _glfwPlatformGetClipboardString(); } GLFWAPI double glfwGetTime(void) diff --git a/src/internal.h b/src/internal.h index 1bfdb8598..4c214638d 100644 --- a/src/internal.h +++ b/src/internal.h @@ -647,8 +647,8 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); +void _glfwPlatformSetClipboardString(const char* string); +const char* _glfwPlatformGetClipboardString(void); int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); void _glfwPlatformUpdateGamepadGUID(char* guid); diff --git a/src/mir_window.c b/src/mir_window.c index c752cdb47..fa28d0cfb 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -858,13 +858,13 @@ int _glfwPlatformGetKeyScancode(int key) return _glfw.mir.scancodes[key]; } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); diff --git a/src/null_window.c b/src/null_window.c index 3cc3905d1..11ccb4f48 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -266,11 +266,11 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { return NULL; } diff --git a/src/win32_window.c b/src/win32_window.c index 6d3e76cc3..564a99ea6 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1796,7 +1796,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) updateCursorImage(window); } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { int characterCount; HANDLE object; @@ -1839,7 +1839,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) CloseClipboard(); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { HANDLE object; WCHAR* buffer; diff --git a/src/wl_window.c b/src/wl_window.c index f0f2637e4..264cf3798 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1008,14 +1008,14 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) } } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { // TODO _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Clipboard setting not implemented yet"); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { // TODO _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/x11_window.c b/src/x11_window.c index c89d2ec51..d9d34b014 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2773,7 +2773,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) } } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { free(_glfw.x11.clipboardString); _glfw.x11.clipboardString = strdup(string); @@ -2791,7 +2791,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) } } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { return getSelectionString(_glfw.x11.CLIPBOARD); } diff --git a/tests/clipboard.c b/tests/clipboard.c index a24d0c07c..7281a05dd 100644 --- a/tests/clipboard.c +++ b/tests/clipboard.c @@ -67,7 +67,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, { const char* string; - string = glfwGetClipboardString(window); + string = glfwGetClipboardString(NULL); if (string) printf("Clipboard contains \"%s\"\n", string); else @@ -79,7 +79,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, if (mods == MODIFIER) { const char* string = "Hello GLFW World!"; - glfwSetClipboardString(window, string); + glfwSetClipboardString(NULL, string); printf("Setting clipboard to \"%s\"\n", string); } break; From 7b877c4e2450aeba17c0ef3ed9134f69561f8b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sat, 4 Nov 2017 21:14:06 +0100 Subject: [PATCH 180/222] Improve placement when forcing windowed mode This is a temporary fix while waiting the for workarea query. Related to #1106. --- src/monitor.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/monitor.c b/src/monitor.c index 0dfb19584..6f64cca5d 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -113,9 +113,11 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) { if (window->monitor == monitor) { - int width, height; + int width, height, xoff, yoff; _glfwPlatformGetWindowSize(window, &width, &height); _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL); + _glfwPlatformSetWindowPos(window, xoff, yoff); } } From 546c99a3a33f5b6f96bd82ed18b704ab0e811904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 6 Nov 2017 00:32:23 +0100 Subject: [PATCH 181/222] Made sharing an example --- .gitignore | 2 +- docs/context.dox | 2 +- examples/CMakeLists.txt | 4 +++- {tests => examples}/sharing.c | 43 ++++------------------------------- tests/CMakeLists.txt | 4 +--- 5 files changed, 11 insertions(+), 44 deletions(-) rename {tests => examples}/sharing.c (86%) diff --git a/.gitignore b/.gitignore index dd88e65e4..f6103c222 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ examples/heightmap examples/offscreen examples/particles examples/splitview +examples/sharing examples/simple examples/wave tests/*.app @@ -74,7 +75,6 @@ tests/joysticks tests/monitors tests/msaa tests/reopen -tests/sharing tests/tearing tests/threads tests/timeout diff --git a/docs/context.dox b/docs/context.dox index 08aa1a985..58c622174 100644 --- a/docs/context.dox +++ b/docs/context.dox @@ -61,7 +61,7 @@ information. The name and number of this chapter unfortunately varies between versions and APIs, but has at times been named _Shared Objects and Multiple Contexts_. -GLFW comes with a barebones object sharing test program called `sharing`. +GLFW comes with a barebones object sharing example program called `sharing`. @subsection context_offscreen Offscreen contexts diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f7a2ebe43..b458609fd 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable(gears WIN32 MACOSX_BUNDLE gears.c ${ICON} ${GLAD}) add_executable(heightmap WIN32 MACOSX_BUNDLE heightmap.c ${ICON} ${GLAD}) add_executable(offscreen offscreen.c ${ICON} ${GLAD}) add_executable(particles WIN32 MACOSX_BUNDLE particles.c ${ICON} ${TINYCTHREAD} ${GETOPT} ${GLAD}) +add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c ${ICON} ${GLAD}) add_executable(simple WIN32 MACOSX_BUNDLE simple.c ${ICON} ${GLAD}) add_executable(splitview WIN32 MACOSX_BUNDLE splitview.c ${ICON} ${GLAD}) add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD}) @@ -44,7 +45,7 @@ if (RT_LIBRARY) target_link_libraries(particles "${RT_LIBRARY}") endif() -set(WINDOWS_BINARIES boing gears heightmap particles simple splitview wave) +set(WINDOWS_BINARIES boing gears heightmap particles sharing simple splitview wave) set(CONSOLE_BINARIES offscreen) set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES @@ -61,6 +62,7 @@ if (APPLE) set_target_properties(gears PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gears") set_target_properties(heightmap PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Heightmap") set_target_properties(particles PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Particles") + set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing") set_target_properties(simple PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Simple") set_target_properties(splitview PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "SplitView") set_target_properties(wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave") diff --git a/tests/sharing.c b/examples/sharing.c similarity index 86% rename from tests/sharing.c rename to examples/sharing.c index e5ffadc95..be35fafff 100644 --- a/tests/sharing.c +++ b/examples/sharing.c @@ -1,5 +1,5 @@ //======================================================================== -// Context sharing test program +// Context sharing example // Copyright (c) Camilla Löwy // // This software is provided 'as-is', without any express or implied @@ -22,15 +22,10 @@ // distribution. // //======================================================================== -// -// This program is used to test sharing of objects between contexts -// -//======================================================================== #include #include -#include #include #include @@ -71,17 +66,6 @@ static void error_callback(int error, const char* description) fprintf(stderr, "Error: %s\n", description); } -void APIENTRY debug_callback(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* user) -{ - fprintf(stderr, "Error: %s\n", message); -} - static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS && key == GLFW_KEY_ESCAPE) @@ -90,28 +74,15 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, int main(int argc, char** argv) { - int ch; GLFWwindow* windows[2]; GLuint texture, program, vertex_buffer; GLint mvp_location, vpos_location, color_location, texture_location; - srand((unsigned int) time(NULL)); - glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(EXIT_FAILURE); - while ((ch = getopt(argc, argv, "d")) != -1) - { - switch (ch) - { - case 'd': - glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); - break; - } - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); @@ -134,12 +105,6 @@ int main(int argc, char** argv) // pointers should be re-usable between them gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); - if (GLAD_GL_KHR_debug) - { - glDebugMessageCallback(debug_callback, NULL); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); - } - // Create the OpenGL objects inside the first context, created above // All objects will be shared with the second context, created below { @@ -150,6 +115,8 @@ int main(int argc, char** argv) glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); + srand((unsigned int) glfwGetTimerValue()); + for (y = 0; y < 16; y++) { for (x = 0; x < 16; x++) @@ -235,8 +202,8 @@ int main(int argc, char** argv) int i; const vec3 colors[2] = { - { 0.3f, 0.4f, 1.f }, - { 0.8f, 0.4f, 1.f } + { 0.8f, 0.4f, 1.f }, + { 0.3f, 0.4f, 1.f } }; for (i = 0; i < 2; i++) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1a39d59d4..278127b6b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,7 +32,6 @@ add_executable(gamma WIN32 MACOSX_BUNDLE gamma.c ${GLAD}) add_executable(icon WIN32 MACOSX_BUNDLE icon.c ${GLAD}) add_executable(inputlag WIN32 MACOSX_BUNDLE inputlag.c ${GETOPT} ${GLAD}) add_executable(joysticks WIN32 MACOSX_BUNDLE joysticks.c ${GLAD}) -add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c ${GETOPT} ${GLAD}) add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT} ${GLAD}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD}) add_executable(timeout WIN32 MACOSX_BUNDLE timeout.c ${GLAD}) @@ -46,7 +45,7 @@ if (RT_LIBRARY) target_link_libraries(threads "${RT_LIBRARY}") endif() -set(WINDOWS_BINARIES empty gamma icon inputlag joysticks sharing tearing threads +set(WINDOWS_BINARIES empty gamma icon inputlag joysticks tearing threads timeout title windows) set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen cursor) @@ -76,7 +75,6 @@ if (APPLE) set_target_properties(gamma PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gamma") set_target_properties(inputlag PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Input Lag") set_target_properties(joysticks PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Joysticks") - set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing") set_target_properties(tearing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Tearing") set_target_properties(threads PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Threads") set_target_properties(timeout PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Timeout") From 79e2433eb06f5b3528f146369bbc937cabd91374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 6 Nov 2017 17:42:15 +0100 Subject: [PATCH 182/222] Fix termination on sync object creation failure --- src/init.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/init.c b/src/init.c index 19a13e0df..336932e58 100644 --- a/src/init.c +++ b/src/init.c @@ -205,12 +205,13 @@ GLFWAPI int glfwInit(void) return GLFW_FALSE; } - if (!_glfwPlatformCreateMutex(&_glfw.errorLock)) - return GLFW_FALSE; - if (!_glfwPlatformCreateTls(&_glfw.errorSlot)) - return GLFW_FALSE; - if (!_glfwPlatformCreateTls(&_glfw.contextSlot)) + if (!_glfwPlatformCreateMutex(&_glfw.errorLock) || + !_glfwPlatformCreateTls(&_glfw.errorSlot) || + !_glfwPlatformCreateTls(&_glfw.contextSlot)) + { + terminate(); return GLFW_FALSE; + } _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); From 71018b4ab508638fc5a1ecc2ea519949f4298843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 6 Nov 2017 17:44:44 +0100 Subject: [PATCH 183/222] Fix termination on mapping parse error --- src/init.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/init.c b/src/init.c index 336932e58..5d6577ebb 100644 --- a/src/init.c +++ b/src/init.c @@ -219,7 +219,12 @@ GLFWAPI int glfwInit(void) _glfw.timer.offset = _glfwPlatformGetTimerValue(); glfwDefaultWindowHints(); - glfwUpdateGamepadMappings(_glfwDefaultMappings); + + if (!glfwUpdateGamepadMappings(_glfwDefaultMappings)) + { + terminate(); + return GLFW_FALSE; + } return GLFW_TRUE; } From 98990217bcb21bcb0da5d666cfcef2cb8337a49d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 6 Nov 2017 18:27:39 +0100 Subject: [PATCH 184/222] Cleanup --- src/win32_platform.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win32_platform.h b/src/win32_platform.h index 1bfc638f4..608d375f5 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -348,8 +348,8 @@ typedef struct _GLFWmonitorWin32 // This size matches the static size of DISPLAY_DEVICE.DeviceName WCHAR adapterName[32]; WCHAR displayName[32]; - char publicAdapterName[64]; - char publicDisplayName[64]; + char publicAdapterName[32]; + char publicDisplayName[32]; GLFWbool modesPruned; GLFWbool modeChanged; From baed2dad5604b20d28feba4e0cff7cf22b68f924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 8 Nov 2017 15:30:30 +0100 Subject: [PATCH 185/222] Cleanup --- src/glx_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/glx_context.c b/src/glx_context.c index 708663a9e..40da6c2fd 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -634,7 +634,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, // Returns the Visual and depth of the chosen GLXFBConfig // GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { From 49130ab8ec3fc21456fc2ec57b786ff81d2eaffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 7 Nov 2017 22:50:01 +0100 Subject: [PATCH 186/222] Rename framebuffer transparency hint This is a breaking change of an unreleased API. --- README.md | 4 ++-- docs/compat.dox | 4 ++-- docs/news.dox | 5 +++-- docs/window.dox | 30 +++++++++++++++++------------- examples/gears.c | 2 +- include/GLFW/glfw3.h | 7 ++++--- src/window.c | 4 ++-- 7 files changed, 31 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index fe6a73259..56a42b117 100644 --- a/README.md +++ b/README.md @@ -152,8 +152,8 @@ information on what to include when reporting a bug. functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header -- Added `GLFW_TRANSPARENT` window hint for enabling window framebuffer - transparency (#197,#663,#715,#723,#1078) +- Added `GLFW_TRANSPARENT_FRAMEBUFFER` window hint for enabling window + framebuffer transparency (#197,#663,#715,#723,#1078) - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) diff --git a/docs/compat.dox b/docs/compat.dox index a27f58f3d..380244662 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -82,8 +82,8 @@ extension, regular accelerated mouse motion will be used. GLFW uses both the XRender extension and the compositing manager to support transparent window framebuffers. If the running X server does not support this -extension or there is no running compositing manager, the `GLFW_TRANSPARENT` -framebuffer hint will have no effect. +extension or there is no running compositing manager, the +`GLFW_TRANSPARENT_FRAMEBUFFER` framebuffer hint will have no effect. @section compat_glx GLX extensions diff --git a/docs/news.dox b/docs/news.dox index 03a9c8dc5..f570ec3dd 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -97,8 +97,9 @@ be disabled with the @ref GLFW_JOYSTICK_HAT_BUTTONS init hint. @subsection news_33_transparent Support for transparent window framebuffer GLFW now supports the creation of windows with transparent framebuffers on -systems with desktop compositing enabled with the @ref GLFW_TRANSPARENT window -hint and attribute. Any window decorations will still be opaque. +systems with desktop compositing enabled with the @ref +GLFW_TRANSPARENT_FRAMEBUFFER window hint and attribute. Any window decorations +will still be opaque. @subsection news_33_centercursor Cursor centering window hint diff --git a/docs/window.dox b/docs/window.dox index 3e8c748f0..0e37e5e57 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -225,9 +225,9 @@ __GLFW_CENTER_CURSOR__ specifies whether the cursor should be centered over newly created full screen windows. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. This hint is ignored for windowed mode windows. -@anchor GLFW_TRANSPARENT_hint -__GLFW_TRANSPARENT__ specifies whether the window framebuffer will be -transparent. If enabled and supported by the system, the window framebuffer +@anchor GLFW_TRANSPARENT_FRAMEBUFFER_hint +__GLFW_TRANSPARENT_FRAMEBUFFER__ specifies whether the window framebuffer will +be transparent. If enabled and supported by the system, the window framebuffer alpha channel will be used to combine the framebuffer with the background. This does not affect window decorations. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. @@ -477,7 +477,7 @@ GLFW_AUTO_ICONIFY | `GLFW_TRUE` | `GLFW_TRUE` or `GL GLFW_FLOATING | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_MAXIMIZED | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_CENTER_CURSOR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` -GLFW_TRANSPARENT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` +GLFW_TRANSPARENT_FRAMEBUFFER | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_RED_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_GREEN_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_BLUE_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` @@ -1092,21 +1092,24 @@ the window or framebuffer is resized. @subsection window_transparency Window transparency Window framebuffers can be made transparent on a per-pixel per-frame basis with -the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT_hint) window hint. +the [GLFW_TRANSPARENT_FRAMEBUFFER](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) +window hint. @code -glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); +glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); @endcode -If supported by the system, the window framebuffer will be composited with the +If supported by the system, the window content area will be composited with the background using the framebuffer per-pixel alpha channel. This requires desktop compositing to be enabled on the system. It does not affect window decorations. You can check whether the window framebuffer was successfully made transparent -with the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT_attrib) window attribute. +with the +[GLFW_TRANSPARENT_FRAMEBUFFER](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib) +window attribute. @code -if (glfwGetWindowAttrib(window, GLFW_TRANSPARENT)) +if (glfwGetWindowAttrib(window, GLFW_TRANSPARENT_FRAMEBUFFER)) { // window framebuffer is currently transparent } @@ -1182,10 +1185,11 @@ called topmost or always-on-top. This can be set before creation with the [GLFW_FLOATING](@ref GLFW_FLOATING_hint) window hint or after with @ref glfwSetWindowAttrib. -@anchor GLFW_TRANSPARENT_attrib -__GLFW_TRANSPARENT__ indicates whether the specified window has a transparent -framebuffer, i.e. the window contents is composited with the background using -the window framebuffer alpha channel. See @ref window_transparency for details. +@anchor GLFW_TRANSPARENT_FRAMEBUFFER_attrib +__GLFW_TRANSPARENT_FRAMEBUFFER__ indicates whether the specified window has +a transparent framebuffer, i.e. the window contents is composited with the +background using the window framebuffer alpha channel. See @ref +window_transparency for details. @subsubsection window_attribs_ctx Context related attributes diff --git a/examples/gears.c b/examples/gears.c index f14b300a7..467a955b2 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -312,7 +312,7 @@ int main(int argc, char *argv[]) } glfwWindowHint(GLFW_DEPTH_BITS, 16); - glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); if (!window) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index fc7d3cb3b..80f671207 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -789,10 +789,11 @@ extern "C" { #define GLFW_CENTER_CURSOR 0x00020009 /*! @brief Window framebuffer transparency hint and attribute * - * Window framebuffer transparency [window hint](@ref GLFW_TRANSPARENT_hint) - * and [window attribute](@ref GLFW_TRANSPARENT_attrib). + * Window framebuffer transparency + * [window hint](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) and + * [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib). */ -#define GLFW_TRANSPARENT 0x0002000A +#define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A /*! @brief Framebuffer bit depth hint. * diff --git a/src/window.c b/src/window.c index 303217338..8b927d988 100644 --- a/src/window.c +++ b/src/window.c @@ -316,7 +316,7 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_DOUBLEBUFFER: _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_TRANSPARENT: + case GLFW_TRANSPARENT_FRAMEBUFFER: _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_SAMPLES: @@ -743,7 +743,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return _glfwPlatformWindowVisible(window); case GLFW_MAXIMIZED: return _glfwPlatformWindowMaximized(window); - case GLFW_TRANSPARENT: + case GLFW_TRANSPARENT_FRAMEBUFFER: return _glfwPlatformFramebufferTransparent(window); case GLFW_RESIZABLE: return window->resizable; From fb4f633243840cfe1ae3ebda6f2b2ff5fc40dc86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 9 Nov 2017 23:30:00 +0100 Subject: [PATCH 187/222] Fix y-axis sign for XInput thumb sticks This breaks strict compatibility but does it to make XInput y-axes consistent with every other API and OS. Fixes #1083. --- src/win32_joystick.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index ad2dbb2f1..d9d341ff5 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -711,9 +711,9 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) return GLFW_TRUE; _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f); - _glfwInputJoystickAxis(js, 1, (xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f); - _glfwInputJoystickAxis(js, 3, (xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f); _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f); From adebcc7111b9031f1194744a50fd73eed763edcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 14 Nov 2017 23:28:12 +0100 Subject: [PATCH 188/222] Deprecate charmods callback --- include/GLFW/glfw3.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 80f671207..a1e7df4ba 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1384,6 +1384,8 @@ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); * @sa @ref input_char * @sa @ref glfwSetCharModsCallback * + * @deprecated Scheduled for removal in version 4.0. + * * @since Added in version 3.1. * * @ingroup input @@ -4119,6 +4121,8 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or an * [error](@ref error_handling) occurred. * + * @deprecated Scheduled for removal in version 4.0. + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. From bf7cc2ffacaf76a00b3dc18183886e36af016b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Nov 2017 04:21:41 +0100 Subject: [PATCH 189/222] Fix missing inclusion guard needed for unity build Fixes #1127. --- src/internal.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/internal.h b/src/internal.h index 4c214638d..4225e3fd1 100644 --- a/src/internal.h +++ b/src/internal.h @@ -25,6 +25,8 @@ // //======================================================================== +#pragma once + #if defined(_GLFW_USE_CONFIG_H) #include "glfw_config.h" #endif From aef4edadd0b580fd55a93299ac171caade586fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Nov 2017 13:58:20 +0100 Subject: [PATCH 190/222] Move uninstall target to GLFW3 folder Fixes #1129. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 239a8bfce..8acfe359a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -401,6 +401,7 @@ if (GLFW_INSTALL) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${GLFW_BINARY_DIR}/cmake_uninstall.cmake") + set_target_properties(uninstall PROPERTIES FOLDER "GLFW3") endif() endif() From 11e47f08b14436c9759dcfb87af213c0696667db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 25 Sep 2017 23:14:45 +0200 Subject: [PATCH 191/222] Add glfwGetWindowOpacity and glfwSetWindowOpacity This adds support for setting the opacity of the whole window, including any decorations. Fixes #1089. --- README.md | 6 ++- docs/news.dox | 11 +++-- docs/window.dox | 33 ++++++++++++++ include/GLFW/glfw3.h | 56 +++++++++++++++++++++++ src/cocoa_window.m | 10 ++++ src/internal.h | 2 + src/mir_window.c | 9 ++++ src/null_window.c | 9 ++++ src/win32_window.c | 33 ++++++++++++++ src/window.c | 28 ++++++++++++ src/wl_window.c | 9 ++++ src/x11_init.c | 9 ++++ src/x11_platform.h | 2 + src/x11_window.c | 37 +++++++++++++-- tests/CMakeLists.txt | 6 ++- tests/opacity.c | 106 +++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 354 insertions(+), 12 deletions(-) create mode 100644 tests/opacity.c diff --git a/README.md b/README.md index 56a42b117..631b2042d 100644 --- a/README.md +++ b/README.md @@ -152,8 +152,10 @@ information on what to include when reporting a bug. functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header -- Added `GLFW_TRANSPARENT_FRAMEBUFFER` window hint for enabling window - framebuffer transparency (#197,#663,#715,#723,#1078) +- Added `GLFW_TRANSPARENT_FRAMEBUFFER` window hint and attribute for controlling + per-pixel framebuffer transparency (#197,#663,#715,#723,#1078) +- Added `glfwGetWindowOpacity` and `glfwSetWindowOpacity` for controlling whole + window transparency (#1089) - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) diff --git a/docs/news.dox b/docs/news.dox index f570ec3dd..adbb7724f 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -94,12 +94,17 @@ be disabled with the @ref GLFW_JOYSTICK_HAT_BUTTONS init hint. @see @ref joystick_hat -@subsection news_33_transparent Support for transparent window framebuffer +@subsection news_33_transparent Support for transparent windows and framebuffers GLFW now supports the creation of windows with transparent framebuffers on systems with desktop compositing enabled with the @ref -GLFW_TRANSPARENT_FRAMEBUFFER window hint and attribute. Any window decorations -will still be opaque. +GLFW_TRANSPARENT_FRAMEBUFFER window hint and attribute. This hint must be set +before window creation and leaves any window decorations opaque. + +GLFW now also supports whole window transparency with @ref glfwGetWindowOpacity +and @ref glfwSetWindowOpacity. This value controls the opacity of the whole +window including decorations and unlike framebuffer transparency can be changed +at any time after window creation. @subsection news_33_centercursor Cursor centering window hint diff --git a/docs/window.dox b/docs/window.dox index 0e37e5e57..2c9cec917 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -1091,6 +1091,14 @@ the window or framebuffer is resized. @subsection window_transparency Window transparency +GLFW supports two kinds of transparency for windows; framebuffer transparency +and whole window transparency. A single window may not use both methods. The +results of doing this are undefined. + +Both methods require the platform to support it and not every version of every +platform GLFW supports does this, so there are mechanisms to check whether the +window really is transparent. + Window framebuffers can be made transparent on a per-pixel per-frame basis with the [GLFW_TRANSPARENT_FRAMEBUFFER](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) window hint. @@ -1115,6 +1123,31 @@ if (glfwGetWindowAttrib(window, GLFW_TRANSPARENT_FRAMEBUFFER)) } @endcode +GLFW comes with an example that enabled framebuffer transparency called `gears`. + +The opacity of the whole window, including any decorations, can be set with @ref +glfwSetWindowOpacity. + +@code +glfwSetWindowOpacity(window, 0.5f); +@endcode + +The opacity (or alpha) value is a positive finite number between zero and one, +where 0 (zero) is fully transparent and 1 (one) is fully opaque. The initial +opacity value for newly created windows is 1. + +The current opacity of a window can be queried with @ref glfwGetWindowOpacity. + +@code +float opacity = glfwGetWindowOpacity(window); +@endcode + +If the system does not support whole window transparency, this function always +returns one. + +GLFW comes with a test program that lets you control whole window transparency +at run-time called `opacity`. + @subsection window_attribs Window attributes diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index a1e7df4ba..9dc347795 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2837,6 +2837,62 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int */ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* yscale); +/*! @brief Returns the opacity of the whole window. + * + * This function returns the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. If the system + * does not support whole window transparency, this function always returns one. + * + * The initial opacity value for newly created windows is one. + * + * @param[in] window The window to query. + * @return The opacity value of the specified window. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwSetWindowOpacity + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI float glfwGetWindowOpacity(GLFWwindow* window); + +/*! @brief Sets the opacity of the whole window. + * + * This function sets the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. + * + * The initial opacity value for newly created windows is one. + * + * A window created with framebuffer transparency may not use whole window + * transparency. The results of doing this are undefined. + * + * @param[in] window The window to set the opacity for. + * @param[in] opacity The desired opacity of the specified window. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwGetWindowOpacity + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity); + /*! @brief Iconifies the specified window. * * This function iconifies (minimizes) the specified window if it was diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 5f2686b29..c952ddc6b 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1493,6 +1493,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) [window->ns.object setLevel:NSNormalWindowLevel]; } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return (float) [window->ns.object alphaValue]; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + [window->ns.object setAlphaValue:opacity]; +} + void _glfwPlatformPollEvents(void) { for (;;) diff --git a/src/internal.h b/src/internal.h index 4225e3fd1..0a2cbc4d6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -687,9 +687,11 @@ int _glfwPlatformWindowIconified(_GLFWwindow* window); int _glfwPlatformWindowVisible(_GLFWwindow* window); int _glfwPlatformWindowMaximized(_GLFWwindow* window); int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity); void _glfwPlatformPollEvents(void); void _glfwPlatformWaitEvents(void); diff --git a/src/mir_window.c b/src/mir_window.c index fa28d0cfb..fd8f2914d 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -648,6 +648,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformPollEvents(void) { EventNode* node = NULL; diff --git a/src/null_window.c b/src/null_window.c index 11ccb4f48..6eb4ac6e2 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -182,6 +182,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformShowWindow(_GLFWwindow* window) { } diff --git a/src/win32_window.c b/src/win32_window.c index 564a99ea6..78084b45a 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1591,6 +1591,39 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + BYTE alpha; + DWORD flags; + + if ((GetWindowLongW(window->win32.handle, GWL_EXSTYLE) & WS_EX_LAYERED) && + GetLayeredWindowAttributes(window->win32.handle, NULL, &alpha, &flags)) + { + if (flags & LWA_ALPHA) + return alpha / 255.f; + } + + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + if (opacity < 1.f) + { + const BYTE alpha = (BYTE) (255 * opacity); + DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + style |= WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + SetLayeredWindowAttributes(window->win32.handle, 0, alpha, LWA_ALPHA); + } + else + { + DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + style &= ~WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + } +} + void _glfwPlatformPollEvents(void) { MSG msg; diff --git a/src/window.c b/src/window.c index 8b927d988..f4468e169 100644 --- a/src/window.c +++ b/src/window.c @@ -648,6 +648,34 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, _glfwPlatformGetWindowContentScale(window, xscale, yscale); } +GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(1.f); + return _glfwPlatformGetWindowOpacity(window); +} + +GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(opacity == opacity); + assert(opacity >= 0.f); + assert(opacity <= 1.f); + + _GLFW_REQUIRE_INIT(); + + if (opacity != opacity || opacity < 0.f || opacity > 1.f) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid window opacity %f", opacity); + return; + } + + _glfwPlatformSetWindowOpacity(window, opacity); +} + GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index 264cf3798..b2ae7aae2 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -692,6 +692,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) "Wayland: Window attribute setting not implemented yet"); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformPollEvents(void) { handleEvents(0); diff --git a/src/x11_init.c b/src/x11_init.c index b603a15f2..4c863c38c 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -737,9 +737,18 @@ static GLFWbool initExtensions(void) XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); _glfw.x11.NET_WM_BYPASS_COMPOSITOR = XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); + _glfw.x11.NET_WM_WINDOW_OPACITY = + XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False); _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + // The compositing manager selection name contains the screen number + { + char name[32]; + snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); + _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False); + } + return GLFW_TRUE; } diff --git a/src/x11_platform.h b/src/x11_platform.h index 7eba441d5..c5a11cf24 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -257,6 +257,8 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_STATE_DEMANDS_ATTENTION; Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_WM_FULLSCREEN_MONITORS; + Atom NET_WM_WINDOW_OPACITY; + Atom NET_WM_CM_Sx; Atom NET_ACTIVE_WINDOW; Atom NET_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS; diff --git a/src/x11_window.c b/src/x11_window.c index d9d34b014..32fff63b6 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2449,11 +2449,7 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) if (!window->x11.transparent) return GLFW_FALSE; - // Check whether a compositing manager is running - char name[32]; - snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); - const Atom selection = XInternAtom(_glfw.x11.display, name, False); - return XGetSelectionOwner(_glfw.x11.display, selection) != None; + return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) @@ -2559,6 +2555,37 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) XFlush(_glfw.x11.display); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + float opacity = 1.f; + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx)) + { + CARD32* value = NULL; + + if (_glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_WINDOW_OPACITY, + XA_CARDINAL, + (unsigned char**) &value)) + { + opacity = (float) (*value / (double) 0xffffffffu); + } + + if (value) + XFree(value); + } + + return opacity; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + const CARD32 value = (CARD32) (0xffffffffu * (double) opacity); + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); +} + void _glfwPlatformPollEvents(void) { _GLFWwindow* window; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 278127b6b..52b08389d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,6 +32,7 @@ add_executable(gamma WIN32 MACOSX_BUNDLE gamma.c ${GLAD}) add_executable(icon WIN32 MACOSX_BUNDLE icon.c ${GLAD}) add_executable(inputlag WIN32 MACOSX_BUNDLE inputlag.c ${GETOPT} ${GLAD}) add_executable(joysticks WIN32 MACOSX_BUNDLE joysticks.c ${GLAD}) +add_executable(opacity WIN32 MACOSX_BUNDLE opacity.c ${GLAD}) add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT} ${GLAD}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD}) add_executable(timeout WIN32 MACOSX_BUNDLE timeout.c ${GLAD}) @@ -45,8 +46,8 @@ if (RT_LIBRARY) target_link_libraries(threads "${RT_LIBRARY}") endif() -set(WINDOWS_BINARIES empty gamma icon inputlag joysticks tearing threads - timeout title windows) +set(WINDOWS_BINARIES empty gamma icon inputlag joysticks opacity tearing + threads timeout title windows) set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen cursor) @@ -75,6 +76,7 @@ if (APPLE) set_target_properties(gamma PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gamma") set_target_properties(inputlag PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Input Lag") set_target_properties(joysticks PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Joysticks") + set_target_properties(opacity PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Opacity") set_target_properties(tearing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Tearing") set_target_properties(threads PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Threads") set_target_properties(timeout PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Timeout") diff --git a/tests/opacity.c b/tests/opacity.c new file mode 100644 index 000000000..3176c9ff9 --- /dev/null +++ b/tests/opacity.c @@ -0,0 +1,106 @@ +//======================================================================== +// Window opacity test program +// Copyright (c) Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include + +#define NK_IMPLEMENTATION +#define NK_INCLUDE_FIXED_TYPES +#define NK_INCLUDE_FONT_BAKING +#define NK_INCLUDE_DEFAULT_FONT +#define NK_INCLUDE_DEFAULT_ALLOCATOR +#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT +#define NK_INCLUDE_STANDARD_VARARGS +#include + +#define NK_GLFW_GL2_IMPLEMENTATION +#include + +#include +#include + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +int main(int argc, char** argv) +{ + GLFWmonitor* monitor = NULL; + GLFWwindow* window; + struct nk_context* nk; + struct nk_font_atlas* atlas; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(400, 400, "Opacity", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + glfwSwapInterval(1); + + nk = nk_glfw3_init(window, NK_GLFW3_INSTALL_CALLBACKS); + nk_glfw3_font_stash_begin(&atlas); + nk_glfw3_font_stash_end(); + + while (!glfwWindowShouldClose(window)) + { + int width, height; + struct nk_rect area; + + glfwGetWindowSize(window, &width, &height); + area = nk_rect(0.f, 0.f, (float) width, (float) height); + + glClear(GL_COLOR_BUFFER_BIT); + nk_glfw3_new_frame(); + if (nk_begin(nk, "", area, 0)) + { + float opacity = glfwGetWindowOpacity(window); + nk_layout_row_dynamic(nk, 30, 2); + if (nk_slider_float(nk, 0.f, &opacity, 1.f, 0.001f)) + glfwSetWindowOpacity(window, opacity); + nk_labelf(nk, NK_TEXT_LEFT, "%0.3f", opacity); + } + + nk_end(nk); + nk_glfw3_render(NK_ANTI_ALIASING_ON); + + glfwSwapBuffers(window); + glfwWaitEventsTimeout(1.0); + } + + nk_glfw3_shutdown(); + glfwTerminate(); + exit(EXIT_SUCCESS); +} + From d73ab0bd58e7b562cb35911bf00f4d8cc5b3f83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Nov 2017 10:08:38 +0100 Subject: [PATCH 192/222] Documentation work The reference for glfwCreateWindow listed the wrong default icon for Windows. Fixes #1130. --- include/GLFW/glfw3.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 9dc347795..a3f986407 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2291,8 +2291,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it * will be set as the initial icon for the window. If no such icon is present, - * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see - * @ref glfwSetWindowIcon. + * the `IDI_APPLICATION` icon will be used instead. To set a different icon, + * see @ref glfwSetWindowIcon. * * @remark @win32 The context to share resources with must not be current on * any other thread. From 9903f88947be41c3bcba7ec5017f83665ec73aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Nov 2017 11:02:16 +0100 Subject: [PATCH 193/222] Documentation work --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 631b2042d..a0b9c548f 100644 --- a/README.md +++ b/README.md @@ -148,14 +148,14 @@ information on what to include when reporting a bug. - Added `glfwGetJoystickHats` function for querying joystick hats (#889,#906,#934) - Added `glfwInitHint` and `glfwInitHintString` for setting initialization hints +- Added `glfwGetWindowOpacity` and `glfwSetWindowOpacity` for controlling whole + window transparency (#1089) - Added `glfwGetX11SelectionString` and `glfwSetX11SelectionString` functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header - Added `GLFW_TRANSPARENT_FRAMEBUFFER` window hint and attribute for controlling per-pixel framebuffer transparency (#197,#663,#715,#723,#1078) -- Added `glfwGetWindowOpacity` and `glfwSetWindowOpacity` for controlling whole - window transparency (#1089) - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) From 8b81a03a5abc8cbb82dccdf892b9bd992a230569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Nov 2017 10:42:01 +0100 Subject: [PATCH 194/222] Cocoa: Remove double resize of full screen window Related to #1085. --- README.md | 1 + src/cocoa_window.m | 28 ++++++---------------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index a0b9c548f..aded8a58a 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,7 @@ information on what to include when reporting a bug. notification was shown (#971,#1028) - [Cocoa] Bugfix: Some characters did not repeat due to Press and Hold (#1010) - [Cocoa] Bugfix: Window title was lost when full screen or undecorated (#1082) +- [Cocoa] Bugfix: Window was resized twice when entering full screen (#1085) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` diff --git a/src/cocoa_window.m b/src/cocoa_window.m index c952ddc6b..58d6362d8 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1385,28 +1385,6 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, [window->ns.object setStyleMask:styleMask]; [window->ns.object makeFirstResponder:window->ns.view]; - NSRect contentRect; - - if (monitor) - { - GLFWvidmode mode; - - _glfwPlatformGetVideoMode(window->monitor, &mode); - _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); - - contentRect = NSMakeRect(xpos, transformY(ypos + mode.height), - mode.width, mode.height); - } - else - { - contentRect = NSMakeRect(xpos, transformY(ypos + height), - width, height); - } - - NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect - styleMask:styleMask]; - [window->ns.object setFrame:frameRect display:YES]; - if (monitor) { [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; @@ -1416,6 +1394,12 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, } else { + NSRect contentRect = NSMakeRect(xpos, transformY(ypos + height), + width, height); + NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect + styleMask:styleMask]; + [window->ns.object setFrame:frameRect display:YES]; + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) { From d6306846549af827bd4a2b5bfec33cce9faffc2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Nov 2017 11:03:05 +0100 Subject: [PATCH 195/222] Win32: Remove double resize of full screen window Related to #1085. --- README.md | 1 + src/win32_window.c | 19 ++++++------------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index aded8a58a..d9de5f85e 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ information on what to include when reporting a bug. (#650,#1071) - [Win32] Bugfix: Returned key names did not match other platforms (#943) - [Win32] Bugfix: Undecorated windows did not maximize to workarea (#899) +- [Win32] Bugfix: Window was resized twice when entering full screen (#1085) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X diff --git a/src/win32_window.c b/src/win32_window.c index 78084b45a..1aa3213e7 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1497,26 +1497,19 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, if (monitor) { - GLFWvidmode mode; - DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); - UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; - if (window->decorated) { + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_FRAMECHANGED | SWP_SHOWWINDOW | + SWP_NOACTIVATE | SWP_NOCOPYBITS | + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE; + style &= ~WS_OVERLAPPEDWINDOW; style |= getWindowStyle(window); SetWindowLongW(window->win32.handle, GWL_STYLE, style); - - flags |= SWP_FRAMECHANGED; + SetWindowPos(window->win32.handle, HWND_TOPMOST, 0, 0, 0, 0, flags); } - _glfwPlatformGetVideoMode(monitor, &mode); - _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos); - - SetWindowPos(window->win32.handle, HWND_TOPMOST, - xpos, ypos, mode.width, mode.height, - flags); - acquireMonitor(window); } else From 1fe319d234e828c17fccb8a5226b16dd54ff0a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Nov 2017 11:34:42 +0100 Subject: [PATCH 196/222] Cocoa: Filter out duplicate size events Fixes #1085. --- README.md | 1 + src/cocoa_platform.h | 4 ++++ src/cocoa_window.m | 28 +++++++++++++++++++++++++--- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d9de5f85e..1aa9bf129 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Some characters did not repeat due to Press and Hold (#1010) - [Cocoa] Bugfix: Window title was lost when full screen or undecorated (#1082) - [Cocoa] Bugfix: Window was resized twice when entering full screen (#1085) +- [Cocoa] Bugfix: Duplicate size events were not filtered (#1085) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 61d0ee916..d5cc2379a 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -88,6 +88,10 @@ typedef struct _GLFWwindowNS GLFWbool maximized; + // Cached window and framebuffer sizes used to filter out duplicate events + int width, height; + int fbWidth, fbHeight; + // The total sum of the distances the cursor has been warped // since the last cursor motion event was processed // This is kept to counteract Cocoa doing the same internally diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 58d6362d8..16fbb7bfd 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -267,8 +267,21 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; - _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); - _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); + if (fbRect.size.width != window->ns.fbWidth || + fbRect.size.height != window->ns.fbHeight) + { + window->ns.fbWidth = fbRect.size.width; + window->ns.fbHeight = fbRect.size.height; + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + } + + if (contentRect.size.width != window->ns.width || + contentRect.size.height != window->ns.height) + { + window->ns.width = contentRect.size.width; + window->ns.height = contentRect.size.height; + _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); + } } - (void)windowDidMove:(NSNotification *)notification @@ -551,7 +564,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; - _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + if (fbRect.size.width != window->ns.fbWidth || + fbRect.size.height != window->ns.fbHeight) + { + window->ns.fbWidth = fbRect.size.width; + window->ns.fbHeight = fbRect.size.height; + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + } } - (void)drawRect:(NSRect)rect @@ -1095,6 +1114,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, [window->ns.object setAcceptsMouseMovedEvents:YES]; [window->ns.object setRestorable:NO]; + _glfwPlatformGetWindowSize(window, &window->ns.width, &window->ns.height); + _glfwPlatformGetFramebufferSize(window, &window->ns.fbWidth, &window->ns.fbHeight); + return GLFW_TRUE; } From 68809869f93d77d57e8909ef4c65907875eb9675 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 20 Nov 2017 16:09:39 +0530 Subject: [PATCH 197/222] Fix spurious error from glfwInitHintString Closes #1138 --- src/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.c b/src/init.c index 5d6577ebb..8dea3ac88 100644 --- a/src/init.c +++ b/src/init.c @@ -265,11 +265,11 @@ GLFWAPI void glfwInitHintString(int hint, const char* value) case GLFW_X11_WM_CLASS_NAME: strncpy(_glfwInitHints.x11.className, value, sizeof(_glfwInitHints.x11.className) - 1); - break; + return; case GLFW_X11_WM_CLASS_CLASS: strncpy(_glfwInitHints.x11.classClass, value, sizeof(_glfwInitHints.x11.classClass) - 1); - break; + return; } _glfwInputError(GLFW_INVALID_ENUM, From 9c513346ada1f52d559c4eb4c1ec9d80c05696af Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Fri, 17 Nov 2017 12:17:43 +0000 Subject: [PATCH 198/222] Documentation work Gamma will never be supported on Wayland. Closes #1134. --- include/GLFW/glfw3.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index a3f986407..157a48201 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2089,8 +2089,8 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * - * @remark @wayland Gamma handling is currently unavailable, this function will - * always emit @ref GLFW_PLATFORM_ERROR. + * @remark @wayland Gamma handling is a priviledged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * @@ -2113,8 +2113,9 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @wayland Gamma handling is currently unavailable, this function will - * always return `NULL` and emit @ref GLFW_PLATFORM_ERROR. + * @remark @wayland Gamma handling is a priviledged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while + * returning `NULL`. * * @pointer_lifetime The returned structure and its arrays are allocated and * freed by GLFW. You should not free them yourself. They are valid until the @@ -2156,8 +2157,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); * * @remark @win32 The gamma ramp size must be 256. * - * @remark @wayland Gamma handling is currently unavailable, this function will - * always emit @ref GLFW_PLATFORM_ERROR. + * @remark @wayland Gamma handling is a priviledged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified gamma ramp is copied before this function * returns. From bb13275b728de07d0f32e9675ea7f6c59d5a1153 Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Thu, 16 Nov 2017 14:10:51 -0500 Subject: [PATCH 199/222] Cocoa: Fix Xcode Warnings Closes #1132. --- src/cocoa_joystick.m | 14 +++++++------- src/cocoa_window.m | 6 +++--- src/input.c | 6 +++--- src/osmesa_context.h | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 3a5751ef0..0831809f8 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -247,9 +247,9 @@ static void matchCallback(void* context, compareElements, NULL); js = _glfwAllocJoystick(name, guid, - CFArrayGetCount(axes), - CFArrayGetCount(buttons), - CFArrayGetCount(hats)); + (int) CFArrayGetCount(axes), + (int) CFArrayGetCount(buttons), + (int) CFArrayGetCount(hats)); js->ns.device = device; js->ns.axes = axes; @@ -399,11 +399,11 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) const long delta = axis->maximum - axis->minimum; if (delta == 0) - _glfwInputJoystickAxis(js, i, 0.f); + _glfwInputJoystickAxis(js, (int) i, 0.f); else { const float value = (2.f * (raw - axis->minimum) / delta) - 1.f; - _glfwInputJoystickAxis(js, i, value); + _glfwInputJoystickAxis(js, (int) i, value); } } } @@ -417,7 +417,7 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.buttons, i); const char value = getElementValue(js, button) - button->minimum; - _glfwInputJoystickButton(js, i, value); + _glfwInputJoystickButton(js, (int) i, value); } for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) @@ -441,7 +441,7 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) if (state < 0 || state > 8) state = 8; - _glfwInputJoystickHat(js, i, states[state]); + _glfwInputJoystickHat(js, (int) i, states[state]); } } diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 16fbb7bfd..68246342a 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -686,17 +686,17 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; [sender draggingLocation].x, contentRect.size.height - [sender draggingLocation].y); - const int count = [files count]; + const NSUInteger count = [files count]; if (count) { NSEnumerator* e = [files objectEnumerator]; char** paths = calloc(count, sizeof(char*)); - int i; + NSUInteger i; for (i = 0; i < count; i++) paths[i] = strdup([[e nextObject] UTF8String]); - _glfwInputDrop(window, count, (const char**) paths); + _glfwInputDrop(window, (int) count, (const char**) paths); for (i = 0; i < count; i++) free(paths[i]); diff --git a/src/input.c b/src/input.c index c06715aa4..b20e9e687 100644 --- a/src/input.c +++ b/src/input.c @@ -136,9 +136,9 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) if (fields[i].element->type == _GLFW_JOYSTICK_HATBIT) { - const unsigned int hat = strtoul(c + 1, (char**) &c, 10); - const unsigned int bit = strtoul(c + 1, (char**) &c, 10); - fields[i].element->value = (hat << 4) | bit; + const unsigned long hat = strtoul(c + 1, (char**) &c, 10); + const unsigned long bit = strtoul(c + 1, (char**) &c, 10); + fields[i].element->value = (uint8_t) ((hat << 4) | bit); } else fields[i].element->value = (uint8_t) strtoul(c + 1, (char**) &c, 10); diff --git a/src/osmesa_context.h b/src/osmesa_context.h index e6ae57810..07bb469a6 100644 --- a/src/osmesa_context.h +++ b/src/osmesa_context.h @@ -37,7 +37,7 @@ #define OSMESA_CONTEXT_MINOR_VERSION 0x37 typedef void* OSMesaContext; -typedef void (*OSMESAproc)(); +typedef void (*OSMESAproc)(void); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); From 25cf67667f4dedcb9a51ed6a678e491fcddf12cc Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Thu, 16 Nov 2017 17:17:47 +0000 Subject: [PATCH 200/222] Wayland: Tell cmake which libraries to use --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8acfe359a..8e901e7e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -276,13 +276,13 @@ if (_GLFW_WAYLAND) find_package(ECM REQUIRED NO_MODULE) list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}") - find_package(Wayland REQUIRED) + find_package(Wayland REQUIRED Client Cursor Egl) find_package(WaylandScanner REQUIRED) find_package(WaylandProtocols 1.1 REQUIRED) list(APPEND glfw_PKG_DEPS "wayland-egl") - list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIR}") + list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIRS}") list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") find_package(XKBCommon REQUIRED) From cc87d5ab102eff16e562817b2d87f4704bb7abc2 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Thu, 16 Nov 2017 17:21:59 +0000 Subject: [PATCH 201/222] Wayland: Assert that we only get a known axis --- src/wl_init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wl_init.c b/src/wl_init.c index 3841636f2..d3295622c 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -26,6 +26,7 @@ #include "internal.h" +#include #include #include #include @@ -152,6 +153,7 @@ static void pointerHandleAxis(void* data, y = wl_fixed_to_double(value) * scrollFactor; break; default: + assert(GLFW_FALSE); break; } From d18431338a8c8ecb4849e179d734485894997ba8 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Thu, 16 Nov 2017 16:42:11 +0000 Subject: [PATCH 202/222] Wayland: Disable the compose key on old xkbcommon --- CMakeLists.txt | 3 +++ src/glfw_config.h.in | 3 +++ src/wl_init.c | 18 ++++++++++++++++++ src/wl_platform.h | 26 +++++++++++++++++++------- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e901e7e9..edcf9682e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,6 +287,9 @@ if (_GLFW_WAYLAND) find_package(XKBCommon REQUIRED) list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") + + include(CheckIncludeFiles) + check_include_files(xkbcommon/xkbcommon-compose.h HAVE_XKBCOMMON_COMPOSE_H) endif() #-------------------------------------------------------------------- diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index bc9f5d3e1..0b47945c0 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in @@ -55,3 +55,6 @@ // Define this to 1 to force use of high-performance GPU on hybrid systems #cmakedefine _GLFW_USE_HYBRID_HPG +// Define this to 1 if xkbcommon supports the compose key +#cmakedefine HAVE_XKBCOMMON_COMPOSE_H + diff --git a/src/wl_init.c b/src/wl_init.c index d3295622c..d6832aaa5 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -176,8 +176,12 @@ static void keyboardHandleKeymap(void* data, { struct xkb_keymap* keymap; struct xkb_state* state; + +#ifdef HAVE_XKBCOMMON_COMPOSE_H struct xkb_compose_table* composeTable; struct xkb_compose_state* composeState; +#endif + char* mapStr; const char* locale; @@ -225,6 +229,7 @@ static void keyboardHandleKeymap(void* data, if (!locale) locale = "C"; +#ifdef HAVE_XKBCOMMON_COMPOSE_H composeTable = xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); @@ -244,6 +249,7 @@ static void keyboardHandleKeymap(void* data, _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create XKB compose table"); } +#endif xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_state_unref(_glfw.wl.xkb.state); @@ -294,6 +300,7 @@ static int toGLFWKeyCode(uint32_t key) return GLFW_KEY_UNKNOWN; } +#ifdef HAVE_XKBCOMMON_COMPOSE_H static xkb_keysym_t composeSymbol(xkb_keysym_t sym) { if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) @@ -313,6 +320,7 @@ static xkb_keysym_t composeSymbol(xkb_keysym_t sym) return sym; } } +#endif static void inputChar(_GLFWwindow* window, uint32_t key) { @@ -326,7 +334,11 @@ static void inputChar(_GLFWwindow* window, uint32_t key) if (numSyms == 1) { +#ifdef HAVE_XKBCOMMON_COMPOSE_H sym = composeSymbol(syms[0]); +#else + sym = syms[0]; +#endif cp = _glfwKeySym2Unicode(sym); if (cp != -1) { @@ -672,6 +684,8 @@ int _glfwPlatformInit(void) dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods) dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); + +#ifdef HAVE_XKBCOMMON_COMPOSE_H _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) @@ -686,6 +700,7 @@ int _glfwPlatformInit(void) dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); +#endif _glfw.wl.display = wl_display_connect(NULL); if (!_glfw.wl.display) @@ -740,7 +755,10 @@ void _glfwPlatformTerminate(void) _glfwTerminateEGL(); _glfwTerminateJoysticksLinux(); +#ifdef HAVE_XKBCOMMON_COMPOSE_H xkb_compose_state_unref(_glfw.wl.xkb.composeState); +#endif + xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_state_unref(_glfw.wl.xkb.state); xkb_context_unref(_glfw.wl.xkb.context); diff --git a/src/wl_platform.h b/src/wl_platform.h index 059ea2eee..96c0a9915 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -26,7 +26,9 @@ #include #include +#ifdef HAVE_XKBCOMMON_COMPOSE_H #include +#endif #include typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; @@ -78,13 +80,6 @@ typedef void (* PFN_xkb_state_unref)(struct xkb_state*); typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**); typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t); typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component); -typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); -typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); -typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags); -typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*); -typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t); -typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*); -typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*); #define xkb_context_new _glfw.wl.xkb.context_new #define xkb_context_unref _glfw.wl.xkb.context_unref #define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string @@ -95,6 +90,15 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st #define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms #define xkb_state_update_mask _glfw.wl.xkb.state_update_mask #define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods + +#ifdef HAVE_XKBCOMMON_COMPOSE_H +typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); +typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); +typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags); +typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*); +typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t); +typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*); +typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*); #define xkb_compose_table_new_from_locale _glfw.wl.xkb.compose_table_new_from_locale #define xkb_compose_table_unref _glfw.wl.xkb.compose_table_unref #define xkb_compose_state_new _glfw.wl.xkb.compose_state_new @@ -102,6 +106,7 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st #define xkb_compose_state_feed _glfw.wl.xkb.compose_state_feed #define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status #define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym +#endif // Wayland-specific per-window data @@ -164,7 +169,11 @@ typedef struct _GLFWlibraryWayland struct xkb_context* context; struct xkb_keymap* keymap; struct xkb_state* state; + +#ifdef HAVE_XKBCOMMON_COMPOSE_H struct xkb_compose_state* composeState; +#endif + xkb_mod_mask_t controlMask; xkb_mod_mask_t altMask; xkb_mod_mask_t shiftMask; @@ -181,6 +190,8 @@ typedef struct _GLFWlibraryWayland PFN_xkb_state_key_get_syms state_key_get_syms; PFN_xkb_state_update_mask state_update_mask; PFN_xkb_state_serialize_mods state_serialize_mods; + +#ifdef HAVE_XKBCOMMON_COMPOSE_H PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; PFN_xkb_compose_table_unref compose_table_unref; PFN_xkb_compose_state_new compose_state_new; @@ -188,6 +199,7 @@ typedef struct _GLFWlibraryWayland PFN_xkb_compose_state_feed compose_state_feed; PFN_xkb_compose_state_get_status compose_state_get_status; PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym; +#endif } xkb; _GLFWwindow* pointerFocus; From 40ab709aacc5f905ab488d7da781381b0a35ca13 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Thu, 16 Nov 2017 15:03:42 +0000 Subject: [PATCH 203/222] Add Wayland to Travis CI build Closes #1131. --- .travis.yml | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef11ea1a0..abb0a46e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,15 +4,10 @@ branches: only: - ci - master -os: - - linux - - osx sudo: false dist: trusty addons: apt: - sources: - - kubuntu-backports packages: - cmake - libxrandr-dev @@ -22,13 +17,46 @@ addons: env: global: - CFLAGS=-Werror - matrix: - - BUILD_SHARED_LIBS=ON - - BUILD_SHARED_LIBS=OFF +matrix: + include: + - os: linux + env: BUILD_SHARED_LIBS=ON + - os: linux + env: BUILD_SHARED_LIBS=OFF + - os: linux + sudo: required + addons: + apt: + packages: + - libwayland-dev + - libxkbcommon-dev + - libegl1-mesa-dev + env: + - USE_WAYLAND=ON + - BUILD_SHARED_LIBS=ON + - os: linux + sudo: required + addons: + apt: + packages: + - libwayland-dev + - libxkbcommon-dev + - libegl1-mesa-dev + env: + - USE_WAYLAND=ON + - BUILD_SHARED_LIBS=OFF + - os: osx + env: BUILD_SHARED_LIBS=ON + - os: osx + env: BUILD_SHARED_LIBS=OFF script: - mkdir build - cd build - - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} .. + - if test -n "${USE_WAYLAND}"; then wget https://mirrors.kernel.org/ubuntu/pool/universe/e/extra-cmake-modules/extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; fi + - if test -n "${USE_WAYLAND}"; then sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; fi + - if test -n "${USE_WAYLAND}"; then git clone git://anongit.freedesktop.org/wayland/wayland-protocols; fi + - if test -n "${USE_WAYLAND}"; then pushd wayland-protocols; ./autogen.sh --prefix=/usr; make -j; sudo make install; popd; fi + - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} .. - cmake --build . notifications: email: From b5e24676a479d823326c0de578ff015ccbb161f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Nov 2017 18:55:43 +0100 Subject: [PATCH 204/222] Move contribution guide to visible directory --- README.md | 4 ++-- {.github => docs}/CONTRIBUTING.md | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename {.github => docs}/CONTRIBUTING.md (100%) diff --git a/README.md b/README.md index 1aa9bf129..b8e18a688 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ and the API reference. ## Contributing to GLFW See the [contribution -guide](https://github.com/glfw/glfw/blob/master/.github/CONTRIBUTING.md) for +guide](https://github.com/glfw/glfw/blob/master/docs/CONTRIBUTING.md) for more information. @@ -118,7 +118,7 @@ find that tool. Bugs are reported to our [issue tracker](https://github.com/glfw/glfw/issues). Please check the [contribution -guide](https://github.com/glfw/glfw/blob/master/.github/CONTRIBUTING.md) for +guide](https://github.com/glfw/glfw/blob/master/docs/CONTRIBUTING.md) for information on what to include when reporting a bug. diff --git a/.github/CONTRIBUTING.md b/docs/CONTRIBUTING.md similarity index 100% rename from .github/CONTRIBUTING.md rename to docs/CONTRIBUTING.md From 65166858ffc8e1bb85fd091aaadefcfdc398137e Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Fri, 17 Feb 2017 15:52:50 +0000 Subject: [PATCH 205/222] Wayland: Add support for the idle-inhibit protocol Closes #955. --- include/GLFW/glfw3.h | 3 ++- src/CMakeLists.txt | 4 ++++ src/wl_init.c | 9 +++++++++ src/wl_platform.h | 5 +++++ src/wl_window.c | 26 ++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 1 deletion(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 157a48201..dfff8d3de 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2358,7 +2358,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * icons, the window will inherit the one defined in the application's * desktop file, so this function emits @ref GLFW_PLATFORM_ERROR. * - * @remark @wayland Screensaver inhibition is currently unimplemented. + * @remark @wayland Screensaver inhibition requires the idle-inhibit protocol + * to be implemented in the user's compositor. * * @thread_safety This function must only be called from the main thread. * diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b14512cc5..01c01053a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,10 @@ elseif (_GLFW_WAYLAND) PROTOCOL "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" BASENAME pointer-constraints-unstable-v1) + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml + BASENAME idle-inhibit-unstable-v1) elseif (_GLFW_MIR) set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h posix_time.h posix_thread.h xkb_unicode.h egl_context.h diff --git a/src/wl_init.c b/src/wl_init.c index d6832aaa5..ec25f206b 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -501,6 +501,13 @@ static void registryHandleGlobal(void* data, &zwp_pointer_constraints_v1_interface, 1); } + else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) + { + _glfw.wl.idleInhibitManager = + wl_registry_bind(registry, name, + &zwp_idle_inhibit_manager_v1_interface, + 1); + } } static void registryHandleGlobalRemove(void *data, @@ -786,6 +793,8 @@ void _glfwPlatformTerminate(void) zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager); if (_glfw.wl.pointerConstraints) zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints); + if (_glfw.wl.idleInhibitManager) + zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager); if (_glfw.wl.registry) wl_registry_destroy(_glfw.wl.registry); if (_glfw.wl.display) diff --git a/src/wl_platform.h b/src/wl_platform.h index 96c0a9915..516c84be8 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -54,6 +54,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" +#include "wayland-idle-inhibit-unstable-v1-client-protocol.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -138,6 +139,9 @@ typedef struct _GLFWwindowWayland struct zwp_relative_pointer_v1* relativePointer; struct zwp_locked_pointer_v1* lockedPointer; } pointerLock; + + struct zwp_idle_inhibitor_v1* idleInhibitor; + } _GLFWwindowWayland; // Wayland-specific global data @@ -154,6 +158,7 @@ typedef struct _GLFWlibraryWayland struct wl_keyboard* keyboard; struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_pointer_constraints_v1* pointerConstraints; + struct zwp_idle_inhibit_manager_v1* idleInhibitManager; int compositorVersion; diff --git a/src/wl_window.c b/src/wl_window.c index b2ae7aae2..9759ba26f 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -189,6 +189,24 @@ static void setOpaqueRegion(_GLFWwindow* window) wl_region_destroy(region); } +static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) +{ + if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager) + { + window->wl.idleInhibitor = + zwp_idle_inhibit_manager_v1_create_inhibitor( + _glfw.wl.idleInhibitManager, window->wl.surface); + if (!window->wl.idleInhibitor) + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Idle inhibitor creation failed"); + } + else if (!enable && window->wl.idleInhibitor) + { + zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); + window->wl.idleInhibitor = NULL; + } +} + static GLFWbool createSurface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { @@ -239,14 +257,17 @@ static GLFWbool createShellSurface(_GLFWwindow* window) WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, window->monitor->wl.output); + setIdleInhibitor(window, GLFW_TRUE); } else if (window->wl.maximized) { wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); + setIdleInhibitor(window, GLFW_FALSE); } else { wl_shell_surface_set_toplevel(window->wl.shellSurface); + setIdleInhibitor(window, GLFW_FALSE); } wl_surface_commit(window->wl.surface); @@ -452,6 +473,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) _glfwInputWindowFocus(window, GLFW_FALSE); } + if (window->wl.idleInhibitor) + zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); + if (window->context.destroy) window->context.destroy(window); @@ -637,10 +661,12 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, refreshRate * 1000, // Convert Hz to mHz. monitor->wl.output); + setIdleInhibitor(window, GLFW_TRUE); } else { wl_shell_surface_set_toplevel(window->wl.shellSurface); + setIdleInhibitor(window, GLFW_FALSE); } _glfwInputWindowMonitor(window, monitor); } From fe9c7a01c5db93082ea2e92da97ba735955e4522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 23 Nov 2017 19:17:46 +0100 Subject: [PATCH 206/222] Update gamepad mappings and source URL This matches the recent upstream update. --- CMake/GenerateMappings.cmake | 2 +- src/mappings.h | 324 +++++++++++++++++++++-------------- 2 files changed, 196 insertions(+), 130 deletions(-) diff --git a/CMake/GenerateMappings.cmake b/CMake/GenerateMappings.cmake index 9fb304e87..2d929deed 100644 --- a/CMake/GenerateMappings.cmake +++ b/CMake/GenerateMappings.cmake @@ -1,7 +1,7 @@ # Usage: # cmake -P GenerateMappings.cmake -set(source_url "https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt") +set(source_url "https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb_204.txt") set(source_path "${CMAKE_CURRENT_BINARY_DIR}/gamecontrollerdb.txt") set(template_path "${CMAKE_ARGV3}") set(target_path "${CMAKE_ARGV4}") diff --git a/src/mappings.h b/src/mappings.h index 6c1b800d7..32f81dac3 100644 --- a/src/mappings.h +++ b/src/mappings.h @@ -59,177 +59,243 @@ // 3. This notice may not be removed or altered from any source distribution. const char* _glfwDefaultMappings = +"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,\n" "8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" "341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,\n" +"d81d0b00000000000000504944564944,BUFFALO BSGP1601 Series ,platform:Windows,x:b4,a:b5,b:b3,y:b2,back:b12,start:b13,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b6,rightshoulder:b9,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"5e048e02000000000000504944564944,Controller (XBOX 360 For Windows),platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,righttrigger:a2,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" +"0d0f8500000000000000504944564944,Fighting Commander 2016 PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f5f00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f5e00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:a3,platform:Windows,\n" +"0d0f8400000000000000504944564944,Fighting Commander 5,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f8700000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f8800000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b9,guide:b12,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f2700000000000000504944564944,FIGHTING STICK V3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" "ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,\n" "6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"45130010000000000000504944564944,Generic USB Joystick,a:b0,b:b1,x:b2,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"d8140862000000000000504944564944,HitBox Edition Cthulhu+,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,\n" +"0d0f4000000000000000504944564944,Hori Fighting Stick Mini 3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,\n" "0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f4d00000000000000504944564944,HORIPAD3 A,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"25090017000000000000504944564944,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b5,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b6,platform:Windows,\n" +"d81d0f00000000000000504944564944,iBUFFALO BSGP1204 Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"d81d1000000000000000504944564944,iBUFFALO BSGP1204P Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,\n" +"6f0e2401000000000000504944564944,INJUSTICE FightStick for PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Windows\n" +"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,\n" "6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"38075032000000000000504944564944,Mad Catz FightPad PRO PS3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"38075082000000000000504944564944,Mad Catz FightPad PRO PS4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b13,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" +"38078433000000000000504944564944,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"38078483000000000000504944564944,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:b6,platform:Windows,\n" +"38078134000000000000504944564944,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b7,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b4,platform:Windows,\n" +"38078184000000000000504944564944,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:b7,platform:Windows,\n" +"38078034000000000000504944564944,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"38078084000000000000504944564944,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"38078532000000000000504944564944,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"38073888000000000000504944564944,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"38071888000000000000504944564944,MadCatz SFIV FightStick PS3,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b6,platform:Windows,\n" +"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"25090128000000000000504944564944,Mayflash Arcade Stick,a:b1,b:b2,x:b5,y:b6,back:b8,start:b9,leftshoulder:b0,rightshoulder:b3,leftx:a0,lefty:a1,rightx:h0.4,righty:h0.0,lefttrigger:b4,righttrigger:b7,platform:Windows,\n" +"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"8f0e1030000000000000504944564944,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b6,rightshoulder:b2,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" +"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,\n" +"bd1215d0000000000000504944564944,Nintendo Retrolink USB Super SNES Classic Controller,y:b0,b:b1,a:b2,x:b3,leftshoulder:b4,rightshoulder:b5,start:b9,back:b8,leftx:a0,lefty:a1,platform:Windows,\n" +"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,\n" +"120cf60e000000000000504944564944,P4 Wired Gamepad,a:b1,b:b2,x:b0,y:b3,back:b12,guide:b8,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.0,lefttrigger:b7,righttrigger:b6,platform:Windows,\n" +"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,\n" "88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,\n" "4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,\n" "25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,\n" -"4c05c405000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,\n" -"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" +"10008200000000000000504944564944,PS360+ v1.66,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,\n" +"300f0011000000000000504944564944,QanBa Arcade JoyStick 1008,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b10,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,\n" +"300f1611000000000000504944564944,QanBa Arcade JoyStick 4018,a:b1,b:b2,x:b0,y:b3,back:b10,guide:b9,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"222c0020000000000000504944564944,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"300f1210000000000000504944564944,QanBa Joystick Plus,a:b0,b:b1,x:b2,y:b3,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Windows,\n" +"341a0104000000000000504944564944,QanBa Joystick Q4RAF,a:b5,b:b6,x:b1,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b0,rightshoulder:b3,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b7,platform:Windows,\n" +"222c0223000000000000504944564944,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"222c0023000000000000504944564944,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,x:b0,y:b3,back:b13,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"0d0f1100000000000000504944564944,REAL ARCADE PRO.3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f8b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"0d0f8a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" +"0d0f6b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"0d0f6a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" +"0d0f7000000000000000504944564944,REAL ARCADE PRO.4 VLX,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f2200000000000000504944564944,REAL ARCADE Pro.V3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" "00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" "00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" -"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" -"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,\n" -"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" -"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" "6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,\n" -"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,\n" -"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"300f1201000000000000504944564944,Saitek Dual Analog Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" +"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" "300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" -"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,\n" +"9b280500000000000000504944564944,Saturn_Adapter_2.0,a:b1,b:b2,x:b0,y:b3,start:b9,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Windows,\n" +"79001100000000000000504944564944,Sega Saturn Gamepad,a:b1,b:b2,x:b4,y:b5,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a4,lefttrigger:b3,righttrigger:b0,platform:Windows,\n" +"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,\n" +"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" +"66660488000000000000504944564944,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpdown:b14,dpleft:b15,dpright:b13,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,platform:Windows,\n" +"38076652000000000000504944564944,UnKnown,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" "63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"ff113133000000000000504944564944,Gembird JPD-DualForce,platform:Windows,a:b2,b:b3,x:b0,y:b1,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11,\n" -"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" -"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,\n" -"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,\n" -"79000600000000000000504944564944,NGS Phantom,a:b2,b:b3,y:b1,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"79001b18000000000000504944564944,Venom Arcade Joystick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" +"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,\n" +"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,\n" +"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" "6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" "6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" "6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" "6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" -"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,\n" -"4c05000000000000c405000000000000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" -"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" -"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" -"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,\n" -"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,\n" +"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" +"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,\n" +"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,\n" "8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" -"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" -"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,\n" -"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,\n" +"4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,\n" +"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,\n" "79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X,\n" +"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,\n" +"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" +"4c05000000000000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" +"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,\n" +"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"10080000000000000100000000000000,Twin USB Joystick,a:b4,b:b2,x:b6,y:b0,back:b16,start:b18,leftstick:b20,rightstick:b22,leftshoulder:b12,rightshoulder:b14,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a2,rightx:a6,righty:a4,lefttrigger:b8,righttrigger:b10,platform:Mac OS X,\n" +"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,\n" +"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,\n" +"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" "5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" "5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" "5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,\n" -"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,\n" -"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" -"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,\n" -"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,\n" -"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,\n" +"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" +"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,\n" +"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,\n" "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,\n" +"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,\n" +"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"03000000ff1100004133000010010000,GreenAsia Inc.USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"06000000adde0000efbe000002010000,Hidromancer Game Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,\n" +"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,\n" +"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,\n" +"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7\n" +"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,\n" +"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,\n" +"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" "03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,\n" +"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" "030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" -"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" "030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,\n" +"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" "030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" "030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,\n" +"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,\n" +"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,\n" +"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,\n" +"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" +"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,\n" +"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,\n" +"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,\n" +"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" +"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" +"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" "030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,\n" -"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" +"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" +"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" +"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,platform:Linux,x:b1,a:b0,b:b4,y:b5,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" +"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" +"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" +"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,platform:Linux,a:b12,b:b10,x:b13,y:b11,back:b4,start:b5,leftstick:b14,rightstick:b15,leftshoulder:b9,rightshoulder:b8,dpup:b0,dpdown:b2,dpleft:b3,dpright:b1,leftx:a1,lefty:a0,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"030000004c050000c405000011810000,Sony DualShock 4,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"050000004c050000cc09000000810000,Sony DualShock 4 (CUH-ZCT2U) (Bluetooth),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"030000004c050000cc09000011810000,Sony DualShock 4 (CUH-ZCT2U) (USB),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" "050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,\n" "030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" "050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" "030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" -"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,\n" +"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,\n" +"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" +"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,\n" +"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" +"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" +"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,\n" +"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" +"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" +"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" "03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" "030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" "030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" -"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" -"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" -"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,\n" -"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,\n" -"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,\n" -"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,\n" -"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" -"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" -"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,\n" -"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,\n" -"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" -"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" -"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" -"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a3,rightx:a1,righty:a4,\n" -"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,\n" -"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" -"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" -"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" -"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,\n" -"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,\n" -"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7\n" -"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"030000005e040000a102000000010000,X360 Wireless Controller,platform:Linux,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,\n" "0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000790000001100000010010000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,\n" -"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" -"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,\n" -"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" -"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,\n" -"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,\n" -"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,\n" -"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,\n" -"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" -"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,\n" -"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,\n" -"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,\n" +"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,platform:Linux,y:b0,x:b1,b:b3,a:b4,leftshoulder:b2,rightshoulder:b5,back:b6,start:b7,guide:b9,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftx:a0,lefty:a1,\n" "78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" "78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" From 3169179de1284988c442d16a319d46b6c61825e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 23 Nov 2017 20:54:44 +0100 Subject: [PATCH 207/222] Fix string literal exceeding max length Fixes #1145. --- CMake/GenerateMappings.cmake | 2 +- src/init.c | 13 +- src/mappings.h | 493 ++++++++++++++++++----------------- src/mappings.h.in | 19 +- 4 files changed, 270 insertions(+), 257 deletions(-) diff --git a/CMake/GenerateMappings.cmake b/CMake/GenerateMappings.cmake index 2d929deed..400df577d 100644 --- a/CMake/GenerateMappings.cmake +++ b/CMake/GenerateMappings.cmake @@ -24,7 +24,7 @@ endif() file(STRINGS "${source_path}" lines) foreach(line ${lines}) if ("${line}" MATCHES "^[0-9a-fA-F].*$") - set(GLFW_GAMEPAD_MAPPINGS "${GLFW_GAMEPAD_MAPPINGS}\"${line}\\n\"\n") + set(GLFW_GAMEPAD_MAPPINGS "${GLFW_GAMEPAD_MAPPINGS}\"${line}\",\n") endif() endforeach() diff --git a/src/init.c b/src/init.c index 8dea3ac88..ae82831bf 100644 --- a/src/init.c +++ b/src/init.c @@ -220,10 +220,17 @@ GLFWAPI int glfwInit(void) glfwDefaultWindowHints(); - if (!glfwUpdateGamepadMappings(_glfwDefaultMappings)) { - terminate(); - return GLFW_FALSE; + int i; + + for (i = 0; _glfwDefaultMappings[i]; i++) + { + if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i])) + { + terminate(); + return GLFW_FALSE; + } + } } return GLFW_TRUE; diff --git a/src/mappings.h b/src/mappings.h index 32f81dac3..dd7476085 100644 --- a/src/mappings.h +++ b/src/mappings.h @@ -58,250 +58,253 @@ // // 3. This notice may not be removed or altered from any source distribution. -const char* _glfwDefaultMappings = -"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,\n" -"8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" -"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,\n" -"d81d0b00000000000000504944564944,BUFFALO BSGP1601 Series ,platform:Windows,x:b4,a:b5,b:b3,y:b2,back:b12,start:b13,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b6,rightshoulder:b9,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"5e048e02000000000000504944564944,Controller (XBOX 360 For Windows),platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,righttrigger:a2,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" -"0d0f8500000000000000504944564944,Fighting Commander 2016 PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f5f00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f5e00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:a3,platform:Windows,\n" -"0d0f8400000000000000504944564944,Fighting Commander 5,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f8700000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f8800000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b9,guide:b12,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f2700000000000000504944564944,FIGHTING STICK V3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" -"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,\n" -"6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" -"45130010000000000000504944564944,Generic USB Joystick,a:b0,b:b1,x:b2,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"d8140862000000000000504944564944,HitBox Edition Cthulhu+,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,\n" -"0d0f4000000000000000504944564944,Hori Fighting Stick Mini 3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,\n" -"0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f4d00000000000000504944564944,HORIPAD3 A,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"25090017000000000000504944564944,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b5,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b6,platform:Windows,\n" -"d81d0f00000000000000504944564944,iBUFFALO BSGP1204 Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"d81d1000000000000000504944564944,iBUFFALO BSGP1204P Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,\n" -"6f0e2401000000000000504944564944,INJUSTICE FightStick for PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Windows\n" -"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,\n" -"6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" -"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"38075032000000000000504944564944,Mad Catz FightPad PRO PS3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"38075082000000000000504944564944,Mad Catz FightPad PRO PS4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b13,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" -"38078433000000000000504944564944,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"38078483000000000000504944564944,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:b6,platform:Windows,\n" -"38078134000000000000504944564944,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b7,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b4,platform:Windows,\n" -"38078184000000000000504944564944,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:b7,platform:Windows,\n" -"38078034000000000000504944564944,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"38078084000000000000504944564944,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"38078532000000000000504944564944,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"38073888000000000000504944564944,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"38071888000000000000504944564944,MadCatz SFIV FightStick PS3,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b6,platform:Windows,\n" -"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"25090128000000000000504944564944,Mayflash Arcade Stick,a:b1,b:b2,x:b5,y:b6,back:b8,start:b9,leftshoulder:b0,rightshoulder:b3,leftx:a0,lefty:a1,rightx:h0.4,righty:h0.0,lefttrigger:b4,righttrigger:b7,platform:Windows,\n" -"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"8f0e1030000000000000504944564944,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b6,rightshoulder:b2,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" -"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,\n" -"bd1215d0000000000000504944564944,Nintendo Retrolink USB Super SNES Classic Controller,y:b0,b:b1,a:b2,x:b3,leftshoulder:b4,rightshoulder:b5,start:b9,back:b8,leftx:a0,lefty:a1,platform:Windows,\n" -"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,\n" -"120cf60e000000000000504944564944,P4 Wired Gamepad,a:b1,b:b2,x:b0,y:b3,back:b12,guide:b8,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.0,lefttrigger:b7,righttrigger:b6,platform:Windows,\n" -"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,\n" -"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,\n" -"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,\n" -"10008200000000000000504944564944,PS360+ v1.66,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,\n" -"300f0011000000000000504944564944,QanBa Arcade JoyStick 1008,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b10,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,\n" -"300f1611000000000000504944564944,QanBa Arcade JoyStick 4018,a:b1,b:b2,x:b0,y:b3,back:b10,guide:b9,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"222c0020000000000000504944564944,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"300f1210000000000000504944564944,QanBa Joystick Plus,a:b0,b:b1,x:b2,y:b3,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Windows,\n" -"341a0104000000000000504944564944,QanBa Joystick Q4RAF,a:b5,b:b6,x:b1,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b0,rightshoulder:b3,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b7,platform:Windows,\n" -"222c0223000000000000504944564944,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"222c0023000000000000504944564944,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,x:b0,y:b3,back:b13,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"0d0f1100000000000000504944564944,REAL ARCADE PRO.3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f8b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"0d0f8a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" -"0d0f6b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"0d0f6a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" -"0d0f7000000000000000504944564944,REAL ARCADE PRO.4 VLX,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f2200000000000000504944564944,REAL ARCADE Pro.V3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" -"00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" -"6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"300f1201000000000000504944564944,Saitek Dual Analog Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" -"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" -"300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" -"9b280500000000000000504944564944,Saturn_Adapter_2.0,a:b1,b:b2,x:b0,y:b3,start:b9,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Windows,\n" -"79001100000000000000504944564944,Sega Saturn Gamepad,a:b1,b:b2,x:b4,y:b5,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a4,lefttrigger:b3,righttrigger:b0,platform:Windows,\n" -"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,\n" -"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" -"66660488000000000000504944564944,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpdown:b14,dpleft:b15,dpright:b13,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,platform:Windows,\n" -"38076652000000000000504944564944,UnKnown,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"79001b18000000000000504944564944,Venom Arcade Joystick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" -"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" -"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,\n" -"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,\n" -"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" -"6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" -"6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" -"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" -"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" -"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,\n" -"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,\n" -"8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,\n" -"4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,\n" -"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,\n" -"79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X,\n" -"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,\n" -"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" -"4c05000000000000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" -"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,\n" -"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"10080000000000000100000000000000,Twin USB Joystick,a:b4,b:b2,x:b6,y:b0,back:b16,start:b18,leftstick:b20,rightstick:b22,leftshoulder:b12,rightshoulder:b14,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a2,rightx:a6,righty:a4,lefttrigger:b8,righttrigger:b10,platform:Mac OS X,\n" -"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,\n" -"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,\n" -"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" -"5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" -"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,\n" -"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,\n" -"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,\n" -"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,\n" -"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"03000000ff1100004133000010010000,GreenAsia Inc.USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"06000000adde0000efbe000002010000,Hidromancer Game Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,\n" -"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,\n" -"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,\n" -"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7\n" -"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,\n" -"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,\n" -"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,\n" -"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" -"030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,\n" -"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" -"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,\n" -"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,\n" -"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,\n" -"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,\n" -"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" -"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,\n" -"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,\n" -"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,\n" -"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" -"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" -"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,\n" -"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" -"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" -"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" -"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,platform:Linux,x:b1,a:b0,b:b4,y:b5,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" -"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" -"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" -"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,platform:Linux,a:b12,b:b10,x:b13,y:b11,back:b4,start:b5,leftstick:b14,rightstick:b15,leftshoulder:b9,rightshoulder:b8,dpup:b0,dpdown:b2,dpleft:b3,dpright:b1,leftx:a1,lefty:a0,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"030000004c050000c405000011810000,Sony DualShock 4,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"050000004c050000cc09000000810000,Sony DualShock 4 (CUH-ZCT2U) (Bluetooth),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"030000004c050000cc09000011810000,Sony DualShock 4 (CUH-ZCT2U) (USB),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,\n" -"030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" -"050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" -"030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" -"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,\n" -"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,\n" -"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" -"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,\n" -"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" -"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" -"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,\n" -"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" -"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" -"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"030000005e040000a102000000010000,X360 Wireless Controller,platform:Linux,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,\n" -"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,platform:Linux,y:b0,x:b1,b:b3,a:b4,leftshoulder:b2,rightshoulder:b5,back:b6,start:b7,guide:b9,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftx:a0,lefty:a1,\n" +const char* _glfwDefaultMappings[] = +{ +"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,", +"8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,", +"d81d0b00000000000000504944564944,BUFFALO BSGP1601 Series ,platform:Windows,x:b4,a:b5,b:b3,y:b2,back:b12,start:b13,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b6,rightshoulder:b9,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"5e048e02000000000000504944564944,Controller (XBOX 360 For Windows),platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,righttrigger:a2,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,", +"0d0f8500000000000000504944564944,Fighting Commander 2016 PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f5f00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f5e00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:a3,platform:Windows,", +"0d0f8400000000000000504944564944,Fighting Commander 5,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f8700000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f8800000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b9,guide:b12,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f2700000000000000504944564944,FIGHTING STICK V3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,", +"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"45130010000000000000504944564944,Generic USB Joystick,a:b0,b:b1,x:b2,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"d8140862000000000000504944564944,HitBox Edition Cthulhu+,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,", +"0d0f4000000000000000504944564944,Hori Fighting Stick Mini 3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,", +"0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f4d00000000000000504944564944,HORIPAD3 A,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"25090017000000000000504944564944,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b5,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b6,platform:Windows,", +"d81d0f00000000000000504944564944,iBUFFALO BSGP1204 Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"d81d1000000000000000504944564944,iBUFFALO BSGP1204P Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,", +"6f0e2401000000000000504944564944,INJUSTICE FightStick for PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Windows", +"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,", +"6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"38075032000000000000504944564944,Mad Catz FightPad PRO PS3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"38075082000000000000504944564944,Mad Catz FightPad PRO PS4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b13,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", +"38078433000000000000504944564944,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"38078483000000000000504944564944,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:b6,platform:Windows,", +"38078134000000000000504944564944,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b7,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b4,platform:Windows,", +"38078184000000000000504944564944,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:b7,platform:Windows,", +"38078034000000000000504944564944,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"38078084000000000000504944564944,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"38078532000000000000504944564944,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"38073888000000000000504944564944,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"38071888000000000000504944564944,MadCatz SFIV FightStick PS3,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b6,platform:Windows,", +"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"25090128000000000000504944564944,Mayflash Arcade Stick,a:b1,b:b2,x:b5,y:b6,back:b8,start:b9,leftshoulder:b0,rightshoulder:b3,leftx:a0,lefty:a1,rightx:h0.4,righty:h0.0,lefttrigger:b4,righttrigger:b7,platform:Windows,", +"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"8f0e1030000000000000504944564944,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b6,rightshoulder:b2,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b5,righttrigger:b7,platform:Windows,", +"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,", +"bd1215d0000000000000504944564944,Nintendo Retrolink USB Super SNES Classic Controller,y:b0,b:b1,a:b2,x:b3,leftshoulder:b4,rightshoulder:b5,start:b9,back:b8,leftx:a0,lefty:a1,platform:Windows,", +"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,", +"120cf60e000000000000504944564944,P4 Wired Gamepad,a:b1,b:b2,x:b0,y:b3,back:b12,guide:b8,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.0,lefttrigger:b7,righttrigger:b6,platform:Windows,", +"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,", +"88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,", +"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,", +"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,", +"10008200000000000000504944564944,PS360+ v1.66,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"300f0011000000000000504944564944,QanBa Arcade JoyStick 1008,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b10,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,", +"300f1611000000000000504944564944,QanBa Arcade JoyStick 4018,a:b1,b:b2,x:b0,y:b3,back:b10,guide:b9,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"222c0020000000000000504944564944,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"300f1210000000000000504944564944,QanBa Joystick Plus,a:b0,b:b1,x:b2,y:b3,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Windows,", +"341a0104000000000000504944564944,QanBa Joystick Q4RAF,a:b5,b:b6,x:b1,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b0,rightshoulder:b3,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b7,platform:Windows,", +"222c0223000000000000504944564944,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"222c0023000000000000504944564944,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,x:b0,y:b3,back:b13,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"0d0f1100000000000000504944564944,REAL ARCADE PRO.3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f8b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"0d0f8a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", +"0d0f6b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"0d0f6a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", +"0d0f7000000000000000504944564944,REAL ARCADE PRO.4 VLX,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f2200000000000000504944564944,REAL ARCADE Pro.V3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,", +"00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,", +"6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"300f1201000000000000504944564944,Saitek Dual Analog Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,", +"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,", +"300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,", +"9b280500000000000000504944564944,Saturn_Adapter_2.0,a:b1,b:b2,x:b0,y:b3,start:b9,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Windows,", +"79001100000000000000504944564944,Sega Saturn Gamepad,a:b1,b:b2,x:b4,y:b5,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a4,lefttrigger:b3,righttrigger:b0,platform:Windows,", +"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,", +"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,", +"66660488000000000000504944564944,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpdown:b14,dpleft:b15,dpright:b13,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,platform:Windows,", +"38076652000000000000504944564944,UnKnown,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"79001b18000000000000504944564944,Venom Arcade Joystick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", +"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,", +"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", +"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,", +"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,", +"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,", +"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,", +"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,", +"8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,", +"4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,", +"79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X,", +"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,", +"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", +"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", +"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,", +"4c05000000000000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,", +"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,", +"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,", +"10080000000000000100000000000000,Twin USB Joystick,a:b4,b:b2,x:b6,y:b0,back:b16,start:b18,leftstick:b20,rightstick:b22,leftshoulder:b12,rightshoulder:b14,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a2,rightx:a6,righty:a4,lefttrigger:b8,righttrigger:b10,platform:Mac OS X,", +"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,", +"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,", +"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", +"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", +"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,", +"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,", +"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,", +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,", +"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"03000000ff1100004133000010010000,GreenAsia Inc.USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"06000000adde0000efbe000002010000,Hidromancer Game Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,", +"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,", +"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,", +"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7", +"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,", +"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", +"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,", +"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,", +"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,", +"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,", +"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,", +"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,", +"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,", +"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,", +"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,", +"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,", +"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,", +"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,", +"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,", +"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,", +"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", +"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", +"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", +"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", +"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,platform:Linux,x:b1,a:b0,b:b4,y:b5,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", +"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", +"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", +"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,", +"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,", +"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,", +"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,platform:Linux,a:b12,b:b10,x:b13,y:b11,back:b4,start:b5,leftstick:b14,rightstick:b15,leftshoulder:b9,rightshoulder:b8,dpup:b0,dpdown:b2,dpleft:b3,dpright:b1,leftx:a1,lefty:a0,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"030000004c050000c405000011810000,Sony DualShock 4,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", +"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"050000004c050000cc09000000810000,Sony DualShock 4 (CUH-ZCT2U) (Bluetooth),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"030000004c050000cc09000011810000,Sony DualShock 4 (CUH-ZCT2U) (USB),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", +"050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", +"030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", +"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,", +"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,", +"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,", +"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,", +"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", +"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,", +"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,", +"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,", +"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,", +"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,", +"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,", +"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,", +"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", +"030000005e040000a102000000010000,X360 Wireless Controller,platform:Linux,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", +"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,platform:Linux,y:b0,x:b1,b:b3,a:b4,leftshoulder:b2,rightshoulder:b5,back:b6,start:b7,guide:b9,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftx:a0,lefty:a1,", -"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n"; +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +NULL +}; diff --git a/src/mappings.h.in b/src/mappings.h.in index bf7206701..207d40b9f 100644 --- a/src/mappings.h.in +++ b/src/mappings.h.in @@ -58,13 +58,16 @@ // // 3. This notice may not be removed or altered from any source distribution. -const char* _glfwDefaultMappings = +const char* _glfwDefaultMappings[] = +{ @GLFW_GAMEPAD_MAPPINGS@ -"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n"; +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +NULL +}; From 1a250234ea1ea774c461c96173c83e7be19b572b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 26 Nov 2017 22:12:41 +0100 Subject: [PATCH 208/222] Add revert button to gamma ramp test --- tests/gamma.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/gamma.c b/tests/gamma.c index 500d41c40..c692cf9ac 100644 --- a/tests/gamma.c +++ b/tests/gamma.c @@ -38,6 +38,7 @@ #define NK_INCLUDE_DEFAULT_ALLOCATOR #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT #define NK_INCLUDE_STANDARD_VARARGS +#define NK_BUTTON_TRIGGER_ON_RELEASE #include #define NK_GLFW_GL2_IMPLEMENTATION @@ -85,6 +86,7 @@ int main(int argc, char** argv) { GLFWmonitor* monitor = NULL; GLFWwindow* window; + GLFWgammaramp orig_ramp; struct nk_context* nk; struct nk_font_atlas* atlas; float gamma_value = 1.f; @@ -103,6 +105,18 @@ int main(int argc, char** argv) exit(EXIT_FAILURE); } + { + const GLFWgammaramp* ramp = glfwGetGammaRamp(monitor); + const size_t array_size = ramp->size * sizeof(short); + orig_ramp.size = ramp->size; + orig_ramp.red = malloc(array_size); + orig_ramp.green = malloc(array_size); + orig_ramp.blue = malloc(array_size); + memcpy(orig_ramp.red, ramp->red, array_size); + memcpy(orig_ramp.green, ramp->green, array_size); + memcpy(orig_ramp.blue, ramp->blue, array_size); + } + glfwMakeContextCurrent(window); gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); glfwSwapInterval(1); @@ -125,13 +139,17 @@ int main(int argc, char** argv) nk_glfw3_new_frame(); if (nk_begin(nk, "", area, 0)) { - const GLFWgammaramp* ramp = glfwGetGammaRamp(monitor); + const GLFWgammaramp* ramp; nk_window_set_bounds(nk, area); - nk_layout_row_dynamic(nk, 30, 2); + nk_layout_row_dynamic(nk, 30, 3); if (nk_slider_float(nk, 0.1f, &gamma_value, 5.f, 0.1f)) glfwSetGamma(monitor, gamma_value); nk_labelf(nk, NK_TEXT_LEFT, "%0.1f", gamma_value); + if (nk_button_label(nk, "Revert")) + glfwSetGammaRamp(monitor, &orig_ramp); + + ramp = glfwGetGammaRamp(monitor); nk_layout_row_dynamic(nk, height - 60.f, 3); chart_ramp_array(nk, nk_rgb(255, 0, 0), ramp->size, ramp->red); @@ -146,6 +164,10 @@ int main(int argc, char** argv) glfwWaitEventsTimeout(1.0); } + free(orig_ramp.red); + free(orig_ramp.green); + free(orig_ramp.blue); + nk_glfw3_shutdown(); glfwTerminate(); exit(EXIT_SUCCESS); From bfe2d42af4bf26880b165496fba3c4f5be8b064b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 27 Nov 2017 01:18:51 +0100 Subject: [PATCH 209/222] Documentation work --- docs/context.dox | 3 +-- docs/window.dox | 6 ++++++ include/GLFW/glfw3.h | 11 +++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/context.dox b/docs/context.dox index 58c622174..e94448dcd 100644 --- a/docs/context.dox +++ b/docs/context.dox @@ -129,8 +129,7 @@ error. @section context_swap Buffer swapping -Buffer swapping is part of the window and framebuffer, not the context. See -@ref buffer_swap. +See @ref buffer_swap in the window guide. @section context_glext OpenGL and OpenGL ES extensions diff --git a/docs/window.dox b/docs/window.dox index 2c9cec917..db29d6115 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -1334,4 +1334,10 @@ Note that this may not work on all machines, as some drivers have user-controlled settings that override any swap interval the application requests. +A context that supports either the `WGL_EXT_swap_control_tear` or the +`GLX_EXT_swap_control_tear` extension also accepts _negative_ swap intervals, +which allows the driver to swap immediately even if a frame arrives a little bit +late. This trades the risk of visible tears for greater framerate stability. +You can check for these extensions with @ref glfwExtensionSupported. + */ diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index dfff8d3de..9c02401d9 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4969,12 +4969,11 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * is sometimes called _vertical synchronization_, _vertical retrace * synchronization_ or just _vsync_. * - * Contexts that support either of the `WGL_EXT_swap_control_tear` and - * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, - * which allow the driver to swap even if a frame arrives a little bit late. - * You can check for the presence of these extensions using @ref - * glfwExtensionSupported. For more information about swap tearing, see the - * extension specifications. + * A context that support either of the `WGL_EXT_swap_control_tear` and + * `GLX_EXT_swap_control_tear` extensions also accepts _negative_ swap + * intervals, which allows the driver to swap immediately even if a frame + * arrives a little bit late. You can check for these extensions with @ref + * glfwExtensionSupported. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. From 8094a1c99e83b5a5d0458e584b44d307e36d4e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 27 Nov 2017 15:53:59 +0100 Subject: [PATCH 210/222] Documentation work --- include/GLFW/glfw3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 9c02401d9..f97202a71 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4969,7 +4969,7 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * is sometimes called _vertical synchronization_, _vertical retrace * synchronization_ or just _vsync_. * - * A context that support either of the `WGL_EXT_swap_control_tear` and + * A context that supports either of the `WGL_EXT_swap_control_tear` and * `GLX_EXT_swap_control_tear` extensions also accepts _negative_ swap * intervals, which allows the driver to swap immediately even if a frame * arrives a little bit late. You can check for these extensions with @ref From 9e6c0c747be838d1f3dc38c2924a47a42416c081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 27 Nov 2017 15:54:33 +0100 Subject: [PATCH 211/222] X11: Fix segfault when using NVidia EGL --- README.md | 1 + src/x11_init.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b8e18a688..595e49ee7 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Incremental reading of selections was not supported (#275) - [X11] Bugfix: Selection I/O reported but did not support `COMPOUND_TEXT` - [X11] Bugfix: Latin-1 text read from selections was not converted to UTF-8 +- [X11] Bugfix: NVidia EGL would segfault if unloaded before closing the display - [Linux] Moved to evdev for joystick input (#906,#1005) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Linux] Bugfix: The joystick device path could be truncated (#1025) diff --git a/src/x11_init.c b/src/x11_init.c index 4c863c38c..6786231c8 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -994,8 +994,6 @@ void _glfwPlatformTerminate(void) _glfw.x11.im = NULL; } - _glfwTerminateEGL(); - if (_glfw.x11.display) { XCloseDisplay(_glfw.x11.display); @@ -1026,8 +1024,9 @@ void _glfwPlatformTerminate(void) _glfw.x11.xinerama.handle = NULL; } - // NOTE: This needs to be done after XCloseDisplay, as libGL registers - // cleanup callbacks that get called by it + // NOTE: These need to be unloaded after XCloseDisplay, as they register + // cleanup callbacks that get called by that function + _glfwTerminateEGL(); _glfwTerminateGLX(); #if defined(__linux__) From 390a66d2e74927a0bbaf708bcf7a7bc49a731369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 28 Nov 2017 14:20:54 +0100 Subject: [PATCH 212/222] Fix missing header in gamma test --- tests/gamma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/gamma.c b/tests/gamma.c index c692cf9ac..fbd37622e 100644 --- a/tests/gamma.c +++ b/tests/gamma.c @@ -46,6 +46,7 @@ #include #include +#include static void error_callback(int error, const char* description) { From 30489c5aa1392f698e904c6aced1d7a486634c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 28 Nov 2017 14:37:49 +0100 Subject: [PATCH 213/222] X11: Expose zero monitor for functional headless Fixes #1147. --- src/x11_monitor.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/x11_monitor.c b/src/x11_monitor.c index d68c58886..d9144bb48 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -203,8 +203,7 @@ void _glfwPollMonitorsX11(void) free(disconnected); } - - if (!_glfw.monitorCount) + else { const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); From 7c87948eafa63cf8b6b3d020a26189df6a6d3527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 28 Nov 2017 19:59:59 +0100 Subject: [PATCH 214/222] Win32: Fix accidentally working bit tests Good grief. --- src/win32_window.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/win32_window.c b/src/win32_window.c index 1aa3213e7..f817ead77 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -384,13 +384,13 @@ static int getKeyMods(void) { int mods = 0; - if (GetKeyState(VK_SHIFT) & (1 << 31)) + if (GetKeyState(VK_SHIFT) & 0x8000) mods |= GLFW_MOD_SHIFT; - if (GetKeyState(VK_CONTROL) & (1 << 31)) + if (GetKeyState(VK_CONTROL) & 0x8000) mods |= GLFW_MOD_CONTROL; - if (GetKeyState(VK_MENU) & (1 << 31)) + if (GetKeyState(VK_MENU) & 0x8000) mods |= GLFW_MOD_ALT; - if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31)) + if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; return mods; @@ -402,13 +402,13 @@ static int getAsyncKeyMods(void) { int mods = 0; - if (GetAsyncKeyState(VK_SHIFT) & (1 << 31)) + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) mods |= GLFW_MOD_SHIFT; - if (GetAsyncKeyState(VK_CONTROL) & (1 << 31)) + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) mods |= GLFW_MOD_CONTROL; - if (GetAsyncKeyState(VK_MENU) & (1 << 31)) + if (GetAsyncKeyState(VK_MENU) & 0x8000) mods |= GLFW_MOD_ALT; - if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31)) + if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; return mods; From c2858e9ed7e51d0fa62e936ce9dbb10bbb7b751e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 29 Nov 2017 19:30:08 +0100 Subject: [PATCH 215/222] Verify gamepad mapping indices match hardware --- src/input.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/input.c b/src/input.c index b20e9e687..c0154c27a 100644 --- a/src/input.c +++ b/src/input.c @@ -57,6 +57,58 @@ static _GLFWmapping* findMapping(const char* guid) return NULL; } +// Checks whether a gamepad mapping element is present in the hardware +// +static GLFWbool isValidElementForJoystick(const _GLFWmapelement* e, + const _GLFWjoystick* js) +{ + if (e->type == _GLFW_JOYSTICK_HATBIT && (e->value >> 4) >= js->hatCount) + return GLFW_FALSE; + else if (e->type == _GLFW_JOYSTICK_BUTTON && e->value >= js->buttonCount) + return GLFW_FALSE; + else if (e->type == _GLFW_JOYSTICK_AXIS && e->value >= js->axisCount) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +// Finds a mapping based on joystick GUID and verifies element indices +// +static _GLFWmapping* findValidMapping(const _GLFWjoystick* js) +{ + _GLFWmapping* mapping = findMapping(js->guid); + if (mapping) + { + int i; + + for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) + { + if (!isValidElementForJoystick(mapping->buttons + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid button in gamepad mapping %s (%s)", + mapping->guid, + mapping->name); + return NULL; + } + } + + for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) + { + if (!isValidElementForJoystick(mapping->axes + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid axis in gamepad mapping %s (%s)", + mapping->guid, + mapping->name); + return NULL; + } + } + } + + return mapping; +} + // Parses an SDL_GameControllerDB line and adds it to the mapping list // static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) @@ -318,9 +370,9 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, js->axisCount = axisCount; js->buttonCount = buttonCount; js->hatCount = hatCount; - js->mapping = findMapping(guid); strcpy(js->guid, guid); + js->mapping = findValidMapping(js); return js; } @@ -973,7 +1025,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) { _GLFWjoystick* js = _glfw.joysticks + jid; if (js->present) - js->mapping = findMapping(js->guid); + js->mapping = findValidMapping(js); } return GLFW_TRUE; From df434c839a0588c4bc56c59bb54e30e7abb15954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 4 Dec 2017 03:44:58 +0100 Subject: [PATCH 216/222] Add mapping file drop support to joystick test --- tests/joysticks.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/joysticks.c b/tests/joysticks.c index d2be6475d..1d2993759 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -85,6 +85,32 @@ static void joystick_callback(int jid, int event) glfwRequestWindowAttention(window); } +static void drop_callback(GLFWwindow* window, int count, const char** paths) +{ + int i; + + for (i = 0; i < count; i++) + { + long size; + char* text; + FILE* stream = fopen(paths[i], "rb"); + if (!stream) + continue; + + fseek(stream, 0, SEEK_END); + size = ftell(stream); + fseek(stream, 0, SEEK_SET); + + text = malloc(size + 1); + text[size] = '\0'; + if (fread(text, 1, size, stream) == size) + glfwUpdateGamepadMappings(text); + + free(text); + fclose(stream); + } +} + static const char* joystick_label(int jid) { static char label[1024]; @@ -176,6 +202,7 @@ int main(void) } glfwSetJoystickCallback(joystick_callback); + glfwSetDropCallback(window, drop_callback); while (!glfwWindowShouldClose(window)) { From b8df6ae3c14234f1b1c8584e56abbaab05b489b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 29 Nov 2017 21:03:38 +0100 Subject: [PATCH 217/222] Finish deprecating charmods callback --- README.md | 1 + docs/input.dox | 20 +------------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 595e49ee7..eae1c5303 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,7 @@ information on what to include when reporting a bug. [OSMesa](https://www.mesa3d.org/osmesa.html) (#281) - Added `GenerateMappings.cmake` script for updating gamepad mappings - Deprecated window parameter of clipboard string functions +- Deprecated charmods callback - Removed `GLFW_USE_RETINA` compile-time option - Removed `GLFW_USE_CHDIR` compile-time option - Removed `GLFW_USE_MENUBAR` compile-time option diff --git a/docs/input.dox b/docs/input.dox index 89ff98320..e3190d483 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -186,8 +186,7 @@ encode the code points into UTF-8 or any other encoding you prefer. Because an `unsigned int` is 32 bits long on all platforms supported by GLFW, you can treat the code point argument as native endian UTF-32. -There are two callbacks for receiving Unicode code points. If you wish to -offer regular text input, set a character callback. +If you wish to offer regular text input, set a character callback. @code glfwSetCharCallback(window, character_callback); @@ -203,23 +202,6 @@ void character_callback(GLFWwindow* window, unsigned int codepoint) } @endcode -If you also wish to receive those Unicode code points generated with modifier -key combinations that a plain text field would ignore, or want to know exactly -what modifier keys were used, set a character with modifiers callback. - -@code -glfwSetCharModsCallback(window, charmods_callback); -@endcode - -The callback function receives Unicode code points and -[modifier bits](@ref mods). - -@code -void charmods_callback(GLFWwindow* window, unsigned int codepoint, int mods) -{ -} -@endcode - @subsection input_key_name Key names From 638c4b604ef68e5f76adccd29015352fa3599526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 29 Nov 2017 21:04:57 +0100 Subject: [PATCH 218/222] Cleanup --- src/win32_platform.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/win32_platform.h b/src/win32_platform.h index 608d375f5..73bcb49b1 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -105,12 +105,11 @@ #endif #if WINVER < 0x0601 -typedef struct tagCHANGEFILTERSTRUCT +typedef struct { DWORD cbSize; DWORD ExtStatus; - -} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT; +} CHANGEFILTERSTRUCT; #ifndef MSGFLT_ALLOW #define MSGFLT_ALLOW 1 #endif @@ -129,13 +128,13 @@ typedef struct #endif /*Windows Vista*/ #ifndef DPI_ENUMS_DECLARED -typedef enum PROCESS_DPI_AWARENESS +typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; -typedef enum MONITOR_DPI_TYPE +typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, @@ -209,7 +208,7 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID* // user32.dll function pointer typedefs typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); -typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); +typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*); #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ From d81946a35bff9149f9f79b473c21b2ba3fcd5f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 4 Dec 2017 16:40:44 +0100 Subject: [PATCH 219/222] Add window mode toggling to tearing test --- tests/CMakeLists.txt | 2 +- tests/tearing.c | 73 +++++++++++++++----------------------------- 2 files changed, 26 insertions(+), 49 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 52b08389d..a9900a0d4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -33,7 +33,7 @@ add_executable(icon WIN32 MACOSX_BUNDLE icon.c ${GLAD}) add_executable(inputlag WIN32 MACOSX_BUNDLE inputlag.c ${GETOPT} ${GLAD}) add_executable(joysticks WIN32 MACOSX_BUNDLE joysticks.c ${GLAD}) add_executable(opacity WIN32 MACOSX_BUNDLE opacity.c ${GLAD}) -add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT} ${GLAD}) +add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GLAD}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD}) add_executable(timeout WIN32 MACOSX_BUNDLE timeout.c ${GLAD}) add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD}) diff --git a/tests/tearing.c b/tests/tearing.c index 1d8a00a40..eed4f04d8 100644 --- a/tests/tearing.c +++ b/tests/tearing.c @@ -36,7 +36,6 @@ #include #include "linmath.h" -#include "getopt.h" static const struct { @@ -69,14 +68,6 @@ static int swap_tear; static int swap_interval; static double frame_rate; -static void usage(void) -{ - printf("Usage: tearing [-h] [-f]\n"); - printf("Options:\n"); - printf(" -f create full screen window\n"); - printf(" -h show this help\n"); -} - static void update_window_title(GLFWwindow* window) { char title[256]; @@ -138,64 +129,50 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, 1); break; + + case GLFW_KEY_F11: + case GLFW_KEY_ENTER: + { + static int x, y, width, height; + + if (mods != GLFW_MOD_ALT) + return; + + if (glfwGetWindowMonitor(window)) + glfwSetWindowMonitor(window, NULL, x, y, width, height, 0); + else + { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + glfwGetWindowPos(window, &x, &y); + glfwGetWindowSize(window, &width, &height); + glfwSetWindowMonitor(window, monitor, + 0, 0, mode->width, mode->height, + mode->refreshRate); + } + + break; + } } } int main(int argc, char** argv) { - int ch, width, height; unsigned long frame_count = 0; double last_time, current_time; - int fullscreen = GLFW_FALSE; - GLFWmonitor* monitor = NULL; GLFWwindow* window; GLuint vertex_buffer, vertex_shader, fragment_shader, program; GLint mvp_location, vpos_location; - while ((ch = getopt(argc, argv, "fh")) != -1) - { - switch (ch) - { - case 'h': - usage(); - exit(EXIT_SUCCESS); - - case 'f': - fullscreen = GLFW_TRUE; - break; - } - } - glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(EXIT_FAILURE); - if (fullscreen) - { - const GLFWvidmode* mode; - - monitor = glfwGetPrimaryMonitor(); - mode = glfwGetVideoMode(monitor); - - glfwWindowHint(GLFW_RED_BITS, mode->redBits); - glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); - glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); - glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); - - width = mode->width; - height = mode->height; - } - else - { - width = 640; - height = 480; - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - window = glfwCreateWindow(width, height, "", monitor, NULL); + window = glfwCreateWindow(640, 480, "Tearing detector", NULL, NULL); if (!window) { glfwTerminate(); From fd72eb917e57d9933d58fc935c926109996e4fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 5 Dec 2017 01:57:12 +0100 Subject: [PATCH 220/222] Mir: Fix modifier bit translation --- src/mir_window.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mir_window.c b/src/mir_window.c index fd8f2914d..48ac45b2e 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -117,11 +117,11 @@ static int mirModToGLFWMod(uint32_t mods) if (mods & mir_input_event_modifier_alt) publicMods |= GLFW_MOD_ALT; - else if (mods & mir_input_event_modifier_shift) + if (mods & mir_input_event_modifier_shift) publicMods |= GLFW_MOD_SHIFT; - else if (mods & mir_input_event_modifier_ctrl) + if (mods & mir_input_event_modifier_ctrl) publicMods |= GLFW_MOD_CONTROL; - else if (mods & mir_input_event_modifier_meta) + if (mods & mir_input_event_modifier_meta) publicMods |= GLFW_MOD_SUPER; return publicMods; From 0e8c4ea7ce653cc7346bfe9fd5e5ab3933961934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 29 Nov 2017 20:42:37 +0100 Subject: [PATCH 221/222] Add lock key modifier bits input mode This adds the GLFW_MOD_CAPS_LOCK and GLFW_MOD_NUM_LOCK modifier bits. Set the GLFW_LOCK_KEY_MODS input mode to enable these for all callbacks that receive modifier bits. Fixes #946. --- README.md | 1 + docs/input.dox | 13 +++++++++++++ include/GLFW/glfw3.h | 43 +++++++++++++++++++++++++++++++++++-------- src/cocoa_window.m | 3 +++ src/input.c | 17 +++++++++++++++-- src/internal.h | 1 + src/mir_window.c | 4 ++++ src/win32_window.c | 8 ++++++++ src/wl_init.c | 8 ++++++++ src/wl_platform.h | 2 ++ src/x11_window.c | 4 ++++ tests/events.c | 13 +++++++++++++ 12 files changed, 107 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index eae1c5303..638d956f0 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,7 @@ information on what to include when reporting a bug. - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) +- Added `GLFW_LOCK_KEY_MODS` input mode and `GLFW_MOD_*_LOCK` mod bits (#946) - Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint - Added macOS specific `GLFW_COCOA_FRAME_AUTOSAVE` window hint (#195) - Added macOS specific `GLFW_COCOA_GRAPHICS_SWITCHING` window hint (#377,#935) diff --git a/docs/input.dox b/docs/input.dox index e3190d483..0c00494f8 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -170,6 +170,19 @@ When sticky keys mode is enabled, the pollable state of a key will remain it has been polled, if a key release event had been processed in the meantime, the state will reset to `GLFW_RELEASE`, otherwise it will remain `GLFW_PRESS`. +@anchor GLFW_LOCK_KEY_MODS +If you wish to know what the state of the Caps Lock and Num Lock keys was when +input events were generated, set the `GLFW_LOCK_KEY_MODS` input mode. + +@code +glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, 1); +@endcode + +When this input mode is enabled, any callback that receives +[modifier bits](@ref mods) will have the @ref GLFW_MOD_CAPS_LOCK bit set if Caps +Lock was on when the event occurred and the @ref GLFW_MOD_NUM_LOCK bit set if +Num Lock was on. + The `GLFW_KEY_LAST` constant holds the highest value of any [named key](@ref keys). diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index f97202a71..07f8b172e 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -493,17 +493,37 @@ extern "C" { * @{ */ /*! @brief If this bit is set one or more Shift keys were held down. + * + * If this bit is set one or more Shift keys were held down. */ #define GLFW_MOD_SHIFT 0x0001 /*! @brief If this bit is set one or more Control keys were held down. + * + * If this bit is set one or more Control keys were held down. */ #define GLFW_MOD_CONTROL 0x0002 /*! @brief If this bit is set one or more Alt keys were held down. + * + * If this bit is set one or more Alt keys were held down. */ #define GLFW_MOD_ALT 0x0004 /*! @brief If this bit is set one or more Super keys were held down. + * + * If this bit is set one or more Super keys were held down. */ #define GLFW_MOD_SUPER 0x0008 +/*! @brief If this bit is set the Caps Lock key is enabled. + * + * If this bit is set the Caps Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +#define GLFW_MOD_CAPS_LOCK 0x0010 +/*! @brief If this bit is set the Num Lock key is enabled. + * + * If this bit is set the Num Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +#define GLFW_MOD_NUM_LOCK 0x0020 /*! @} */ @@ -963,6 +983,7 @@ extern "C" { #define GLFW_CURSOR 0x00033001 #define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 +#define GLFW_LOCK_KEY_MODS 0x00033004 #define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_HIDDEN 0x00034002 @@ -3657,12 +3678,12 @@ GLFWAPI void glfwPostEmptyEvent(void); /*! @brief Returns the value of an input option for the specified window. * * This function returns the value of an input option for the specified window. - * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or - * @ref GLFW_STICKY_MOUSE_BUTTONS. + * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. * * @param[in] window The window to query. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. @@ -3680,8 +3701,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); /*! @brief Sets an input option for the specified window. * * This function sets an input mode option for the specified window. The mode - * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or - * @ref GLFW_STICKY_MOUSE_BUTTONS. + * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. * * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * modes: @@ -3707,9 +3728,15 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * you are only interested in whether mouse buttons have been pressed but not * when or in which order. * + * If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to + * enable lock key modifier bits, or `GLFW_FALSE` to disable them. If enabled, + * callbacks that receive modifier bits will also have the @ref + * GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on, + * and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on. + * * @param[in] window The window whose input mode to set. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. * @param[in] value The new value of the specified input mode. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 68246342a..cbea7374b 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -43,6 +43,7 @@ #define NSEventModifierFlagControl NSControlKeyMask #define NSEventModifierFlagOption NSAlternateKeyMask #define NSEventModifierFlagShift NSShiftKeyMask + #define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask #define NSEventMaskAny NSAnyEventMask #define NSEventTypeApplicationDefined NSApplicationDefined @@ -177,6 +178,8 @@ static int translateFlags(NSUInteger flags) mods |= GLFW_MOD_ALT; if (flags & NSEventModifierFlagCommand) mods |= GLFW_MOD_SUPER; + if (flags & NSEventModifierFlagCapsLock) + mods |= GLFW_MOD_CAPS_LOCK; return mods; } diff --git a/src/input.c b/src/input.c index c0154c27a..c64de2515 100644 --- a/src/input.c +++ b/src/input.c @@ -245,6 +245,9 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m action = GLFW_REPEAT; } + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (window->callbacks.key) window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); } @@ -254,6 +257,9 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) return; + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (window->callbacks.charmods) window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); @@ -275,6 +281,9 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) return; + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (action == GLFW_RELEASE && window->stickyMouseButtons) window->mouseButtons[button] = _GLFW_STICK; else @@ -406,6 +415,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) return window->stickyKeys; case GLFW_STICKY_MOUSE_BUTTONS: return window->stickyMouseButtons; + case GLFW_LOCK_KEY_MODS: + return window->lockKeyMods; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); @@ -461,7 +472,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) } } - window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE; + window->stickyKeys = value; } else if (mode == GLFW_STICKY_MOUSE_BUTTONS) { @@ -481,8 +492,10 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) } } - window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE; + window->stickyMouseButtons = value; } + else if (mode == GLFW_LOCK_KEY_MODS) + window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; else _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); } diff --git a/src/internal.h b/src/internal.h index 0a2cbc4d6..84d096c48 100644 --- a/src/internal.h +++ b/src/internal.h @@ -419,6 +419,7 @@ struct _GLFWwindow GLFWbool stickyKeys; GLFWbool stickyMouseButtons; + GLFWbool lockKeyMods; int cursorMode; char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; char keys[GLFW_KEY_LAST + 1]; diff --git a/src/mir_window.c b/src/mir_window.c index 48ac45b2e..ad06cb073 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -123,6 +123,10 @@ static int mirModToGLFWMod(uint32_t mods) publicMods |= GLFW_MOD_CONTROL; if (mods & mir_input_event_modifier_meta) publicMods |= GLFW_MOD_SUPER; + if (mods & mir_input_event_modifier_caps_lock) + publicMods |= GLFW_MOD_CAPS_LOCK; + if (mods & mir_input_event_modifier_num_lock) + publicMods |= GLFW_MOD_NUM_LOCK; return publicMods; } diff --git a/src/win32_window.c b/src/win32_window.c index f817ead77..60b2f275a 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -392,6 +392,10 @@ static int getKeyMods(void) mods |= GLFW_MOD_ALT; if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; + if (GetKeyState(VK_CAPITAL) & 1) + mods |= GLFW_MOD_CAPS_LOCK; + if (GetKeyState(VK_NUMLOCK) & 1) + mods |= GLFW_MOD_NUM_LOCK; return mods; } @@ -410,6 +414,10 @@ static int getAsyncKeyMods(void) mods |= GLFW_MOD_ALT; if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; + if (GetAsyncKeyState(VK_CAPITAL) & 1) + mods |= GLFW_MOD_CAPS_LOCK; + if (GetAsyncKeyState(VK_NUMLOCK) & 1) + mods |= GLFW_MOD_NUM_LOCK; return mods; } diff --git a/src/wl_init.c b/src/wl_init.c index ec25f206b..597275c9e 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -264,6 +264,10 @@ static void keyboardHandleKeymap(void* data, 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); _glfw.wl.xkb.superMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); + _glfw.wl.xkb.capsLockMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); + _glfw.wl.xkb.numLockMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); } static void keyboardHandleEnter(void* data, @@ -409,6 +413,10 @@ static void keyboardHandleModifiers(void* data, modifiers |= GLFW_MOD_SHIFT; if (mask & _glfw.wl.xkb.superMask) modifiers |= GLFW_MOD_SUPER; + if (mask & _glfw.wl.xkb.capsLockMask) + modifiers |= GLFW_MOD_CAPS_LOCK; + if (mask & _glfw.wl.xkb.numLockMask) + modifiers |= GLFW_MOD_NUM_LOCK; _glfw.wl.xkb.modifiers = modifiers; } diff --git a/src/wl_platform.h b/src/wl_platform.h index 516c84be8..c3cebecf9 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -183,6 +183,8 @@ typedef struct _GLFWlibraryWayland xkb_mod_mask_t altMask; xkb_mod_mask_t shiftMask; xkb_mod_mask_t superMask; + xkb_mod_mask_t capsLockMask; + xkb_mod_mask_t numLockMask; unsigned int modifiers; PFN_xkb_context_new context_new; diff --git a/src/x11_window.c b/src/x11_window.c index 32fff63b6..e9708f985 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -212,6 +212,10 @@ static int translateState(int state) mods |= GLFW_MOD_ALT; if (state & Mod4Mask) mods |= GLFW_MOD_SUPER; + if (state & LockMask) + mods |= GLFW_MOD_CAPS_LOCK; + if (state & Mod2Mask) + mods |= GLFW_MOD_NUM_LOCK; return mods; } diff --git a/tests/events.c b/tests/events.c index 7b42e4fd3..b9cf5bf2e 100644 --- a/tests/events.c +++ b/tests/events.c @@ -244,6 +244,10 @@ static const char* get_mods_name(int mods) strcat(name, " alt"); if (mods & GLFW_MOD_SUPER) strcat(name, " super"); + if (mods & GLFW_MOD_CAPS_LOCK) + strcat(name, " capslock-on"); + if (mods & GLFW_MOD_NUM_LOCK) + strcat(name, " numlock-on"); return name; } @@ -400,6 +404,15 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, printf("(( closing %s ))\n", slot->closeable ? "enabled" : "disabled"); break; } + + case GLFW_KEY_L: + { + const int state = glfwGetInputMode(window, GLFW_LOCK_KEY_MODS); + glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, !state); + + printf("(( lock key mods %s ))\n", !state ? "enabled" : "disabled"); + break; + } } } From 682f1cf203707f21c2eed4fa3f89c23c52accc49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 6 Dec 2017 12:47:05 +0100 Subject: [PATCH 222/222] Fix wrong element array for hat to axis --- src/input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input.c b/src/input.c index c64de2515..88a27fa31 100644 --- a/src/input.c +++ b/src/input.c @@ -1150,8 +1150,8 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) state->axes[i] = js->axes[js->mapping->axes[i].value]; else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) { - const unsigned int hat = js->mapping->buttons[i].value >> 4; - const unsigned int bit = js->mapping->buttons[i].value & 0xf; + const unsigned int hat = js->mapping->axes[i].value >> 4; + const unsigned int bit = js->mapping->axes[i].value & 0xf; if (js->hats[hat] & bit) state->axes[i] = 1.f; }