From eabc64fb7dd2a0a3006fd0d5079beb1a7c5f8daf Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 08:06:38 +0100 Subject: [PATCH 001/156] Disable unused prototypes --- tests/glfwinfo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index fce3885f2..a6ec9c242 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -23,8 +23,9 @@ // //======================================================================== -#include +#define VK_NO_PROTOTYPES #include +#include #include #include From d6975a708a6a3ec6b7e24746d92b32a04e555fe1 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 08:26:45 +0100 Subject: [PATCH 002/156] Fix search path for 32-bit Vulkan import library --- CMake/modules/FindVulkan.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CMake/modules/FindVulkan.cmake b/CMake/modules/FindVulkan.cmake index c7190bcbd..ce8a762af 100644 --- a/CMake/modules/FindVulkan.cmake +++ b/CMake/modules/FindVulkan.cmake @@ -7,8 +7,13 @@ if (WIN32) find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS "$ENV{VK_SDK_PATH}/Include") - find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS - "$ENV{VK_SDK_PATH}/Bin") + if (CMAKE_CL_64) + find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS + "$ENV{VK_SDK_PATH}/Bin") + else() + find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS + "$ENV{VK_SDK_PATH}/Bin32") + endif() else() find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS "$ENV{VULKAN_SDK}/include") From b955936ee110567e710636d110ef8540ba8f009b Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 08:55:24 +0100 Subject: [PATCH 003/156] Semantics fix --- src/vulkan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vulkan.c b/src/vulkan.c index b7b67fe57..ae13d4ce9 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -61,7 +61,7 @@ void _glfwInitVulkan(void) } _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) - vkGetInstanceProcAddr(0, "vkEnumerateInstanceExtensionProperties"); + vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); if (!_glfw.vk.EnumerateInstanceExtensionProperties) { _glfwInputError(GLFW_API_UNAVAILABLE, From 41b82903a80f689594da009e87cb9e835cf7f03b Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 09:10:48 +0100 Subject: [PATCH 004/156] Documentation work --- docs/vulkan.dox | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/docs/vulkan.dox b/docs/vulkan.dox index 7cd25abc2..6b9b3b470 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -4,22 +4,24 @@ @tableofcontents -This guide is intended to fill the gaps between the Vulkan documentation and the -rest of the GLFW documentation and is not a replacement for either. +This guide is intended to fill the gaps between the [Vulkan +documentation](https://www.khronos.org/vulkan/) and the rest of the GLFW +documentation and is not a replacement for either. It assumes some familiarity +with Vulkan concepts like loaders, devices, queues and surfaces. To develop for Vulkan you should install an SDK for your platform, for example -the [LunarG Vulkan SDK](http://lunarg.com/vulkan-sdk/). Apart from the headers -and libraries, it also provides the validation layers necessary for development. +the [LunarG Vulkan SDK](https://vulkan.lunarg.com/). Apart from the headers and +libraries, it also provides the validation layers necessary for development. -GLFW itself does not need a Vulkan SDK to enable support for Vulkan. However, -any Vulkan-specific test and example programs are built only if the CMake files -find the LunarG SDK. +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. @section vulkan_include Including the Vulkan and GLFW header files -To include the Vulkan header, define `GLFW_INCLUDE_VULKAN` before including the -GLFW header. +To include the Vulkan header, define [GLFW_INCLUDE_VULKAN](@ref build_macros) +before including the GLFW header. @code #define GLFW_INCLUDE_VULKAN @@ -30,15 +32,15 @@ If you want to include the Vulkan header from a custom location or use your own custom Vulkan header then you need to include them before the GLFW header. @code -#include +#include #include @endcode Unless a Vulkan header is included, either by the GLFW header or above it, any -GLFW functions that use Vulkan types will not be declared. +GLFW functions that take or return Vulkan types will not be declared. The `VK_USE_PLATFORM_*_KHR` macros do not need to be defined for the Vulkan part -of GLFW to work. +of GLFW to work. Define them only if you are using these extensions directly. @section vulkan_support Querying for Vulkan support @@ -110,8 +112,9 @@ be passed to @ref glfwGetPhysicalDevicePresentationSupport and @ref glfwCreateWindowSurface. The set of extensions will vary depending on platform and may also vary depending on graphics drivers and other factors. -If it fails it will return `NULL` and Vulkan window surface creation will not be -possible. You may still use Vulkan for off-screen rendering and compute work. +If it fails it will return `NULL` and GLFW will not be able to create Vulkan +window surfaces. You can still use Vulkan for off-screen rendering and compute +work. The returned array will always contain `VK_KHR_surface`, so if you don't require any additional extensions you can pass this list directly to the @@ -134,7 +137,7 @@ array, as it is an error to specify an extension more than once in the @section vulkan_present Querying for Vulkan presentation support -Not every Vulkan queue family of every device can present images to surfaces. +Not every queue family of every Vulkan device can present images to surfaces. To check whether a specific queue family of a physical device supports image presentation without first having to create a window and surface, call @ref glfwGetPhysicalDevicePresentationSupport. @@ -146,15 +149,15 @@ if (glfwGetPhysicalDevicePresentationSupport(instance, physical_device, queue_fa } @endcode -The `VK_KHR_surface` extension also provides the +The `VK_KHR_surface` extension additionally provides the `vkGetPhysicalDeviceSurfaceSupportKHR` function, which performs the same test on an existing Vulkan surface. @section vulkan_window Creating the window -Unless you will be using OpenGL or OpenGL ES in addition to Vulkan, there is no -need to create a context for that window. You can disable context creation by +Unless you will be using OpenGL or OpenGL ES with the same window as Vulkan, +there is no need to create a context. You can disable context creation by setting the [GLFW_CLIENT_API](@ref window_hints_ctx) hint to `GLFW_NO_API`. @code From 95c44ab2988496954ede8887389b65ef4970fc03 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 14:52:01 +0100 Subject: [PATCH 005/156] Fix cursor coordinate phrasing Fixes #387. --- docs/input.dox | 5 +++-- include/GLFW/glfw3.h | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/input.dox b/docs/input.dox index e36770ade..5798fde41 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -224,8 +224,9 @@ position callback. glfwSetCursorPosCallback(window, cursor_pos_callback); @endcode -The callback functions receives the cursor position. On platforms that provide -it, the full sub-pixel cursor position is passed on. +The callback functions receives the cursor position, measured in screen +coordinates but relative to the top-left corner of the window client area. On +platforms that provide it, the full sub-pixel cursor position is passed on. @code static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 71aac1713..4bd7e26c4 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -956,8 +956,10 @@ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); * This is the function signature for cursor position callback functions. * * @param[in] window The window that received the event. - * @param[in] xpos The new x-coordinate, in screen coordinates, of the cursor. - * @param[in] ypos The new y-coordinate, in screen coordinates, of the cursor. + * @param[in] xpos The new cursor x-coordinate, relative to the left edge of + * the client area. + * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the + * client area. * * @sa @ref cursor_pos * @sa glfwSetCursorPosCallback From 08ea80b7084685271cc0f9022388d658c466f5f2 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 15:03:26 +0100 Subject: [PATCH 006/156] Clarify language on instance function loading --- docs/vulkan.dox | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/vulkan.dox b/docs/vulkan.dox index 6b9b3b470..b58f7b0f4 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -45,6 +45,10 @@ of GLFW to work. Define them only if you are using these extensions directly. @section vulkan_support Querying for Vulkan support +If you are linking directly against the Vulkan loader then you can skip this +section. The canonical desktop loader library exports all Vulkan core and +Khronos extension functions, allowing them to be called directly. + If you are loading the Vulkan loader dynamically instead of linking directly against it, you can check for the availability of a loader with @ref glfwVulkanSupported. @@ -66,14 +70,23 @@ generate a @ref GLFW_API_UNAVAILABLE error. @subsection vulkan_proc Querying Vulkan function pointers To load any Vulkan core or extension function from the found loader, call @ref -glfwGetInstanceProcAddress. +glfwGetInstanceProcAddress. To load functions needed for instance creation, +pass `NULL` as the instance. + +@code +PFN_vkCreateInstance pfnCreateInstance = (PFN_vkCreateInstance) + glfwGetInstanceProcAddress(NULL, "vkCreateInstance"); +@endcode + +Once you have created an instance, you can load from it all other Vulkan core +functions and functions from any instance extensions you enabled. @code PFN_vkCreateDevice pfnCreateDevice = (PFN_vkCreateDevice) glfwGetInstanceProcAddress(instance, "vkCreateDevice"); @endcode -This is equivalent to calling `vkGetInstanceProcAddr`. If that fails, the +This function in turn calls `vkGetInstanceProcAddr`. If that fails, the function falls back to a platform-specific query of the Vulkan loader (i.e. `dlsym` or `GetProcAddress`). If that also fails, the function returns `NULL`. For more information about `vkGetInstanceProcAddr`, see the Vulkan From be94eb67be3ca2231ca61df0e89c0669623eac9a Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 17:17:08 +0100 Subject: [PATCH 007/156] Add support for EGL_KHR_gl_colorspace Fixes #285. --- docs/window.dox | 5 +++-- src/egl_context.c | 21 +++++++++++++++++++-- src/egl_context.h | 3 +++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/docs/window.dox b/docs/window.dox index 876927c7c..acb58858c 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -206,8 +206,9 @@ Zero disables multisampling. `GLFW_DONT_CARE` means the application has no preference. `GLFW_SRGB_CAPABLE` specifies whether the framebuffer should be sRGB capable. -If supported, the created context will provide `GL_ARB_framebuffer_sRGB` or -`GL_EXT_framebuffer_sRGB`. +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. `GLFW_DOUBLEBUFFER` specifies whether the framebuffer should be double buffered. You nearly always want to use double buffering. This is a hard constraint. diff --git a/src/egl_context.c b/src/egl_context.c index 579e17f10..00d4a7b4b 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -259,6 +259,8 @@ GLFWbool _glfwInitEGL(void) _glfwPlatformExtensionSupported("EGL_KHR_create_context"); _glfw.egl.KHR_create_context_no_error = _glfwPlatformExtensionSupported("EGL_KHR_create_context_no_error"); + _glfw.egl.KHR_gl_colorspace = + _glfwPlatformExtensionSupported("EGL_KHR_gl_colorspace"); return GLFW_TRUE; } @@ -288,7 +290,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - int attribs[40]; + EGLint attribs[40]; EGLConfig config; EGLContext share = NULL; @@ -401,11 +403,26 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, return GLFW_FALSE; } + // Set up attributes for surface creation + { + int index = 0; + + if (fbconfig->sRGB) + { + if (_glfw.egl.KHR_gl_colorspace) + { + setEGLattrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); + } + } + + setEGLattrib(EGL_NONE, EGL_NONE); + } + window->context.egl.surface = eglCreateWindowSurface(_glfw.egl.display, config, _GLFW_EGL_NATIVE_WINDOW, - NULL); + attribs); if (window->context.egl.surface == EGL_NO_SURFACE) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/egl_context.h b/src/egl_context.h index c73e1e02a..15d5a1258 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -104,6 +104,8 @@ typedef MirEGLNativeWindowType EGLNativeWindowType; #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd #define EGL_CONTEXT_FLAGS_KHR 0x30fc #define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 +#define EGL_GL_COLORSPACE_KHR 0x309d +#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 typedef int EGLint; typedef unsigned int EGLBoolean; @@ -174,6 +176,7 @@ typedef struct _GLFWlibraryEGL GLFWbool KHR_create_context; GLFWbool KHR_create_context_no_error; + GLFWbool KHR_gl_colorspace; void* handle; From 2accdb76bde03dc0f60953e6f4ff0064c6fa7f0d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 21:30:17 +0100 Subject: [PATCH 008/156] Cleanup --- src/egl_context.c | 4 ++-- src/init.c | 4 ++-- src/vulkan.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/egl_context.c b/src/egl_context.c index 00d4a7b4b..ea970708e 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -68,9 +68,9 @@ static const char* getErrorString(EGLint error) return "A NativeWindowType argument does not refer to a valid native window"; case EGL_CONTEXT_LOST: return "The application must destroy all contexts and reinitialise"; + default: + return "ERROR: UNKNOWN EGL ERROR"; } - - return "UNKNOWN EGL ERROR"; } // Returns the specified attribute of the specified EGLConfig diff --git a/src/init.c b/src/init.c index f245c7c14..06b097121 100644 --- a/src/init.c +++ b/src/init.c @@ -74,9 +74,9 @@ static const char* getErrorString(int error) return "The requested format is unavailable"; case GLFW_NO_WINDOW_CONTEXT: return "The specified window has no context"; + default: + return "ERROR: UNKNOWN GLFW ERROR"; } - - return "ERROR: UNKNOWN ERROR TOKEN PASSED TO glfwErrorString"; } diff --git a/src/vulkan.c b/src/vulkan.c index ae13d4ce9..04db23e07 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -181,7 +181,7 @@ const char* _glfwGetVulkanResultString(VkResult result) case VK_ERROR_VALIDATION_FAILED_EXT: return "A validation layer found an error"; default: - return "ERROR: UNKNOWN VULKAN ERROR TOKEN"; + return "ERROR: UNKNOWN VULKAN ERROR"; } } From b0b77bc0f2a154fd979e96537102047a27605e74 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 21:48:09 +0100 Subject: [PATCH 009/156] Documentation work --- docs/vulkan.dox | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/vulkan.dox b/docs/vulkan.dox index b58f7b0f4..098507e56 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -7,7 +7,8 @@ This guide is intended to fill the gaps between the [Vulkan documentation](https://www.khronos.org/vulkan/) and the rest of the GLFW documentation and is not a replacement for either. It assumes some familiarity -with Vulkan concepts like loaders, devices, queues and surfaces. +with Vulkan concepts like loaders, devices, queues and surfaces and leaves it to +the Vulkan documentation to explain the details of Vulkan functions. To develop for Vulkan you should install an SDK for your platform, for example the [LunarG Vulkan SDK](https://vulkan.lunarg.com/). Apart from the headers and @@ -170,8 +171,8 @@ an existing Vulkan surface. @section vulkan_window Creating the window Unless you will be using OpenGL or OpenGL ES with the same window as Vulkan, -there is no need to create a context. You can disable context creation by -setting the [GLFW_CLIENT_API](@ref window_hints_ctx) hint to `GLFW_NO_API`. +there is no need to create a context. You can disable context creation with the +[GLFW_CLIENT_API](@ref window_hints_ctx) hint. @code glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); From bdbad880c428da956013de359cb51e882d596865 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 21:48:48 +0100 Subject: [PATCH 010/156] Move GitHub documentation to .github --- CONTRIBUTING.md => .github/CONTRIBUTING.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (100%) diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md From 2826f3d42fc9d12b4336145ff647730e9e692945 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 15 Feb 2016 15:34:33 +0100 Subject: [PATCH 011/156] Check success of MakeCurrent before updating TLS Fixes #706. --- src/egl_context.c | 28 ++++++++++++++++++++-------- src/glx_context.c | 20 ++++++++++++++++---- src/wgl_context.c | 21 ++++++++++++++++++--- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/egl_context.c b/src/egl_context.c index ea970708e..827ccbfd3 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -583,17 +583,29 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) { if (window) { - eglMakeCurrent(_glfw.egl.display, - window->context.egl.surface, - window->context.egl.surface, - window->context.egl.handle); + if (!eglMakeCurrent(_glfw.egl.display, + window->context.egl.surface, + window->context.egl.surface, + window->context.egl.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to make context current: %s", + getErrorString(eglGetError())); + return; + } } else { - eglMakeCurrent(_glfw.egl.display, - EGL_NO_SURFACE, - EGL_NO_SURFACE, - EGL_NO_CONTEXT); + if (!eglMakeCurrent(_glfw.egl.display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to clear current context: %s", + getErrorString(eglGetError())); + return; + } } _glfwPlatformSetCurrentContext(window); diff --git a/src/glx_context.c b/src/glx_context.c index 84c0c7015..22ec7e10a 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -545,12 +545,24 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) { if (window) { - glXMakeCurrent(_glfw.x11.display, - window->context.glx.window, - window->context.glx.handle); + if (!glXMakeCurrent(_glfw.x11.display, + window->context.glx.window, + window->context.glx.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to make context current"); + return; + } } else - glXMakeCurrent(_glfw.x11.display, None, NULL); + { + if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to clear current context"); + return; + } + } _glfwPlatformSetCurrentContext(window); } diff --git a/src/wgl_context.c b/src/wgl_context.c index 55138e70e..afc85bab1 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -594,11 +594,26 @@ int _glfwAnalyzeContextWGL(_GLFWwindow* window, void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) { if (window) - wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle); + { + if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) + _glfwPlatformSetCurrentContext(window); + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to make context current"); + _glfwPlatformSetCurrentContext(NULL); + } + } else - wglMakeCurrent(NULL, NULL); + { + if (!wglMakeCurrent(NULL, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to clear current context"); + } - _glfwPlatformSetCurrentContext(window); + _glfwPlatformSetCurrentContext(NULL); + } } void _glfwPlatformSwapBuffers(_GLFWwindow* window) From 511183e76cffb526056c21b53892ec21ec735cfc Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 17 Feb 2016 22:03:12 +0100 Subject: [PATCH 012/156] Remove CRLF line endings --- .appveyor.yml | 44 ++--- .github/CONTRIBUTING.md | 212 ++++++++++----------- docs/vulkan.dox | 404 ++++++++++++++++++++-------------------- 3 files changed, 330 insertions(+), 330 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 74a2f0aab..ae658cc37 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,22 +1,22 @@ -branches: - only: - - ci - - master -skip_tags: true -environment: - matrix: - - BUILD_SHARED_LIBS: ON - - BUILD_SHARED_LIBS: OFF -matrix: - fast_finish: true -build_script: - - mkdir build - - cd build - - cmake -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% .. - - cmake --build . -notifications: - - provider: Email - to: - - ci@glfw.org - - on_build_failure: true - - on_build_success: false +branches: + only: + - ci + - master +skip_tags: true +environment: + matrix: + - BUILD_SHARED_LIBS: ON + - BUILD_SHARED_LIBS: OFF +matrix: + fast_finish: true +build_script: + - mkdir build + - cd build + - cmake -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% .. + - cmake --build . +notifications: + - provider: Email + to: + - ci@glfw.org + - on_build_failure: true + - on_build_success: false diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fbe09669b..53c3a6c3c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,106 +1,106 @@ -# Contribution Guide - -This file is a work in progress and you can report errors or submit patches for -it the same as any other file. - - -## Reporting a bug - -If GLFW is behaving unexpectedly, make sure you have set an error callback. -GLFW will often tell you the cause of an issue via this callback. - -If GLFW is crashing or triggering asserts, make sure that all your object -handles and other pointers are valid. - -Always include the __operating system name and version__ (i.e. `Windows -7 64-bit` or `Ubuntu 15.10`). If you are using an official release of GLFW, -include the __GLFW release version__ (i.e. `3.1.2`), otherwise include the -__GLFW commit ID__ (i.e. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git. -If possible, please also include the __GLFW version string__ (`3.2.0 X11 EGL -clock_gettime /dev/js XI Xf86vm`), as described -[here](http://www.glfw.org/docs/latest/intro.html#intro_version_string). - - -### Reporting a compile or link bug - -__Note:__ GLFW needs many system APIs to do its job. See the [Building -applications](http://www.glfw.org/docs/latest/build.html) guide for more -information. - -In addition to the information above, always include the complete build log from -your compiler and linker. Issue posts are editable so it can always be -shortened later. - - -### Reporting a context creation bug - -__Note:__ Windows ships with graphics drivers that do not support OpenGL. If -GLFW says that your machine lacks support for OpenGL, it very likely does. -Install drivers from the computer manufacturer or graphics card manufacturer -([Nvidia](http://www.geforce.com/drivers), - [AMD](http://support.amd.com/en-us/download), - [Intel](https://www-ssl.intel.com/content/www/us/en/support/detect.html)) to -fix this. - -__Note:__ AMD only supports OpenGL ES on Windows via EGL. EGL support is not -enabled in GLFW by default. You need to [enable EGL when -compiling](http://www.glfw.org/docs/latest/compile.html) GLFW to use this. - -The `glfwinfo` tool is included in the GLFW source tree as `tests/glfwinfo.c` -and is built along with the library. It lets you request any kind of context -and framebuffer format supported by the GLFW API without having to recompile. -If context creation fails in your application, please verify that it also fails -with this tool before reporting it as a bug. - -In addition to the information above (OS and GLFW version), always include the -__GPU model and driver version__ (i.e. `GeForce GTX660 with 352.79`) when -reporting this kind of bug. - - -### Reporting a monitor or video mode bug - -__Note:__ On headless systems on some platforms, no monitors are reported. This -causes glfwGetPrimaryMonitor to return `NULL`, which not all applications are -prepared for. - -__Note:__ Some third-party tools report more video modes than those approved of -by the OS. For safety and compatbility, GLFW only reports video modes the OS -wants programs to use. This is not a bug. - -The `monitors` tool is included in the GLFW source tree as `tests/monitors.c` -and is built along with the library. lists all information about connected -monitors made available by GLFW. - -In addition to the information above (OS and GLFW version), please also include -the output of the `monitors` tool when reporting this kind of bug. If it -doesn't work at all, please mention this. - - -### Reporting a window event bug - -__Note:__ While GLFW tries to provide the exact same behavior between platforms, -the exact ordering of related window events will sometimes differ. - -The `events` tool is included in the GLFW source tree as `tests/events.c` and is -built along with the library. It prints all information provided to every -callback supported by GLFW as events occur. Each event is listed with the time -and a unique number to make discussions about event logs easier. The tool has -command-line options for creating multiple windows and full screen windows. - - -### Reporting a documentation bug - -If you found the error in the generated documentation then it's fine to just -link to that webpage. You don't need to figure out which documentation source -file the text comes from. - - -## Contributing a bug fix - -There should be text here, but there isn't. - - -## Contributing a feature - -This is not (yet) the text you are looking for. - +# Contribution Guide + +This file is a work in progress and you can report errors or submit patches for +it the same as any other file. + + +## Reporting a bug + +If GLFW is behaving unexpectedly, make sure you have set an error callback. +GLFW will often tell you the cause of an issue via this callback. + +If GLFW is crashing or triggering asserts, make sure that all your object +handles and other pointers are valid. + +Always include the __operating system name and version__ (i.e. `Windows +7 64-bit` or `Ubuntu 15.10`). If you are using an official release of GLFW, +include the __GLFW release version__ (i.e. `3.1.2`), otherwise include the +__GLFW commit ID__ (i.e. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git. +If possible, please also include the __GLFW version string__ (`3.2.0 X11 EGL +clock_gettime /dev/js XI Xf86vm`), as described +[here](http://www.glfw.org/docs/latest/intro.html#intro_version_string). + + +### Reporting a compile or link bug + +__Note:__ GLFW needs many system APIs to do its job. See the [Building +applications](http://www.glfw.org/docs/latest/build.html) guide for more +information. + +In addition to the information above, always include the complete build log from +your compiler and linker. Issue posts are editable so it can always be +shortened later. + + +### Reporting a context creation bug + +__Note:__ Windows ships with graphics drivers that do not support OpenGL. If +GLFW says that your machine lacks support for OpenGL, it very likely does. +Install drivers from the computer manufacturer or graphics card manufacturer +([Nvidia](http://www.geforce.com/drivers), + [AMD](http://support.amd.com/en-us/download), + [Intel](https://www-ssl.intel.com/content/www/us/en/support/detect.html)) to +fix this. + +__Note:__ AMD only supports OpenGL ES on Windows via EGL. EGL support is not +enabled in GLFW by default. You need to [enable EGL when +compiling](http://www.glfw.org/docs/latest/compile.html) GLFW to use this. + +The `glfwinfo` tool is included in the GLFW source tree as `tests/glfwinfo.c` +and is built along with the library. It lets you request any kind of context +and framebuffer format supported by the GLFW API without having to recompile. +If context creation fails in your application, please verify that it also fails +with this tool before reporting it as a bug. + +In addition to the information above (OS and GLFW version), always include the +__GPU model and driver version__ (i.e. `GeForce GTX660 with 352.79`) when +reporting this kind of bug. + + +### Reporting a monitor or video mode bug + +__Note:__ On headless systems on some platforms, no monitors are reported. This +causes glfwGetPrimaryMonitor to return `NULL`, which not all applications are +prepared for. + +__Note:__ Some third-party tools report more video modes than those approved of +by the OS. For safety and compatbility, GLFW only reports video modes the OS +wants programs to use. This is not a bug. + +The `monitors` tool is included in the GLFW source tree as `tests/monitors.c` +and is built along with the library. lists all information about connected +monitors made available by GLFW. + +In addition to the information above (OS and GLFW version), please also include +the output of the `monitors` tool when reporting this kind of bug. If it +doesn't work at all, please mention this. + + +### Reporting a window event bug + +__Note:__ While GLFW tries to provide the exact same behavior between platforms, +the exact ordering of related window events will sometimes differ. + +The `events` tool is included in the GLFW source tree as `tests/events.c` and is +built along with the library. It prints all information provided to every +callback supported by GLFW as events occur. Each event is listed with the time +and a unique number to make discussions about event logs easier. The tool has +command-line options for creating multiple windows and full screen windows. + + +### Reporting a documentation bug + +If you found the error in the generated documentation then it's fine to just +link to that webpage. You don't need to figure out which documentation source +file the text comes from. + + +## Contributing a bug fix + +There should be text here, but there isn't. + + +## Contributing a feature + +This is not (yet) the text you are looking for. + diff --git a/docs/vulkan.dox b/docs/vulkan.dox index 098507e56..af9ffce01 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -1,202 +1,202 @@ -/*! - -@page vulkan Vulkan guide - -@tableofcontents - -This guide is intended to fill the gaps between the [Vulkan -documentation](https://www.khronos.org/vulkan/) and the rest of the GLFW -documentation and is not a replacement for either. It assumes some familiarity -with Vulkan concepts like loaders, devices, queues and surfaces and leaves it to -the Vulkan documentation to explain the details of Vulkan functions. - -To develop for Vulkan you should install an SDK for your platform, for example -the [LunarG Vulkan SDK](https://vulkan.lunarg.com/). Apart from the headers and -libraries, it also provides the validation layers necessary for development. - -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. - - -@section vulkan_include Including the Vulkan and GLFW header files - -To include the Vulkan header, define [GLFW_INCLUDE_VULKAN](@ref build_macros) -before including the GLFW header. - -@code -#define GLFW_INCLUDE_VULKAN -#include -@endcode - -If you want to include the Vulkan header from a custom location or use your own -custom Vulkan header then you need to include them before the GLFW header. - -@code -#include -#include -@endcode - -Unless a Vulkan header is included, either by the GLFW header or above it, any -GLFW functions that take or return Vulkan types will not be declared. - -The `VK_USE_PLATFORM_*_KHR` macros do not need to be defined for the Vulkan part -of GLFW to work. Define them only if you are using these extensions directly. - - -@section vulkan_support Querying for Vulkan support - -If you are linking directly against the Vulkan loader then you can skip this -section. The canonical desktop loader library exports all Vulkan core and -Khronos extension functions, allowing them to be called directly. - -If you are loading the Vulkan loader dynamically instead of linking directly -against it, you can check for the availability of a loader with @ref -glfwVulkanSupported. - -@code -if (glfwVulkanSupported()) -{ - // Vulkan is available, at least for compute -} -@endcode - -This function returns `GLFW_TRUE` if the Vulkan loader was found. This check is -performed by @ref glfwInit. - -If no loader was found, calling any other Vulkan related GLFW function will -generate a @ref GLFW_API_UNAVAILABLE error. - - -@subsection vulkan_proc Querying Vulkan function pointers - -To load any Vulkan core or extension function from the found loader, call @ref -glfwGetInstanceProcAddress. To load functions needed for instance creation, -pass `NULL` as the instance. - -@code -PFN_vkCreateInstance pfnCreateInstance = (PFN_vkCreateInstance) - glfwGetInstanceProcAddress(NULL, "vkCreateInstance"); -@endcode - -Once you have created an instance, you can load from it all other Vulkan core -functions and functions from any instance extensions you enabled. - -@code -PFN_vkCreateDevice pfnCreateDevice = (PFN_vkCreateDevice) - glfwGetInstanceProcAddress(instance, "vkCreateDevice"); -@endcode - -This function in turn calls `vkGetInstanceProcAddr`. If that fails, the -function falls back to a platform-specific query of the Vulkan loader (i.e. -`dlsym` or `GetProcAddress`). If that also fails, the function returns `NULL`. -For more information about `vkGetInstanceProcAddr`, see the Vulkan -documentation. - -Vulkan also provides `vkGetDeviceProcAddr` for loading device-specific versions -of Vulkan function. This function can be retrieved from an instance with @ref -glfwGetInstanceProcAddress. - -@code -PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr) - glfwGetInstanceProcAddress(instance, "vkGetDeviceProcAddr"); -@endcode - -Device-specific functions may execute a little bit faster, due to not having to -dispatch internally based on the device passed to them. For more information -about `vkGetDeviceProcAddr`, see the Vulkan documentation. - - -@section vulkan_ext Querying required Vulkan extensions - -To do anything useful with Vulkan you need to create an instance. If you want -to use Vulkan to render to a window, you must enable the instance extensions -GLFW requires to create Vulkan surfaces. - -To query the instance extensions required, call @ref -glfwGetRequiredInstanceExtensions. - -@code -int count; -const char** extensions = glfwGetRequiredInstanceExtensions(&count); -@endcode - -These extensions must all be enabled when creating instances that are going to -be passed to @ref glfwGetPhysicalDevicePresentationSupport and @ref -glfwCreateWindowSurface. The set of extensions will vary depending on platform -and may also vary depending on graphics drivers and other factors. - -If it fails it will return `NULL` and GLFW will not be able to create Vulkan -window surfaces. You can still use Vulkan for off-screen rendering and compute -work. - -The returned array will always contain `VK_KHR_surface`, so if you don't -require any additional extensions you can pass this list directly to the -`VkInstanceCreateInfo` struct. - -@code -VkInstanceCreateInfo ici; - -memset(&ici, 0, sizeof(ici)); -ici.enabledExtensionCount = count; -ici.ppEnabledExtensionNames = extensions; -... -@endcode - -Additional extensions may be required by future versions of GLFW. You should -check whether any extensions you wish to enable are already in the returned -array, as it is an error to specify an extension more than once in the -`VkInstanceCreateInfo` struct. - - -@section vulkan_present Querying for Vulkan presentation support - -Not every queue family of every Vulkan device can present images to surfaces. -To check whether a specific queue family of a physical device supports image -presentation without first having to create a window and surface, call @ref -glfwGetPhysicalDevicePresentationSupport. - -@code -if (glfwGetPhysicalDevicePresentationSupport(instance, physical_device, queue_family_index)) -{ - // Queue family supports image presentation -} -@endcode - -The `VK_KHR_surface` extension additionally provides the -`vkGetPhysicalDeviceSurfaceSupportKHR` function, which performs the same test on -an existing Vulkan surface. - - -@section vulkan_window Creating the window - -Unless you will be using OpenGL or OpenGL ES with the same window as Vulkan, -there is no need to create a context. You can disable context creation with the -[GLFW_CLIENT_API](@ref window_hints_ctx) hint. - -@code -glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); -GLFWwindow* window = glfwCreateWindow(640, 480, "Window Title", NULL, NULL); -@endcode - -See @ref context_less for more information. - - -@section vulkan_surface Creating a Vulkan window surface - -You can create a Vulkan surface (as defined by the `VK_KHR_surface` extension) -for a GLFW window with @ref glfwCreateWindowSurface. - -@code -VkSurfaceKHR surface; -VkResult err = glfwCreateWindowSurface(instance, window, NULL, &surface); -if (err) -{ - // Window surface creation failed -} -@endcode - -It is your responsibility to destroy the surface. GLFW does not destroy it for -you. Call `vkDestroySurfaceKHR` function from the same extension to destroy it. - -*/ +/*! + +@page vulkan Vulkan guide + +@tableofcontents + +This guide is intended to fill the gaps between the [Vulkan +documentation](https://www.khronos.org/vulkan/) and the rest of the GLFW +documentation and is not a replacement for either. It assumes some familiarity +with Vulkan concepts like loaders, devices, queues and surfaces and leaves it to +the Vulkan documentation to explain the details of Vulkan functions. + +To develop for Vulkan you should install an SDK for your platform, for example +the [LunarG Vulkan SDK](https://vulkan.lunarg.com/). Apart from the headers and +libraries, it also provides the validation layers necessary for development. + +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. + + +@section vulkan_include Including the Vulkan and GLFW header files + +To include the Vulkan header, define [GLFW_INCLUDE_VULKAN](@ref build_macros) +before including the GLFW header. + +@code +#define GLFW_INCLUDE_VULKAN +#include +@endcode + +If you want to include the Vulkan header from a custom location or use your own +custom Vulkan header then you need to include them before the GLFW header. + +@code +#include +#include +@endcode + +Unless a Vulkan header is included, either by the GLFW header or above it, any +GLFW functions that take or return Vulkan types will not be declared. + +The `VK_USE_PLATFORM_*_KHR` macros do not need to be defined for the Vulkan part +of GLFW to work. Define them only if you are using these extensions directly. + + +@section vulkan_support Querying for Vulkan support + +If you are linking directly against the Vulkan loader then you can skip this +section. The canonical desktop loader library exports all Vulkan core and +Khronos extension functions, allowing them to be called directly. + +If you are loading the Vulkan loader dynamically instead of linking directly +against it, you can check for the availability of a loader with @ref +glfwVulkanSupported. + +@code +if (glfwVulkanSupported()) +{ + // Vulkan is available, at least for compute +} +@endcode + +This function returns `GLFW_TRUE` if the Vulkan loader was found. This check is +performed by @ref glfwInit. + +If no loader was found, calling any other Vulkan related GLFW function will +generate a @ref GLFW_API_UNAVAILABLE error. + + +@subsection vulkan_proc Querying Vulkan function pointers + +To load any Vulkan core or extension function from the found loader, call @ref +glfwGetInstanceProcAddress. To load functions needed for instance creation, +pass `NULL` as the instance. + +@code +PFN_vkCreateInstance pfnCreateInstance = (PFN_vkCreateInstance) + glfwGetInstanceProcAddress(NULL, "vkCreateInstance"); +@endcode + +Once you have created an instance, you can load from it all other Vulkan core +functions and functions from any instance extensions you enabled. + +@code +PFN_vkCreateDevice pfnCreateDevice = (PFN_vkCreateDevice) + glfwGetInstanceProcAddress(instance, "vkCreateDevice"); +@endcode + +This function in turn calls `vkGetInstanceProcAddr`. If that fails, the +function falls back to a platform-specific query of the Vulkan loader (i.e. +`dlsym` or `GetProcAddress`). If that also fails, the function returns `NULL`. +For more information about `vkGetInstanceProcAddr`, see the Vulkan +documentation. + +Vulkan also provides `vkGetDeviceProcAddr` for loading device-specific versions +of Vulkan function. This function can be retrieved from an instance with @ref +glfwGetInstanceProcAddress. + +@code +PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr) + glfwGetInstanceProcAddress(instance, "vkGetDeviceProcAddr"); +@endcode + +Device-specific functions may execute a little bit faster, due to not having to +dispatch internally based on the device passed to them. For more information +about `vkGetDeviceProcAddr`, see the Vulkan documentation. + + +@section vulkan_ext Querying required Vulkan extensions + +To do anything useful with Vulkan you need to create an instance. If you want +to use Vulkan to render to a window, you must enable the instance extensions +GLFW requires to create Vulkan surfaces. + +To query the instance extensions required, call @ref +glfwGetRequiredInstanceExtensions. + +@code +int count; +const char** extensions = glfwGetRequiredInstanceExtensions(&count); +@endcode + +These extensions must all be enabled when creating instances that are going to +be passed to @ref glfwGetPhysicalDevicePresentationSupport and @ref +glfwCreateWindowSurface. The set of extensions will vary depending on platform +and may also vary depending on graphics drivers and other factors. + +If it fails it will return `NULL` and GLFW will not be able to create Vulkan +window surfaces. You can still use Vulkan for off-screen rendering and compute +work. + +The returned array will always contain `VK_KHR_surface`, so if you don't +require any additional extensions you can pass this list directly to the +`VkInstanceCreateInfo` struct. + +@code +VkInstanceCreateInfo ici; + +memset(&ici, 0, sizeof(ici)); +ici.enabledExtensionCount = count; +ici.ppEnabledExtensionNames = extensions; +... +@endcode + +Additional extensions may be required by future versions of GLFW. You should +check whether any extensions you wish to enable are already in the returned +array, as it is an error to specify an extension more than once in the +`VkInstanceCreateInfo` struct. + + +@section vulkan_present Querying for Vulkan presentation support + +Not every queue family of every Vulkan device can present images to surfaces. +To check whether a specific queue family of a physical device supports image +presentation without first having to create a window and surface, call @ref +glfwGetPhysicalDevicePresentationSupport. + +@code +if (glfwGetPhysicalDevicePresentationSupport(instance, physical_device, queue_family_index)) +{ + // Queue family supports image presentation +} +@endcode + +The `VK_KHR_surface` extension additionally provides the +`vkGetPhysicalDeviceSurfaceSupportKHR` function, which performs the same test on +an existing Vulkan surface. + + +@section vulkan_window Creating the window + +Unless you will be using OpenGL or OpenGL ES with the same window as Vulkan, +there is no need to create a context. You can disable context creation with the +[GLFW_CLIENT_API](@ref window_hints_ctx) hint. + +@code +glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); +GLFWwindow* window = glfwCreateWindow(640, 480, "Window Title", NULL, NULL); +@endcode + +See @ref context_less for more information. + + +@section vulkan_surface Creating a Vulkan window surface + +You can create a Vulkan surface (as defined by the `VK_KHR_surface` extension) +for a GLFW window with @ref glfwCreateWindowSurface. + +@code +VkSurfaceKHR surface; +VkResult err = glfwCreateWindowSurface(instance, window, NULL, &surface); +if (err) +{ + // Window surface creation failed +} +@endcode + +It is your responsibility to destroy the surface. GLFW does not destroy it for +you. Call `vkDestroySurfaceKHR` function from the same extension to destroy it. + +*/ From c56af32bb78a851b8062e9fbc9d45bb9cadb0481 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 18 Feb 2016 14:20:36 +0100 Subject: [PATCH 013/156] Fix use of undeclared constant --- src/wl_window.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 75aa912e4..ea301434e 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -80,8 +80,7 @@ static void checkScaleChange(_GLFWwindow* window) int monitorScale; // Check if we will be able to set the buffer scale or not. - if (_glfw.wl.wl_compositor_version < - WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) + if (_glfw.wl.wl_compositor_version < 3) return; // Get the scale factor from the highest scale monitor. From b6a72db2ad91d1472e9146d985dad64ef8b6e718 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 18 Feb 2016 14:48:07 +0100 Subject: [PATCH 014/156] Add missing inclusion of linux/input.h --- src/mir_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mir_init.c b/src/mir_init.c index 0ca57a663..3f649670d 100644 --- a/src/mir_init.c +++ b/src/mir_init.c @@ -26,6 +26,7 @@ #include "internal.h" +#include #include #include From 5e5fea2293511e3f3b0bda3a1fdc0d6c314332d0 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 18 Feb 2016 14:48:33 +0100 Subject: [PATCH 015/156] Fix struct member names of Mir WSI --- src/mir_window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mir_window.c b/src/mir_window.c index 88875f976..acc0a2cc5 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -762,8 +762,8 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR; - sci.display = _glfw.mir.connection; - sci.surface = window->mir.surface; + sci.connection = _glfw.mir.connection; + sci.mirSurface = window->mir.surface; err = vkCreateMirSurfaceKHR(instance, &sci, allocator, surface); if (err) From 65870346e412e905edfc4f5aa7bfc6b8cb02bb08 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 18 Feb 2016 15:16:03 +0100 Subject: [PATCH 016/156] Add Vulkan functions to thread safety section --- docs/intro.dox | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/intro.dox b/docs/intro.dox index cb3bdbc94..a54bf96f5 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -250,6 +250,15 @@ version related functions may be called 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: + + - @ref glfwVulkanSupported + - @ref glfwGetRequiredInstanceExtensions + - @ref glfwGetInstanceProcAddress + - @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. From 6e103d5dca51f98577f02374699038d789842a84 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 18 Feb 2016 19:35:48 +0100 Subject: [PATCH 017/156] Change priority order of X11 WSI extensions --- src/x11_window.c | 108 +++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 8ffd81c57..83fe01f9e 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2123,19 +2123,19 @@ char** _glfwPlatformGetRequiredInstanceExtensions(int* count) *count = 0; - if (!_glfw.vk.KHR_xlib_surface) + if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle) { - if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle) + if (!_glfw.vk.KHR_xlib_surface) return NULL; } extensions = calloc(2, sizeof(char*)); extensions[0] = strdup("VK_KHR_surface"); - if (_glfw.vk.KHR_xlib_surface) - extensions[1] = strdup("VK_KHR_xlib_surface"); - else + if (_glfw.vk.KHR_xcb_surface) extensions[1] = strdup("VK_KHR_xcb_surface"); + else + extensions[1] = strdup("VK_KHR_xlib_surface"); *count = 2; return extensions; @@ -2148,24 +2148,7 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display, _glfw.x11.screen)); - if (_glfw.vk.KHR_xlib_surface) - { - PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = - (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) - vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); - if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); - return GLFW_FALSE; - } - - return vkGetPhysicalDeviceXlibPresentationSupportKHR(device, - queuefamily, - _glfw.x11.display, - visualID); - } - else + if (_glfw.vk.KHR_xcb_surface) { PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) @@ -2191,6 +2174,23 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, connection, visualID); } + else + { + PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); + if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceXlibPresentationSupportKHR(device, + queuefamily, + _glfw.x11.display, + visualID); + } } VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, @@ -2198,37 +2198,7 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { - if (_glfw.vk.KHR_xlib_surface) - { - VkResult err; - VkXlibSurfaceCreateInfoKHR sci; - PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; - - vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) - vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"); - if (!vkCreateXlibSurfaceKHR) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); - return VK_ERROR_EXTENSION_NOT_PRESENT; - } - - memset(&sci, 0, sizeof(sci)); - sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - sci.dpy = _glfw.x11.display; - sci.window = window->x11.handle; - - err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface); - if (err) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to create Vulkan X11 surface: %s", - _glfwGetVulkanResultString(err)); - } - - return err; - } - else + if (_glfw.vk.KHR_xcb_surface) { VkResult err; VkXcbSurfaceCreateInfoKHR sci; @@ -2265,6 +2235,36 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _glfwGetVulkanResultString(err)); } + return err; + } + else + { + VkResult err; + VkXlibSurfaceCreateInfoKHR sci; + PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; + + vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"); + if (!vkCreateXlibSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + sci.dpy = _glfw.x11.display; + sci.window = window->x11.handle; + + err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create Vulkan X11 surface: %s", + _glfwGetVulkanResultString(err)); + } + return err; } } From bad778c1c4316b2c199f7d54dac71df1ce235733 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 18 Feb 2016 21:56:06 +0100 Subject: [PATCH 018/156] OpenGL headers not required for compilation --- docs/compile.dox | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/compile.dox b/docs/compile.dox index d1a0dd529..97907cc7f 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -87,10 +87,10 @@ Once you have Xcode installed, move on to @ref compile_generate. @subsubsection compile_deps_x11 Dependencies for Linux and X11 -To compile GLFW for X11, you need to have the X11 and OpenGL header packages -installed, as well as the basic development tools like GCC and make. For -example, on Ubuntu and other distributions based on Debian GNU/Linux, you need -to install the `xorg-dev` package, which pulls in all X.org header packages. +To compile GLFW for X11, you need to have the X11 packages installed, as well as +the basic development tools like GCC and make. For example, on Ubuntu and other +distributions based on Debian GNU/Linux, you need to install the `xorg-dev` +package, which pulls in all X.org header packages. Once you have installed the necessary packages, move on to @ref compile_generate. From 7da0ffa5ea08a4aa60a55946bc66e1b85871d95d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 18 Feb 2016 22:27:44 +0100 Subject: [PATCH 019/156] Formatting --- src/x11_window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 83fe01f9e..eaac057aa 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -920,7 +920,7 @@ static void processEvent(XEvent *event) while (c - chars < count) _glfwInputChar(window, decodeUTF8(&c), mods, plain); } -#else +#else /*X_HAVE_UTF8_STRING*/ wchar_t buffer[16]; wchar_t* chars = buffer; @@ -944,7 +944,7 @@ static void processEvent(XEvent *event) for (i = 0; i < count; i++) _glfwInputChar(window, chars[i], mods, plain); } -#endif +#endif /*X_HAVE_UTF8_STRING*/ if (chars != buffer) free(chars); From 3b64bae32341d564881d51adcd95dcc691756d75 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 19 Feb 2016 08:56:46 +0100 Subject: [PATCH 020/156] Fix X11 WSI extension selection logic --- src/x11_window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index eaac057aa..46e2d32b0 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2148,7 +2148,7 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display, _glfw.x11.screen)); - if (_glfw.vk.KHR_xcb_surface) + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) { PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) @@ -2198,7 +2198,7 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { - if (_glfw.vk.KHR_xcb_surface) + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) { VkResult err; VkXcbSurfaceCreateInfoKHR sci; From 001c50cfc6d32603fc572b49ce26896d5a6e99cf Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 19 Feb 2016 09:13:56 +0100 Subject: [PATCH 021/156] Add paragraphs on GL helpers not being for Vulkan --- include/GLFW/glfw3.h | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 4bd7e26c4..3b07bdf53 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3532,14 +3532,18 @@ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); /*! @brief Swaps the front and back buffers of the specified window. * - * This function swaps the front and back buffers of the specified window. If - * the swap interval is greater than zero, the GPU driver waits the specified - * number of screen updates before swapping the buffers. + * This function swaps the front and back buffers of the specified window when + * rendering with OpenGL or OpenGL ES. If the swap interval is greater than + * zero, the GPU driver waits the specified number of screen updates before + * swapping the buffers. * * The specified window must have an OpenGL or OpenGL ES context. Specifying * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT * error. * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see `vkQueuePresentKHR` instead. + * * @param[in] window The window whose buffers to swap. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref @@ -3562,11 +3566,11 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); /*! @brief Sets the swap interval for the current context. * - * This function sets the swap interval for the current context, i.e. the - * number of screen updates to wait from the time @ref glfwSwapBuffers was - * called before swapping the buffers and returning. This is sometimes called - * _vertical synchronization_, _vertical retrace synchronization_ or just - * _vsync_. + * This function sets the swap interval for the current OpenGL or OpenGL ES + * context, i.e. the number of screen updates to wait from the time @ref + * glfwSwapBuffers was called before swapping the buffers and returning. This + * 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, @@ -3578,6 +3582,9 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * 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. * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see the present mode of your swapchain instead. + * * @param[in] interval The minimum number of screen updates to wait for * until the buffers are swapped by @ref glfwSwapBuffers. * @@ -3607,9 +3614,9 @@ GLFWAPI void glfwSwapInterval(int interval); /*! @brief Returns whether the specified extension is available. * * This function returns whether the specified - * [client API extension](@ref context_glext) is supported by the current - * OpenGL or OpenGL ES context. It searches both for OpenGL and OpenGL ES - * extension and platform-specific context creation API extensions. + * [API extension](@ref context_glext) is supported by the current OpenGL or + * OpenGL ES context. It searches both for client API extension and context + * creation API extensions. * * 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. @@ -3619,6 +3626,10 @@ GLFWAPI void glfwSwapInterval(int interval); * frequently. The extension strings will not change during the lifetime of * a context, so there is no danger in doing this. * + * This function does not apply to Vulkan. If you are using Vulkan, see @ref + * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` + * and `vkEnumerateDeviceExtensionProperties` instead. + * * @param[in] extension The ASCII encoded name of the extension. * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` * otherwise. @@ -3641,13 +3652,17 @@ GLFWAPI int glfwExtensionSupported(const char* extension); /*! @brief Returns the address of the specified function for the current * context. * - * This function returns the address of the specified + * This function returns the address of the specified OpenGL or OpenGL ES * [core or extension function](@ref context_glext), if it is supported * by the current context. * * 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. * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and + * `vkGetDeviceProcAddr` instead. + * * @param[in] procname The ASCII encoded name of the function. * @return The address of the function, or `NULL` if an * [error](@ref error_handling) occurred. From 80c203f3bb1259dbba8ea8bcef9e637d15e695da Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 19 Feb 2016 10:29:13 +0100 Subject: [PATCH 022/156] Separate guide and reference documentation tags --- docs/build.dox | 8 ++++---- docs/compat.dox | 2 +- docs/compile.dox | 6 +++--- docs/context.dox | 17 ++++++++++------- docs/input.dox | 15 ++++++++------- docs/internal.dox | 2 +- docs/intro.dox | 19 +++++++++++-------- docs/main.dox | 28 ++++++++++++++-------------- docs/monitor.dox | 15 ++++++++------- docs/moving.dox | 4 ++-- docs/news.dox | 2 +- docs/quick.dox | 16 ++++++++-------- docs/rift.dox | 2 +- docs/vulkan.dox | 12 +++++++++++- docs/window.dox | 15 ++++++++------- include/GLFW/glfw3.h | 32 ++++++++++++++++---------------- 16 files changed, 107 insertions(+), 88 deletions(-) diff --git a/docs/build.dox b/docs/build.dox index 16cb35a4f..4e812b38a 100644 --- a/docs/build.dox +++ b/docs/build.dox @@ -1,13 +1,13 @@ /*! -@page build Building applications +@page build_guide Building applications @tableofcontents This is about compiling and linking applications that use GLFW. For information on -how to write such applications, start with the [introductory tutorial](@ref quick). -For information on how to compile the GLFW library itself, see the @ref compile -guide. +how to write such applications, start with the +[introductory tutorial](@ref quick_guide). For information on how to compile +the GLFW library itself, see @ref compile_guide. This is not a tutorial on compilation or linking. It assumes basic understanding of how to compile and link a C program as well as how to use the diff --git a/docs/compat.dox b/docs/compat.dox index be1cf70d9..030d359a7 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -1,6 +1,6 @@ /*! -@page compat Standards conformance +@page compat_guide Standards conformance @tableofcontents diff --git a/docs/compile.dox b/docs/compile.dox index 97907cc7f..387100085 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -1,11 +1,11 @@ /*! -@page compile Compiling GLFW +@page compile_guide Compiling GLFW @tableofcontents This is about compiling the GLFW library itself. For information on how to -build applications that use GLFW, see the @ref build guide. +build applications that use GLFW, see @ref build_guide. @section compile_cmake Using CMake @@ -156,7 +156,7 @@ necessary to compile GLFW. Go ahead and compile the actual GLFW library with these files, as you would with any other project. Once the GLFW library is compiled, you are ready to build your applications, -linking it to the GLFW library. See the @ref build guide for more information. +linking it to the GLFW library. See @ref build_guide for more information. @subsection compile_options CMake options diff --git a/docs/context.dox b/docs/context.dox index 57aed221a..62bbc61fb 100644 --- a/docs/context.dox +++ b/docs/context.dox @@ -1,16 +1,19 @@ /*! -@page context Context guide +@page context_guide Context guide @tableofcontents This guide introduces the OpenGL and OpenGL ES context related functions of -GLFW. There are also guides for the other areas of the GLFW API. +GLFW. For details on a specific function, see the +[reference documentation](@ref context). There are also guides for the other +areas of the GLFW API. - - @ref intro - - @ref window - - @ref monitor - - @ref input + - @ref intro_guide + - @ref window_guide + - @ref vulkan_guide + - @ref monitor_guide + - @ref input_guide @section context_object Context objects @@ -29,7 +32,7 @@ the `glfwinfo` test program. @note Vulkan does not have a context and the Vulkan instance is created via the Vulkan API itself. If you will be using Vulkan to render to a window, disable context creation by setting the [GLFW_CLIENT_API](@ref window_hints_ctx) hint to -`GLFW_NO_API`. For more information, see the @ref vulkan. +`GLFW_NO_API`. For more information, see the @ref vulkan_guide. @subsection context_hints Context creation hints diff --git a/docs/input.dox b/docs/input.dox index 5798fde41..136319b92 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -1,16 +1,17 @@ /*! -@page input Input guide +@page input_guide Input guide @tableofcontents -This guide introduces the input related functions of GLFW. There are also -guides for the other areas of GLFW. +This guide introduces the input related functions of GLFW. For details on +a specific function, see the [reference documentation](@ref input). There are +also guides for the other areas of GLFW. - - @ref intro - - @ref window - - @ref context - - @ref monitor + - @ref intro_guide + - @ref window_guide + - @ref context_guide + - @ref monitor_guide GLFW provides many kinds of input. While some can only be polled, like time, or only received via callbacks, like scrolling, there are those that provide both diff --git a/docs/internal.dox b/docs/internal.dox index 0389af6ec..593ad67d3 100644 --- a/docs/internal.dox +++ b/docs/internal.dox @@ -1,6 +1,6 @@ /*! -@page internals Internal structure +@page internals_guide Internal structure @tableofcontents diff --git a/docs/intro.dox b/docs/intro.dox index a54bf96f5..b0be0a8b7 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -1,18 +1,21 @@ /*! -@page intro Introduction to the API +@page intro_guide Introduction to the API @tableofcontents -This guide introduces the basic concepts of GLFW and describes initialization, +This guide introduces the basic concepts of GLFW and describes initialization reference error handling and API guarantees and limitations. For a broad but shallow -tutorial, see @ref quick instead. There are also guides for the other areas of -GLFW. +tutorial, see @ref quick_guide instead. For details on a specific function, see the +[reference documentation](@ref init). - - @ref window - - @ref context - - @ref monitor - - @ref input +There are also guides for the other areas of GLFW. + + - @ref window_guide + - @ref context_guide + - @ref vulkan_guide + - @ref monitor_guide + - @ref input_guide @section intro_init Initialization and termination diff --git a/docs/main.dox b/docs/main.dox index 9b59822e5..9669001be 100644 --- a/docs/main.dox +++ b/docs/main.dox @@ -11,20 +11,20 @@ for creating windows, contexts and surfaces, reading input, handling events, etc See @ref news_32 for release highlights or the [version history](http://www.glfw.org/changelog.html) for details. -@ref quick is a guide for those new to GLFW. It takes you through how to write -a small but complete program. For people coming from GLFW 2, the @ref moving -guide explains what has changed and how to update existing code to use the new -API. +@ref quick_guide is a guide for those new to GLFW. It takes you through how to +write a small but complete program. For people coming from GLFW 2, @ref +moving_guide explains what has changed and how to update existing code to use +the new API. There are guides for each of the various areas of the API. - - @ref intro – initialization, error handling and high-level design - - @ref window – creating and working with windows and framebuffers - - @ref context – working with OpenGL and OpenGL ES contexts - - @ref monitor – enumerating and working with monitors and video modes - - @ref input – receiving events, polling and processing input + - @ref intro_guide – initialization, error handling and high-level design + - @ref window_guide – creating and working with windows and framebuffers + - @ref context_guide – working with OpenGL and OpenGL ES contexts + - @ref monitor_guide – enumerating and working with monitors and video modes + - @ref input_guide – receiving events, polling and processing input -Once you have written a program, see the @ref compile and @ref build guides. +Once you have written a program, see @ref compile_guide and @ref build_guide. The [reference documentation](modules.html) provides more detailed information about specific functions. @@ -32,15 +32,15 @@ about specific functions. There is a section on @ref guarantees_limitations for pointer lifetimes, reentrancy, thread safety, event order and backward and forward compatibility. -The @ref vulkan guide fills in the gaps for how to use Vulkan with GLFW. +The @ref vulkan_guide guide fills in the gaps for how to use Vulkan with GLFW. -The @ref rift fills in the gaps for how to use LibOVR with GLFW. +The @ref rift_guide fills in the gaps for how to use LibOVR with GLFW. The [FAQ](http://www.glfw.org/faq.html) answers many common questions about the design, implementation and use of GLFW. -Finally, the @ref compat guide explains what APIs, standards and protocols GLFW -uses and what happens when they are not present on a given machine. +Finally, the @ref compat_guide guide explains what APIs, standards and protocols +GLFW uses and what happens when they are not present on a given machine. This documentation was generated with Doxygen. The sources for it are available in both the [source distribution](http://www.glfw.org/download.html) and diff --git a/docs/monitor.dox b/docs/monitor.dox index 3b3c843c1..16fb1c82a 100644 --- a/docs/monitor.dox +++ b/docs/monitor.dox @@ -1,16 +1,17 @@ /*! -@page monitor Monitor guide +@page monitor_guide Monitor guide @tableofcontents -This guide introduces the monitor related functions of GLFW. There are also -guides for the other areas of GLFW. +This guide introduces the monitor related functions of GLFW. For details on +a specific function, see the [reference documentation](@ref monitor). There are +also guides for the other areas of GLFW. - - @ref intro - - @ref window - - @ref context - - @ref input + - @ref intro_guide + - @ref window_guide + - @ref context_guide + - @ref input_guide @section monitor_object Monitor objects diff --git a/docs/moving.dox b/docs/moving.dox index a222a3572..7baab6f19 100644 --- a/docs/moving.dox +++ b/docs/moving.dox @@ -1,6 +1,6 @@ /*! -@page moving Moving from GLFW 2 to 3 +@page moving_guide Moving from GLFW 2 to 3 @tableofcontents @@ -130,7 +130,7 @@ GLFW 3 provides support for multiple monitors. To request a full screen mode wi instead of passing `GLFW_FULLSCREEN` you specify which monitor you wish the window to use. The @ref glfwGetPrimaryMonitor function returns the monitor that GLFW 2 would have selected, but there are many other -[monitor functions](@ref monitor). Monitor handles are pointers to the +[monitor functions](@ref monitor_guide). Monitor handles are pointers to the [opaque](https://en.wikipedia.org/wiki/Opaque_data_type) type @ref GLFWmonitor. @par Old basic full screen diff --git a/docs/news.dox b/docs/news.dox index 0ccb4c89d..ed13fb7ff 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -96,7 +96,7 @@ and the cursor position directly instead of returning cached data. @subsection news_31_libovr Better interoperability with Oculus Rift GLFW now provides native access functions for the OS level handles corresponding -to monitor objects, as well as a [brief guide](@ref rift). It is also regularly +to monitor objects, as well as the @ref rift_guide. It is also regularly tested for compatibility with the latest version of LibOVR (0.4.4 on release). diff --git a/docs/quick.dox b/docs/quick.dox index 543932724..dccc834d9 100644 --- a/docs/quick.dox +++ b/docs/quick.dox @@ -1,6 +1,6 @@ /*! -@page quick Getting started +@page quick_guide Getting started @tableofcontents @@ -10,7 +10,7 @@ and exit when the user closes the window or presses _Escape_. This guide will introduce a few of the most commonly used functions, but there are many more. This guide assumes no experience with earlier versions of GLFW. If you -have used GLFW 2 in the past, read the @ref moving guide, as some functions +have used GLFW 2 in the past, read @ref moving_guide, as some functions behave differently in GLFW 3. @@ -346,11 +346,11 @@ This tutorial used only a few of the many functions GLFW provides. There are guides for each of the areas covered by GLFW. Each guide will introduce all the functions for that category. - - @ref intro - - @ref window - - @ref context - - @ref monitor - - @ref input + - @ref intro_guide + - @ref window_guide + - @ref context_guide + - @ref monitor_guide + - @ref input_guide You can access reference documentation for any GLFW function by clicking it and the reference for each function links to related functions and guide sections. @@ -359,6 +359,6 @@ The tutorial ends here. Once you have written a program that uses GLFW, you will need to compile and link it. How to do that depends on the development environment you are using and is best explained by the documentation for that environment. To learn about the details that are specific to GLFW, see -@ref build. +@ref build_guide. */ diff --git a/docs/rift.dox b/docs/rift.dox index edf206f76..bb518dd72 100644 --- a/docs/rift.dox +++ b/docs/rift.dox @@ -1,6 +1,6 @@ /*! -@page rift Oculus Rift guide +@page rift_guide Oculus Rift guide @tableofcontents diff --git a/docs/vulkan.dox b/docs/vulkan.dox index af9ffce01..97099f879 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -1,6 +1,6 @@ /*! -@page vulkan Vulkan guide +@page vulkan_guide Vulkan guide @tableofcontents @@ -18,6 +18,16 @@ 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. +For details on a specific function, see the +[reference documentation](@ref vulkan). There are also guides for the other +areas of the GLFW API. + + - @ref intro_guide + - @ref window_guide + - @ref context_guide + - @ref monitor_guide + - @ref input_guide + @section vulkan_include Including the Vulkan and GLFW header files diff --git a/docs/window.dox b/docs/window.dox index acb58858c..1612e2746 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -1,16 +1,17 @@ /*! -@page window Window guide +@page window_guide Window guide @tableofcontents -This guide introduces the window related functions of GLFW. There are also -guides for the other areas of GLFW. +This guide introduces the window related functions of GLFW. For details on +a specific function, see the [reference documentation](@ref window). There are +also guides for the other areas of GLFW. - - @ref intro - - @ref context - - @ref monitor - - @ref input + - @ref intro_guide + - @ref context_guide + - @ref monitor_guide + - @ref input_guide @section window_object Window objects diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 3b07bdf53..43b33f14c 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -46,37 +46,37 @@ extern "C" { * * For more information about how to use this file, see @ref build_include. */ -/*! @defgroup context Context handling +/*! @defgroup context Context reference * - * This is the reference documentation for context related functions. For more - * information, see the @ref context. + * This is the reference documentation for OpenGL and OpenGL ES context related + * functions. For more task-oriented information, see the @ref context_guide. */ -/*! @defgroup vulkan Vulkan support +/*! @defgroup vulkan Vulkan reference * - * This is the reference documentation for Vulkan related functions. For more - * information, see the @ref vulkan. + * This is the reference documentation for Vulkan related functions and types. + * For more task-oriented information, see the @ref vulkan_guide. */ -/*! @defgroup init Initialization, version and errors +/*! @defgroup init Initialization, version and error reference * * This is the reference documentation for initialization and termination of - * the library, version management and error handling. For more information, - * see the @ref intro. + * the library, version management and error handling. For more task-oriented + * information, see the @ref intro_guide. */ -/*! @defgroup input Input handling +/*! @defgroup input Input reference * * This is the reference documentation for input related functions and types. - * For more information, see the @ref input. + * For more task-oriented information, see the @ref input_guide. */ -/*! @defgroup monitor Monitor handling +/*! @defgroup monitor Monitor reference * * This is the reference documentation for monitor related functions and types. - * For more information, see the @ref monitor. + * For more task-oriented information, see the @ref monitor_guide. */ -/*! @defgroup window Window handling +/*! @defgroup window Window reference * * This is the reference documentation for window related functions and types, - * including creation, deletion and event polling. For more information, see - * the @ref window. + * including creation, deletion and event polling. For more task-oriented + * information, see the @ref window_guide. */ From cbcadded186c29f5e87b0e9bf0f3129aa0df80d0 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 19 Feb 2016 10:42:28 +0100 Subject: [PATCH 023/156] Update documentation main page --- docs/main.dox | 20 ++++++++++---------- docs/rift.dox | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/main.dox b/docs/main.dox index 9669001be..9f9ef7977 100644 --- a/docs/main.dox +++ b/docs/main.dox @@ -11,16 +11,15 @@ for creating windows, contexts and surfaces, reading input, handling events, etc See @ref news_32 for release highlights or the [version history](http://www.glfw.org/changelog.html) for details. -@ref quick_guide is a guide for those new to GLFW. It takes you through how to -write a small but complete program. For people coming from GLFW 2, @ref -moving_guide explains what has changed and how to update existing code to use -the new API. +@ref quick_guide is a guide for users new to GLFW. It takes you through how to +write a small but complete program. -There are guides for each of the various areas of the API. +There are guides for each section of the API: - @ref intro_guide – initialization, error handling and high-level design - @ref window_guide – creating and working with windows and framebuffers - @ref context_guide – working with OpenGL and OpenGL ES contexts + - @ref vulkan_guide - working with Vulkan objects and extensions - @ref monitor_guide – enumerating and working with monitors and video modes - @ref input_guide – receiving events, polling and processing input @@ -29,18 +28,19 @@ Once you have written a program, see @ref compile_guide and @ref build_guide. The [reference documentation](modules.html) provides more detailed information about specific functions. +@ref moving_guide explains what has changed and how to update existing code to +use the new API. + There is a section on @ref guarantees_limitations for pointer lifetimes, reentrancy, thread safety, event order and backward and forward compatibility. -The @ref vulkan_guide guide fills in the gaps for how to use Vulkan with GLFW. - -The @ref rift_guide fills in the gaps for how to use LibOVR with GLFW. +@ref rift_guide fills in the gaps for how to use LibOVR with GLFW. The [FAQ](http://www.glfw.org/faq.html) answers many common questions about the design, implementation and use of GLFW. -Finally, the @ref compat_guide guide explains what APIs, standards and protocols -GLFW uses and what happens when they are not present on a given machine. +Finally, @ref compat_guide explains what APIs, standards and protocols GLFW uses +and what happens when they are not present on a given machine. This documentation was generated with Doxygen. The sources for it are available in both the [source distribution](http://www.glfw.org/download.html) and diff --git a/docs/rift.dox b/docs/rift.dox index bb518dd72..2de395fc8 100644 --- a/docs/rift.dox +++ b/docs/rift.dox @@ -1,6 +1,6 @@ /*! -@page rift_guide Oculus Rift guide +@page rift_guide Using GLFW with LibOVR @tableofcontents From f3f0eaa59e64d5a8b683d81ceb578f147d4aa003 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 19 Feb 2016 14:27:51 +0100 Subject: [PATCH 024/156] Add OpenGL error check to glfwinfo --- tests/glfwinfo.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index a6ec9c242..002a9bc41 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -354,6 +354,7 @@ int main(int argc, char** argv) int ch, api, major, minor, revision, profile; GLint redbits, greenbits, bluebits, alphabits, depthbits, stencilbits; int list_extensions = GLFW_FALSE, list_layers = GLFW_FALSE; + GLenum error; GLFWwindow* window; enum { API, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS, LAYERS, @@ -609,6 +610,10 @@ int main(int argc, char** argv) glfwMakeContextCurrent(window); gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + error = glGetError(); + if (error != GL_NO_ERROR) + printf("*** OpenGL error after make current: 0x%08x ***\n", error); + // Report client API version api = glfwGetWindowAttrib(window, GLFW_CLIENT_API); From 710586367ca4f8633c0d508069f9b538e1a78530 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 19 Feb 2016 14:38:04 +0100 Subject: [PATCH 025/156] Add Vulkan headers to test dependency list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9fe915965..57b1b7217 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ used by the tests and examples and are not required to build the library. [glad](https://github.com/Dav1dde/glad) for examples using modern OpenGL - [linmath.h](https://github.com/datenwolf/linmath.h) for linear algebra in examples + - [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. From 8c4ce9a3de195d09dd2e65c4e58caca5c5dc63ee Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 8 Feb 2016 16:23:44 +0100 Subject: [PATCH 026/156] Documentation work [ci skip] --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 57b1b7217..26f92a92b 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,8 @@ GLFW itself needs 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. -GLFW bundles a number of dependencies in the `deps/` directory. These are only -used by the tests and examples and are not required to build the library. +The examples and test programs depend on a number of tiny libraries. These are +located in the `deps/` directory. - [getopt\_port](https://github.com/kimgr/getopt_port/) for examples with command-line options @@ -68,6 +68,9 @@ used by the tests and examples and are not required to build the library. The Vulkan example additionally requires the Vulkan SDK to be installed, or it will not be included in the build. +The documentation is generated with [Doxygen](http://doxygen.org/). If CMake +does not find Doxygen, the documentation will not be generated. + ## Changelog From a10caa46313d181b34d38be7bdded738e19baefd Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 13 Oct 2015 12:50:59 +0200 Subject: [PATCH 027/156] Add glfwMaximizeWindow and GLFW_MAXIMIZED Fixes #266. --- README.md | 1 + docs/news.dox | 6 ++++ docs/window.dox | 7 ++++ include/GLFW/glfw3.h | 28 +++++++++++++++- src/cocoa_window.m | 19 ++++++++++- src/internal.h | 11 +++++++ src/mir_window.c | 13 ++++++++ src/win32_window.c | 21 ++++++++++-- src/window.c | 12 +++++++ src/wl_window.c | 12 +++++++ src/x11_init.c | 4 +++ src/x11_platform.h | 2 ++ src/x11_window.c | 77 +++++++++++++++++++++++++++++++++++++++++++- tests/iconify.c | 10 ++++-- 14 files changed, 215 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 26f92a92b..87b858644 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ does not find Doxygen, the documentation will not be generated. - Added `glfwVulkanSupported`, `glfwGetRequiredInstanceExtensions`, `glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and `glfwCreateWindowSurface` for platform independent Vulkan support + - Added `glfwMaximizeWindow` for maximizing windows - Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting absolute and relative window size limits - Added `glfwGetKeyName` for querying the layout-specific name of printable diff --git a/docs/news.dox b/docs/news.dox index ed13fb7ff..601eee483 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -26,6 +26,12 @@ Vulkan header inclusion can be selected with [GLFW_INCLUDE_VULKAN](@ref build_macros). +@subsection news_32_maximize Window maxmimization supprot + +GLFW now supports window maximization with @ref glfwMaximizeWindow and the +[GLFW_MAXIMIZED](@ref window_attribs_wnd) window hint and attribute. + + @section news_31 New features in 3.1 These are the release highlights. For a full list of changes see the diff --git a/docs/window.dox b/docs/window.dox index 1612e2746..b7c7b7310 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -175,6 +175,9 @@ above other regular windows, also called topmost or always-on-top. This is intended primarily for debugging purposes and cannot be used to implement proper full screen windows. This hint is ignored for full screen windows. +`GLFW_MAXIMIZED` specifies whether the windowed mode window will be maximized +when created. This hint is ignored for full screen windows. + @subsubsection window_hints_fb Framebuffer related hints @@ -323,6 +326,7 @@ Window hint | Default value | Supported values `GLFW_FOCUSED` | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` `GLFW_AUTO_ICONIFY` | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` `GLFW_FLOATING` | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` +`GLFW_MAXIMIZED` | `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` @@ -791,6 +795,9 @@ same name. `GLFW_ICONIFIED` indicates whether the specified window is iconified, whether by the user or with @ref glfwIconifyWindow. +`GLFW_MAXIMIZED` indicates whether the specified window is maximized, whether by +the user or with @ref glfwMaximizeWindow. + `GLFW_VISIBLE` indicates whether the specified window is visible. Window visibility can be controlled with @ref glfwShowWindow and @ref glfwHideWindow and initial visibility is controlled by the [window hint](@ref window_hints_wnd) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 43b33f14c..783467144 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -626,6 +626,7 @@ extern "C" { #define GLFW_DECORATED 0x00020005 #define GLFW_AUTO_ICONIFY 0x00020006 #define GLFW_FLOATING 0x00020007 +#define GLFW_MAXIMIZED 0x00020008 #define GLFW_RED_BITS 0x00021001 #define GLFW_GREEN_BITS 0x00021002 @@ -2180,6 +2181,7 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int * * @sa @ref window_iconify * @sa glfwRestoreWindow + * @sa glfwMaximizeWindow * * @since Added in version 2.1. * @glfw3 Added window handle parameter. @@ -2191,7 +2193,8 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); /*! @brief Restores the specified window. * * This function restores the specified window if it was previously iconified - * (minimized). If the window is already restored, this function does nothing. + * (minimized) or maximized. If the window is already restored, this function + * does nothing. * * If the specified window is a full screen window, the resolution chosen for * the window is restored on the selected monitor. @@ -2205,6 +2208,7 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); * * @sa @ref window_iconify * @sa glfwIconifyWindow + * @sa glfwMaximizeWindow * * @since Added in version 2.1. * @glfw3 Added window handle parameter. @@ -2213,6 +2217,28 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); */ GLFWAPI void glfwRestoreWindow(GLFWwindow* window); +/*! @brief Maximizes the specified window. + * + * This function maximizes the specified window if it was previously not + * maximized. If the window is already maximized, this function does nothing. + * + * If the specified window is a full screen window, this function does nothing. + * + * @param[in] window The window to maximize. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_iconify + * @sa glfwIconifyWindow + * @sa glfwRestoreWindow + * + * @since Added in GLFW 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); + /*! @brief Makes the specified window visible. * * This function makes the specified window visible if it was previously diff --git a/src/cocoa_window.m b/src/cocoa_window.m index fb03419ba..a32437503 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -851,6 +851,9 @@ static GLFWbool createWindow(_GLFWwindow* window, if (wndconfig->floating) [window->ns.object setLevel:NSFloatingWindowLevel]; + + if (wndconfig->maximized) + [window->ns.object zoom:nil]; } window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; @@ -1023,7 +1026,16 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window) void _glfwPlatformRestoreWindow(_GLFWwindow* window) { - [window->ns.object deminiaturize:nil]; + if ([window->ns.object isMiniaturized]) + [window->ns.object deminiaturize:nil]; + else if ([window->ns.object isZoomed]) + [window->ns.object zoom:nil]; +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (![window->ns.object isZoomed]) + [window->ns.object zoom:nil]; } void _glfwPlatformShowWindow(_GLFWwindow* window) @@ -1062,6 +1074,11 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window) return [window->ns.object isVisible]; } +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return [window->ns.object isZoomed]; +} + void _glfwPlatformPollEvents(void) { for (;;) diff --git a/src/internal.h b/src/internal.h index 2fe2aee47..3d8edc88c 100644 --- a/src/internal.h +++ b/src/internal.h @@ -255,6 +255,7 @@ struct _GLFWwndconfig GLFWbool focused; GLFWbool autoIconify; GLFWbool floating; + GLFWbool maximized; _GLFWmonitor* monitor; }; @@ -673,6 +674,11 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window); */ void _glfwPlatformRestoreWindow(_GLFWwindow* window); +/*! @copydoc glfwMaximizeWindow + * @ingroup platform + */ +void _glfwPlatformMaximizeWindow(_GLFWwindow* window); + /*! @copydoc glfwShowWindow * @ingroup platform */ @@ -702,6 +708,11 @@ int _glfwPlatformWindowIconified(_GLFWwindow* window); */ int _glfwPlatformWindowVisible(_GLFWwindow* window); +/*! @brief Returns whether the window is maximized. + * @ingroup platform + */ +int _glfwPlatformWindowMaximized(_GLFWwindow* window); + /*! @copydoc glfwPollEvents * @ingroup platform */ diff --git a/src/mir_window.c b/src/mir_window.c index acc0a2cc5..6e0ee16b8 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -467,6 +467,12 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) mir_surface_set_state(window->mir.surface, mir_surface_state_restored); } +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + void _glfwPlatformHideWindow(_GLFWwindow* window) { MirSurfaceSpec* spec; @@ -514,6 +520,13 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window) return mir_surface_get_visibility(window->mir.surface) == mir_surface_visibility_exposed; } +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return GLFW_FALSE; +} + void _glfwPlatformPollEvents(void) { EventNode* node = NULL; diff --git a/src/win32_window.c b/src/win32_window.c index 0de246db7..55d98b9af 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -653,6 +653,8 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; + DWORD style = getWindowStyle(window); + DWORD exStyle = getWindowExStyle(window); if (wndconfig->monitor) { @@ -671,7 +673,10 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) xpos = CW_USEDEFAULT; ypos = CW_USEDEFAULT; - getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + if (wndconfig->maximized) + style |= WS_MAXIMIZE; + + getFullWindowSize(style, exStyle, wndconfig->width, wndconfig->height, &fullWidth, &fullHeight); } @@ -684,10 +689,10 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) return GLFW_FALSE; } - window->win32.handle = CreateWindowExW(getWindowExStyle(window), + window->win32.handle = CreateWindowExW(exStyle, _GLFW_WNDCLASSNAME, wideTitle, - getWindowStyle(window), + style, xpos, ypos, fullWidth, fullHeight, NULL, // No parent window @@ -1026,6 +1031,11 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) ShowWindow(window->win32.handle, SW_RESTORE); } +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_MAXIMIZE); +} + void _glfwPlatformShowWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_SHOW); @@ -1059,6 +1069,11 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window) return IsWindowVisible(window->win32.handle); } +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return IsZoomed(window->win32.handle); +} + void _glfwPlatformPollEvents(void) { MSG msg; diff --git a/src/window.c b/src/window.c index f0063e359..f051370e1 100644 --- a/src/window.c +++ b/src/window.c @@ -339,6 +339,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_FLOATING: _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE; break; + case GLFW_MAXIMIZED: + _glfw.hints.window.maximized = hint ? GLFW_TRUE : GLFW_FALSE; + break; case GLFW_VISIBLE: _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; break; @@ -593,6 +596,13 @@ GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) _glfwPlatformRestoreWindow(window); } +GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformMaximizeWindow(window); +} + GLFWAPI void glfwShowWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; @@ -634,6 +644,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return _glfwPlatformWindowIconified(window); case GLFW_VISIBLE: return _glfwPlatformWindowVisible(window); + case GLFW_MAXIMIZED: + return _glfwPlatformWindowMaximized(window); case GLFW_RESIZABLE: return window->resizable; case GLFW_DECORATED: diff --git a/src/wl_window.c b/src/wl_window.c index ea301434e..c3303d702 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -459,6 +459,12 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) fprintf(stderr, "_glfwPlatformRestoreWindow not implemented yet\n"); } +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + // TODO + fprintf(stderr, "_glfwPlatformMaximizeWindow not implemented yet\n"); +} + void _glfwPlatformShowWindow(_GLFWwindow* window) { wl_shell_surface_set_toplevel(window->wl.shell_surface); @@ -494,6 +500,12 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window) return GLFW_FALSE; } +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + // TODO + return GLFW_FALSE; +} + void _glfwPlatformPollEvents(void) { handleEvents(0); diff --git a/src/x11_init.c b/src/x11_init.c index e17a7170c..bf9253b0a 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -444,6 +444,10 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); _glfw.x11.NET_WM_STATE_FULLSCREEN = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = + 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_FULLSCREEN_MONITORS = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); _glfw.x11.NET_WM_NAME = diff --git a/src/x11_platform.h b/src/x11_platform.h index 65aba0ed8..6d0f43a10 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -175,6 +175,8 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_STATE; Atom NET_WM_STATE_ABOVE; Atom NET_WM_STATE_FULLSCREEN; + Atom NET_WM_STATE_MAXIMIZED_VERT; + Atom NET_WM_STATE_MAXIMIZED_HORZ; 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 46e2d32b0..beba43cc2 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -355,6 +355,24 @@ static GLFWbool createWindow(_GLFWwindow* window, 0, 1, 0); } } + + if (wndconfig->maximized) + { + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + const Atom states[2] = + { + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ + }; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &states, 2); + } + } } @@ -1820,10 +1838,42 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) return; } - XMapWindow(_glfw.x11.display, window->x11.handle); + if (_glfwPlatformWindowIconified(window)) + XMapWindow(_glfw.x11.display, window->x11.handle); + else + { + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); + } + } + XFlush(_glfw.x11.display); } +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); + XFlush(_glfw.x11.display); + } +} + void _glfwPlatformShowWindow(_GLFWwindow* window) { XMapRaised(_glfw.x11.display, window->x11.handle); @@ -1863,6 +1913,31 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window) return wa.map_state == IsViewable; } +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + Atom* states; + unsigned long i; + GLFWbool maximized = GLFW_FALSE; + const unsigned long count = + _glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + (unsigned char**) &states); + + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + maximized = GLFW_TRUE; + break; + } + } + + XFree(states); + return maximized; +} + void _glfwPlatformPollEvents(void) { int count = XPending(_glfw.x11.display); diff --git a/tests/iconify.c b/tests/iconify.c index a5675574e..3eeaf749a 100644 --- a/tests/iconify.c +++ b/tests/iconify.c @@ -62,9 +62,15 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, switch (key) { - case GLFW_KEY_SPACE: + case GLFW_KEY_I: glfwIconifyWindow(window); break; + case GLFW_KEY_M: + glfwMaximizeWindow(window); + break; + case GLFW_KEY_R: + glfwRestoreWindow(window); + break; case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GLFW_TRUE); break; @@ -240,7 +246,7 @@ int main(int argc, char** argv) for (;;) { - glfwPollEvents(); + glfwWaitEvents(); for (i = 0; i < window_count; i++) { From bda18bc899ccf3667233680e75202d7f2eee0446 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 21 Feb 2016 18:17:04 +0100 Subject: [PATCH 028/156] Remove XInput2 XI_Motion support Sadly, this interferes with the Steam overlay. Fixes #304. --- CMakeLists.txt | 15 ---------- README.md | 1 + docs/compat.dox | 4 --- docs/compile.dox | 2 -- src/glfw_config.h.in | 2 -- src/x11_init.c | 22 --------------- src/x11_platform.h | 16 ----------- src/x11_window.c | 65 -------------------------------------------- 8 files changed, 1 insertion(+), 126 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6585a1c7..9fa78e5e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,21 +234,6 @@ if (_GLFW_X11) list(APPEND glfw_LIBRARIES "${X11_Xinerama_LIB}") list(APPEND glfw_PKG_DEPS "xinerama") - # Check for XInput (high-resolution cursor motion) - if (X11_Xinput_FOUND) - list(APPEND glfw_INCLUDE_DIRS "${X11_Xinput_INCLUDE_PATH}") - list(APPEND glfw_PKG_DEPS "xi") - - if (X11_Xinput_LIB) - list(APPEND glfw_LIBRARIES "${X11_Xinput_LIB}") - else() - # Backwards compatibility (bug in CMake 2.8.7) - list(APPEND glfw_LIBRARIES Xi) - endif() - - set(_GLFW_HAS_XINPUT TRUE) - endif() - # Check for Xf86VidMode (fallback gamma control) if (X11_xf86vmode_FOUND) list(APPEND glfw_INCLUDE_DIRS "${X11_xf86vmode_INCLUDE_PATH}") diff --git a/README.md b/README.md index 87b858644..f50333f16 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ does not find Doxygen, the documentation will not be generated. - [X11] Bugfix: Monitor connection and disconnection events were not reported - [X11] Bugfix: Decoding of UTF-8 text from XIM could continue past the end - [X11] Bugfix: An XKB structure was leaked during `glfwInit` + - [X11] Bugfix: XInput2 `XI_Motion` events interfered with the Steam overlay - [POSIX] Bugfix: An unrelated TLS key could be deleted by `glfwTerminate` - [WGL] Changed extension loading to only be performed once - [WGL] Removed dependency on external WGL headers diff --git a/docs/compat.dox b/docs/compat.dox index 030d359a7..ee10770f5 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -63,10 +63,6 @@ GLFW uses the to provide file drop events. If the application originating the drag does not support this protocol, drag and drop will not work. -GLFW uses the XInput 2 extension to provide sub-pixel cursor motion events. If -the running X server does not support this version of this extension, cursor -motion will be snapped to the pixel grid. - GLFW uses the XRandR 1.3 extension to provide multi-monitor support. If the running X server does not support this version of this extension, multi-monitor support will not function and only a single, desktop-spanning monitor will be diff --git a/docs/compile.dox b/docs/compile.dox index 387100085..4bcc623c8 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -274,8 +274,6 @@ must also define `_GLFW_BUILD_DLL`. Otherwise, you must not define it. If you are using the X11 window creation API, support for the following X11 extensions can be enabled: - - `_GLFW_HAS_XINPUT` to use XInput2 for high-resolution cursor motion - (recommended) - `_GLFW_HAS_XF86VM` to use Xxf86vm as a fallback when RandR gamma is broken (recommended) diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index 6de975091..ab57dd59d 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in @@ -60,8 +60,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 the XInput X11 extension is available -#cmakedefine _GLFW_HAS_XINPUT // Define this to 1 if the Xxf86vm X11 extension is available #cmakedefine _GLFW_HAS_XF86VM diff --git a/src/x11_init.c b/src/x11_init.c index bf9253b0a..4e8eb6965 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -544,25 +544,6 @@ static GLFWbool initExtensions(void) _glfw.x11.xinerama.available = GLFW_TRUE; } -#if defined(_GLFW_HAS_XINPUT) - if (XQueryExtension(_glfw.x11.display, - "XInputExtension", - &_glfw.x11.xi.majorOpcode, - &_glfw.x11.xi.eventBase, - &_glfw.x11.xi.errorBase)) - { - _glfw.x11.xi.major = 2; - _glfw.x11.xi.minor = 0; - - if (XIQueryVersion(_glfw.x11.display, - &_glfw.x11.xi.major, - &_glfw.x11.xi.minor) != BadRequest) - { - _glfw.x11.xi.available = GLFW_TRUE; - } - } -#endif /*_GLFW_HAS_XINPUT*/ - // Check if Xkb is supported on this display _glfw.x11.xkb.major = 1; _glfw.x11.xkb.minor = 0; @@ -856,9 +837,6 @@ const char* _glfwPlatformGetVersionString(void) #if defined(__linux__) " /dev/js" #endif -#if defined(_GLFW_HAS_XINPUT) - " XI" -#endif #if defined(_GLFW_HAS_XF86VM) " Xf86vm" #endif diff --git a/src/x11_platform.h b/src/x11_platform.h index 6d0f43a10..8d791f074 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -47,11 +47,6 @@ // The Xinerama extension provides legacy monitor indices #include -#if defined(_GLFW_HAS_XINPUT) - // The XInput2 extension provides improved input events - #include -#endif - #if defined(_GLFW_HAS_XF86VM) // The Xf86VidMode extension provides fallback gamma control #include @@ -250,17 +245,6 @@ typedef struct _GLFWlibraryX11 XGETXCBCONNECTION_T XGetXCBConnection; } x11xcb; -#if defined(_GLFW_HAS_XINPUT) - struct { - GLFWbool available; - int majorOpcode; - int eventBase; - int errorBase; - int major; - int minor; - } xi; -#endif /*_GLFW_HAS_XINPUT*/ - #if defined(_GLFW_HAS_XF86VM) struct { GLFWbool available; diff --git a/src/x11_window.c b/src/x11_window.c index beba43cc2..24ebba327 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -469,23 +469,6 @@ static GLFWbool createWindow(_GLFWwindow* window, XFree(hint); } -#if defined(_GLFW_HAS_XINPUT) - if (_glfw.x11.xi.available) - { - // Select for XInput2 events - - XIEventMask eventmask; - unsigned char mask[] = { 0 }; - - eventmask.deviceid = 2; - eventmask.mask_len = sizeof(mask); - eventmask.mask = mask; - XISetMask(mask, XI_Motion); - - XISelectEvents(_glfw.x11.display, window->x11.handle, &eventmask, 1); - } -#endif /*_GLFW_HAS_XINPUT*/ - if (_glfw.x11.XdndAware) { // Announce support for Xdnd (drag and drop) @@ -1388,54 +1371,6 @@ static void processEvent(XEvent *event) case DestroyNotify: return; - -#if defined(_GLFW_HAS_XINPUT) - case GenericEvent: - { - if (event->xcookie.extension == _glfw.x11.xi.majorOpcode && - XGetEventData(_glfw.x11.display, &event->xcookie)) - { - if (event->xcookie.evtype == XI_Motion) - { - XIDeviceEvent* data = (XIDeviceEvent*) event->xcookie.data; - - window = findWindowByHandle(data->event); - if (window) - { - if (data->event_x != window->x11.warpPosX || - data->event_y != window->x11.warpPosY) - { - // The cursor was moved by something other than GLFW - - double x, y; - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - if (_glfw.cursorWindow != window) - return; - - x = data->event_x - window->x11.cursorPosX; - y = data->event_y - window->x11.cursorPosY; - } - else - { - x = data->event_x; - y = data->event_y; - } - - _glfwInputCursorMotion(window, x, y); - } - - window->x11.cursorPosX = data->event_x; - window->x11.cursorPosY = data->event_y; - } - } - } - - XFreeEventData(_glfw.x11.display, &event->xcookie); - return; - } -#endif /*_GLFW_HAS_XINPUT*/ } } From 2be2e0fa8647b7cc069a067aeefa81334146d46e Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 21 Feb 2016 18:36:28 +0100 Subject: [PATCH 029/156] Fix X11 WSI extension selection logic --- 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 24ebba327..ddfc9159d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2142,7 +2142,7 @@ char** _glfwPlatformGetRequiredInstanceExtensions(int* count) extensions = calloc(2, sizeof(char*)); extensions[0] = strdup("VK_KHR_surface"); - if (_glfw.vk.KHR_xcb_surface) + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) extensions[1] = strdup("VK_KHR_xcb_surface"); else extensions[1] = strdup("VK_KHR_xlib_surface"); From 7669ade19c7980206953a6b42be8b3b48539bac1 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 22 Feb 2016 10:44:37 +0100 Subject: [PATCH 030/156] Make instance extension count unsigned Fixes #714. --- docs/vulkan.dox | 2 +- include/GLFW/glfw3.h | 2 +- src/cocoa_window.m | 2 +- src/internal.h | 4 ++-- src/mir_window.c | 2 +- src/vulkan.c | 2 +- src/win32_window.c | 2 +- src/wl_window.c | 2 +- src/x11_window.c | 2 +- tests/glfwinfo.c | 2 +- tests/vulkan.c | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/vulkan.dox b/docs/vulkan.dox index 97099f879..a54000324 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -127,7 +127,7 @@ To query the instance extensions required, call @ref glfwGetRequiredInstanceExtensions. @code -int count; +unsigned int count; const char** extensions = glfwGetRequiredInstanceExtensions(&count); @endcode diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 783467144..55c891ec2 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3785,7 +3785,7 @@ GLFWAPI int glfwVulkanSupported(void); * * @ingroup vulkan */ -GLFWAPI const char** glfwGetRequiredInstanceExtensions(int* count); +GLFWAPI const char** glfwGetRequiredInstanceExtensions(unsigned int* count); #if defined(VK_VERSION_1_0) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index a32437503..093d2b0a2 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1339,7 +1339,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return _glfw.ns.clipboardString; } -char** _glfwPlatformGetRequiredInstanceExtensions(int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) { *count = 0; return NULL; diff --git a/src/internal.h b/src/internal.h index 3d8edc88c..358da2562 100644 --- a/src/internal.h +++ b/src/internal.h @@ -438,7 +438,7 @@ struct _GLFWlibrary GLFWbool available; void* handle; char** extensions; - int extensionCount; + unsigned int extensionCount; PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; PFN_vkGetInstanceProcAddr GetInstanceProcAddr; GLFWbool KHR_surface; @@ -784,7 +784,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); /*! @ingroup platform */ -char** _glfwPlatformGetRequiredInstanceExtensions(int* count); +char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count); /*! @ingroup platform */ diff --git a/src/mir_window.c b/src/mir_window.c index 6e0ee16b8..0642d08de 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -719,7 +719,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return NULL; } -char** _glfwPlatformGetRequiredInstanceExtensions(int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) { char** extensions; diff --git a/src/vulkan.c b/src/vulkan.c index 04db23e07..504ed636e 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -196,7 +196,7 @@ GLFWAPI int glfwVulkanSupported(void) return _glfw.vk.available; } -GLFWAPI const char** glfwGetRequiredInstanceExtensions(int* count) +GLFWAPI const char** glfwGetRequiredInstanceExtensions(unsigned int* count) { *count = 0; diff --git a/src/win32_window.c b/src/win32_window.c index 55d98b9af..b2c627d25 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1418,7 +1418,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return _glfw.win32.clipboardString; } -char** _glfwPlatformGetRequiredInstanceExtensions(int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) { char** extensions; diff --git a/src/wl_window.c b/src/wl_window.c index c3303d702..706f52a36 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -710,7 +710,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return NULL; } -char** _glfwPlatformGetRequiredInstanceExtensions(int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) { char** extensions; diff --git a/src/x11_window.c b/src/x11_window.c index ddfc9159d..2f9130a74 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2127,7 +2127,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return _glfw.x11.clipboardString; } -char** _glfwPlatformGetRequiredInstanceExtensions(int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) { char** extensions; diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index 002a9bc41..d74b49fd0 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -798,7 +798,7 @@ int main(int argc, char** argv) PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; - re = glfwGetRequiredInstanceExtensions((int*) &re_count); + re = glfwGetRequiredInstanceExtensions(&re_count); printf("Vulkan required instance extensions:"); for (i = 0; i < re_count; i++) diff --git a/tests/vulkan.c b/tests/vulkan.c index 21dd0137a..dfc517106 100644 --- a/tests/vulkan.c +++ b/tests/vulkan.c @@ -1732,7 +1732,7 @@ static void demo_init_vk(struct demo *demo) { } /* Look for instance extensions */ - required_extensions = glfwGetRequiredInstanceExtensions((int*) &required_extension_count); + required_extensions = glfwGetRequiredInstanceExtensions(&required_extension_count); if (!required_extensions) { ERR_EXIT("glfwGetRequiredInstanceExtensions failed to find the " "platform surface extensions.\n\nDo you have a compatible " From 97fc9b437daf8b61aa1e18448afe6f40bae906dd Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 22 Feb 2016 10:47:05 +0100 Subject: [PATCH 031/156] Fix loader-not-found error message --- tests/vulkan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/vulkan.c b/tests/vulkan.c index dfc517106..cacba9c05 100644 --- a/tests/vulkan.c +++ b/tests/vulkan.c @@ -2106,8 +2106,7 @@ static void demo_init_connection(struct demo *demo) { } if (!glfwVulkanSupported()) { - printf("Cannot find a compatible Vulkan installable client driver " - "(ICD).\nExiting ...\n"); + printf("GLFW failed to find the Vulkan loader.\nExiting ...\n"); fflush(stdout); exit(1); } From 4702be74887d9c5f672d99ca53b1e00c29cd908f Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 22 Feb 2016 10:50:13 +0100 Subject: [PATCH 032/156] Update changelog --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f50333f16..49939a976 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ does not find Doxygen, the documentation will not be generated. - Added `glfwVulkanSupported`, `glfwGetRequiredInstanceExtensions`, `glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and `glfwCreateWindowSurface` for platform independent Vulkan support - - Added `glfwMaximizeWindow` for maximizing windows + - Added `glfwMaximizeWindow` and `GLFW_MAXIMIZED` for window maximization - Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting absolute and relative window size limits - Added `glfwGetKeyName` for querying the layout-specific name of printable From 70ffae74303028c6f7748152e6e2ba67bb386b98 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 22 Feb 2016 11:54:56 +0100 Subject: [PATCH 033/156] Documentation work --- include/GLFW/glfw3.h | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 55c891ec2..516ea5073 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2741,13 +2741,42 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); /*! @brief Returns the localized name of the specified printable key. * * This function returns the localized name of the specified printable key. + * This is intended for displaying key bindings to the user. * - * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used, otherwise the - * scancode is ignored. + * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise + * the scancode is ignored. If a non-printable key or (if the key is + * `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is + * specified, this function returns `NULL`. + * + * This behavior allows you to pass in the arguments passed to the + * [key callback](@ref input_key) without modification. + * + * The printable keys are: + * - `GLFW_KEY_APOSTROPHE` + * - `GLFW_KEY_COMMA` + * - `GLFW_KEY_MINUS` + * - `GLFW_KEY_PERIOD` + * - `GLFW_KEY_SLASH` + * - `GLFW_KEY_SEMICOLON` + * - `GLFW_KEY_EQUAL` + * - `GLFW_KEY_LEFT_BRACKET` + * - `GLFW_KEY_RIGHT_BRACKET` + * - `GLFW_KEY_BACKSLASH` + * - `GLFW_KEY_WORLD_1` + * - `GLFW_KEY_WORLD_2` + * - `GLFW_KEY_0` to `GLFW_KEY_9` + * - `GLFW_KEY_A` to `GLFW_KEY_Z` + * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` + * - `GLFW_KEY_KP_DECIMAL` + * - `GLFW_KEY_KP_DIVIDE` + * - `GLFW_KEY_KP_MULTIPLY` + * - `GLFW_KEY_KP_SUBTRACT` + * - `GLFW_KEY_KP_ADD` + * - `GLFW_KEY_KP_EQUAL` * * @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. + * @return The localized name of the key, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. From bb3b3452f36eb43efce999d751a4d2e8b94a6fcf Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 22 Feb 2016 12:29:52 +0100 Subject: [PATCH 034/156] Cleanup --- src/x11_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 4e8eb6965..e4e137299 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -620,7 +620,7 @@ static GLFWbool initExtensions(void) // Create a blank cursor for hidden and disabled cursor modes // -static Cursor createNULLCursor(void) +static Cursor createHiddenCursor(void) { unsigned char pixels[16 * 16 * 4]; GLFWimage image = { 16, 16, pixels }; @@ -743,7 +743,7 @@ int _glfwPlatformInit(void) if (!initExtensions()) return GLFW_FALSE; - _glfw.x11.cursor = createNULLCursor(); + _glfw.x11.cursor = createHiddenCursor(); if (XSupportsLocale()) { From c7f3bd0d22f11e68774de02f28472fd8d0eaebd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 9 Dec 2015 14:03:32 +0800 Subject: [PATCH 035/156] wayland: Use modules from ECM for finding deps We were using a copied FindWayland cmake script, but lets use the ones from ECM (extra-cmake-modules) instead. This is more important in the future when building extensions from wayland-protocols. --- CMake/modules/FindWayland.cmake | 66 --------------------------------- CMakeLists.txt | 8 +++- 2 files changed, 6 insertions(+), 68 deletions(-) delete mode 100644 CMake/modules/FindWayland.cmake diff --git a/CMake/modules/FindWayland.cmake b/CMake/modules/FindWayland.cmake deleted file mode 100644 index f93218b87..000000000 --- a/CMake/modules/FindWayland.cmake +++ /dev/null @@ -1,66 +0,0 @@ -# Try to find Wayland on a Unix system -# -# This will define: -# -# WAYLAND_FOUND - True if Wayland is found -# WAYLAND_LIBRARIES - Link these to use Wayland -# WAYLAND_INCLUDE_DIR - Include directory for Wayland -# WAYLAND_DEFINITIONS - Compiler flags for using Wayland -# -# In addition the following more fine grained variables will be defined: -# -# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES -# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES -# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES -# -# Copyright (c) 2013 Martin Gräßlin -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -IF (NOT WIN32) - IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES) - # In the cache already - SET(WAYLAND_FIND_QUIETLY TRUE) - ENDIF () - - # Use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - FIND_PACKAGE(PkgConfig) - PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor) - - SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS}) - - FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - - FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - - set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR} ${WAYLAND_CURSOR_INCLUDE_DIR}) - - set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES}) - - list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR) - - include(FindPackageHandleStandardArgs) - - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CURSOR DEFAULT_MSG WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR) - - MARK_AS_ADVANCED( - WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES - WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES - WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES - WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES - WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES - ) - -ENDIF () diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fa78e5e6..46229dfd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,11 +271,15 @@ endif() # Use Wayland for window creation #-------------------------------------------------------------------- if (_GLFW_WAYLAND) + find_package(ECM REQUIRED NO_MODULE) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) + find_package(Wayland REQUIRED) + list(APPEND glfw_PKG_DEPS "wayland-egl") - list(APPEND glfw_INCLUDE_DIRS "${WAYLAND_INCLUDE_DIR}") - list(APPEND glfw_LIBRARIES "${WAYLAND_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") + list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") find_package(XKBCommon REQUIRED) list(APPEND glfw_PKG_DEPS "xkbcommon") From cb08dc574c55626460eb4860652f4de03fa2b0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 9 Dec 2015 15:29:37 +0800 Subject: [PATCH 036/156] wayland: Implement 'DISABLED' cursor mode This implements support for the 'DISABLED' cursor mode, which effectively means locking the pointer to the surface. The cursor is also explicitly hidden. This adds two new build dependencies: wayland-scanner and wayland-protocols. Closes #708. --- .gitignore | 4 + CMake/modules/FindWaylandProtocols.cmake | 26 +++++ CMakeLists.txt | 2 + src/CMakeLists.txt | 9 ++ src/wl_init.c | 19 +++- src/wl_platform.h | 9 ++ src/wl_window.c | 123 ++++++++++++++++++++++- 7 files changed, 182 insertions(+), 10 deletions(-) create mode 100644 CMake/modules/FindWaylandProtocols.cmake diff --git a/.gitignore b/.gitignore index 61ba29b93..c2450f75c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,10 @@ src/glfw_config.h src/glfw3.pc src/glfw3Config.cmake src/glfw3ConfigVersion.cmake +src/wayland-pointer-constraints-unstable-v1-client-protocol.h +src/wayland-pointer-constraints-unstable-v1-protocol.c +src/wayland-relative-pointer-unstable-v1-client-protocol.h +src/wayland-relative-pointer-unstable-v1-protocol.c # Compiled binaries src/libglfw.so diff --git a/CMake/modules/FindWaylandProtocols.cmake b/CMake/modules/FindWaylandProtocols.cmake new file mode 100644 index 000000000..8eb83f27e --- /dev/null +++ b/CMake/modules/FindWaylandProtocols.cmake @@ -0,0 +1,26 @@ +find_package(PkgConfig) + +pkg_check_modules(WaylandProtocols QUIET wayland-protocols>=${WaylandProtocols_FIND_VERSION}) + +execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=pkgdatadir wayland-protocols + OUTPUT_VARIABLE WaylandProtocols_PKGDATADIR + RESULT_VARIABLE _pkgconfig_failed) +if (_pkgconfig_failed) + message(FATAL_ERROR "Missing wayland-protocols pkgdatadir") +endif() + +string(REGEX REPLACE "[\r\n]" "" WaylandProtocols_PKGDATADIR "${WaylandProtocols_PKGDATADIR}") + +find_package_handle_standard_args(WaylandProtocols + FOUND_VAR + WaylandProtocols_FOUND + REQUIRED_VARS + WaylandProtocols_PKGDATADIR + VERSION_VAR + WaylandProtocols_VERSION + HANDLE_COMPONENTS +) + +set(WAYLAND_PROTOCOLS_FOUND ${WaylandProtocols_FOUND}) +set(WAYLAND_PROTOCOLS_PKGDATADIR ${WaylandProtocols_PKGDATADIR}) +set(WAYLAND_PROTOCOLS_VERSION ${WaylandProtocols_VERSION}) diff --git a/CMakeLists.txt b/CMakeLists.txt index 46229dfd1..ddaa518be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,8 @@ if (_GLFW_WAYLAND) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) find_package(Wayland REQUIRED) + find_package(WaylandScanner REQUIRED) + find_package(WaylandProtocols 1.1 REQUIRED) list(APPEND glfw_PKG_DEPS "wayland-egl") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d44f873c9..dab94ef12 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,15 @@ elseif (_GLFW_WAYLAND) posix_time.h posix_tls.h xkb_unicode.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) + + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + ${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 + 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) diff --git a/src/wl_init.c b/src/wl_init.c index 90dc507be..29509ae91 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -84,12 +84,7 @@ static void pointerHandleMotion(void* data, return; if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - /* TODO */ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: GLFW_CURSOR_DISABLED not supported"); return; - } else { window->wl.cursorPosX = wl_fixed_to_double(sx); @@ -413,6 +408,20 @@ static void registryHandleGlobal(void* data, wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); } } + else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) + { + _glfw.wl.relativePointerManager = + wl_registry_bind(registry, name, + &zwp_relative_pointer_manager_v1_interface, + 1); + } + else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) + { + _glfw.wl.pointerConstraints = + wl_registry_bind(registry, name, + &zwp_pointer_constraints_v1_interface, + 1); + } } static void registryHandleGlobalRemove(void *data, diff --git a/src/wl_platform.h b/src/wl_platform.h index 56ce16311..100b12bc0 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -56,6 +56,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #error "The Wayland backend depends on EGL platform support" #endif +#include "wayland-relative-pointer-unstable-v1-client-protocol.h" +#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" + #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) @@ -95,6 +98,10 @@ typedef struct _GLFWwindowWayland int monitorsCount; int monitorsSize; + struct { + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + } pointerLock; } _GLFWwindowWayland; @@ -110,6 +117,8 @@ typedef struct _GLFWlibraryWayland struct wl_seat* seat; struct wl_pointer* pointer; struct wl_keyboard* keyboard; + struct zwp_relative_pointer_manager_v1* relativePointerManager; + struct zwp_pointer_constraints_v1* pointerConstraints; int wl_compositor_version; diff --git a/src/wl_window.c b/src/wl_window.c index 706f52a36..521dc3c28 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -529,11 +529,17 @@ void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) *ypos = window->wl.cursorPosY; } +static GLFWbool isPointerLocked(_GLFWwindow* window); + void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { - // A Wayland client can not set the cursor position - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Cursor position setting not supported"); + if (isPointerLocked(window)) + { + zwp_locked_pointer_v1_set_cursor_position_hint( + window->wl.pointerLock.lockedPointer, + wl_fixed_from_double(x), wl_fixed_from_double(y)); + wl_surface_commit(window->wl.surface); + } } void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) @@ -631,6 +637,103 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) wl_buffer_destroy(cursor->wl.buffer); } +static void handleRelativeMotion(void* data, + struct zwp_relative_pointer_v1* pointer, + uint32_t timeHi, + uint32_t timeLo, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t dxUnaccel, + wl_fixed_t dyUnaccel) +{ + _GLFWwindow* window = data; + + if (window->cursorMode != GLFW_CURSOR_DISABLED) + return; + + _glfwInputCursorMotion(window, + wl_fixed_to_double(dxUnaccel), + wl_fixed_to_double(dyUnaccel)); +} + +static const struct zwp_relative_pointer_v1_listener relativePointerListener = { + handleRelativeMotion +}; + +static void handleLocked(void* data, + struct zwp_locked_pointer_v1* lockedPointer) +{ +} + +static void unlockPointer(_GLFWwindow* window) +{ + struct zwp_relative_pointer_v1* relativePointer = + window->wl.pointerLock.relativePointer; + struct zwp_locked_pointer_v1* lockedPointer = + window->wl.pointerLock.lockedPointer; + + zwp_relative_pointer_v1_destroy(relativePointer); + zwp_locked_pointer_v1_destroy(lockedPointer); + + window->wl.pointerLock.relativePointer = NULL; + window->wl.pointerLock.lockedPointer = NULL; +} + +static void lockPointer(_GLFWwindow* window); + +static void handleUnlocked(void* data, + struct zwp_locked_pointer_v1* lockedPointer) +{ +} + +static const struct zwp_locked_pointer_v1_listener lockedPointerListener = { + handleLocked, + handleUnlocked +}; + +static void lockPointer(_GLFWwindow* window) +{ + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + + if (!_glfw.wl.relativePointerManager) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: no relative pointer manager"); + return; + } + + relativePointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + _glfw.wl.relativePointerManager, + _glfw.wl.pointer); + zwp_relative_pointer_v1_add_listener(relativePointer, + &relativePointerListener, + window); + + lockedPointer = + zwp_pointer_constraints_v1_lock_pointer( + _glfw.wl.pointerConstraints, + window->wl.surface, + _glfw.wl.pointer, + NULL, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + zwp_locked_pointer_v1_add_listener(lockedPointer, + &lockedPointerListener, + window); + + window->wl.pointerLock.relativePointer = relativePointer; + window->wl.pointerLock.lockedPointer = lockedPointer; + + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + NULL, 0, 0); +} + +static GLFWbool isPointerLocked(_GLFWwindow* window) +{ + return window->wl.pointerLock.lockedPointer != NULL; +} + void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { struct wl_buffer* buffer; @@ -648,6 +751,10 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) if (window != _glfw.wl.pointerFocus) return; + // Unlock possible pointer lock if no longer disabled. + if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window)) + unlockPointer(window); + if (window->cursorMode == GLFW_CURSOR_NORMAL) { if (cursor) @@ -691,9 +798,15 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) wl_surface_commit(surface); } } - else /* Cursor is hidden set cursor surface to NULL */ + else if (window->cursorMode == GLFW_CURSOR_DISABLED) { - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, NULL, 0, 0); + if (!isPointerLocked(window)) + lockPointer(window); + } + else if (window->cursorMode == GLFW_CURSOR_HIDDEN) + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + NULL, 0, 0); } } From 71c72db1e35ae4ca7a0688e055aad3e4f193cb58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 17 Feb 2016 13:51:08 +0800 Subject: [PATCH 037/156] wayland: Pre-multiply custom cursor image alpha Since the Wayland SHM buffer format is implicitly premultiplied and the GLFWimage pixels are defined to be non-premultiplied, we need to convert the non-premultiplied pixels to premultiplied when filling the buffer. Related to #707. --- src/internal.h | 7 +++++++ src/wl_window.c | 10 ++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/internal.h b/src/internal.h index 358da2562..0e41fbd7c 100644 --- a/src/internal.h +++ b/src/internal.h @@ -233,6 +233,13 @@ typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const c y = t; \ } +// Helper for non-premultiplied alpha to premultiplied alpha conversion +static inline unsigned char _glfwMultiplyAlpha(unsigned char alpha, + unsigned char value) +{ + return (unsigned char) ((value * (unsigned int) alpha) / 255); +} + //======================================================================== // Platform-independent structures diff --git a/src/wl_window.c b/src/wl_window.c index 521dc3c28..ca91a2f50 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -588,10 +588,12 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, unsigned char* target = data; for (i = 0; i < image->width * image->height; i++, source += 4) { - *target++ = source[2]; - *target++ = source[1]; - *target++ = source[0]; - *target++ = source[3]; + unsigned char alpha = source[3]; + + *target++ = _glfwMultiplyAlpha(alpha, source[2]); + *target++ = _glfwMultiplyAlpha(alpha, source[1]); + *target++ = _glfwMultiplyAlpha(alpha, source[0]); + *target++ = alpha; } cursor->wl.buffer = From 9160a7ceb3ac9e30973ea65f0908e72c2f476e74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 17 Feb 2016 13:53:57 +0800 Subject: [PATCH 038/156] x11: Premultiply custom cursor image alpha As with Wayland, X11 expects cursor pixels to have the alpha premultiplied, so lets convert the non-premultiplied pixels to premultiplied pixels. Fixes #353. Closes #707. --- src/x11_init.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index e4e137299..0125a8b7b 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -690,10 +690,12 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) for (i = 0; i < image->width * image->height; i++, target++, source += 4) { - *target = (source[3] << 24) | - (source[0] << 16) | - (source[1] << 8) | - source[2]; + unsigned char alpha = source[3]; + + *target = (alpha << 24) | + (_glfwMultiplyAlpha(alpha, source[0]) << 16) | + (_glfwMultiplyAlpha(alpha, source[1]) << 8) | + _glfwMultiplyAlpha(alpha, source[2]); } cursor = XcursorImageLoadCursor(_glfw.x11.display, native); From db49aa6bd99b06ddbf6161614c54dc8cb6855aa8 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 22 Feb 2016 13:16:43 +0100 Subject: [PATCH 039/156] Cleanup --- 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 516ea5073..41e5f7d8c 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -124,7 +124,7 @@ extern "C" { /* Include the chosen client API headers. */ -#if defined(__APPLE_CC__) +#if defined(__APPLE__) #if defined(GLFW_INCLUDE_GLCOREARB) #include #if defined(GLFW_INCLUDE_GLEXT) From d956dbbd2ceb1b7f88b7038f9d54935c5ddb0c18 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 18 Feb 2016 13:34:21 +0100 Subject: [PATCH 040/156] Cleanup --- src/win32_monitor.c | 8 -------- src/win32_platform.h | 6 ++++++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 4cac01fff..0341c26ac 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -32,14 +32,6 @@ #include #include -// These constants are missing on MinGW -#ifndef EDS_ROTATEDMODE - #define EDS_ROTATEDMODE 0x00000004 -#endif -#ifndef DISPLAY_DEVICE_ACTIVE - #define DISPLAY_DEVICE_ACTIVE 0x00000001 -#endif - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// diff --git a/src/win32_platform.h b/src/win32_platform.h index 9c9983a84..47b4999a6 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -92,6 +92,12 @@ #ifndef GET_XBUTTON_WPARAM #define GET_XBUTTON_WPARAM(w) (HIWORD(w)) #endif +#ifndef EDS_ROTATEDMODE + #define EDS_ROTATEDMODE 0x00000004 +#endif +#ifndef DISPLAY_DEVICE_ACTIVE + #define DISPLAY_DEVICE_ACTIVE 0x00000001 +#endif #if WINVER < 0x0601 typedef struct tagCHANGEFILTERSTRUCT From 0ea193c4e28cff1a17fd832ae761ea7da6e17850 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 23 Feb 2016 11:27:33 +0100 Subject: [PATCH 041/156] Fix detection of Win32 software monitor events Fixes #53. --- README.md | 2 ++ src/win32_window.c | 11 +++-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 49939a976..f9469332e 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ does not find Doxygen, the documentation will not be generated. - [Win32] Bugfix: MinGW import library lacked the `lib` prefix - [Win32] Bugfix: Monitor connection and disconnection events were not reported when no windows existed + - [Win32] Bugfix: Activating or deactivating displays in software did not + trigger monitor callback - [Cocoa] Removed support for OS X 10.6 - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault diff --git a/src/win32_window.c b/src/win32_window.c index b2c627d25..2c3914d63 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -264,15 +264,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, break; } - case WM_DEVICECHANGE: + case WM_DISPLAYCHANGE: { - if (wParam == DBT_DEVNODES_CHANGED) - { - _glfwInputMonitorChange(); - return TRUE; - } - - break; + _glfwInputMonitorChange(); + return 0; } } From 165171f9c8cffeef4a2edcc5a876d3f85d9343ed Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 23 Feb 2016 11:30:17 +0100 Subject: [PATCH 042/156] Add comment for Win32 helper window path --- src/win32_window.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/win32_window.c b/src/win32_window.c index 2c3914d63..5bbd04096 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -255,6 +255,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, _GLFWwindow* window = (_GLFWwindow*) GetWindowLongPtrW(hWnd, 0); if (!window) { + // This is the message handling for the hidden helper window + switch (uMsg) { case WM_NCCREATE: From 93b4c828c1a1f3703c4811bb126d4f4400ec53ca Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 23 Feb 2016 11:47:14 +0100 Subject: [PATCH 043/156] Fix VC++ build failure Regression caused by 71c72db1e35ae4ca7a0688e055aad3e4f193cb58. --- src/internal.h | 7 ------- src/wl_window.c | 10 +++++----- src/x11_init.c | 8 ++++---- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/internal.h b/src/internal.h index 0e41fbd7c..358da2562 100644 --- a/src/internal.h +++ b/src/internal.h @@ -233,13 +233,6 @@ typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const c y = t; \ } -// Helper for non-premultiplied alpha to premultiplied alpha conversion -static inline unsigned char _glfwMultiplyAlpha(unsigned char alpha, - unsigned char value) -{ - return (unsigned char) ((value * (unsigned int) alpha) / 255); -} - //======================================================================== // Platform-independent structures diff --git a/src/wl_window.c b/src/wl_window.c index ca91a2f50..b3b9bea23 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -588,12 +588,12 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, unsigned char* target = data; for (i = 0; i < image->width * image->height; i++, source += 4) { - unsigned char alpha = source[3]; + unsigned int alpha = source[3]; - *target++ = _glfwMultiplyAlpha(alpha, source[2]); - *target++ = _glfwMultiplyAlpha(alpha, source[1]); - *target++ = _glfwMultiplyAlpha(alpha, source[0]); - *target++ = alpha; + *target++ = (unsigned char) ((source[2] * alpha) / 255); + *target++ = (unsigned char) ((source[1] * alpha) / 255); + *target++ = (unsigned char) ((source[0] * alpha) / 255); + *target++ = (unsigned char) alpha; } cursor->wl.buffer = diff --git a/src/x11_init.c b/src/x11_init.c index 0125a8b7b..e73bb1314 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -690,12 +690,12 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) for (i = 0; i < image->width * image->height; i++, target++, source += 4) { - unsigned char alpha = source[3]; + unsigned int alpha = source[3]; *target = (alpha << 24) | - (_glfwMultiplyAlpha(alpha, source[0]) << 16) | - (_glfwMultiplyAlpha(alpha, source[1]) << 8) | - _glfwMultiplyAlpha(alpha, source[2]); + ((unsigned char) ((source[0] * alpha) / 255) << 16) | + ((unsigned char) ((source[1] * alpha) / 255) << 8) | + ((unsigned char) ((source[2] * alpha) / 255) << 0); } cursor = XcursorImageLoadCursor(_glfw.x11.display, native); From de3e413aab6a558427dd0b73f679748c2cb1eb92 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 23 Feb 2016 11:52:33 +0100 Subject: [PATCH 044/156] Fix VC++ signed/unsigned mismatch warning --- src/vulkan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vulkan.c b/src/vulkan.c index 504ed636e..51bba9714 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -120,7 +120,7 @@ void _glfwInitVulkan(void) void _glfwTerminateVulkan(void) { - int i; + unsigned int i; for (i = 0; i < _glfw.vk.extensionCount; i++) free(_glfw.vk.extensions[i]); From baf574494da1f1b6a07ff426c62670090e67b445 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 21 Feb 2016 15:42:49 +0100 Subject: [PATCH 045/156] Add glfwFocusWindow This removes the (undocumented) behavior where glfwShowWindow would bring the window to front and set input focus. That function now does what it says. --- README.md | 1 + docs/news.dox | 5 +++++ docs/window.dox | 7 +++++++ include/GLFW/glfw3.h | 28 ++++++++++++++++++++++++++++ src/cocoa_window.m | 21 +++++++++++---------- src/internal.h | 9 +++++---- src/mir_window.c | 2 +- src/win32_window.c | 15 +++++++-------- src/window.c | 15 ++++++++++++--- src/wl_window.c | 12 ++++++------ src/x11_window.c | 39 ++++++++++++++++++++------------------- 11 files changed, 103 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index f9469332e..7bac54861 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ does not find Doxygen, the documentation will not be generated. `glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and `glfwCreateWindowSurface` for platform independent Vulkan support - Added `glfwMaximizeWindow` and `GLFW_MAXIMIZED` for window maximization + - Added `glfwFocusWindow` for giving windows input focus - Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting absolute and relative window size limits - Added `glfwGetKeyName` for querying the layout-specific name of printable diff --git a/docs/news.dox b/docs/news.dox index 601eee483..6bf800acd 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -32,6 +32,11 @@ GLFW now supports window maximization with @ref glfwMaximizeWindow and the [GLFW_MAXIMIZED](@ref window_attribs_wnd) window hint and attribute. +@subsection news_32_focus Window input focus control + +GLFW now supports giving windows input focus with @ref glfwFocusWindow. + + @section news_31 New features in 3.1 These are the release highlights. For a full list of changes see the diff --git a/docs/window.dox b/docs/window.dox index b7c7b7310..a40005d9d 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -715,6 +715,13 @@ int visible = glfwGetWindowAttrib(window, GLFW_VISIBLE); @subsection window_focus Window input focus +Windows can be given input focus and brought to the front with @ref +glfwFocusWindow. + +@code +glfwFocusWindow(window); +@endcode + 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. diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 41e5f7d8c..68d005dd1 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2283,6 +2283,34 @@ GLFWAPI void glfwShowWindow(GLFWwindow* window); */ GLFWAPI void glfwHideWindow(GLFWwindow* window); +/*! @brief Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable + * this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * @param[in] window The window to give input focus. + * + * @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_focus + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwFocusWindow(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 093d2b0a2..1ad9cc1ac 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -84,6 +84,7 @@ static GLFWbool enterFullscreenMode(_GLFWwindow* window) bounds.size.height); [window->ns.object setFrame:frame display:YES]; + _glfwPlatformFocusWindow(window); return status; } @@ -1039,6 +1040,16 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) } void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + [window->ns.object orderFront:nil]; +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + [window->ns.object orderOut:nil]; +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) { // Make us the active application // HACK: This has been moved here from initializeAppKit to prevent @@ -1049,16 +1060,6 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) [window->ns.object makeKeyAndOrderFront:nil]; } -void _glfwPlatformUnhideWindow(_GLFWwindow* window) -{ - [window->ns.object orderFront:nil]; -} - -void _glfwPlatformHideWindow(_GLFWwindow* window) -{ - [window->ns.object orderOut:nil]; -} - int _glfwPlatformWindowFocused(_GLFWwindow* window) { return [window->ns.object isKeyWindow]; diff --git a/src/internal.h b/src/internal.h index 358da2562..48488233f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -684,15 +684,16 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window); */ void _glfwPlatformShowWindow(_GLFWwindow* window); -/*! @ingroup platform - */ -void _glfwPlatformUnhideWindow(_GLFWwindow* window); - /*! @copydoc glfwHideWindow * @ingroup platform */ void _glfwPlatformHideWindow(_GLFWwindow* window); +/*! @copydoc glfwFocusWindow + * @ingroup platform + */ +void _glfwPlatformFocusWindow(_GLFWwindow* window); + /*! @brief Returns whether the window is focused. * @ingroup platform */ diff --git a/src/mir_window.c b/src/mir_window.c index 0642d08de..9d8f1fd3b 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -495,7 +495,7 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) mir_surface_spec_release(spec); } -void _glfwPlatformUnhideWindow(_GLFWwindow* window) +void _glfwPlatformFocusWindow(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); diff --git a/src/win32_window.c b/src/win32_window.c index 5bbd04096..85a72ad95 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1034,14 +1034,6 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) } void _glfwPlatformShowWindow(_GLFWwindow* window) -{ - ShowWindow(window->win32.handle, SW_SHOW); - BringWindowToTop(window->win32.handle); - SetForegroundWindow(window->win32.handle); - SetFocus(window->win32.handle); -} - -void _glfwPlatformUnhideWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_SHOW); } @@ -1051,6 +1043,13 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) ShowWindow(window->win32.handle, SW_HIDE); } +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + BringWindowToTop(window->win32.handle); + SetForegroundWindow(window->win32.handle); + SetFocus(window->win32.handle); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { return window->win32.handle == GetActiveWindow(); diff --git a/src/window.c b/src/window.c index f051370e1..daff54869 100644 --- a/src/window.c +++ b/src/window.c @@ -231,10 +231,9 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, { if (wndconfig.visible) { + _glfwPlatformShowWindow(window); if (wndconfig.focused) - _glfwPlatformShowWindow(window); - else - _glfwPlatformUnhideWindow(window); + _glfwPlatformFocusWindow(window); } } @@ -629,6 +628,16 @@ GLFWAPI void glfwHideWindow(GLFWwindow* handle) _glfwPlatformHideWindow(window); } +GLFWAPI void glfwFocusWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window); + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformFocusWindow(window); +} + GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index b3b9bea23..1fe5b86a9 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -470,18 +470,18 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) wl_shell_surface_set_toplevel(window->wl.shell_surface); } -void _glfwPlatformUnhideWindow(_GLFWwindow* window) -{ - // TODO - fprintf(stderr, "_glfwPlatformUnhideWindow not implemented yet\n"); -} - void _glfwPlatformHideWindow(_GLFWwindow* window) { wl_surface_attach(window->wl.surface, NULL, 0, 0); wl_surface_commit(window->wl.surface); } +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + // TODO + fprintf(stderr, "_glfwPlatformFocusWindow not implemented yet\n"); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { // TODO diff --git a/src/x11_window.c b/src/x11_window.c index 2f9130a74..ad007d9f3 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -763,19 +763,7 @@ static void enterFullscreenMode(_GLFWwindow* window) 0); } - if (_glfw.x11.NET_ACTIVE_WINDOW) - { - // Ask the window manager to raise and focus the GLFW window - // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end up - // on top of all other windows ("Stacking order" in EWMH spec) - sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); - } - else - { - XRaiseWindow(_glfw.x11.display, window->x11.handle); - XSetInputFocus(_glfw.x11.display, window->x11.handle, - RevertToParent, CurrentTime); - } + _glfwPlatformFocusWindow(window); if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) { @@ -1810,12 +1798,6 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) } void _glfwPlatformShowWindow(_GLFWwindow* window) -{ - XMapRaised(_glfw.x11.display, window->x11.handle); - XFlush(_glfw.x11.display); -} - -void _glfwPlatformUnhideWindow(_GLFWwindow* window) { XMapWindow(_glfw.x11.display, window->x11.handle); XFlush(_glfw.x11.display); @@ -1827,6 +1809,25 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + if (_glfw.x11.NET_ACTIVE_WINDOW) + { + // Ask the window manager to raise and focus the GLFW window + // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end up + // on top of all other windows ("Stacking order" in EWMH spec) + sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); + } + else + { + XRaiseWindow(_glfw.x11.display, window->x11.handle); + XSetInputFocus(_glfw.x11.display, window->x11.handle, + RevertToParent, CurrentTime); + } + + XFlush(_glfw.x11.display); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { Window focused; From d3f5d036f870ab9e13e15d38b79b88382f1ec4eb Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 26 Feb 2016 08:37:30 +0100 Subject: [PATCH 046/156] Fix OS X modifier flags cache getting out of date Fixes #566. Closes #567. --- README.md | 1 + src/cocoa_window.m | 3 +++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 7bac54861..d6d1b06bb 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ does not find Doxygen, the documentation will not be generated. - [Cocoa] Removed support for OS X 10.6 - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault + - [Cocoa] Bugfix: Modifier flags cache was not updated when window became key - [X11] Bugfix: Monitor connection and disconnection events were not reported - [X11] Bugfix: Decoding of UTF-8 text from XIM could continue past the end - [X11] Bugfix: An XKB structure was leaked during `glfwInit` diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 1ad9cc1ac..47af1e9a7 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -206,6 +206,9 @@ static int translateKey(unsigned int key) - (void)windowDidBecomeKey:(NSNotification *)notification { + window->ns.modifierFlags = + [NSEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask; + if (_glfw.cursorWindow == window && window->cursorMode == GLFW_CURSOR_DISABLED) { From ca1f4db50c3c7a0930082d65d000fb1f16aed4ba Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 26 Feb 2016 09:36:47 +0100 Subject: [PATCH 047/156] Remove unused CMake find modules --- CMake/modules/FindEGL.cmake | 16 ---------------- CMake/modules/FindGLESv1.cmake | 16 ---------------- CMake/modules/FindGLESv2.cmake | 16 ---------------- 3 files changed, 48 deletions(-) delete mode 100644 CMake/modules/FindEGL.cmake delete mode 100644 CMake/modules/FindGLESv1.cmake delete mode 100644 CMake/modules/FindGLESv2.cmake diff --git a/CMake/modules/FindEGL.cmake b/CMake/modules/FindEGL.cmake deleted file mode 100644 index 83bb9e36b..000000000 --- a/CMake/modules/FindEGL.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# Find EGL -# -# EGL_INCLUDE_DIR -# EGL_LIBRARY -# EGL_FOUND - -find_path(EGL_INCLUDE_DIR NAMES EGL/egl.h PATHS /opt/vc/include) - -set(EGL_NAMES ${EGL_NAMES} egl EGL libEGL) -find_library(EGL_LIBRARY NAMES ${EGL_NAMES} PATHS /opt/vc/lib) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR) - -mark_as_advanced(EGL_INCLUDE_DIR EGL_LIBRARY) - diff --git a/CMake/modules/FindGLESv1.cmake b/CMake/modules/FindGLESv1.cmake deleted file mode 100644 index 70d3eb9fc..000000000 --- a/CMake/modules/FindGLESv1.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# Find GLESv1 -# -# GLESv1_INCLUDE_DIR -# GLESv1_LIBRARY -# GLESv1_FOUND - -find_path(GLESv1_INCLUDE_DIR NAMES GLES/gl.h PATHS /opt/vc/include) - -set(GLESv1_NAMES ${GLESv1_NAMES} GLESv1_CM libGLES_CM) -find_library(GLESv1_LIBRARY NAMES ${GLESv1_NAMES} PATHS /opt/vc/lib) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GLESv1 DEFAULT_MSG GLESv1_LIBRARY GLESv1_INCLUDE_DIR) - -mark_as_advanced(GLESv1_INCLUDE_DIR GLESv1_LIBRARY) - diff --git a/CMake/modules/FindGLESv2.cmake b/CMake/modules/FindGLESv2.cmake deleted file mode 100644 index ff5ba954c..000000000 --- a/CMake/modules/FindGLESv2.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# Find GLESv2 -# -# GLESv2_INCLUDE_DIR -# GLESv2_LIBRARY -# GLESv2_FOUND - -find_path(GLESv2_INCLUDE_DIR NAMES GLES2/gl2.h PATHS /opt/vc/include) - -set(GLESv2_NAMES ${GLESv2_NAMES} GLESv2 libGLESv2) -find_library(GLESv2_LIBRARY NAMES ${GLESv2_NAMES} PATHS /opt/vc/lib) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GLESv2 DEFAULT_MSG GLESv2_LIBRARY GLESv2_INCLUDE_DIR) - -mark_as_advanced(GLESv2_INCLUDE_DIR GLESv2_LIBRARY) - From 9f5658c8ac16c8da4c86fd5c11e3408d731c7a08 Mon Sep 17 00:00:00 2001 From: Xo Wang Date: Sun, 26 Jul 2015 18:40:54 -0700 Subject: [PATCH 048/156] Removed OS X modifier flags cache Related to #566. Related to #567. --- README.md | 1 + src/cocoa_platform.h | 1 - src/cocoa_window.m | 33 +++++++++++++++++++++++++-------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d6d1b06bb..cf15b75ba 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,7 @@ skills. - Simon Voordouw - Torsten Walluhn - Patrick Walton + - Xo Wang - Jay Weisskopf - Frank Wille - yuriks diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index a2025e1da..212a8ad8a 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -66,7 +66,6 @@ typedef struct _GLFWwindowNS id object; id delegate; id view; - unsigned int modifierFlags; // The total sum of the distances the cursor has been warped // since the last cursor motion event was processed diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 47af1e9a7..1a7662b1c 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -123,6 +123,29 @@ static int translateKey(unsigned int key) return _glfw.ns.publicKeys[key]; } +// Translate a GLFW keycode to a Cocoa modifier flag +// +static NSUInteger translateKeyToModifierFlag(int key) +{ + switch (key) + { + case GLFW_KEY_LEFT_SHIFT: + case GLFW_KEY_RIGHT_SHIFT: + return NSShiftKeyMask; + case GLFW_KEY_LEFT_CONTROL: + case GLFW_KEY_RIGHT_CONTROL: + return NSControlKeyMask; + case GLFW_KEY_LEFT_ALT: + case GLFW_KEY_RIGHT_ALT: + return NSAlternateKeyMask; + case GLFW_KEY_LEFT_SUPER: + case GLFW_KEY_RIGHT_SUPER: + return NSCommandKeyMask; + } + + return 0; +} + //------------------------------------------------------------------------ // Delegate for window related notifications @@ -206,9 +229,6 @@ static int translateKey(unsigned int key) - (void)windowDidBecomeKey:(NSNotification *)notification { - window->ns.modifierFlags = - [NSEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask; - if (_glfw.cursorWindow == window && window->cursorMode == GLFW_CURSOR_DISABLED) { @@ -502,21 +522,18 @@ static int translateKey(unsigned int key) [event modifierFlags] & NSDeviceIndependentModifierFlagsMask; const int key = translateKey([event keyCode]); const int mods = translateFlags(modifierFlags); + const NSUInteger keyFlag = translateKeyToModifierFlag(key); - if (modifierFlags == window->ns.modifierFlags) + if (keyFlag & modifierFlags) { if (window->keys[key] == GLFW_PRESS) action = GLFW_RELEASE; else action = GLFW_PRESS; } - else if (modifierFlags > window->ns.modifierFlags) - action = GLFW_PRESS; else action = GLFW_RELEASE; - window->ns.modifierFlags = modifierFlags; - _glfwInputKey(window, key, [event keyCode], action, mods); } From 3107c9548d7911d9424ab589fd2ab8ca8043a84a Mon Sep 17 00:00:00 2001 From: Mario Dorn Date: Fri, 13 Nov 2015 17:19:20 +0100 Subject: [PATCH 049/156] Implement NSTextInputClient protocol on OS X This provides support for IME character composition. Fixes #456. Closes #643. --- README.md | 2 + src/cocoa_window.m | 107 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 95 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index cf15b75ba..2f0479471 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ does not find Doxygen, the documentation will not be generated. - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault - [Cocoa] Bugfix: Modifier flags cache was not updated when window became key + - [Cocoa] Bugfix: Dead key character composition did not work - [X11] Bugfix: Monitor connection and disconnection events were not reported - [X11] Bugfix: Decoding of UTF-8 text from XIM could continue past the end - [X11] Bugfix: An XKB structure was leaked during `glfwInit` @@ -165,6 +166,7 @@ skills. - Paul R. Deppe - Michael Dickens - Роман Донченко + - Mario Dorn - Jonathan Dummer - Ralph Eastwood - Siavash Eliasi diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 1a7662b1c..f9c9c3da7 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -146,6 +146,10 @@ static NSUInteger translateKeyToModifierFlag(int key) return 0; } +// Defines a constant for empty ranges in NSTextInputClient +// +static const NSRange kEmptyRange = {NSNotFound, 0}; + //------------------------------------------------------------------------ // Delegate for window related notifications @@ -296,10 +300,11 @@ static NSUInteger translateKeyToModifierFlag(int key) // Content view class for the GLFW window //------------------------------------------------------------------------ -@interface GLFWContentView : NSView +@interface GLFWContentView : NSView { _GLFWwindow* window; NSTrackingArea* trackingArea; + NSMutableAttributedString* markedText; } - (id)initWithGlfwWindow:(_GLFWwindow *)initWindow; @@ -329,6 +334,7 @@ static NSUInteger translateKeyToModifierFlag(int key) { window = initWindow; trackingArea = nil; + markedText = [[NSMutableAttributedString alloc] init]; [self updateTrackingAreas]; [self registerForDraggedTypes:[NSArray arrayWithObjects: @@ -338,9 +344,10 @@ static NSUInteger translateKeyToModifierFlag(int key) return self; } --(void)dealloc +- (void)dealloc { [trackingArea release]; + [markedText release]; [super dealloc]; } @@ -501,18 +508,7 @@ static NSUInteger translateKeyToModifierFlag(int key) _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); - NSString* characters = [event characters]; - NSUInteger i, length = [characters length]; - const int plain = !(mods & GLFW_MOD_SUPER); - - for (i = 0; i < length; i++) - { - const unichar codepoint = [characters characterAtIndex:i]; - if ((codepoint & 0xff00) == 0xf700) - continue; - - _glfwInputChar(window, codepoint, mods, plain); - } + [self interpretKeyEvents:[NSArray arrayWithObject:event]]; } - (void)flagsChanged:(NSEvent *)event @@ -614,6 +610,89 @@ static NSUInteger translateKeyToModifierFlag(int key) [self setNeedsDisplay:YES]; } +- (BOOL)hasMarkedText +{ + return (markedText.length > 0); +} + +- (NSRange)markedRange +{ + return (markedText.length > 0) ? + NSMakeRange(0, markedText.length-1) : + kEmptyRange; +} + +- (NSRange)selectedRange +{ + return kEmptyRange; +} + +- (void)setMarkedText:(id)aString + selectedRange:(NSRange)selectedRange + replacementRange:(NSRange)replacementRange +{ + if( [aString isKindOfClass: [NSAttributedString class]] ) + { + [markedText initWithAttributedString: aString]; + } + else + { + [markedText initWithString: aString]; + } +} + +- (void)unmarkText +{ + [[markedText mutableString] setString:@""]; +} + +- (NSArray*)validAttributesForMarkedText +{ + return [NSArray array]; +} + +- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)aRange + actualRange:(NSRangePointer)actualRange +{ + return nil; +} + +- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint +{ + return 0; +} + +- (NSRect)firstRectForCharacterRange:(NSRange)aRange + actualRange:(NSRangePointer)actualRange +{ + return NSMakeRect(0, 0, 0, 0); +} + +- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange +{ + NSEvent* event = [NSApp currentEvent]; + const int mods = translateFlags([event modifierFlags]); + + NSString* characters; + if ([aString isKindOfClass: [NSAttributedString class]]) { + characters = [aString string]; + } else { + characters = (NSString*)aString; + } + + NSUInteger i, length = [characters length]; + const int plain = !(mods & GLFW_MOD_SUPER); + + for (i = 0; i < length; i++) + { + const unichar codepoint = [characters characterAtIndex:i]; + if ((codepoint & 0xff00) == 0xf700) + continue; + + _glfwInputChar(window, codepoint, mods, plain); + } +} + @end From 59dbd3b6cef71909e31c3d5e0f2390fabd0a64d1 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 26 Feb 2016 10:34:23 +0100 Subject: [PATCH 050/156] Cleanup --- src/cocoa_window.m | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index f9c9c3da7..6bcacba04 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -148,7 +148,7 @@ static NSUInteger translateKeyToModifierFlag(int key) // Defines a constant for empty ranges in NSTextInputClient // -static const NSRange kEmptyRange = {NSNotFound, 0}; +static const NSRange kEmptyRange = { NSNotFound, 0 }; //------------------------------------------------------------------------ @@ -612,14 +612,15 @@ static const NSRange kEmptyRange = {NSNotFound, 0}; - (BOOL)hasMarkedText { - return (markedText.length > 0); + return [markedText length] > 0; } - (NSRange)markedRange { - return (markedText.length > 0) ? - NSMakeRange(0, markedText.length-1) : - kEmptyRange; + if ([markedText length] > 0) + return NSMakeRange(0, [markedText length] - 1); + else + return kEmptyRange; } - (NSRange)selectedRange @@ -627,18 +628,14 @@ static const NSRange kEmptyRange = {NSNotFound, 0}; return kEmptyRange; } -- (void)setMarkedText:(id)aString +- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange { - if( [aString isKindOfClass: [NSAttributedString class]] ) - { - [markedText initWithAttributedString: aString]; - } + if ([string isKindOfClass:[NSAttributedString class]]) + [markedText initWithAttributedString:string]; else - { - [markedText initWithString: aString]; - } + [markedText initWithString:string]; } - (void)unmarkText @@ -651,37 +648,36 @@ static const NSRange kEmptyRange = {NSNotFound, 0}; return [NSArray array]; } -- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)aRange +- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange { return nil; } -- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint +- (NSUInteger)characterIndexForPoint:(NSPoint)point { return 0; } -- (NSRect)firstRectForCharacterRange:(NSRange)aRange +- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange { return NSMakeRect(0, 0, 0, 0); } -- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange +- (void)insertText:(id)string replacementRange:(NSRange)replacementRange { + NSString* characters; NSEvent* event = [NSApp currentEvent]; const int mods = translateFlags([event modifierFlags]); + const int plain = !(mods & GLFW_MOD_SUPER); - NSString* characters; - if ([aString isKindOfClass: [NSAttributedString class]]) { - characters = [aString string]; - } else { - characters = (NSString*)aString; - } + if ([string isKindOfClass:[NSAttributedString class]]) + characters = [string string]; + else + characters = (NSString*) string; NSUInteger i, length = [characters length]; - const int plain = !(mods & GLFW_MOD_SUPER); for (i = 0; i < length; i++) { From e7bb03d8e7bee64530b8b6a39dc03967b7214e71 Mon Sep 17 00:00:00 2001 From: Yoshiki Shibukawa Date: Fri, 26 Feb 2016 10:46:49 +0100 Subject: [PATCH 051/156] Improve OS X IME candidate window placement --- README.md | 1 + src/cocoa_window.m | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f0479471..9d9001b3a 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,7 @@ skills. - SephiRok - Steve Sexton - Systemcluster + - Yoshiki Shibukawa - Dmitri Shuralyov - Daniel Skorupski - Bradley Smith diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 6bcacba04..c53ec24a0 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -662,7 +662,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - return NSMakeRect(0, 0, 0, 0); + int x, y; + _glfwPlatformGetWindowPos(window, &x, &y); + const NSRect contentRect = [window->ns.view frame]; + return NSMakeRect(x, transformY(y+contentRect.size.height), 0, 0); } - (void)insertText:(id)string replacementRange:(NSRange)replacementRange From a9b9c4cc33b17321936c3ac5f2daf4d36be895e1 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 26 Feb 2016 10:47:29 +0100 Subject: [PATCH 052/156] Cleanup --- src/cocoa_window.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index c53ec24a0..7d3f0ed80 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -662,10 +662,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - int x, y; - _glfwPlatformGetWindowPos(window, &x, &y); + int xpos, ypos; + _glfwPlatformGetWindowPos(window, &xpos, &ypos); const NSRect contentRect = [window->ns.view frame]; - return NSMakeRect(x, transformY(y+contentRect.size.height), 0, 0); + return NSMakeRect(xpos, transformY(ypos + contentRect.size.height), 0.0, 0.0); } - (void)insertText:(id)string replacementRange:(NSRange)replacementRange From 22a09a53e6aacbaf40d2d975b170a0515d212e2f Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 24 Feb 2016 10:23:06 +0100 Subject: [PATCH 053/156] Centralize documentation generation logic --- CMakeLists.txt | 8 -------- docs/CMakeLists.txt | 32 ++++++++++++++++++++++++++++++-- docs/Doxyfile.in | 18 +----------------- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ddaa518be..d3d277b15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,10 +71,6 @@ find_package(Vulkan) if (GLFW_BUILD_DOCS) set(DOXYGEN_SKIP_DOT TRUE) find_package(Doxygen) - - if (GLFW_DOCUMENT_INTERNALS) - set(GLFW_INTERNAL_DOCS "${GLFW_SOURCE_DIR}/src/internal.h ${GLFW_SOURCE_DIR}/docs/internal.dox") - endif() endif() #-------------------------------------------------------------------- @@ -369,10 +365,6 @@ write_basic_package_version_file(src/glfw3ConfigVersion.cmake VERSION ${GLFW_VERSION_FULL} COMPATIBILITY SameMajorVersion) -if (GLFW_BUILD_DOCS) - configure_file(docs/Doxyfile.in docs/Doxyfile @ONLY) -endif() - configure_file(src/glfw_config.h.in src/glfw_config.h @ONLY) configure_file(src/glfw3.pc.in src/glfw3.pc @ONLY) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 45a6162e8..063aa48a4 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,5 +1,33 @@ -add_custom_target(docs ALL ${DOXYGEN_EXECUTABLE} - WORKING_DIRECTORY ${GLFW_BINARY_DIR}/docs +set(glfw_DOCS_SOURCES + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h" + "${GLFW_SOURCE_DIR}/docs/main.dox" + "${GLFW_SOURCE_DIR}/docs/news.dox" + "${GLFW_SOURCE_DIR}/docs/moving.dox" + "${GLFW_SOURCE_DIR}/docs/quick.dox" + "${GLFW_SOURCE_DIR}/docs/compile.dox" + "${GLFW_SOURCE_DIR}/docs/build.dox" + "${GLFW_SOURCE_DIR}/docs/intro.dox" + "${GLFW_SOURCE_DIR}/docs/context.dox" + "${GLFW_SOURCE_DIR}/docs/monitor.dox" + "${GLFW_SOURCE_DIR}/docs/window.dox" + "${GLFW_SOURCE_DIR}/docs/input.dox" + "${GLFW_SOURCE_DIR}/docs/vulkan.dox" + "${GLFW_SOURCE_DIR}/docs/rift.dox" + "${GLFW_SOURCE_DIR}/docs/compat.dox") + +if (GLFW_DOCUMENT_INTERNALS) + list(APPEND glfw_DOCS_SOURCES "${GLFW_SOURCE_DIR}/src/internal.h") +endif() + +foreach(arg ${glfw_DOCS_SOURCES}) + set(GLFW_DOCS_SOURCES "${GLFW_DOCS_SOURCES} ${arg}") +endforeach() + +configure_file(Doxyfile.in Doxyfile @ONLY) + +add_custom_target(docs ALL "${DOXYGEN_EXECUTABLE}" + WORKING_DIRECTORY "${GLFW_BINARY_DIR}/docs" COMMENT "Generating HTML documentation" VERBATIM) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 696cb2cf1..b046f898b 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -660,23 +660,7 @@ WARN_LOGFILE = @GLFW_BINARY_DIR@/docs/warnings.txt # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = @GLFW_INTERNAL_DOCS@ \ - @GLFW_SOURCE_DIR@/include/GLFW/glfw3.h \ - @GLFW_SOURCE_DIR@/include/GLFW/glfw3native.h \ - @GLFW_SOURCE_DIR@/docs/main.dox \ - @GLFW_SOURCE_DIR@/docs/news.dox \ - @GLFW_SOURCE_DIR@/docs/moving.dox \ - @GLFW_SOURCE_DIR@/docs/quick.dox \ - @GLFW_SOURCE_DIR@/docs/compile.dox \ - @GLFW_SOURCE_DIR@/docs/build.dox \ - @GLFW_SOURCE_DIR@/docs/intro.dox \ - @GLFW_SOURCE_DIR@/docs/context.dox \ - @GLFW_SOURCE_DIR@/docs/monitor.dox \ - @GLFW_SOURCE_DIR@/docs/window.dox \ - @GLFW_SOURCE_DIR@/docs/input.dox \ - @GLFW_SOURCE_DIR@/docs/vulkan.dox \ - @GLFW_SOURCE_DIR@/docs/rift.dox \ - @GLFW_SOURCE_DIR@/docs/compat.dox +INPUT = @GLFW_DOCS_SOURCES@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is From 239ede725d7dd3ee7d321835bdd32bd0eb3ee4d4 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 24 Feb 2016 18:15:07 +0100 Subject: [PATCH 054/156] Add cache variable setting to source tree method By default both tests, examples and documentation is built when the GLFW source tree is included in a larger CMake project. --- docs/build.dox | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/build.dox b/docs/build.dox index 4e812b38a..7fccf8737 100644 --- a/docs/build.dox +++ b/docs/build.dox @@ -158,7 +158,17 @@ build_link_cmake_module. With just a few changes to your `CMakeLists.txt` you can have the GLFW source tree built along with your application. -Firstly, add the root directory of the GLFW source tree to your project. This +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 +cache variables before adding the GLFW source tree. + +@code +set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) +set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) +set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +@endcode + +Then add the root directory of the GLFW source tree to your project. This will add the `glfw` target and the necessary cache variables to your project. @code{.cmake} From 4b63f702856297746dc827f4cfa1a1b9770d684b Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 19 Oct 2015 00:46:26 +0200 Subject: [PATCH 055/156] Fix no monitors found on VMware Windows guest Monitor enumeration now switches to adapters if no displays are connected to active adapters. This should provide usable monitor objects on headless and VMware guest systems. Fixes #441. Fixes #556. Fixes #594. --- README.md | 1 + src/win32_monitor.c | 166 ++++++++++++++++++++++++++++---------------- 2 files changed, 108 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 9d9001b3a..38bec8fa1 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ does not find Doxygen, the documentation will not be generated. when no windows existed - [Win32] Bugfix: Activating or deactivating displays in software did not trigger monitor callback + - [Win32] Bugfix: No monitors were listed on headless and VMware guest systems - [Cocoa] Removed support for OS X 10.6 - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 0341c26ac..a6eeeb1ed 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -33,6 +33,59 @@ #include +// Create monitor from an adapter and (optionally) a display +// +static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, + DISPLAY_DEVICEW* display) +{ + _GLFWmonitor* monitor; + char* name; + HDC dc; + + if (display) + name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString); + else + name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString); + if (!name) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string to UTF-8"); + return NULL; + } + + dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL); + + monitor = _glfwAllocMonitor(name, + GetDeviceCaps(dc, HORZSIZE), + GetDeviceCaps(dc, VERTSIZE)); + + DeleteDC(dc); + free(name); + + if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED) + monitor->win32.modesPruned = GLFW_TRUE; + + wcscpy(monitor->win32.adapterName, adapter->DeviceName); + WideCharToMultiByte(CP_UTF8, 0, + adapter->DeviceName, -1, + monitor->win32.publicAdapterName, + sizeof(monitor->win32.publicAdapterName), + NULL, NULL); + + if (display) + { + wcscpy(monitor->win32.displayName, display->DeviceName); + WideCharToMultiByte(CP_UTF8, 0, + display->DeviceName, -1, + monitor->win32.publicDisplayName, + sizeof(monitor->win32.publicDisplayName), + NULL, NULL); + } + + return monitor; +} + + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -96,17 +149,18 @@ void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) _GLFWmonitor** _glfwPlatformGetMonitors(int* count) { int found = 0; + DWORD adapterIndex, displayIndex, primaryIndex = 0; + DISPLAY_DEVICEW adapter, display; + GLFWbool hasDisplays = GLFW_FALSE; _GLFWmonitor** monitors = NULL; - DWORD adapterIndex, displayIndex; *count = 0; + // HACK: Check if any active adapters have connected displays + // If not, this is a headless system or a VMware guest + for (adapterIndex = 0; ; adapterIndex++) { - DISPLAY_DEVICEW adapter; - int widthMM, heightMM; - HDC dc; - ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); adapter.cb = sizeof(DISPLAY_DEVICEW); @@ -116,71 +170,65 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; - dc = CreateDCW(L"DISPLAY", adapter.DeviceName, NULL, NULL); - widthMM = GetDeviceCaps(dc, HORZSIZE); - heightMM = GetDeviceCaps(dc, VERTSIZE); - DeleteDC(dc); + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); - for (displayIndex = 0; ; displayIndex++) + if (EnumDisplayDevicesW(adapter.DeviceName, 0, &display, 0)) { - DISPLAY_DEVICEW display; - _GLFWmonitor* monitor; - char* name; - - ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); - display.cb = sizeof(DISPLAY_DEVICEW); - - if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) - break; - - name = _glfwCreateUTF8FromWideStringWin32(display.DeviceString); - if (!name) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Failed to convert string to UTF-8"); - continue; - } - - monitor = _glfwAllocMonitor(name, widthMM, heightMM); - free(name); - - if (adapter.StateFlags & DISPLAY_DEVICE_MODESPRUNED) - monitor->win32.modesPruned = GLFW_TRUE; - - wcscpy(monitor->win32.adapterName, adapter.DeviceName); - wcscpy(monitor->win32.displayName, display.DeviceName); - - WideCharToMultiByte(CP_UTF8, 0, - adapter.DeviceName, -1, - monitor->win32.publicAdapterName, - sizeof(monitor->win32.publicAdapterName), - NULL, NULL); - - WideCharToMultiByte(CP_UTF8, 0, - display.DeviceName, -1, - monitor->win32.publicDisplayName, - sizeof(monitor->win32.publicDisplayName), - NULL, NULL); - - found++; - monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); - monitors[found - 1] = monitor; - - if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE && - displayIndex == 0) - { - _GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]); - } + hasDisplays = GLFW_TRUE; + break; } } + for (adapterIndex = 0; ; adapterIndex++) + { + ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); + adapter.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) + break; + + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + primaryIndex = found; + + if (hasDisplays) + { + for (displayIndex = 0; ; displayIndex++) + { + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) + break; + + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[found - 1] = createMonitor(&adapter, &display); + } + } + else + { + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[found - 1] = createMonitor(&adapter, NULL); + } + } + + _GLFW_SWAP_POINTERS(monitors[0], monitors[primaryIndex]); + *count = found; return monitors; } GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) { - return wcscmp(first->win32.displayName, second->win32.displayName) == 0; + if (wcslen(first->win32.displayName)) + return wcscmp(first->win32.displayName, second->win32.displayName) == 0; + else + return wcscmp(first->win32.adapterName, second->win32.adapterName) == 0; } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) From dd4d66d1bf2893584d67fed821765d7d9f5e90de Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sat, 27 Feb 2016 21:58:09 +0100 Subject: [PATCH 056/156] Language --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38bec8fa1..4cf5858da 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ for creating windows, contexts and surfaces, reading input, handling events, etc Version 3.2 is _not yet described_. If you are new to GLFW, you may find the -[introductory tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW +[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. From 73216e5fb1f6ff07d1f586df039f6099bfca9ca4 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 28 Feb 2016 10:53:48 +0100 Subject: [PATCH 057/156] Fix NSBeep being emitted for some keys Fixes #719. --- src/cocoa_window.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 7d3f0ed80..0086e8d00 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -692,6 +692,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; } } +- (void)doCommandBySelector:(SEL)selector +{ +} + @end From e51e27fcabcbf0aa7c5c540250d549739fe82e3d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 28 Feb 2016 16:05:02 +0100 Subject: [PATCH 058/156] Add back tracking of X11 override-redirect --- src/x11_platform.h | 2 ++ src/x11_window.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/x11_platform.h b/src/x11_platform.h index 8d791f074..caad2530b 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -116,6 +116,8 @@ typedef struct _GLFWwindowX11 Window handle; XIC ic; + GLFWbool overrideRedirect; + // Cached position and size used to filter out duplicate events int width, height; int xpos, ypos; diff --git a/src/x11_window.c b/src/x11_window.c index ad007d9f3..3d5dd9803 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -318,6 +318,8 @@ static GLFWbool createWindow(_GLFWwindow* window, window->x11.handle, CWOverrideRedirect, &attributes); + + window->x11.overrideRedirect = GLFW_TRUE; } } else @@ -1737,7 +1739,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, void _glfwPlatformIconifyWindow(_GLFWwindow* window) { - if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN) + if (window->x11.overrideRedirect) { // Override-redirect windows cannot be iconified or restored, as those // tasks are performed by the window manager @@ -1752,7 +1754,7 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window) void _glfwPlatformRestoreWindow(_GLFWwindow* window) { - if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN) + if (window->x11.overrideRedirect) { // Override-redirect windows cannot be iconified or restored, as those // tasks are performed by the window manager From 6494da3101eba2ad0d9c8b814e98465456c11273 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 28 Feb 2016 16:05:23 +0100 Subject: [PATCH 059/156] Fix reporting of non-root X11 window positions Fixes #517. --- src/x11_window.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/x11_window.c b/src/x11_window.c index 3d5dd9803..1ee5f1ff7 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1114,6 +1114,9 @@ static void processEvent(XEvent *event) case ConfigureNotify: { + if (!window->x11.overrideRedirect && !event->xany.send_event) + return; + if (event->xconfigure.width != window->x11.width || event->xconfigure.height != window->x11.height) { From 5dc9d0f5810864c4048abd2cf2b8ae00e0c26470 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 28 Feb 2016 18:41:10 +0100 Subject: [PATCH 060/156] Avoid X11 frame size query of undecorated windows This also works around an issue where Xfwm4 ignores Motif hints when calculating frame extents. --- src/x11_window.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/x11_window.c b/src/x11_window.c index 1ee5f1ff7..65cc8a55c 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1678,6 +1678,9 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, { long* extents = NULL; + if (window->monitor || !window->decorated) + return; + if (_glfw.x11.NET_FRAME_EXTENTS == None) return; From b2d2e30ac8a60c1a5f17e3ed2f58687102414abe Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 28 Feb 2016 19:16:50 +0100 Subject: [PATCH 061/156] Make windows test wait for events --- tests/windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/windows.c b/tests/windows.c index b0d15e7fe..89a4b2249 100644 --- a/tests/windows.c +++ b/tests/windows.c @@ -130,7 +130,7 @@ int main(int argc, char** argv) running = GLFW_FALSE; } - glfwPollEvents(); + glfwWaitEvents(); } glfwTerminate(); From da446259707a370b7c7dbb6eed6e03619709cc40 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 29 Feb 2016 13:19:27 +0100 Subject: [PATCH 062/156] Cleanup --- tests/glfwinfo.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index d74b49fd0..806763550 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -806,9 +806,7 @@ int main(int argc, char** argv) putchar('\n'); if (list_extensions) - { list_vulkan_instance_extensions(); - } if (list_layers) list_vulkan_instance_layers(); From 5fa7e2faa4a301c5e407b81ca89c855be8ea3372 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 1 Mar 2016 19:36:05 +0100 Subject: [PATCH 063/156] Release autorelease pool last --- src/cocoa_init.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 0d990a8de..16b8c9f9f 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -265,9 +265,6 @@ void _glfwPlatformTerminate(void) _glfw.ns.delegate = nil; } - [_glfw.ns.autoreleasePool release]; - _glfw.ns.autoreleasePool = nil; - [_glfw.ns.cursor release]; _glfw.ns.cursor = nil; @@ -276,6 +273,9 @@ void _glfwPlatformTerminate(void) _glfwTerminateNSGL(); _glfwTerminateJoysticksNS(); _glfwTerminateThreadLocalStoragePOSIX(); + + [_glfw.ns.autoreleasePool release]; + _glfw.ns.autoreleasePool = nil; } const char* _glfwPlatformGetVersionString(void) From de2d4c77639968780b14c7d4604f4a28f2519286 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 2 Mar 2016 17:58:05 +0100 Subject: [PATCH 064/156] Clarify pointer assertions --- src/context.c | 6 +++--- src/input.c | 42 +++++++++++++++++++------------------- src/monitor.c | 20 +++++++++--------- src/vulkan.c | 4 ++-- src/window.c | 56 +++++++++++++++++++++++++-------------------------- 5 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/context.c b/src/context.c index 455beeabd..c06018962 100644 --- a/src/context.c +++ b/src/context.c @@ -567,7 +567,7 @@ GLFWAPI GLFWwindow* glfwGetCurrentContext(void) GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -597,7 +597,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) { _GLFWwindow* window; - assert(extension); + assert(extension != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); @@ -661,7 +661,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) { - assert(procname); + assert(procname != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); diff --git a/src/input.c b/src/input.c index 01184c324..be93e39b0 100644 --- a/src/input.c +++ b/src/input.c @@ -240,7 +240,7 @@ GLFWbool _glfwIsPrintable(int key) GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(0); @@ -261,7 +261,7 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -291,7 +291,7 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode) GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); @@ -314,7 +314,7 @@ GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); @@ -338,7 +338,7 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); if (xpos) *xpos = 0; @@ -361,7 +361,7 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -385,7 +385,7 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) { _GLFWcursor* cursor; - assert(image); + assert(image != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -471,7 +471,7 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) { _GLFWwindow* window = (_GLFWwindow*) windowHandle; _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -483,7 +483,7 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun); @@ -493,7 +493,7 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun); @@ -503,7 +503,7 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun); @@ -514,7 +514,7 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, GLFWmousebuttonfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun); @@ -525,7 +525,7 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, GLFWcursorposfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun); @@ -536,7 +536,7 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, GLFWcursorenterfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun); @@ -547,7 +547,7 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, GLFWscrollfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun); @@ -557,7 +557,7 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun); @@ -579,7 +579,7 @@ GLFWAPI int glfwJoystickPresent(int joy) GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count) { - assert(count); + assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -595,7 +595,7 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count) GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count) { - assert(count); + assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -625,9 +625,9 @@ GLFWAPI const char* glfwGetJoystickName(int joy) GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); - assert(string); + assert(string != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformSetClipboardString(window, string); @@ -636,7 +636,7 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return _glfwPlatformGetClipboardString(window); diff --git a/src/monitor.c b/src/monitor.c index 1aebf0ba8..a17c1f634 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -294,7 +294,7 @@ void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) GLFWAPI GLFWmonitor** glfwGetMonitors(int* count) { - assert(count); + assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -316,7 +316,7 @@ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void) GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - assert(monitor); + assert(monitor != NULL); if (xpos) *xpos = 0; @@ -331,7 +331,7 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - assert(monitor); + assert(monitor != NULL); if (widthMM) *widthMM = 0; @@ -349,7 +349,7 @@ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - assert(monitor); + assert(monitor != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return monitor->name; @@ -365,9 +365,9 @@ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - assert(monitor); + assert(monitor != NULL); - assert(count); + assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -382,7 +382,7 @@ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count) GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - assert(monitor); + assert(monitor != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -431,7 +431,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - assert(monitor); + assert(monitor != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -444,9 +444,9 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - assert(monitor); + assert(monitor != NULL); - assert(ramp); + assert(ramp != NULL); _GLFW_REQUIRE_INIT(); diff --git a/src/vulkan.c b/src/vulkan.c index 51bba9714..b4712127c 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -262,9 +262,9 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, VkSurfaceKHR* surface) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); - assert(surface); + assert(surface != NULL); *surface = VK_NULL_HANDLE; _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED); diff --git a/src/window.c b/src/window.c index daff54869..2dbec86d4 100644 --- a/src/window.c +++ b/src/window.c @@ -125,7 +125,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, _GLFWwindow* window; _GLFWwindow* previous; - assert(title); + assert(title != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -420,7 +420,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(0); return window->closed; @@ -429,7 +429,7 @@ GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); window->closed = value; @@ -438,9 +438,9 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value) GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); - assert(title); + assert(title != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformSetWindowTitle(window, title); @@ -449,7 +449,7 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); if (xpos) *xpos = 0; @@ -463,7 +463,7 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -480,7 +480,7 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); if (width) *width = 0; @@ -494,7 +494,7 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -512,7 +512,7 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, int maxwidth, int maxheight) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -527,7 +527,7 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -562,7 +562,7 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, int* right, int* bottom) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); if (left) *left = 0; @@ -580,7 +580,7 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformIconifyWindow(window); @@ -589,7 +589,7 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformRestoreWindow(window); @@ -605,7 +605,7 @@ GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) GLFWAPI void glfwShowWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -618,7 +618,7 @@ GLFWAPI void glfwShowWindow(GLFWwindow* handle) GLFWAPI void glfwHideWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -631,7 +631,7 @@ GLFWAPI void glfwHideWindow(GLFWwindow* handle) GLFWAPI void glfwFocusWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -641,7 +641,7 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* handle) GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(0); @@ -690,7 +690,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return (GLFWmonitor*) window->monitor; @@ -699,7 +699,7 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT(); window->userPointer = pointer; @@ -708,7 +708,7 @@ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return window->userPointer; @@ -718,7 +718,7 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, GLFWwindowposfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun); @@ -729,7 +729,7 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, GLFWwindowsizefun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun); @@ -740,7 +740,7 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, GLFWwindowclosefun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun); @@ -751,7 +751,7 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, GLFWwindowrefreshfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun); @@ -762,7 +762,7 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, GLFWwindowfocusfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun); @@ -773,7 +773,7 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, GLFWwindowiconifyfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun); @@ -784,7 +784,7 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle GLFWframebuffersizefun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window); + assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun); From 663ee327b0cba9455c0cb40da830b59a76e69d75 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 2 Mar 2016 23:14:55 +0100 Subject: [PATCH 065/156] Decrease amount of Hocus Pocus --- src/x11_window.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 65cc8a55c..e106fc40b 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -976,12 +976,13 @@ static void processEvent(XEvent *event) next.xkey.window == event->xkey.window && next.xkey.keycode == keycode) { - // HACK: Repeat events sometimes leak through due to - // some sort of time drift, so add an epsilon - // Toshiyuki Takahashi can press a button 16 times - // per second so it's fairly safe to assume that - // no human is pressing the key 50 times per - // second (value is ms) + // HACK: The time of repeat events sometimes doesn't + // match that of the press event, so add an + // epsilon + // Toshiyuki Takahashi can press a button + // 16 times per second so it's fairly safe to + // assume that no human is pressing the key 50 + // times per second (value is ms) if ((next.xkey.time - event->xkey.time) < 20) { // This is very likely a server-generated key repeat From 3c9142f37ec38189677f9a368e8ee1b775c97aae Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sat, 5 Mar 2016 23:56:40 +0100 Subject: [PATCH 066/156] Add check for VULKAN_SDK envvar on Windows The LunarG SDK will be standardizing on this name. --- CMake/modules/FindVulkan.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMake/modules/FindVulkan.cmake b/CMake/modules/FindVulkan.cmake index ce8a762af..75cc25c79 100644 --- a/CMake/modules/FindVulkan.cmake +++ b/CMake/modules/FindVulkan.cmake @@ -6,12 +6,15 @@ if (WIN32) find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS + "$ENV{VULKAN_SDK}/Include" "$ENV{VK_SDK_PATH}/Include") if (CMAKE_CL_64) find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS + "$ENV{VULKAN_SDK}/Bin" "$ENV{VK_SDK_PATH}/Bin") else() find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS + "$ENV{VULKAN_SDK}/Bin32" "$ENV{VK_SDK_PATH}/Bin32") endif() else() From 8221aadea3c89541ed85fd17625dca3991c34a14 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 6 Mar 2016 09:40:16 +0100 Subject: [PATCH 067/156] Include stddef.h unconditionally in public header --- include/GLFW/glfw3.h | 5 ++--- src/internal.h | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 68d005dd1..9259f55e0 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -117,10 +117,9 @@ extern "C" { /* Most Windows GLU headers need wchar_t. * The OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. */ -#if !defined(GLFW_INCLUDE_NONE) - #include -#endif +#include /* Include the chosen client API headers. */ diff --git a/src/internal.h b/src/internal.h index 48488233f..cbc04828c 100644 --- a/src/internal.h +++ b/src/internal.h @@ -47,8 +47,6 @@ #define GLFW_INCLUDE_NONE #include "../include/GLFW/glfw3.h" -#include - #if defined(_MSC_VER) && (_MSC_VER < 1600) typedef unsigned __int64 GLFWuint64; #else From 31f67dd3cc5dbcb5ce973353060926e2344dd535 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 6 Mar 2016 11:38:55 +0100 Subject: [PATCH 068/156] Add glfwGetTimerValue and glfwGetTimerFrequency This adds raw timer access to the public API and builds the floating-point time functions on top. It also makes the GLFWuint64 type public. --- README.md | 2 ++ docs/input.dox | 15 ++++++++++++ docs/news.dox | 6 +++++ include/GLFW/glfw3.h | 54 ++++++++++++++++++++++++++++++++++++++++++++ src/cocoa_platform.h | 3 +-- src/cocoa_time.c | 21 ++++------------- src/init.c | 2 ++ src/input.c | 18 +++++++++++++-- src/internal.h | 17 +++++--------- src/posix_time.c | 52 ++++++++++++++++-------------------------- src/posix_time.h | 3 +-- src/win32_platform.h | 3 +-- src/win32_time.c | 40 ++++++++++++-------------------- src/x11_window.c | 8 ++++--- 14 files changed, 148 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index 4cf5858da..3362aa07d 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ does not find Doxygen, the documentation will not be generated. absolute and relative window size limits - Added `glfwGetKeyName` for querying the layout-specific name of printable keys + - Added `glfwGetTimerValue` and `glfwGetTimerFrequency` for raw timer access + - Added `GLFWuint64` for platform-independent 64-bit unsigned values - Added `GLFW_NO_API` for creating window without contexts - Added `GLFW_CONTEXT_NO_ERROR` context hint for `GL_KHR_no_error` support - Added `GLFW_INCLUDE_VULKAN` for including the Vulkan header diff --git a/docs/input.dox b/docs/input.dox index 136319b92..2be3d0231 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -554,6 +554,21 @@ glfwSetTime(4.0); This sets the timer to the specified time, in seconds. +You can also access the raw timer value, in 1 / frequency seconds, +with @ref glfwGetTimerValue. + +@code +GLFWuint64 value = glfwGetTimerValue(); +@endcode + +The frequency of the raw timer varies depending on what time sources are +available on the machine. You can query its frequency, in Hz, with @ref +glfwGetTimerFrequency. + +@code +GLFWuint64 freqency = glfwGetTimerFrequency(); +@endcode + @section clipboard Clipboard input and output diff --git a/docs/news.dox b/docs/news.dox index 6bf800acd..71e29d573 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -37,6 +37,12 @@ GLFW now supports window maximization with @ref glfwMaximizeWindow and the GLFW now supports giving windows input focus with @ref glfwFocusWindow. +@subsection news_32_timer Raw timer access + +GLFW now supports raw timer values with @ref glfwGetTimerValue and @ref +glfwGetTimerFrequency. + + @section news_31 New features in 3.1 These are the release highlights. For a full list of changes see the diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 9259f55e0..85510d641 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -728,6 +728,19 @@ extern "C" { * GLFW API types *************************************************************************/ +/*! @brief 64-bit unsigned integer. + * + * 64-bit unsigned integer. + * + * @since Added in version 3.2. + */ +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef unsigned __int64 GLFWuint64; +#else + #include +typedef uint64_t GLFWuint64; +#endif + /*! @brief Client API function pointer type. * * Generic function pointer used for returning client API function pointers @@ -3557,6 +3570,47 @@ GLFWAPI double glfwGetTime(void); */ GLFWAPI void glfwSetTime(double time); +/*! @brief Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer. To get its + * frequency, call @ref glfwGetTimerFrequency. + * + * @return The value of the timer, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerFrequency + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWuint64 glfwGetTimerValue(void); + +/*! @brief Returns the frequency, in Hz, of the raw timer. + * + * @return The frequency of the timer, in Hz, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerValue + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWuint64 glfwGetTimerFrequency(void); + /*! @brief Makes the context of the specified window current for the calling * thread. * diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 212a8ad8a..bb52252d7 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -118,8 +118,7 @@ typedef struct _GLFWcursorNS // typedef struct _GLFWtimeNS { - double base; - double resolution; + GLFWuint64 frequency; } _GLFWtimeNS; diff --git a/src/cocoa_time.c b/src/cocoa_time.c index 1a644868b..20b938d78 100644 --- a/src/cocoa_time.c +++ b/src/cocoa_time.c @@ -29,14 +29,6 @@ #include -// Return raw time -// -static uint64_t getRawTime(void) -{ - return mach_absolute_time(); -} - - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -48,8 +40,7 @@ void _glfwInitTimerNS(void) mach_timebase_info_data_t info; mach_timebase_info(&info); - _glfw.ns_time.resolution = (double) info.numer / (info.denom * 1.0e9); - _glfw.ns_time.base = getRawTime(); + _glfw.ns_time.frequency = (info.denom * 1e9) / info.numer; } @@ -57,15 +48,13 @@ void _glfwInitTimerNS(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -double _glfwPlatformGetTime(void) +GLFWuint64 _glfwPlatformGetTimerValue(void) { - return (double) (getRawTime() - _glfw.ns_time.base) * - _glfw.ns_time.resolution; + return mach_absolute_time(); } -void _glfwPlatformSetTime(double time) +GLFWuint64 _glfwPlatformGetTimerFrequency(void) { - _glfw.ns_time.base = getRawTime() - - (uint64_t) (time / _glfw.ns_time.resolution); + return _glfw.ns_time.frequency; } diff --git a/src/init.c b/src/init.c index 06b097121..3674dcf01 100644 --- a/src/init.c +++ b/src/init.c @@ -135,6 +135,8 @@ GLFWAPI int glfwInit(void) _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); _glfwInitialized = GLFW_TRUE; + _glfw.timerOffset = _glfwPlatformGetTimerValue(); + // Not all window hints have zero as their default value glfwDefaultWindowHints(); diff --git a/src/input.c b/src/input.c index be93e39b0..368a55696 100644 --- a/src/input.c +++ b/src/input.c @@ -645,7 +645,8 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) GLFWAPI double glfwGetTime(void) { _GLFW_REQUIRE_INIT_OR_RETURN(0.0); - return _glfwPlatformGetTime(); + return (double) (_glfwPlatformGetTimerValue() - _glfw.timerOffset) / + _glfwPlatformGetTimerFrequency(); } GLFWAPI void glfwSetTime(double time) @@ -658,6 +659,19 @@ GLFWAPI void glfwSetTime(double time) return; } - _glfwPlatformSetTime(time); + _glfw.timerOffset = _glfwPlatformGetTimerValue() - + (GLFWuint64) (time * _glfwPlatformGetTimerFrequency()); +} + +GLFWAPI GLFWuint64 glfwGetTimerValue(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformGetTimerValue(); +} + +GLFWAPI GLFWuint64 glfwGetTimerFrequency(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformGetTimerFrequency(); } diff --git a/src/internal.h b/src/internal.h index cbc04828c..68e2d7d1c 100644 --- a/src/internal.h +++ b/src/internal.h @@ -47,13 +47,6 @@ #define GLFW_INCLUDE_NONE #include "../include/GLFW/glfw3.h" -#if defined(_MSC_VER) && (_MSC_VER < 1600) -typedef unsigned __int64 GLFWuint64; -#else - #include -typedef uint64_t GLFWuint64; -#endif - typedef int GLFWbool; typedef struct _GLFWwndconfig _GLFWwndconfig; @@ -432,6 +425,8 @@ struct _GLFWlibrary _GLFWmonitor** monitors; int monitorCount; + GLFWuint64 timerOffset; + struct { GLFWbool available; void* handle; @@ -596,15 +591,15 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count); */ const char* _glfwPlatformGetJoystickName(int joy); -/*! @copydoc glfwGetTime +/*! @copydoc glfwGetTimerValue * @ingroup platform */ -double _glfwPlatformGetTime(void); +GLFWuint64 _glfwPlatformGetTimerValue(void); -/*! @copydoc glfwSetTime +/*! @copydoc glfwGetTimerFrequency * @ingroup platform */ -void _glfwPlatformSetTime(double time); +GLFWuint64 _glfwPlatformGetTimerFrequency(void); /*! @ingroup platform */ diff --git a/src/posix_time.c b/src/posix_time.c index ac664124e..228f2f7e0 100644 --- a/src/posix_time.c +++ b/src/posix_time.c @@ -30,28 +30,6 @@ #include #include -// Return raw time -// -static uint64_t getRawTime(void) -{ -#if defined(CLOCK_MONOTONIC) - if (_glfw.posix_time.monotonic) - { - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; - } - else -#endif - { - struct timeval tv; - - gettimeofday(&tv, NULL); - return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; - } -} - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -67,15 +45,14 @@ void _glfwInitTimerPOSIX(void) if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { _glfw.posix_time.monotonic = GLFW_TRUE; - _glfw.posix_time.resolution = 1e-9; + _glfw.posix_time.frequency = 1000000000; } else #endif { - _glfw.posix_time.resolution = 1e-6; + _glfw.posix_time.monotonic = GLFW_FALSE; + _glfw.posix_time.frequency = 1000000; } - - _glfw.posix_time.base = getRawTime(); } @@ -83,15 +60,26 @@ void _glfwInitTimerPOSIX(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -double _glfwPlatformGetTime(void) +GLFWuint64 _glfwPlatformGetTimerValue(void) { - return (double) (getRawTime() - _glfw.posix_time.base) * - _glfw.posix_time.resolution; +#if defined(CLOCK_MONOTONIC) + if (_glfw.posix_time.monotonic) + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; + } + else +#endif + { + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; + } } -void _glfwPlatformSetTime(double time) +GLFWuint64 _glfwPlatformGetTimerFrequency(void) { - _glfw.posix_time.base = getRawTime() - - (uint64_t) (time / _glfw.posix_time.resolution); + return _glfw.posix_time.frequency; } diff --git a/src/posix_time.h b/src/posix_time.h index b3061fda9..31591737d 100644 --- a/src/posix_time.h +++ b/src/posix_time.h @@ -38,8 +38,7 @@ typedef struct _GLFWtimePOSIX { GLFWbool monotonic; - double resolution; - uint64_t base; + GLFWuint64 frequency; } _GLFWtimePOSIX; diff --git a/src/win32_platform.h b/src/win32_platform.h index 47b4999a6..4ac274b6a 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -277,8 +277,7 @@ typedef struct _GLFWcursorWin32 typedef struct _GLFWtimeWin32 { GLFWbool hasPC; - double resolution; - unsigned __int64 base; + GLFWuint64 frequency; } _GLFWtimeWin32; diff --git a/src/win32_time.c b/src/win32_time.c index c8bb61f82..ec6294dbb 100644 --- a/src/win32_time.c +++ b/src/win32_time.c @@ -28,21 +28,6 @@ #include "internal.h" -// Return raw time -// -static unsigned __int64 getRawTime(void) -{ - if (_glfw.win32_time.hasPC) - { - unsigned __int64 time; - QueryPerformanceCounter((LARGE_INTEGER*) &time); - return time; - } - else - return (unsigned __int64) _glfw_timeGetTime(); -} - - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -51,20 +36,18 @@ static unsigned __int64 getRawTime(void) // void _glfwInitTimerWin32(void) { - unsigned __int64 frequency; + GLFWuint64 frequency; if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) { _glfw.win32_time.hasPC = GLFW_TRUE; - _glfw.win32_time.resolution = 1.0 / (double) frequency; + _glfw.win32_time.frequency = frequency; } else { _glfw.win32_time.hasPC = GLFW_FALSE; - _glfw.win32_time.resolution = 0.001; // winmm resolution is 1 ms + _glfw.win32_time.frequency = 1000; } - - _glfw.win32_time.base = getRawTime(); } @@ -72,15 +55,20 @@ void _glfwInitTimerWin32(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -double _glfwPlatformGetTime(void) +GLFWuint64 _glfwPlatformGetTimerValue(void) { - return (double) (getRawTime() - _glfw.win32_time.base) * - _glfw.win32_time.resolution; + if (_glfw.win32_time.hasPC) + { + GLFWuint64 value; + QueryPerformanceCounter((LARGE_INTEGER*) &value); + return value; + } + else + return (GLFWuint64) _glfw_timeGetTime(); } -void _glfwPlatformSetTime(double time) +GLFWuint64 _glfwPlatformGetTimerFrequency(void) { - _glfw.win32_time.base = getRawTime() - - (unsigned __int64) (time / _glfw.win32_time.resolution); + return _glfw.win32_time.frequency; } diff --git a/src/x11_window.c b/src/x11_window.c index e106fc40b..5c347694d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1688,7 +1688,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, if (!_glfwPlatformWindowVisible(window) && _glfw.x11.NET_REQUEST_FRAME_EXTENTS) { - double base; + GLFWuint64 base; XEvent event; // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to @@ -1696,13 +1696,14 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS, 0, 0, 0, 0, 0); + base = _glfwPlatformGetTimerValue(); + // HACK: Poll with timeout for the required reply instead of blocking // This is done because some window managers (at least Unity, // Fluxbox and Xfwm) failed to send the required reply // They have been fixed but broken versions are still in the wild // If you are affected by this and your window manager is NOT // listed above, PLEASE report it to their and our issue trackers - base = _glfwPlatformGetTime(); while (!XCheckIfEvent(_glfw.x11.display, &event, isFrameExtentsEvent, @@ -1711,7 +1712,8 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, double remaining; struct timeval timeout; - remaining = 0.5 + base - _glfwPlatformGetTime(); + remaining = 0.5 - (_glfwPlatformGetTimerValue() - base) / + (double) _glfwPlatformGetTimerFrequency(); if (remaining <= 0.0) { _glfwInputError(GLFW_PLATFORM_ERROR, From 487557b343d01ee7e543e0465311e5cddbef1b10 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 6 Mar 2016 11:43:02 +0100 Subject: [PATCH 069/156] Relax thread constraints for glfwSetTime --- include/GLFW/glfw3.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 85510d641..5e653423a 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3534,8 +3534,8 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. + * @thread_safety This function may be called from any thread. Reading of the + * internal timer offset is not atomic. * * @sa @ref time * @@ -3560,7 +3560,8 @@ GLFWAPI double glfwGetTime(void); * floor((264 - 1) / 109) and is due to implementations * storing nanoseconds in 64 bits. The limit may be increased in the future. * - * @thread_safety This function must only be called from the main thread. + * @thread_safety This function may be called from any thread. Writing of the + * internal timer offset is not atomic. * * @sa @ref time * From 9fb00f2ad05f87ac50bc13276e549371516b7a5e Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 6 Mar 2016 11:49:40 +0100 Subject: [PATCH 070/156] Fix speling --- docs/news.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/news.dox b/docs/news.dox index 71e29d573..87fd39648 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -26,7 +26,7 @@ Vulkan header inclusion can be selected with [GLFW_INCLUDE_VULKAN](@ref build_macros). -@subsection news_32_maximize Window maxmimization supprot +@subsection news_32_maximize Window maxmimization support GLFW now supports window maximization with @ref glfwMaximizeWindow and the [GLFW_MAXIMIZED](@ref window_attribs_wnd) window hint and attribute. From 26cfd75d05a2794fc32daed70db26e942f6227be Mon Sep 17 00:00:00 2001 From: Ian Clarkson Date: Sat, 5 Mar 2016 11:52:37 -0500 Subject: [PATCH 071/156] Add Xcode CMake output patterns to .gitignore Closes #722. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index c2450f75c..5556381be 100644 --- a/.gitignore +++ b/.gitignore @@ -13,11 +13,13 @@ Debug Release MinSizeRel RelWithDebInfo +*.xcodeproj # CMake files Makefile CMakeCache.txt CMakeFiles +CMakeScripts cmake_install.cmake cmake_uninstall.cmake From 337c77a39b2f9148106e573d0705c44f6616f9f6 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 6 Mar 2016 14:11:14 +0100 Subject: [PATCH 072/156] Documentation work --- docs/input.dox | 4 ++-- include/GLFW/glfw3.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/input.dox b/docs/input.dox index 2be3d0231..b0fc9f295 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -554,8 +554,8 @@ glfwSetTime(4.0); This sets the timer to the specified time, in seconds. -You can also access the raw timer value, in 1 / frequency seconds, -with @ref glfwGetTimerValue. +You can also access the raw timer value, measured in 1 / frequency +seconds, with @ref glfwGetTimerValue. @code GLFWuint64 value = glfwGetTimerValue(); diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 5e653423a..7199da8cc 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3573,8 +3573,9 @@ GLFWAPI void glfwSetTime(double time); /*! @brief Returns the current value of the raw timer. * - * This function returns the current value of the raw timer. To get its - * frequency, call @ref glfwGetTimerFrequency. + * This function returns the current value of the raw timer, measured in + * 1 / frequency seconds. To get the frequency, call @ref + * glfwGetTimerFrequency. * * @return The value of the timer, or zero if an * [error](@ref error_handling) occurred. From 5620895e8818ad4afc26913b6cb52ce88d1a2f24 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 2 Feb 2016 21:11:16 +0100 Subject: [PATCH 073/156] Add glfwWaitEventsTimeout This function will put the calling thread to sleep until an event arrives or until the specified timeout has elapsed. --- README.md | 1 + docs/input.dox | 11 ++++++++++ docs/news.dox | 6 ++++++ include/GLFW/glfw3.h | 48 ++++++++++++++++++++++++++++++++++++++++++++ src/cocoa_window.m | 13 ++++++++++++ src/internal.h | 5 +++++ src/mir_window.c | 18 +++++++++++++++++ src/win32_window.c | 7 +++++++ src/window.c | 14 +++++++++++++ src/wl_window.c | 5 +++++ src/x11_window.c | 22 ++++++++++++++++++++ 11 files changed, 150 insertions(+) diff --git a/README.md b/README.md index 3362aa07d..257068cdf 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ does not find Doxygen, the documentation will not be generated. absolute and relative window size limits - Added `glfwGetKeyName` for querying the layout-specific name of printable keys + - Added `glfwWaitEventsTimeout` for waiting for events for a set amount of time - Added `glfwGetTimerValue` and `glfwGetTimerFrequency` for raw timer access - Added `GLFWuint64` for platform-independent 64-bit unsigned values - Added `GLFW_NO_API` for creating window without contexts diff --git a/docs/input.dox b/docs/input.dox index b0fc9f295..89587d3db 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -58,6 +58,17 @@ processes all received events. This saves a great deal of CPU cycles and is useful for, for example, editing tools. There must be at least one GLFW window for this function to sleep. +If you want to wait for events but have UI elements that need periodic updates, +call @ref glfwWaitEventsTimeout. + +@code +glfwWaitEventsTimeout(0.7); +@endcode + +It puts the thread to sleep until at least one event has been received, or until +the specified number of seconds have elapsed. It then processes any received +events. + If the main thread is sleeping in @ref glfwWaitEvents, you can wake it from another thread by posting an empty event to the event queue with @ref glfwPostEmptyEvent. diff --git a/docs/news.dox b/docs/news.dox index 87fd39648..b1d0e30da 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -43,6 +43,12 @@ GLFW now supports raw timer values with @ref glfwGetTimerValue and @ref glfwGetTimerFrequency. +@subsection news_32_waittimeout Wait for events with timeout + +GLFW now supports waiting for events for a set amount of time with @ref +glfwWaitEventsTimeout. + + @section news_31 New features in 3.1 These are the release highlights. For a full list of changes see the diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 7199da8cc..8abe5f3bf 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2633,6 +2633,7 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window * * @sa @ref events * @sa glfwWaitEvents + * @sa glfwWaitEventsTimeout * * @since Added in version 1.0. * @@ -2677,6 +2678,7 @@ GLFWAPI void glfwPollEvents(void); * * @sa @ref events * @sa glfwPollEvents + * @sa glfwWaitEventsTimeout * * @since Added in version 2.5. * @@ -2684,6 +2686,52 @@ GLFWAPI void glfwPollEvents(void); */ GLFWAPI void glfwWaitEvents(void); +/*! @brief Waits with timeout until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue, or until the specified timeout is reached. If + * one or more events are available, it behaves exactly like @ref + * glfwPollEvents, i.e. the events in the queue are processed and the function + * then returns immediately. Processing events will cause the window and input + * callbacks associated with those events to be called. + * + * The timeout value must be a positive finite number. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * Event processing is not required for joystick input to work. + * + * @param[in] timeout The maximum amount of time, in seconds, to wait. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa glfwPollEvents + * @sa glfwWaitEvents + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEventsTimeout(double timeout); + /*! @brief Posts an empty event to the event queue. * * This function posts an empty event from the current thread to the event diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 0086e8d00..7c3f56065 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1214,6 +1214,19 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout]; + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:date + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event) + [NSApp sendEvent:event]; + + _glfwPlatformPollEvents(); +} + void _glfwPlatformPostEmptyEvent(void) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; diff --git a/src/internal.h b/src/internal.h index 68e2d7d1c..c9ad097c6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -717,6 +717,11 @@ void _glfwPlatformPollEvents(void); */ void _glfwPlatformWaitEvents(void); +/*! @copydoc glfwWaitEventsTimeout + * @ingroup platform + */ +void _glfwPlatformWaitEventsTimeout(double timeout); + /*! @copydoc glfwPostEmptyEvent * @ingroup platform */ diff --git a/src/mir_window.c b/src/mir_window.c index 9d8f1fd3b..b3c3acf26 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -550,6 +550,24 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + pthread_mutex_lock(&_glfw.mir.event_mutex); + + if (emptyEventQueue(_glfw.mir.event_queue)) + { + struct timespec time; + clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += (long) timeout; + time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9); + pthread_cond_timedwait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex, &time); + } + + pthread_mutex_unlock(&_glfw.mir.event_mutex); + + _glfwPlatformPollEvents(); +} + void _glfwPlatformPostEmptyEvent(void) { } diff --git a/src/win32_window.c b/src/win32_window.c index 85a72ad95..7ee1c8a11 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1142,6 +1142,13 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS); + + _glfwPlatformPollEvents(); +} + void _glfwPlatformPostEmptyEvent(void) { _GLFWwindow* window = _glfw.windowListHead; diff --git a/src/window.c b/src/window.c index 2dbec86d4..8e055b3bd 100644 --- a/src/window.c +++ b/src/window.c @@ -31,6 +31,7 @@ #include #include #include +#include ////////////////////////////////////////////////////////////////////////// @@ -807,6 +808,19 @@ GLFWAPI void glfwWaitEvents(void) _glfwPlatformWaitEvents(); } +GLFWAPI void glfwWaitEventsTimeout(double timeout) +{ + _GLFW_REQUIRE_INIT(); + + if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time"); + return; + } + + _glfwPlatformWaitEventsTimeout(timeout); +} + GLFWAPI void glfwPostEmptyEvent(void) { _GLFW_REQUIRE_INIT(); diff --git a/src/wl_window.c b/src/wl_window.c index 1fe5b86a9..f1d5b520f 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -516,6 +516,11 @@ void _glfwPlatformWaitEvents(void) handleEvents(-1); } +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + handleEvents((int) (timeout * 1e3)); +} + void _glfwPlatformPostEmptyEvent(void) { wl_display_sync(_glfw.wl.display); diff --git a/src/x11_window.c b/src/x11_window.c index 5c347694d..c4bbf9f16 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1912,6 +1912,28 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + const double deadline = timeout + _glfwPlatformGetTimerValue() / + (double) _glfwPlatformGetTimerFrequency(); + + while (!XPending(_glfw.x11.display)) + { + const double remaining = deadline - _glfwPlatformGetTimerValue() / + (double) _glfwPlatformGetTimerFrequency(); + if (remaining <= 0.0) + return; + + const long seconds = (long) remaining; + const long microseconds = (long) ((remaining - seconds) * 1e6); + struct timeval tv = { seconds, microseconds }; + + selectDisplayConnection(&tv); + } + + _glfwPlatformPollEvents(); +} + void _glfwPlatformPostEmptyEvent(void) { XEvent event; From fca5a8ab4895f9f1aa428130c432b60ce05f395c Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 12:30:15 +0100 Subject: [PATCH 074/156] Fix Win32 custom cursor set for non-client area Udating the cursor via glfwSetCursor incorrectly included the non-client area of the window. --- src/win32_window.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/win32_window.c b/src/win32_window.c index 7ee1c8a11..0d0ec89ff 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1319,6 +1319,7 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { + RECT area; POINT pos; if (_glfw.cursorWindow != window) @@ -1333,6 +1334,13 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) if (WindowFromPoint(pos) != window->win32.handle) return; + GetClientRect(window->win32.handle, &area); + ClientToScreen(window->win32.handle, (POINT*) &area.left); + ClientToScreen(window->win32.handle, (POINT*) &area.right); + + if (!PtInRect(&area, pos)) + return; + if (cursor) SetCursor(cursor->win32.handle); else From 3b2e96e0b1eeca47e9ed1df76e6c50d00b8b6538 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 12:33:26 +0100 Subject: [PATCH 075/156] Improve cursor test animation Only set cursor when it's time for a new frame. Use glfwWaitEventsTimeout when waiting for events during animation. --- tests/cursor.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/cursor.c b/tests/cursor.c index cbd5f0ee8..f1bcc42f5 100644 --- a/tests/cursor.c +++ b/tests/cursor.c @@ -195,6 +195,7 @@ int main(void) int i; GLFWwindow* window; GLFWcursor* star_cursors[CURSOR_FRAME_COUNT]; + GLFWcursor* current_frame = NULL; glfwSetErrorCallback(error_callback); @@ -279,11 +280,22 @@ int main(void) if (animate_cursor) { const int i = (int) (glfwGetTime() * 30.0) % CURSOR_FRAME_COUNT; - glfwSetCursor(window, star_cursors[i]); + if (current_frame != star_cursors[i]) + { + glfwSetCursor(window, star_cursors[i]); + current_frame = star_cursors[i]; + } } + else + current_frame = NULL; if (wait_events) - glfwWaitEvents(); + { + if (animate_cursor) + glfwWaitEventsTimeout(1.0 / 30.0); + else + glfwWaitEvents(); + } else glfwPollEvents(); From 9f890bb6fa43caee654973612a457228aeae81b5 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 13:31:23 +0100 Subject: [PATCH 076/156] Add decoration option to multi-window test --- tests/CMakeLists.txt | 2 +- tests/windows.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index adf3004f6..3674bf4a7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,7 +34,7 @@ add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c ${GLAD}) add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT} ${GLAD}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD}) add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD}) -add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${GLAD}) +add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${GETOPT} ${GLAD}) target_link_libraries(empty "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") target_link_libraries(threads "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") diff --git a/tests/windows.c b/tests/windows.c index 89a4b2249..21db08d5c 100644 --- a/tests/windows.c +++ b/tests/windows.c @@ -33,6 +33,8 @@ #include #include +#include "getopt.h" + static const char* titles[] = { "Red", @@ -52,6 +54,14 @@ static const struct { 0.98f, 0.74f, 0.04f } }; +static void usage(void) +{ + printf("Usage: windows [-h] [-b]\n"); + printf("Options:\n"); + printf(" -b create decorated windows\n"); + printf(" -h show this help\n"); +} + static void error_callback(int error, const char* description) { fprintf(stderr, "Error: %s\n", description); @@ -80,16 +90,33 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, int main(int argc, char** argv) { - int i; + int i, ch; + int decorated = GLFW_FALSE; int running = GLFW_TRUE; GLFWwindow* windows[4]; + while ((ch = getopt(argc, argv, "bh")) != -1) + { + switch (ch) + { + case 'b': + decorated = GLFW_TRUE; + break; + case 'h': + usage(); + exit(EXIT_SUCCESS); + default: + usage(); + exit(EXIT_FAILURE); + } + } + glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(EXIT_FAILURE); - glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); + glfwWindowHint(GLFW_DECORATED, decorated); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); for (i = 0; i < 4; i++) From 46fce40fd5a5dafbc2fe1a243d6451423dfed6c2 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 13:35:37 +0100 Subject: [PATCH 077/156] Fix error lists for raw timer functions --- include/GLFW/glfw3.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 8abe5f3bf..712f006d7 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3628,8 +3628,7 @@ GLFWAPI void glfwSetTime(double time); * @return The value of the timer, or zero if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_VALUE. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. * @@ -3647,8 +3646,7 @@ GLFWAPI GLFWuint64 glfwGetTimerValue(void); * @return The frequency of the timer, in Hz, or zero if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_VALUE. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. * From defaea34965d50d161fd8a9f0e5bf5c9b91409fa Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 13:36:54 +0100 Subject: [PATCH 078/156] Documentation work --- include/GLFW/glfw3.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 712f006d7..ce381fe30 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3642,6 +3642,8 @@ GLFWAPI void glfwSetTime(double time); GLFWAPI GLFWuint64 glfwGetTimerValue(void); /*! @brief Returns the frequency, in Hz, of the raw timer. + * + * This function returns the frequency, in Hz, of the raw timer. * * @return The frequency of the timer, in Hz, or zero if an * [error](@ref error_handling) occurred. From ee33dcdf333830b7afe230494384a4ecf27854fb Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 14:42:51 +0100 Subject: [PATCH 079/156] Fix speling [ci skip] --- docs/compile.dox | 2 +- include/GLFW/glfw3.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/compile.dox b/docs/compile.dox index 4bcc623c8..e1646711b 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -166,7 +166,7 @@ available on all supported platforms. Some of these are de facto standards among projects using CMake and so have no `GLFW_` prefix. If you are using the GUI version of CMake, these are listed and can be changed -from there. If you are using the command-line versionof CMake you can use the +from there. If you are using the command-line version of CMake you can use the `ccmake` ncurses GUI to set options. Some package systems like Ubuntu and other distributions based on Debian GNU/Linux have this tool in a separate `cmake-curses-gui` package. diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index ce381fe30..06b64f0c3 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4059,7 +4059,7 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhys * @remarks If an error occurs before the creation call is made, GLFW returns * the Vulkan error code most appropriate for the error. Appropriate use of * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should - * elminiate almost all occurences of these errors. + * eliminate almost all occurrences of these errors. * * @thread_safety This function may be called from any thread. For * synchronization details of Vulkan objects, see the Vulkan specification. From 1e51813d0537c80ae9252fafd29ee0e7235cdb51 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 15:00:31 +0100 Subject: [PATCH 080/156] Fix incorrect changelog term --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 257068cdf..0b673afc9 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ does not find Doxygen, the documentation will not be generated. - [POSIX] Bugfix: An unrelated TLS key could be deleted by `glfwTerminate` - [WGL] Changed extension loading to only be performed once - [WGL] Removed dependency on external WGL headers - - [GLX] Replaced legacy renderable with `GLXWindow` + - [GLX] Replaced legacy drawable with `GLXWindow` - [GLX] Removed dependency on external GLX headers - [GLX] Bugfix: NetBSD does not provide `libGL.so.1` - [EGL] Added `_GLFW_USE_EGLPLATFORM_H` configuration macro for controlling From 793eef1d0a7e09bab2e9fcb89fd27c904e9bad17 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 8 Mar 2016 15:29:03 +0100 Subject: [PATCH 081/156] Fix missing word --- docs/intro.dox | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/intro.dox b/docs/intro.dox index b0be0a8b7..301185c4e 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -267,8 +267,8 @@ to keep track of the current context for each thread. 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 may be updated to allow -calls from any thread in future releases. +but functions that are currently limited to the main thread may be updated to +allow calls from any thread in future releases. @subsection compatibility Version compatibility From b823f7151e0155cdc7f2ee3f93ceaa01d6321c9f Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 14:55:30 +0100 Subject: [PATCH 082/156] Add glfwSetWindowIcon Adds support for setting window icons programmatically on platforms where this makes sense. Fixes #453. Closes #467. --- README.md | 3 + docs/news.dox | 5 ++ docs/window.dox | 20 +++++ include/GLFW/glfw3.h | 39 +++++++++ src/cocoa_window.m | 6 ++ src/internal.h | 5 ++ src/mir_window.c | 7 ++ src/win32_platform.h | 2 + src/win32_window.c | 200 +++++++++++++++++++++++++++++++------------ src/window.c | 12 +++ src/wl_window.c | 7 ++ src/x11_init.c | 2 + src/x11_platform.h | 1 + src/x11_window.c | 45 ++++++++++ 14 files changed, 299 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 0b673afc9..c65e854e1 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ does not find Doxygen, the documentation will not be generated. - Added `glfwGetKeyName` for querying the layout-specific name of printable keys - Added `glfwWaitEventsTimeout` for waiting for events for a set amount of time + - Added `glfwSetWindowIcon` for setting the icon of a window - Added `glfwGetTimerValue` and `glfwGetTimerFrequency` for raw timer access - Added `GLFWuint64` for platform-independent 64-bit unsigned values - Added `GLFW_NO_API` for creating window without contexts @@ -221,6 +222,7 @@ skills. - Peoro - Braden Pellett - Arturo J. Pérez + - Orson Peters - Emmanuel Gil Peyrot - Cyril Pichard - Pieroman @@ -246,6 +248,7 @@ skills. - TTK-Bandit - Sergey Tikhomirov - A. Tombs + - Ioannis Tsakpinis - Samuli Tuomola - urraka - Jari Vetoniemi diff --git a/docs/news.dox b/docs/news.dox index b1d0e30da..37c591e05 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -32,6 +32,11 @@ GLFW now supports window maximization with @ref glfwMaximizeWindow and the [GLFW_MAXIMIZED](@ref window_attribs_wnd) window hint and attribute. +@subsection news_32_icon Window icon support + +GLFW now supports setting the icon of windows with @ref glfwSetWindowIcon. + + @subsection news_32_focus Window input focus control GLFW now supports giving windows input focus with @ref glfwFocusWindow. diff --git a/docs/window.dox b/docs/window.dox index a40005d9d..17bba73ed 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -617,6 +617,26 @@ glfwSetWindowTitle(window, u8"This is always a UTF-8 string"); @endcode +@subsection window_icon Window icon + +Decorated windows have icons on some platforms. You can set this icon by +specifying a list of candidate images with @ref glfwSetWindowIcon. + +@code +GLFWimage images[2]; +images[0] = load_icon("my_icon.png"); +images[1] = load_icon("my_icon_small.png"); + +glfwSetWindowIcon(window, 2, images); +@endcode + +To revert to the default window icon, pass in an empty image array. + +@code +glfwSetWindowIcon(window, 0, NULL); +@endcode + + @subsection window_monitor Window monitor Full screen windows are associated with a specific monitor. You can get the diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 06b64f0c3..7557f1cfe 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1913,6 +1913,45 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); */ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); +/*! @brief Sets the icon for the specified window. + * + * This function sets the icon of the specified window. If passed an array of + * candidate images, those of or closest to the sizes desired by the system are + * selected. If no images are specified, the window reverts to its default + * icon. + * + * 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. + * + * @param[in] window The window whose icon to set. + * @param[in] count The number of images in the specified array, or zero to + * revert to the default window icon. + * @param[in] images The images to create the icon from. This is ignored if + * count is zero. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @remark @osx The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_icon + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); + /*! @brief Retrieves the position of the client area of the specified window. * * This function retrieves the position, in screen coordinates, of the diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 7c3f56065..c7d0a06d8 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1032,6 +1032,12 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) [window->ns.object setTitle:[NSString stringWithUTF8String:title]]; } +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + // Regular windows do not have icons +} + void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { const NSRect contentRect = diff --git a/src/internal.h b/src/internal.h index c9ad097c6..e1466dc52 100644 --- a/src/internal.h +++ b/src/internal.h @@ -617,6 +617,11 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window); */ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title); +/*! @copydoc glfwSetWindowIcon + * @ingroup platform + */ +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images); + /*! @copydoc glfwGetWindowPos * @ingroup platform */ diff --git a/src/mir_window.c b/src/mir_window.c index b3c3acf26..3b2560816 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -403,6 +403,13 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) mir_surface_spec_release(spec); } +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { MirSurfaceSpec* spec; diff --git a/src/win32_platform.h b/src/win32_platform.h index 4ac274b6a..433c45871 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -191,6 +191,8 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)( typedef struct _GLFWwindowWin32 { HWND handle; + HICON bigIcon; + HICON smallIcon; GLFWbool cursorTracked; GLFWbool iconified; diff --git a/src/win32_window.c b/src/win32_window.c index 0d0ec89ff..8d7e2ab76 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -27,6 +27,7 @@ #include "internal.h" +#include #include #include #include @@ -66,6 +67,112 @@ static DWORD getWindowExStyle(const _GLFWwindow* window) return style; } +// Returns the image whose area most closely matches the desired one +// +static const GLFWimage* chooseImage(int count, const GLFWimage* images, + int width, int height) +{ + int i, leastDiff = INT_MAX; + const GLFWimage* closest = NULL; + + for (i = 0; i < count; i++) + { + const int currDiff = abs(images[i].width * images[i].height - + width * height); + if (currDiff < leastDiff) + { + closest = images + i; + leastDiff = currDiff; + } + } + + return closest; +} + +// Creates an RGBA icon or cursor +// +static HICON createIcon(const GLFWimage* image, + int xhot, int yhot, GLFWbool icon) +{ + int i; + HDC dc; + HICON handle; + HBITMAP color, mask; + BITMAPV5HEADER bi; + ICONINFO ii; + unsigned char* target = NULL; + unsigned char* source = image->pixels; + + ZeroMemory(&bi, sizeof(bi)); + bi.bV5Size = sizeof(BITMAPV5HEADER); + bi.bV5Width = image->width; + bi.bV5Height = -image->height; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00ff0000; + bi.bV5GreenMask = 0x0000ff00; + bi.bV5BlueMask = 0x000000ff; + bi.bV5AlphaMask = 0xff000000; + + dc = GetDC(NULL); + color = CreateDIBSection(dc, + (BITMAPINFO*) &bi, + DIB_RGB_COLORS, + (void**) &target, + NULL, + (DWORD) 0); + ReleaseDC(NULL, dc); + + if (!color) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create RGBA bitmap"); + return NULL; + } + + mask = CreateBitmap(image->width, image->height, 1, 1, NULL); + if (!mask) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create mask bitmap"); + DeleteObject(color); + return NULL; + } + + for (i = 0; i < image->width * image->height; i++) + { + target[0] = source[2]; + target[1] = source[1]; + target[2] = source[0]; + target[3] = source[3]; + target += 4; + source += 4; + } + + ZeroMemory(&ii, sizeof(ii)); + ii.fIcon = icon; + ii.xHotspot = xhot; + ii.yHotspot = yhot; + ii.hbmMask = mask; + ii.hbmColor = color; + + handle = CreateIconIndirect(&ii); + + DeleteObject(color); + DeleteObject(mask); + + if (!handle) + { + if (icon) + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create icon"); + else + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create cursor"); + } + + return handle; +} + // Translate client window size to full window size according to styles // static void getFullWindowSize(DWORD style, DWORD exStyle, @@ -886,6 +993,12 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) } destroyWindow(window); + + if (window->win32.bigIcon) + DestroyIcon(window->win32.bigIcon); + + if (window->win32.smallIcon) + DestroyIcon(window->win32.smallIcon); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) @@ -902,6 +1015,37 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) free(wideTitle); } +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + HICON bigIcon = NULL, smallIcon = NULL; + + if (count) + { + const GLFWimage* bigImage = chooseImage(count, images, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON)); + const GLFWimage* smallImage = chooseImage(count, images, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON)); + + bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE); + smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE); + } + + SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); + SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); + + if (window->win32.bigIcon) + DestroyIcon(window->win32.bigIcon); + + if (window->win32.smallIcon) + DestroyIcon(window->win32.smallIcon); + + window->win32.bigIcon = bigIcon; + window->win32.smallIcon = smallIcon; +} + void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { POINT pos = { 0, 0 }; @@ -1236,61 +1380,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) { - HDC dc; - HBITMAP bitmap, mask; - BITMAPV5HEADER bi; - ICONINFO ii; - DWORD* target = 0; - BYTE* source = (BYTE*) image->pixels; - int i; - - ZeroMemory(&bi, sizeof(bi)); - bi.bV5Size = sizeof(BITMAPV5HEADER); - bi.bV5Width = image->width; - bi.bV5Height = -image->height; - bi.bV5Planes = 1; - bi.bV5BitCount = 32; - bi.bV5Compression = BI_BITFIELDS; - bi.bV5RedMask = 0x00ff0000; - bi.bV5GreenMask = 0x0000ff00; - bi.bV5BlueMask = 0x000000ff; - bi.bV5AlphaMask = 0xff000000; - - dc = GetDC(NULL); - bitmap = CreateDIBSection(dc, (BITMAPINFO*) &bi, DIB_RGB_COLORS, - (void**) &target, NULL, (DWORD) 0); - ReleaseDC(NULL, dc); - - if (!bitmap) - return GLFW_FALSE; - - mask = CreateBitmap(image->width, image->height, 1, 1, NULL); - if (!mask) - { - DeleteObject(bitmap); - return GLFW_FALSE; - } - - for (i = 0; i < image->width * image->height; i++, target++, source += 4) - { - *target = (source[3] << 24) | - (source[0] << 16) | - (source[1] << 8) | - source[2]; - } - - ZeroMemory(&ii, sizeof(ii)); - ii.fIcon = FALSE; - ii.xHotspot = xhot; - ii.yHotspot = yhot; - ii.hbmMask = mask; - ii.hbmColor = bitmap; - - cursor->win32.handle = (HCURSOR) CreateIconIndirect(&ii); - - DeleteObject(bitmap); - DeleteObject(mask); - + cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); if (!cursor->win32.handle) return GLFW_FALSE; diff --git a/src/window.c b/src/window.c index 8e055b3bd..8f627ecc0 100644 --- a/src/window.c +++ b/src/window.c @@ -447,6 +447,18 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) _glfwPlatformSetWindowTitle(window, title); } +GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, + int count, const GLFWimage* images) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(count >= 0); + assert(count == 0 || images != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetWindowIcon(window, count, images); +} + GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index f1d5b520f..3920e82e2 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -383,6 +383,13 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) wl_shell_surface_set_title(window->wl.shell_surface, title); } +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + // TODO + fprintf(stderr, "_glfwPlatformSetWindowIcon not implemented yet\n"); +} + void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { // A Wayland client is not aware of its position, so just warn and leave it diff --git a/src/x11_init.c b/src/x11_init.c index e73bb1314..e1c17a3f5 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -454,6 +454,8 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME"); _glfw.x11.NET_WM_ICON_NAME = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON_NAME"); + _glfw.x11.NET_WM_ICON = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON"); _glfw.x11.NET_WM_PID = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PID"); _glfw.x11.NET_WM_PING = diff --git a/src/x11_platform.h b/src/x11_platform.h index caad2530b..929575876 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -167,6 +167,7 @@ typedef struct _GLFWlibraryX11 Atom WM_DELETE_WINDOW; Atom NET_WM_NAME; Atom NET_WM_ICON_NAME; + Atom NET_WM_ICON; Atom NET_WM_PID; Atom NET_WM_PING; Atom NET_WM_STATE; diff --git a/src/x11_window.c b/src/x11_window.c index c4bbf9f16..e198b8154 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1536,6 +1536,51 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) XFlush(_glfw.x11.display); } +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + if (count) + { + int i, j, longCount = 0; + + for (i = 0; i < count; i++) + longCount += 2 + images[i].width * images[i].height; + + long* icon = calloc(longCount, sizeof(long)); + long* target = icon; + + for (i = 0; i < count; i++) + { + *target++ = images[i].width; + *target++ = images[i].height; + + for (j = 0; j < images[i].width * images[i].height; i++) + { + *target++ = (images[i].pixels[i * 4 + 0] << 16) | + (images[i].pixels[i * 4 + 1] << 8) | + (images[i].pixels[i * 4 + 2] << 0) | + (images[i].pixels[i * 4 + 3] << 24); + } + } + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON, + XA_CARDINAL, 32, + PropModeReplace, + (unsigned char*) icon, + longCount); + + free(icon); + } + else + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON); + } + + XFlush(_glfw.x11.display); +} + void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { Window child; From d998e3eebeac5c6257ee43c0ecef2993c17863fe Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Fri, 11 Mar 2016 11:50:37 +0100 Subject: [PATCH 083/156] Add icon test program --- tests/CMakeLists.txt | 3 +- tests/icon.c | 148 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 tests/icon.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3674bf4a7..39614841e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(reopen reopen.c ${GLAD}) add_executable(cursor cursor.c ${GLAD}) add_executable(empty WIN32 MACOSX_BUNDLE empty.c ${TINYCTHREAD} ${GLAD}) +add_executable(icon WIN32 MACOSX_BUNDLE icon.c ${GLAD}) add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c ${GLAD}) add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT} ${GLAD}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD}) @@ -39,7 +40,7 @@ add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${GETOPT} ${GLAD}) target_link_libraries(empty "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") target_link_libraries(threads "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") -set(WINDOWS_BINARIES empty sharing tearing threads title windows) +set(WINDOWS_BINARIES empty icon sharing tearing threads title windows) set(CONSOLE_BINARIES clipboard events msaa gamma glfwinfo iconify joysticks monitors reopen cursor) diff --git a/tests/icon.c b/tests/icon.c new file mode 100644 index 000000000..9144a71a7 --- /dev/null +++ b/tests/icon.c @@ -0,0 +1,148 @@ +//======================================================================== +// Window icon test program +// Copyright (c) Camilla Berglund +// +// 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 program is used to test the icon feature. +// +//======================================================================== + +#include +#include + +#include +#include +#include + +// a simple glfw logo +const char* const logo[] = +{ + "................", + "................", + "...0000..0......", + "...0.....0......", + "...0.00..0......", + "...0..0..0......", + "...0000..0000...", + "................", + "................", + "...000..0...0...", + "...0....0...0...", + "...000..0.0.0...", + "...0....0.0.0...", + "...0....00000...", + "................", + "................" +}; + +const unsigned char icon_colors[5][4] = +{ + { 0, 0, 0, 255 }, // black + { 255, 0, 0, 255 }, // red + { 0, 255, 0, 255 }, // green + { 0, 0, 255, 255 }, // blue + { 255, 255, 255, 255 } // white +}; + +static int cur_icon_color = 0; + +static void set_icon(GLFWwindow* window, int icon_color) +{ + int x, y; + char pixels[16 * 16 * 4]; + char* target = pixels; + GLFWimage img = { 16, 16, pixels }; + + for (y = 0; y < img.width; y++) + { + for (x = 0; x < img.height; x++) + { + if (logo[y][x] == '0') + memcpy(target, icon_colors[icon_color], 4); + else + memset(target, 0, 4); + + target += 4; + } + } + + glfwSetWindowIcon(window, 1, &img); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_ESCAPE: + glfwDestroyWindow(window); + break; + case GLFW_KEY_SPACE: + cur_icon_color = (cur_icon_color + 1) % 5; + set_icon(window, cur_icon_color); + break; + case GLFW_KEY_X: + glfwSetWindowIcon(window, 0, NULL); + break; + } +} + +int main(int argc, char** argv) +{ + GLFWwindow* window; + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + window = glfwCreateWindow(200, 200, "Window Icon", NULL, NULL); + if (!window) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window\n"); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + + glfwSetKeyCallback(window, key_callback); + set_icon(window, cur_icon_color); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + glfwWaitEvents(); + } + + glfwDestroyWindow(window); + glfwTerminate(); + exit(EXIT_SUCCESS); +} + From d2338f3a497e6b4d20328aa4e4833844f1e30af7 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 11 Mar 2016 11:45:53 +0100 Subject: [PATCH 084/156] Fix X11 icon image copy --- src/x11_window.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index e198b8154..8fc8e2cd6 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1554,12 +1554,12 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, *target++ = images[i].width; *target++ = images[i].height; - for (j = 0; j < images[i].width * images[i].height; i++) + for (j = 0; j < images[i].width * images[i].height; j++) { - *target++ = (images[i].pixels[i * 4 + 0] << 16) | - (images[i].pixels[i * 4 + 1] << 8) | - (images[i].pixels[i * 4 + 2] << 0) | - (images[i].pixels[i * 4 + 3] << 24); + *target++ = (images[i].pixels[j * 4 + 0] << 16) | + (images[i].pixels[j * 4 + 1] << 8) | + (images[i].pixels[j * 4 + 2] << 0) | + (images[i].pixels[j * 4 + 3] << 24); } } From 4e4b8727fce6ae1b77760f97b28297b9139311d2 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 11 Mar 2016 14:41:18 +0100 Subject: [PATCH 085/156] Fix Win32 icon restoration --- src/win32_window.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/win32_window.c b/src/win32_window.c index 8d7e2ab76..c0d01ddd4 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1032,6 +1032,11 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE); smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE); } + else + { + bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON); + smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); + } SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); @@ -1042,8 +1047,11 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, if (window->win32.smallIcon) DestroyIcon(window->win32.smallIcon); - window->win32.bigIcon = bigIcon; - window->win32.smallIcon = smallIcon; + if (count) + { + window->win32.bigIcon = bigIcon; + window->win32.smallIcon = smallIcon; + } } void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) From 9dceda8a0346cb2218213d163d7c8d202cb1439a Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 15 Mar 2016 19:21:04 +0100 Subject: [PATCH 086/156] Fix Clang warnings --- tests/icon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/icon.c b/tests/icon.c index 9144a71a7..09742a9d8 100644 --- a/tests/icon.c +++ b/tests/icon.c @@ -69,8 +69,8 @@ static int cur_icon_color = 0; static void set_icon(GLFWwindow* window, int icon_color) { int x, y; - char pixels[16 * 16 * 4]; - char* target = pixels; + unsigned char pixels[16 * 16 * 4]; + unsigned char* target = pixels; GLFWimage img = { 16, 16, pixels }; for (y = 0; y < img.width; y++) From 89f438de5a862802717a5d6e32ebfe462775cccf Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 15 Mar 2016 22:22:14 +0100 Subject: [PATCH 087/156] Fix window focus regression Regression caused by baf574494da1f1b6a07ff426c62670090e67b445. --- src/window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/window.c b/src/window.c index 8f627ecc0..69e9fbe7b 100644 --- a/src/window.c +++ b/src/window.c @@ -626,6 +626,7 @@ GLFWAPI void glfwShowWindow(GLFWwindow* handle) return; _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); } GLFWAPI void glfwHideWindow(GLFWwindow* handle) From cdea4209fc210edbfde7ecf51f0cf6e628b9bf07 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 16 Mar 2016 11:16:06 +0100 Subject: [PATCH 088/156] Add event wait timeout test --- tests/CMakeLists.txt | 4 +- tests/timeout.c | 97 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 tests/timeout.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 39614841e..9339ee594 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,13 +34,14 @@ add_executable(icon WIN32 MACOSX_BUNDLE icon.c ${GLAD}) add_executable(sharing WIN32 MACOSX_BUNDLE sharing.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}) add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD}) add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${GETOPT} ${GLAD}) target_link_libraries(empty "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") target_link_libraries(threads "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") -set(WINDOWS_BINARIES empty icon sharing tearing threads title windows) +set(WINDOWS_BINARIES empty icon sharing tearing threads timeout title windows) set(CONSOLE_BINARIES clipboard events msaa gamma glfwinfo iconify joysticks monitors reopen cursor) @@ -65,6 +66,7 @@ if (APPLE) 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") set_target_properties(title PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Title") set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows") diff --git a/tests/timeout.c b/tests/timeout.c new file mode 100644 index 000000000..13d73dcbe --- /dev/null +++ b/tests/timeout.c @@ -0,0 +1,97 @@ +//======================================================================== +// Event wait timeout test +// Copyright (c) Camilla Berglund +// +// 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 is intended to verify that waiting for events with timeout works +// +//======================================================================== + +#include +#include + +#include +#include +#include + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GLFW_TRUE); +} + +static float nrand(void) +{ + return (float) rand() / (float) RAND_MAX; +} + +int main(void) +{ + int result; + GLFWwindow* window; + + srand((unsigned int) time(NULL)); + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(640, 480, "Event Wait Timeout Test", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + glfwSetKeyCallback(window, key_callback); + + while (!glfwWindowShouldClose(window)) + { + int width, height; + float r = nrand(), g = nrand(), b = nrand(); + float l = (float) sqrt(r * r + g * g + b * b); + + glfwGetFramebufferSize(window, &width, &height); + + glViewport(0, 0, width, height); + glClearColor(r / l, g / l, b / l, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + + glfwWaitEventsTimeout(1.0); + } + + glfwDestroyWindow(window); + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + From 9a78fd049dc09a96a5d54b6491366a66fdbd7a62 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 16 Mar 2016 14:48:53 +0100 Subject: [PATCH 089/156] Fix view not being made first responder --- src/cocoa_window.m | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index c7d0a06d8..7ca03290a 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -965,6 +965,7 @@ static GLFWbool createWindow(_GLFWwindow* window, [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; #endif /*_GLFW_USE_RETINA*/ + [window->ns.object makeFirstResponder:window->ns.view]; [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; [window->ns.object setDelegate:window->ns.delegate]; [window->ns.object setAcceptsMouseMovedEvents:YES]; From 86751b42a6119c34b90767f9d31f2ac6bfe64a2d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 16 Mar 2016 15:05:50 +0100 Subject: [PATCH 090/156] Fix OS X default max window size --- src/cocoa_window.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 7ca03290a..ebf736d0f 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -26,6 +26,7 @@ #include "internal.h" +#include #include // Needed for _NSGetProgname @@ -1086,7 +1087,7 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, [window->ns.object setContentMinSize:NSMakeSize(minwidth, minheight)]; if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) - [window->ns.object setContentMaxSize:NSMakeSize(0, 0)]; + [window->ns.object setContentMaxSize:NSMakeSize(DBL_MAX, DBL_MAX)]; else [window->ns.object setContentMaxSize:NSMakeSize(maxwidth, maxheight)]; } From ea73ccf22d1ead85adc186936aacaee0f0ce274a Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 14 Mar 2016 20:47:48 +0100 Subject: [PATCH 091/156] Add support for EWMH _NET_WM_WINDOW_TYPE --- src/x11_init.c | 4 ++++ src/x11_platform.h | 2 ++ src/x11_window.c | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/src/x11_init.c b/src/x11_init.c index e1c17a3f5..7f7587c9b 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -460,6 +460,10 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PID"); _glfw.x11.NET_WM_PING = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PING"); + _glfw.x11.NET_WM_WINDOW_TYPE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); + _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); _glfw.x11.NET_ACTIVE_WINDOW = getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); _glfw.x11.NET_FRAME_EXTENTS = diff --git a/src/x11_platform.h b/src/x11_platform.h index 929575876..a12374aac 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -170,6 +170,8 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_ICON; Atom NET_WM_PID; Atom NET_WM_PING; + Atom NET_WM_WINDOW_TYPE; + Atom NET_WM_WINDOW_TYPE_NORMAL; Atom NET_WM_STATE; Atom NET_WM_STATE_ABOVE; Atom NET_WM_STATE_FULLSCREEN; diff --git a/src/x11_window.c b/src/x11_window.c index 8fc8e2cd6..03cc3749e 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -411,6 +411,14 @@ static GLFWbool createWindow(_GLFWwindow* window, (unsigned char*) &pid, 1); } + if (_glfw.x11.NET_WM_WINDOW_TYPE && _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL) + { + Atom type = _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &type, 1); + } + // Set ICCCM WM_HINTS property { XWMHints* hints = XAllocWMHints(); From 0d1dd82b890e44d770ea18dba213d5814d13d089 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 14 Mar 2016 20:39:27 +0100 Subject: [PATCH 092/156] Move X11 PPosition hack to glfwSetWindowPos --- src/x11_window.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 03cc3749e..dfcbd387c 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -446,14 +446,6 @@ static GLFWbool createWindow(_GLFWwindow* window, hints->flags |= PPosition; _glfwPlatformGetMonitorPos(wndconfig->monitor, &hints->x, &hints->y); } - else - { - // HACK: Explicitly setting PPosition to any value causes some WMs, - // notably Compiz and Metacity, to honor the position of - // unmapped windows set by XMoveWindow - hints->flags |= PPosition; - hints->x = hints->y = 0; - } if (!wndconfig->resizable) { @@ -1615,6 +1607,24 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { + // HACK: Explicitly setting PPosition to any value causes some WMs, notably + // Compiz and Metacity, to honor the position of unmapped windows + if (!_glfwPlatformWindowVisible(window)) + { + long supplied; + XSizeHints* hints = XAllocSizeHints(); + + if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) + { + hints->flags |= PPosition; + hints->x = hints->y = 0; + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + } + + XFree(hints); + } + XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos); XFlush(_glfw.x11.display); } From 3a6fe042ea1a7bdc0d64473b03b200fe81e8d2a6 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 14 Mar 2016 10:59:14 +0100 Subject: [PATCH 093/156] Cleanup --- src/x11_window.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index dfcbd387c..eaf745479 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1886,12 +1886,7 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformFocusWindow(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW) - { - // Ask the window manager to raise and focus the GLFW window - // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end up - // on top of all other windows ("Stacking order" in EWMH spec) sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); - } else { XRaiseWindow(_glfw.x11.display, window->x11.handle); From ea888114faa779aa40001ef8042e513957cc1d73 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 14 Mar 2016 15:17:28 +0100 Subject: [PATCH 094/156] Remove monitor from _GLFWwndconfig --- src/cocoa_window.m | 10 ++++------ src/internal.h | 1 - src/mir_window.c | 4 ++-- src/win32_window.c | 8 ++++---- src/window.c | 7 +++---- src/wl_window.c | 4 ++-- src/x11_window.c | 8 ++++---- 7 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index ebf736d0f..7e7b3d504 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -904,7 +904,7 @@ static GLFWbool createWindow(_GLFWwindow* window, unsigned int styleMask = 0; - if (wndconfig->monitor || !wndconfig->decorated) + if (window->monitor || !wndconfig->decorated) styleMask = NSBorderlessWindowMask; else { @@ -917,7 +917,7 @@ static GLFWbool createWindow(_GLFWwindow* window, NSRect contentRect; - if (wndconfig->monitor) + if (window->monitor) { GLFWvidmode mode; int xpos, ypos; @@ -945,10 +945,8 @@ static GLFWbool createWindow(_GLFWwindow* window, if (wndconfig->resizable) [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - if (wndconfig->monitor) - { + if (window->monitor) [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; - } else { [window->ns.object center]; @@ -998,7 +996,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, return GLFW_FALSE; } - if (wndconfig->monitor) + if (window->monitor) { _glfwPlatformShowWindow(window); if (!enterFullscreenMode(window)) diff --git a/src/internal.h b/src/internal.h index e1466dc52..01046d0d5 100644 --- a/src/internal.h +++ b/src/internal.h @@ -247,7 +247,6 @@ struct _GLFWwndconfig GLFWbool autoIconify; GLFWbool floating; GLFWbool maximized; - _GLFWmonitor* monitor; }; diff --git a/src/mir_window.c b/src/mir_window.c index 3b2560816..5d2c145b7 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -351,10 +351,10 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, return GLFW_FALSE; } - if (wndconfig->monitor) + if (window->monitor) { GLFWvidmode mode; - _glfwPlatformGetVideoMode(wndconfig->monitor, &mode); + _glfwPlatformGetVideoMode(window->monitor, &mode); mir_surface_set_state(window->mir.surface, mir_surface_state_fullscreen); diff --git a/src/win32_window.c b/src/win32_window.c index c0d01ddd4..7fc8c5e93 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -760,15 +760,15 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) DWORD style = getWindowStyle(window); DWORD exStyle = getWindowExStyle(window); - if (wndconfig->monitor) + if (window->monitor) { GLFWvidmode mode; // NOTE: This window placement is temporary and approximate, as the // correct position and size cannot be known until the monitor // video mode has been set - _glfwPlatformGetMonitorPos(wndconfig->monitor, &xpos, &ypos); - _glfwPlatformGetVideoMode(wndconfig->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); fullWidth = mode.width; fullHeight = mode.height; } @@ -822,7 +822,7 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } - if (wndconfig->floating && !wndconfig->monitor) + if (wndconfig->floating && !window->monitor) { SetWindowPos(window->win32.handle, HWND_TOPMOST, diff --git a/src/window.c b/src/window.c index 69e9fbe7b..01f46b236 100644 --- a/src/window.c +++ b/src/window.c @@ -143,7 +143,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, wndconfig.width = width; wndconfig.height = height; wndconfig.title = title; - wndconfig.monitor = (_GLFWmonitor*) monitor; ctxconfig.share = (_GLFWwindow*) share; if (ctxconfig.share) @@ -155,7 +154,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, } } - if (wndconfig.monitor) + if (monitor) { wndconfig.resizable = GLFW_TRUE; wndconfig.visible = GLFW_TRUE; @@ -176,7 +175,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->videoMode.blueBits = fbconfig.blueBits; window->videoMode.refreshRate = _glfw.hints.refreshRate; - window->monitor = wndconfig.monitor; + window->monitor = (_GLFWmonitor*) monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; window->autoIconify = wndconfig.autoIconify; @@ -218,7 +217,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, _glfwPlatformMakeContextCurrent(previous); } - if (wndconfig.monitor) + if (window->monitor) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); diff --git a/src/wl_window.c b/src/wl_window.c index 3920e82e2..2cc8abffa 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -329,13 +329,13 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, return GLFW_FALSE; } - if (wndconfig->monitor) + if (window->monitor) { wl_shell_surface_set_fullscreen( window->wl.shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, - wndconfig->monitor->wl.output); + window->monitor->wl.output); } else { diff --git a/src/x11_window.c b/src/x11_window.c index eaf745479..0c2016b34 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -300,7 +300,7 @@ static GLFWbool createWindow(_GLFWwindow* window, (XPointer) window); } - if (wndconfig->monitor) + if (window->monitor) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN) { @@ -441,10 +441,10 @@ static GLFWbool createWindow(_GLFWwindow* window, XSizeHints* hints = XAllocSizeHints(); hints->flags = 0; - if (wndconfig->monitor) + if (window->monitor) { hints->flags |= PPosition; - _glfwPlatformGetMonitorPos(wndconfig->monitor, &hints->x, &hints->y); + _glfwPlatformGetMonitorPos(window->monitor, &hints->x, &hints->y); } if (!wndconfig->resizable) @@ -1447,7 +1447,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, #endif } - if (wndconfig->monitor) + if (window->monitor) { _glfwPlatformShowWindow(window); enterFullscreenMode(window); From 99c925efd8a861df68e4991eecfb11d904bfdb8d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 23 Feb 2016 12:34:35 +0100 Subject: [PATCH 095/156] Add tracking of which window 'owns' a monitor --- src/cocoa_window.m | 24 +++++++++++++++--------- src/internal.h | 7 +++++++ src/monitor.c | 5 +++++ src/win32_window.c | 23 ++++++++++++++--------- src/x11_window.c | 28 +++++++++++++++++++--------- 5 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 7e7b3d504..c30c9409f 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -73,9 +73,9 @@ static float transformY(float y) return CGDisplayBounds(CGMainDisplayID()).size.height - y; } -// Enter full screen mode +// Make the specified window and its video mode active on its monitor // -static GLFWbool enterFullscreenMode(_GLFWwindow* window) +static GLFWbool acquireMonitor(_GLFWwindow* window) { const GLFWbool status = _glfwSetVideoModeNS(window->monitor, &window->videoMode); const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID); @@ -85,14 +85,20 @@ static GLFWbool enterFullscreenMode(_GLFWwindow* window) bounds.size.height); [window->ns.object setFrame:frame display:YES]; + _glfwPlatformFocusWindow(window); + _glfwInputMonitorWindowChange(window->monitor, window); return status; } -// Leave full screen mode +// Remove the window and restore the original video mode // -static void leaveFullscreenMode(_GLFWwindow* window) +static void releaseMonitor(_GLFWwindow* window) { + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindowChange(window->monitor, NULL); _glfwRestoreVideoModeNS(window->monitor); } @@ -219,7 +225,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidMiniaturize:(NSNotification *)notification { if (window->monitor) - leaveFullscreenMode(window); + releaseMonitor(window); _glfwInputWindowIconify(window, GLFW_TRUE); } @@ -227,7 +233,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidDeminiaturize:(NSNotification *)notification { if (window->monitor) - enterFullscreenMode(window); + acquireMonitor(window); _glfwInputWindowIconify(window, GLFW_FALSE); } @@ -999,7 +1005,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); - if (!enterFullscreenMode(window)) + if (!acquireMonitor(window)) return GLFW_FALSE; } @@ -1011,7 +1017,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) [window->ns.object orderOut:nil]; if (window->monitor) - leaveFullscreenMode(window); + releaseMonitor(window); if (window->context.api != GLFW_NO_API) _glfwDestroyContextNSGL(window); @@ -1070,7 +1076,7 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) - enterFullscreenMode(window); + acquireMonitor(window); else [window->ns.object setContentSize:NSMakeSize(width, height)]; } diff --git a/src/internal.h b/src/internal.h index 01046d0d5..e003ec503 100644 --- a/src/internal.h +++ b/src/internal.h @@ -381,6 +381,9 @@ struct _GLFWmonitor // Physical dimensions in millimeters. int widthMM, heightMM; + // The window whose video mode is current on this monitor + _GLFWwindow* window; + GLFWvidmode* modes; int modeCount; GLFWvidmode currentMode; @@ -911,6 +914,10 @@ void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered); */ void _glfwInputMonitorChange(void); +/*! @ingroup event + */ +void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window); + /*! @brief Notifies shared code of an error. * @param[in] error The error code most suitable for the error. * @param[in] format The `printf` style format string of the error diff --git a/src/monitor.c b/src/monitor.c index a17c1f634..d21a992b2 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -158,6 +158,11 @@ void _glfwInputMonitorChange(void) _glfwFreeMonitors(monitors, monitorCount); } +void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window) +{ + monitor->window = window; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// diff --git a/src/win32_window.c b/src/win32_window.c index 7fc8c5e93..5c6cc0316 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -328,9 +328,9 @@ static int translateKey(WPARAM wParam, LPARAM lParam) return _glfw.win32.publicKeys[HIWORD(lParam) & 0x1FF]; } -// Enter full screen mode +// Make the specified window and its video mode active on its monitor // -static GLFWbool enterFullscreenMode(_GLFWwindow* window) +static GLFWbool acquireMonitor(_GLFWwindow* window) { GLFWvidmode mode; GLFWbool status; @@ -344,13 +344,18 @@ static GLFWbool enterFullscreenMode(_GLFWwindow* window) SetWindowPos(window->win32.handle, HWND_TOPMOST, xpos, ypos, mode.width, mode.height, SWP_NOCOPYBITS); + _glfwInputMonitorWindowChange(window->monitor, window); return status; } -// Leave full screen mode +// Remove the window and restore the original video mode // -static void leaveFullscreenMode(_GLFWwindow* window) +static void releaseMonitor(_GLFWwindow* window) { + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindowChange(window->monitor, NULL); _glfwRestoreVideoModeWin32(window->monitor); } @@ -597,7 +602,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, { window->win32.iconified = GLFW_TRUE; if (window->monitor) - leaveFullscreenMode(window); + releaseMonitor(window); _glfwInputWindowIconify(window, GLFW_TRUE); } @@ -606,7 +611,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, { window->win32.iconified = GLFW_FALSE; if (window->monitor) - enterFullscreenMode(window); + acquireMonitor(window); _glfwInputWindowIconify(window, GLFW_FALSE); } @@ -971,7 +976,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); - if (!enterFullscreenMode(window)) + if (!acquireMonitor(window)) return GLFW_FALSE; } @@ -981,7 +986,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (window->monitor) - leaveFullscreenMode(window); + releaseMonitor(window); if (window->context.api != GLFW_NO_API) { @@ -1088,7 +1093,7 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) - enterFullscreenMode(window); + acquireMonitor(window); else { int fullWidth, fullHeight; diff --git a/src/x11_window.c b/src/x11_window.c index 0c2016b34..d1f202029 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -711,10 +711,12 @@ static void pushSelectionToManager(_GLFWwindow* window) } } -// Enter full screen mode +// Make the specified window and its video mode active on its monitor // -static void enterFullscreenMode(_GLFWwindow* window) +static GLFWbool acquireMonitor(_GLFWwindow* window) { + GLFWbool status; + if (_glfw.x11.saver.count == 0) { // Remember old screen saver settings @@ -731,7 +733,7 @@ static void enterFullscreenMode(_GLFWwindow* window) _glfw.x11.saver.count++; - _glfwSetVideoModeX11(window->monitor, &window->videoMode); + status = _glfwSetVideoModeX11(window->monitor, &window->videoMode); if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) { @@ -778,12 +780,19 @@ static void enterFullscreenMode(_GLFWwindow* window) _glfw.x11.NET_WM_STATE_FULLSCREEN, 0, 1, 0); } + + _glfwInputMonitorWindowChange(window->monitor, window); + return status; } -// Leave full screen mode +// Remove the window and restore the original video mode // -static void leaveFullscreenMode(_GLFWwindow* window) +static void releaseMonitor(_GLFWwindow* window) { + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindowChange(window->monitor, NULL); _glfwRestoreVideoModeX11(window->monitor); _glfw.x11.saver.count--; @@ -1335,14 +1344,14 @@ static void processEvent(XEvent *event) if (state == IconicState) { if (window->monitor) - leaveFullscreenMode(window); + releaseMonitor(window); _glfwInputWindowIconify(window, GLFW_TRUE); } else if (state == NormalState) { if (window->monitor) - enterFullscreenMode(window); + acquireMonitor(window); _glfwInputWindowIconify(window, GLFW_FALSE); } @@ -1450,7 +1459,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); - enterFullscreenMode(window); + if (!acquireMonitor(window)) + return GLFW_FALSE; } return GLFW_TRUE; @@ -1459,7 +1469,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (window->monitor) - leaveFullscreenMode(window); + releaseMonitor(window); if (window->x11.ic) { From 0365f1ec8291d926b12bee9bf29d16eb865a8c3b Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 18 Mar 2016 10:32:14 +0100 Subject: [PATCH 096/156] Fix warning when building for X11 on Cygwin --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3d277b15..070beae49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,5 @@ +set(CMAKE_LEGACY_CYGWIN_WIN32 OFF) + project(GLFW C) cmake_minimum_required(VERSION 2.8.12) From fc3acdacf6da8d61ba90b118367a1ad5db670b09 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 18 Mar 2016 10:33:23 +0100 Subject: [PATCH 097/156] Remove pointless window hint from Boing example --- examples/boing.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/boing.c b/examples/boing.c index 886cf1f45..68eccfd54 100644 --- a/examples/boing.c +++ b/examples/boing.c @@ -602,8 +602,6 @@ int main( void ) if( !glfwInit() ) exit( EXIT_FAILURE ); - glfwWindowHint(GLFW_DEPTH_BITS, 16); - window = glfwCreateWindow( 400, 400, "Boing (classic Amiga demo)", NULL, NULL ); if (!window) { From e37dbd8b8d1eabb5feaf58ac7c9129c8d336a5c3 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 18 Mar 2016 10:36:33 +0100 Subject: [PATCH 098/156] Fix missing include in event wait timeout test --- tests/timeout.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/timeout.c b/tests/timeout.c index 13d73dcbe..d1a9491e4 100644 --- a/tests/timeout.c +++ b/tests/timeout.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include From fb8a31ba3f37a703ef525f0662053725e870ef71 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 18 Mar 2016 11:00:28 +0100 Subject: [PATCH 099/156] Fix icon test destroying window from callback --- tests/icon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/icon.c b/tests/icon.c index 09742a9d8..781b2cf65 100644 --- a/tests/icon.c +++ b/tests/icon.c @@ -97,7 +97,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, switch (key) { case GLFW_KEY_ESCAPE: - glfwDestroyWindow(window); + glfwSetWindowShouldClose(window, GLFW_TRUE); break; case GLFW_KEY_SPACE: cur_icon_color = (cur_icon_color + 1) % 5; From 6570d0c4b7a1868ad8af4e61dd5f50bf826d9c76 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 23 Feb 2016 12:26:42 +0100 Subject: [PATCH 100/156] Add glfwSetWindowMonitor This adds the ability to switch between windowed and full screen modes, move a full screen window between monitors and update its desired resolution and refresh rate. Fixes #43. --- README.md | 2 + docs/monitor.dox | 5 +- docs/news.dox | 7 + docs/window.dox | 53 +++++- examples/boing.c | 21 +++ include/GLFW/glfw3.h | 107 ++++++++--- src/cocoa_window.m | 145 ++++++++++++-- src/internal.h | 11 ++ src/mir_window.c | 10 + src/monitor.c | 6 +- src/win32_platform.h | 4 - src/win32_window.c | 178 +++++++++++++----- src/window.c | 55 ++++-- src/wl_window.c | 10 + src/x11_window.c | 438 ++++++++++++++++++++++++------------------- tests/iconify.c | 30 +++ 16 files changed, 764 insertions(+), 318 deletions(-) diff --git a/README.md b/README.md index c65e854e1..e329fb29c 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ does not find Doxygen, the documentation will not be generated. - Added `glfwVulkanSupported`, `glfwGetRequiredInstanceExtensions`, `glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and `glfwCreateWindowSurface` for platform independent Vulkan support + - Added `glfwSetWindowMonitor` for switching between windowed and full screen + modes and updating the monitor and desired video mode of full screen windows - Added `glfwMaximizeWindow` and `GLFW_MAXIMIZED` for window maximization - Added `glfwFocusWindow` for giving windows input focus - Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting diff --git a/docs/monitor.dox b/docs/monitor.dox index 16fb1c82a..53e88aac4 100644 --- a/docs/monitor.dox +++ b/docs/monitor.dox @@ -95,8 +95,9 @@ a gamma ramp. @subsection monitor_modes Video modes GLFW generally does a good job selecting a suitable video mode when you create -a full screen window, but it is sometimes useful to know exactly which video -modes are supported. +a full screen window, change its video mode or or make a windowed one full +screen, but it is sometimes useful to know exactly which video modes are +supported. Video modes are represented as @ref GLFWvidmode structures. You can get an array of the video modes supported by a monitor with @ref glfwGetVideoModes. diff --git a/docs/news.dox b/docs/news.dox index 37c591e05..dae843090 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -26,6 +26,13 @@ Vulkan header inclusion can be selected with [GLFW_INCLUDE_VULKAN](@ref build_macros). +@subsection news_32_setwindowmonitor Window mode switching + +GLFW now supports switching between windowed and full screen modes and updating +the monitor and desired resolution and refresh rate of full screen windows with +@ref glfwSetWindowMonitor. + + @subsection news_32_maximize Window maxmimization support GLFW now supports window maximization with @ref glfwMaximizeWindow and the diff --git a/docs/window.dox b/docs/window.dox index 17bba73ed..1b25c553a 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -56,6 +56,10 @@ GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", glfwGetPrimaryMonito Full screen windows cover the entire display area of a monitor, have no border or decorations. +Windowed mode windows can be made full screen by setting a monitor with @ref +glfwSetWindowMonitor, and full screen ones can be made windowed by unsetting it +with the same function. + Each field of the @ref GLFWvidmode structure corresponds to a function parameter or window hint and combine to form the _desired video mode_ for that window. The supported video mode most closely matching the desired video mode will be @@ -71,9 +75,11 @@ GLFWvidmode.greenBits | `GLFW_GREEN_BITS` hint GLFWvidmode.blueBits | `GLFW_BLUE_BITS` hint GLFWvidmode.refreshRate | `GLFW_REFRESH_RATE` hint -Once you have a full screen window, you can change its resolution with @ref -glfwSetWindowSize. The new video mode will be selected and set the same way as -the video mode chosen by @ref glfwCreateWindow. +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 +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. 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 @@ -101,6 +107,18 @@ glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); GLFWwindow* window = glfwCreateWindow(mode->width, mode->height, "My Title", monitor, NULL); @endcode +This also works for windowed mode windows that are made full screen. + +@code +const GLFWvidmode* mode = glfwGetVideoMode(monitor); + +glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); +@endcode + +Note that @ref glfwGetVideoMode returns the _current_ video mode of a monitor, +so if you already have a full screen window on that monitor that you want to +make windowed full screen, you need to have saved the desktop resolution before. + @subsection window_destruction Window destruction @@ -423,7 +441,7 @@ glfwSetWindowSize(window, 640, 480); @endcode For full screen windows, the specified size becomes the new resolution of the -window's *desired video mode*. The video mode most closely matching the new +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. @@ -648,8 +666,31 @@ GLFWmonitor* monitor = glfwGetWindowMonitor(window); This monitor handle is one of those returned by @ref glfwGetMonitors. -For windowed mode windows, this function returns `NULL`. This is the -recommended way to tell full screen windows from windowed mode windows. +For windowed mode windows, this function returns `NULL`. This is how to tell +full screen windows from windowed mode windows. + +You can move windows between monitors or between full screen and windowed mode +with @ref glfwSetWindowMonitor. When making a window full screen on the same or +on a different monitor, specify the desired monitor, resolution and refresh +rate. The position arguments are ignored. + +@code +const GLFWvidmode* mode = glfwGetVideoMode(monitor); + +glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); +@endcode + +When making the window windowed, specify the desired position and size. The +refresh rate argument is ignored. + +@code +glfwSetWindowMonitor(window, NULL, xpos, ypos, width, height, 0); +@endcode + +This restores any previous window settings such as whether it is decorated, +floating, resizable, has size or aspect ratio limits, etc.. To restore a window +that was originally windowed to its original size and position, save these +before making it full screen and then pass them in as above. @subsection window_iconify Window iconification diff --git a/examples/boing.c b/examples/boing.c index 68eccfd54..e55d8d1c4 100644 --- a/examples/boing.c +++ b/examples/boing.c @@ -89,6 +89,7 @@ typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; typedef struct {float x; float y; float z;} vertex_t; /* Global vars */ +int windowed_xpos, windowed_ypos, windowed_width, windowed_height; int width, height; GLfloat deg_rot_y = 0.f; GLfloat deg_rot_y_inc = 2.f; @@ -238,6 +239,26 @@ void key_callback( GLFWwindow* window, int key, int scancode, int action, int mo { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE); + if (key == GLFW_KEY_ENTER && action == GLFW_PRESS && mods == GLFW_MOD_ALT) + { + if (glfwGetWindowMonitor(window)) + { + glfwSetWindowMonitor(window, NULL, + windowed_xpos, windowed_ypos, + windowed_width, windowed_height, 0); + } + else + { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + if (monitor) + { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + glfwGetWindowPos(window, &windowed_xpos, &windowed_ypos); + glfwGetWindowSize(window, &windowed_width, &windowed_height); + glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); + } + } + } } static void set_ball_pos ( GLfloat x, GLfloat y ) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 7557f1cfe..d88e108af 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1718,17 +1718,17 @@ GLFWAPI void glfwWindowHint(int hint, int value); * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. * * To create a full screen window, you need to specify the monitor the window - * will cover. If no monitor is specified, windowed mode will be used. Unless - * you have a way for the user to choose a specific monitor, it is recommended - * that you pick the primary monitor. For more information on how to query - * connected monitors, see @ref monitor_monitors. + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. * * For full screen windows, the specified size becomes the resolution of the - * window's _desired video mode_. As long as a full screen window has input - * focus, the supported video mode most closely matching the desired video mode - * is set for the specified monitor. For more information about full screen - * windows, including the creation of so called _windowed full screen_ or - * _borderless full screen_ windows, see @ref window_windowed_full_screen. + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. * * By default, newly created windows use the placement recommended by the * window system. To create the window at a specific position, make it @@ -1736,8 +1736,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) * it. * - * If a full screen window has input focus, the screensaver is prohibited from - * starting. + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. * * Window systems put limits on window sizes. Very large or very small window * dimensions may be overridden by the window system on creation. Check the @@ -1751,7 +1751,7 @@ GLFWAPI void glfwWindowHint(int hint, int value); * @param[in] height The desired height, in screen coordinates, of the window. * This must be greater than zero. * @param[in] title The initial, UTF-8 encoded window title. - * @param[in] monitor The monitor to use for full screen mode, or `NULL` to use + * @param[in] monitor The monitor to use for full screen mode, or `NULL` for * windowed mode. * @param[in] share The window whose context to share resources with, or `NULL` * to not share resources. @@ -2044,11 +2044,12 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); /*! @brief Sets the size limits of the specified window. * * This function sets the size limits of the client area of the specified - * window. If the window is full screen or not resizable, this function does - * nothing. + * window. If the window is full screen, the size limits only take effect if + * once it is made windowed. If the window is not resizable, this function + * does nothing. * - * The size limits are applied immediately and may cause the window to be - * resized. + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. * * @param[in] window The window to set limits for. * @param[in] minwidth The minimum width, in screen coordinates, of the client @@ -2080,7 +2081,8 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minhe /*! @brief Sets the aspect ratio of the specified window. * * This function sets the required aspect ratio of the client area of the - * specified window. If the window is full screen or not resizable, this + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this * function does nothing. * * The aspect ratio is specified as a numerator and a denominator and both @@ -2090,8 +2092,8 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minhe * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect * ratio limit is disabled. * - * The aspect ratio is applied immediately and may cause the window to be - * resized. + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. * * @param[in] window The window to set limits for. * @param[in] numer The numerator of the desired aspect ratio, or @@ -2121,17 +2123,22 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); * This function sets the size, in screen coordinates, of the client area of * the specified window. * - * For full screen windows, this function selects and switches to the resolution - * closest to the specified size, without affecting the window's context. As - * the context is unaffected, the bit depths of the framebuffer remain - * unchanged. + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. * * The window manager may put limits on what sizes are allowed. GLFW cannot * and should not override these limits. * * @param[in] window The window to resize. - * @param[in] width The desired width of the specified window. - * @param[in] height The desired height of the specified window. + * @param[in] width The desired width, in screen coordinates, of the window + * client area. + * @param[in] height The desired height, in screen coordinates, of the window + * client area. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. @@ -2140,6 +2147,7 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); * * @sa @ref window_size * @sa glfwGetWindowSize + * @sa glfwSetWindowMonitor * * @since Added in version 1.0. * @glfw3 Added window handle parameter. @@ -2376,6 +2384,7 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* window); * @thread_safety This function must only be called from the main thread. * * @sa @ref window_monitor + * @sa glfwSetWindowMonitor * * @since Added in version 3.0. * @@ -2383,6 +2392,54 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* window); */ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); +/*! @brief Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `NULL`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `NULL`, the position, width and height are used to + * place the window client area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc.. + * + * @param[in] window The window whose monitor, size or video mode to set. + * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. + * @param[in] xpos The desired x-coordinate of the upper-left corner of the + * client area. + * @param[in] ypos The desired y-coordinate of the upper-left corner of the + * client area. + * @param[in] width The desired with, in screen coordinates, of the client area + * or video mode. + * @param[in] height The desired height, in screen coordinates, of the client + * area or video mode. + * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode. + * + * @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_monitor + * @sa @ref window_full_screen + * @sa glfwGetWindowMonitor + * @sa glfwSetWindowSize + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + /*! @brief Returns an attribute of the specified window. * * This function returns the value of an attribute of the specified window or diff --git a/src/cocoa_window.m b/src/cocoa_window.m index c30c9409f..99920d030 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -56,6 +56,26 @@ static NSCursor* getStandardCursor(int shape) return nil; } +// Returns the style mask corresponding to the window settings +// +static NSUInteger getStyleMask(_GLFWwindow* window) +{ + NSUInteger styleMask = 0; + + if (window->monitor || !window->decorated) + styleMask |= NSBorderlessWindowMask; + else + { + styleMask |= NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask; + + if (window->resizable) + styleMask |= NSResizableWindowMask; + } + + return styleMask; +} + // Center the cursor in the view of the window // static void centerCursor(_GLFWwindow *window) @@ -86,7 +106,6 @@ static GLFWbool acquireMonitor(_GLFWwindow* window) [window->ns.object setFrame:frame display:YES]; - _glfwPlatformFocusWindow(window); _glfwInputMonitorWindowChange(window->monitor, window); return status; } @@ -908,19 +927,6 @@ static GLFWbool createWindow(_GLFWwindow* window, return GLFW_FALSE; } - unsigned int styleMask = 0; - - if (window->monitor || !wndconfig->decorated) - styleMask = NSBorderlessWindowMask; - else - { - styleMask = NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask; - - if (wndconfig->resizable) - styleMask |= NSResizableWindowMask; - } - NSRect contentRect; if (window->monitor) @@ -938,7 +944,7 @@ static GLFWbool createWindow(_GLFWwindow* window, window->ns.object = [[GLFWWindow alloc] initWithContentRect:contentRect - styleMask:styleMask + styleMask:getStyleMask(window) backing:NSBackingStoreBuffered defer:NO]; @@ -948,15 +954,15 @@ static GLFWbool createWindow(_GLFWwindow* window, return GLFW_FALSE; } - if (wndconfig->resizable) - [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - if (window->monitor) [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; else { [window->ns.object center]; + if (wndconfig->resizable) + [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + if (wndconfig->floating) [window->ns.object setLevel:NSFloatingWindowLevel]; @@ -1005,6 +1011,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); if (!acquireMonitor(window)) return GLFW_FALSE; } @@ -1076,7 +1083,10 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) - acquireMonitor(window); + { + if (window->monitor->window == window) + acquireMonitor(window); + } else [window->ns.object setContentSize:NSMakeSize(width, height)]; } @@ -1174,6 +1184,103 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) [window->ns.object makeKeyAndOrderFront:nil]; } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + const NSRect contentRect = + NSMakeRect(xpos, transformY(ypos + height), width, height); + const NSRect frameRect = + [window->ns.object frameRectForContentRect:contentRect + styleMask:getStyleMask(window)]; + + [window->ns.object setFrame:frameRect display:YES]; + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + + const NSUInteger styleMask = getStyleMask(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]; + [window->ns.object setHasShadow:NO]; + + acquireMonitor(window); + } + else + { + if (window->numer != GLFW_DONT_CARE && + window->denom != GLFW_DONT_CARE) + { + [window->ns.object setContentAspectRatio:NSMakeSize(window->numer, + window->denom)]; + } + + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) + { + [window->ns.object setContentMinSize:NSMakeSize(window->minwidth, + window->minheight)]; + } + + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) + { + [window->ns.object setContentMaxSize:NSMakeSize(window->maxwidth, + window->maxheight)]; + } + + if (window->floating) + [window->ns.object setLevel:NSFloatingWindowLevel]; + else + [window->ns.object setLevel:NSNormalWindowLevel]; + + [window->ns.object setHasShadow:YES]; + } +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { return [window->ns.object isKeyWindow]; diff --git a/src/internal.h b/src/internal.h index e003ec503..ebcd8b31a 100644 --- a/src/internal.h +++ b/src/internal.h @@ -339,6 +339,10 @@ struct _GLFWwindow _GLFWmonitor* monitor; _GLFWcursor* cursor; + int minwidth, minheight; + int maxwidth, maxheight; + int numer, denom; + // Window input state GLFWbool stickyKeys; GLFWbool stickyMouseButtons; @@ -694,6 +698,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window); */ void _glfwPlatformFocusWindow(_GLFWwindow* window); +/*! @copydoc glfwSetWindowMonitor + * @ingroup platform + */ +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + /*! @brief Returns whether the window is focused. * @ingroup platform */ @@ -856,6 +865,8 @@ void _glfwInputWindowDamage(_GLFWwindow* window); */ void _glfwInputWindowCloseRequest(_GLFWwindow* window); +void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor); + /*! @brief Notifies shared code of a physical key event. * @param[in] window The window that received the event. * @param[in] key The key that was pressed or released. diff --git a/src/mir_window.c b/src/mir_window.c index 5d2c145b7..8e6ceb896 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -508,6 +508,16 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/monitor.c b/src/monitor.c index d21a992b2..2ba4ceeee 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -126,7 +126,11 @@ void _glfwInputMonitorChange(void) for (window = _glfw.windowListHead; window; window = window->next) { if (window->monitor == monitors[i]) - window->monitor = NULL; + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + } } if (_glfw.callbacks.monitor) diff --git a/src/win32_platform.h b/src/win32_platform.h index 433c45871..36e3ead24 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -197,10 +197,6 @@ typedef struct _GLFWwindowWin32 GLFWbool cursorTracked; GLFWbool iconified; - int minwidth, minheight; - int maxwidth, maxheight; - int numer, denom; - // The last received cursor position, regardless of source int cursorPosX, cursorPosY; diff --git a/src/win32_window.c b/src/win32_window.c index 5c6cc0316..b120ec4ee 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -42,15 +42,20 @@ static DWORD getWindowStyle(const _GLFWwindow* window) { DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; - if (window->decorated && !window->monitor) - { - style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; - - if (window->resizable) - style |= WS_MAXIMIZEBOX | WS_SIZEBOX; - } - else + if (window->monitor) style |= WS_POPUP; + else + { + if (window->decorated) + { + style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + + if (window->resizable) + style |= WS_MAXIMIZEBOX | WS_THICKFRAME; + } + else + style |= WS_POPUP; + } return style; } @@ -61,8 +66,8 @@ static DWORD getWindowExStyle(const _GLFWwindow* window) { DWORD style = WS_EX_APPWINDOW; - if (window->decorated && !window->monitor) - style |= WS_EX_WINDOWEDGE; + if (window->monitor || window->floating) + style |= WS_EX_TOPMOST; return style; } @@ -190,8 +195,7 @@ static void getFullWindowSize(DWORD style, DWORD exStyle, static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) { int xoff, yoff; - const float ratio = (float) window->win32.numer / - (float) window->win32.denom; + const float ratio = (float) window->numer / (float) window->denom; getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff); @@ -342,7 +346,8 @@ static GLFWbool acquireMonitor(_GLFWwindow* window) _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); SetWindowPos(window->win32.handle, HWND_TOPMOST, - xpos, ypos, mode.width, mode.height, SWP_NOCOPYBITS); + xpos, ypos, mode.width, mode.height, + SWP_NOACTIVATE | SWP_NOCOPYBITS); _glfwInputMonitorWindowChange(window->monitor, window); return status; @@ -639,8 +644,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_SIZING: { - if (window->win32.numer == GLFW_DONT_CARE || - window->win32.denom == GLFW_DONT_CARE) + if (window->numer == GLFW_DONT_CARE || + window->denom == GLFW_DONT_CARE) { break; } @@ -654,21 +659,24 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, int xoff, yoff; MINMAXINFO* mmi = (MINMAXINFO*) lParam; + if (window->monitor) + break; + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff); - if (window->win32.minwidth != GLFW_DONT_CARE && - window->win32.minheight != GLFW_DONT_CARE) + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) { - mmi->ptMinTrackSize.x = window->win32.minwidth + xoff; - mmi->ptMinTrackSize.y = window->win32.minheight + yoff; + mmi->ptMinTrackSize.x = window->minwidth + xoff; + mmi->ptMinTrackSize.y = window->minheight + yoff; } - if (window->win32.maxwidth != GLFW_DONT_CARE && - window->win32.maxheight != GLFW_DONT_CARE) + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) { - mmi->ptMaxTrackSize.x = window->win32.maxwidth + xoff; - mmi->ptMaxTrackSize.y = window->win32.maxheight + yoff; + mmi->ptMaxTrackSize.x = window->maxwidth + xoff; + mmi->ptMaxTrackSize.y = window->maxheight + yoff; } return 0; @@ -827,23 +835,8 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } - if (wndconfig->floating && !window->monitor) - { - SetWindowPos(window->win32.handle, - HWND_TOPMOST, - 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - } - DragAcceptFiles(window->win32.handle, TRUE); - window->win32.minwidth = GLFW_DONT_CARE; - window->win32.minheight = GLFW_DONT_CARE; - window->win32.maxwidth = GLFW_DONT_CARE; - window->win32.maxheight = GLFW_DONT_CARE; - window->win32.numer = GLFW_DONT_CARE; - window->win32.denom = GLFW_DONT_CARE; - return GLFW_TRUE; } @@ -976,6 +969,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); if (!acquireMonitor(window)) return GLFW_FALSE; } @@ -1093,15 +1087,17 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) - acquireMonitor(window); + { + if (window->monitor->window == window) + acquireMonitor(window); + } else { - int fullWidth, fullHeight; - getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), - width, height, &fullWidth, &fullHeight); - + RECT rect = { 0, 0, width, height }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); SetWindowPos(window->win32.handle, HWND_TOP, - 0, 0, fullWidth, fullHeight, + 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); } } @@ -1112,11 +1108,6 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, { RECT area; - window->win32.minwidth = minwidth; - window->win32.minheight = minheight; - window->win32.maxwidth = maxwidth; - window->win32.maxheight = maxheight; - if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) && (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)) { @@ -1134,9 +1125,6 @@ void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom { RECT area; - window->win32.numer = numer; - window->win32.denom = denom; - if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) return; @@ -1207,6 +1195,92 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) SetFocus(window->win32.handle); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + + if (monitor) + { + GLFWvidmode mode; + DWORD style = GetWindowLongPtrW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window->decorated) + { + style &= ~WS_OVERLAPPEDWINDOW; + style |= getWindowStyle(window); + SetWindowLongPtrW(window->win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + _glfwPlatformGetVideoMode(monitor, &mode); + _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + xpos, ypos, mode.width, mode.height, + flags); + + acquireMonitor(window); + } + else + { + HWND after; + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + DWORD style = GetWindowLongPtrW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window->decorated) + { + style &= ~WS_POPUP; + style |= getWindowStyle(window); + SetWindowLongPtrW(window->win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + if (window->floating) + after = HWND_TOPMOST; + else + after = HWND_NOTOPMOST; + + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, after, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + flags); + } +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { return window->win32.handle == GetActiveWindow(); diff --git a/src/window.c b/src/window.c index 01f46b236..c10f9acfe 100644 --- a/src/window.c +++ b/src/window.c @@ -110,6 +110,11 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window) window->callbacks.close((GLFWwindow*) window); } +void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor) +{ + window->monitor = monitor; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// @@ -154,13 +159,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, } } - if (monitor) - { - wndconfig.resizable = GLFW_TRUE; - wndconfig.visible = GLFW_TRUE; - wndconfig.focused = GLFW_TRUE; - } - if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; @@ -182,6 +180,13 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->floating = wndconfig.floating; window->cursorMode = GLFW_CURSOR_NORMAL; + window->minwidth = GLFW_DONT_CARE; + window->minheight = GLFW_DONT_CARE; + window->maxwidth = GLFW_DONT_CARE; + window->maxheight = GLFW_DONT_CARE; + window->numer = GLFW_DONT_CARE; + window->denom = GLFW_DONT_CARE; + // Save the currently current context so it can be restored later previous = _glfwPlatformGetCurrentContext(); @@ -510,11 +515,8 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) _GLFW_REQUIRE_INIT(); - if (window->monitor) - { - window->videoMode.width = width; - window->videoMode.height = height; - } + window->videoMode.width = width; + window->videoMode.height = height; _glfwPlatformSetWindowSize(window, width, height); } @@ -528,6 +530,11 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, _GLFW_REQUIRE_INIT(); + window->minwidth = minwidth; + window->minheight = minheight; + window->maxwidth = maxwidth; + window->maxheight = maxheight; + if (window->monitor || !window->resizable) return; @@ -543,6 +550,9 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) _GLFW_REQUIRE_INIT(); + window->numer = numer; + window->denom = denom; + if (window->monitor || !window->resizable) return; @@ -709,6 +719,27 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) return (GLFWmonitor*) window->monitor; } +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, + GLFWmonitor* mh, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _GLFWwindow* window = (_GLFWwindow*) wh; + _GLFWmonitor* monitor = (_GLFWmonitor*) mh; + assert(window); + + _GLFW_REQUIRE_INIT(); + + window->videoMode.width = width; + window->videoMode.height = height; + window->videoMode.refreshRate = refreshRate; + + _glfwPlatformSetWindowMonitor(window, monitor, + xpos, ypos, width, height, + refreshRate); +} + GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index 2cc8abffa..0deef6d58 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -489,6 +489,16 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) fprintf(stderr, "_glfwPlatformFocusWindow not implemented yet\n"); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + // TODO + fprintf(stderr, "_glfwPlatformSetWindowMonitor not implemented yet\n"); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { // TODO diff --git a/src/x11_window.c b/src/x11_window.c index d1f202029..aaefcd818 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -199,6 +199,145 @@ static void sendEventToWM(_GLFWwindow* window, Atom type, &event); } +// Updates the normal hints according to the window settings +// +static void updateNormalHints(_GLFWwindow* window) +{ + XSizeHints* hints = XAllocSizeHints(); + + if (!window->monitor) + { + if (window->resizable) + { + if (window->minwidth != GLFW_DONT_CARE && + window->minwidth != GLFW_DONT_CARE && + window->maxwidth != GLFW_DONT_CARE && + window->maxwidth != GLFW_DONT_CARE) + { + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = window->minwidth; + hints->min_height = window->minheight; + hints->max_width = window->maxwidth; + hints->max_height = window->maxheight; + } + + if (window->numer != GLFW_DONT_CARE && + window->denom != GLFW_DONT_CARE) + { + hints->flags |= PAspect; + hints->min_aspect.x = hints->max_aspect.x = window->numer; + hints->min_aspect.y = hints->max_aspect.y = window->denom; + } + } + else + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = hints->max_width = width; + hints->min_height = hints->max_height = height; + } + } + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); +} + +// Updates the full screen status of the window +// +static void updateWindowMode(_GLFWwindow* window) +{ + updateNormalHints(window); + + if (window->monitor) + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + sendEventToWM(window, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS, + window->monitor->x11.index, + window->monitor->x11.index, + window->monitor->x11.index, + window->monitor->x11.index, + 0); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + // This is the butcher's way of removing window decorations + // Setting the override-redirect attribute on a window makes the + // window manager ignore the window completely (ICCCM, section 4) + // The good thing is that this makes undecorated full screen windows + // easy to do; the bad thing is that we have to do everything + // manually and some things (like iconify/restore) won't work at + // all, as those are tasks usually performed by the window manager + + XSetWindowAttributes attributes; + attributes.override_redirect = True; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GLFW_TRUE; + } + + if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) + { + const unsigned long value = 1; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); + } + } + else + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + XSetWindowAttributes attributes; + attributes.override_redirect = False; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GLFW_FALSE; + } + + if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR); + } + } +} + // Splits and translates a text/uri-list into separate file paths // NOTE: This function destroys the provided string // @@ -300,84 +439,57 @@ static GLFWbool createWindow(_GLFWwindow* window, (XPointer) window); } - if (window->monitor) + if (!wndconfig->decorated) { - if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN) + struct { - // This is the butcher's way of removing window decorations - // Setting the override-redirect attribute on a window makes the - // window manager ignore the window completely (ICCCM, section 4) - // The good thing is that this makes undecorated full screen windows - // easy to do; the bad thing is that we have to do everything - // manually and some things (like iconify/restore) won't work at - // all, as those are tasks usually performed by the window manager + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } hints; - XSetWindowAttributes attributes; - attributes.override_redirect = True; - XChangeWindowAttributes(_glfw.x11.display, - window->x11.handle, - CWOverrideRedirect, - &attributes); + hints.flags = 2; // Set decorations + hints.decorations = 0; // No decorations - window->x11.overrideRedirect = GLFW_TRUE; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.MOTIF_WM_HINTS, + _glfw.x11.MOTIF_WM_HINTS, 32, + PropModeReplace, + (unsigned char*) &hints, + sizeof(hints) / sizeof(long)); + } + + if (wndconfig->floating) + { + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE) + { + Atom value = _glfw.x11.NET_WM_STATE_ABOVE; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &value, 1); } } - else - { - if (!wndconfig->decorated) - { - struct - { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; - } hints; - hints.flags = 2; // Set decorations - hints.decorations = 0; // No decorations + if (wndconfig->maximized && !window->monitor) + { + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + const Atom states[2] = + { + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ + }; XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.MOTIF_WM_HINTS, - _glfw.x11.MOTIF_WM_HINTS, 32, - PropModeReplace, - (unsigned char*) &hints, - sizeof(hints) / sizeof(long)); - } - - if (wndconfig->floating) - { - if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE) - { - sendEventToWM(window, - _glfw.x11.NET_WM_STATE, - _NET_WM_STATE_ADD, - _glfw.x11.NET_WM_STATE_ABOVE, - 0, 1, 0); - } - } - - if (wndconfig->maximized) - { - if (_glfw.x11.NET_WM_STATE && - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) - { - const Atom states[2] = - { - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ - }; - - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) &states, 2); - } + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &states, 2); } } - // Declare the WM protocols supported by GLFW { int count = 0; @@ -436,27 +548,7 @@ static GLFWbool createWindow(_GLFWwindow* window, XFree(hints); } - // Set ICCCM WM_NORMAL_HINTS property (even if no parts are set) - { - XSizeHints* hints = XAllocSizeHints(); - hints->flags = 0; - - if (window->monitor) - { - hints->flags |= PPosition; - _glfwPlatformGetMonitorPos(window->monitor, &hints->x, &hints->y); - } - - if (!wndconfig->resizable) - { - hints->flags |= (PMinSize | PMaxSize); - hints->min_width = hints->max_width = wndconfig->width; - hints->min_height = hints->max_height = wndconfig->height; - } - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - XFree(hints); - } + updateNormalHints(window); // Set ICCCM WM_CLASS property // HACK: Until a mechanism for specifying the application name is added, the @@ -731,24 +823,17 @@ static GLFWbool acquireMonitor(_GLFWwindow* window) DefaultExposures); } - _glfw.x11.saver.count++; + if (!window->monitor->window) + _glfw.x11.saver.count++; status = _glfwSetVideoModeX11(window->monitor, &window->videoMode); - if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) - { - const unsigned long value = 1; - - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, - PropModeReplace, (unsigned char*) &value, 1); - } - - // Position the window over its monitor + if (window->x11.overrideRedirect) { int xpos, ypos; GLFWvidmode mode; + // Manually position the window over its monitor _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); _glfwPlatformGetVideoMode(window->monitor, &mode); @@ -756,31 +841,6 @@ static GLFWbool acquireMonitor(_GLFWwindow* window) xpos, ypos, mode.width, mode.height); } - if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS) - { - sendEventToWM(window, - _glfw.x11.NET_WM_FULLSCREEN_MONITORS, - window->monitor->x11.index, - window->monitor->x11.index, - window->monitor->x11.index, - window->monitor->x11.index, - 0); - } - - _glfwPlatformFocusWindow(window); - - if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) - { - // Ask the window manager to make the GLFW window a full screen window - // Full screen windows are undecorated and, when focused, are kept - // on top of all other windows - sendEventToWM(window, - _glfw.x11.NET_WM_STATE, - _NET_WM_STATE_ADD, - _glfw.x11.NET_WM_STATE_FULLSCREEN, - 0, 1, 0); - } - _glfwInputMonitorWindowChange(window->monitor, window); return status; } @@ -1124,9 +1184,6 @@ static void processEvent(XEvent *event) case ConfigureNotify: { - if (!window->x11.overrideRedirect && !event->xany.send_event) - return; - if (event->xconfigure.width != window->x11.width || event->xconfigure.height != window->x11.height) { @@ -1145,12 +1202,15 @@ static void processEvent(XEvent *event) if (event->xconfigure.x != window->x11.xpos || event->xconfigure.y != window->x11.ypos) { - _glfwInputWindowPos(window, - event->xconfigure.x, - event->xconfigure.y); + if (window->x11.overrideRedirect || event->xany.send_event) + { + _glfwInputWindowPos(window, + event->xconfigure.x, + event->xconfigure.y); - window->x11.xpos = event->xconfigure.x; - window->x11.ypos = event->xconfigure.y; + window->x11.xpos = event->xconfigure.x; + window->x11.ypos = event->xconfigure.y; + } } return; @@ -1459,6 +1519,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); + updateWindowMode(window); if (!acquireMonitor(window)) return GLFW_FALSE; } @@ -1654,31 +1715,13 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) { - _glfwSetVideoModeX11(window->monitor, &window->videoMode); - - if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN) - { - GLFWvidmode mode; - _glfwPlatformGetVideoMode(window->monitor, &mode); - XResizeWindow(_glfw.x11.display, window->x11.handle, - mode.width, mode.height); - } + if (window->monitor->window == window) + acquireMonitor(window); } else { if (!window->resizable) - { - // Update window size restrictions to match new window size - - XSizeHints* hints = XAllocSizeHints(); - - hints->flags |= (PMinSize | PMaxSize); - hints->min_width = hints->max_width = width; - hints->min_height = hints->max_height = height; - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - XFree(hints); - } + updateNormalHints(window); XResizeWindow(_glfw.x11.display, window->x11.handle, width, height); } @@ -1690,55 +1733,14 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { - long supplied; - XSizeHints* hints = XAllocSizeHints(); - - if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) - { - if (minwidth == GLFW_DONT_CARE || minwidth == GLFW_DONT_CARE) - hints->flags &= ~PMinSize; - else - { - hints->flags |= PMinSize; - hints->min_width = minwidth; - hints->min_height = minheight; - } - - if (maxwidth == GLFW_DONT_CARE || maxwidth == GLFW_DONT_CARE) - hints->flags &= ~PMaxSize; - else - { - hints->flags |= PMaxSize; - hints->max_width = maxwidth; - hints->max_height = maxheight; - } - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - } - - XFree(hints); + updateNormalHints(window); + XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { - long supplied; - XSizeHints* hints = XAllocSizeHints(); - - if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) - { - if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) - hints->flags &= ~PAspect; - else - { - hints->flags |= PAspect; - hints->min_aspect.x = hints->max_aspect.x = numer; - hints->min_aspect.y = hints->max_aspect.y = denom; - } - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - } - - XFree(hints); + updateNormalHints(window); + XFlush(_glfw.x11.display); } void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) @@ -1907,6 +1909,48 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, width, height); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + updateWindowMode(window); + + if (window->monitor) + { + XMapRaised(_glfw.x11.display, window->x11.handle); + acquireMonitor(window); + } + else + { + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, width, height); + } + + XFlush(_glfw.x11.display); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { Window focused; diff --git a/tests/iconify.c b/tests/iconify.c index 3eeaf749a..7990c08f1 100644 --- a/tests/iconify.c +++ b/tests/iconify.c @@ -36,6 +36,8 @@ #include "getopt.h" +static int windowed_xpos, windowed_ypos, windowed_width, windowed_height; + static void usage(void) { printf("Usage: iconify [-h] [-f [-a] [-n]]\n"); @@ -74,6 +76,34 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GLFW_TRUE); break; + case GLFW_KEY_ENTER: + { + if (mods != GLFW_MOD_ALT) + return; + + if (glfwGetWindowMonitor(window)) + { + glfwSetWindowMonitor(window, NULL, + windowed_xpos, windowed_ypos, + windowed_width, windowed_height, + 0); + } + else + { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + if (monitor) + { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + glfwGetWindowPos(window, &windowed_xpos, &windowed_ypos); + glfwGetWindowSize(window, &windowed_width, &windowed_height); + glfwSetWindowMonitor(window, monitor, + 0, 0, mode->width, mode->height, + mode->refreshRate); + } + } + + break; + } } } From 17bcefeac1fd5d6096c3e06b7c5f96551ea6f0bd Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 18 Mar 2016 12:01:48 +0100 Subject: [PATCH 101/156] Fix CGL context not being released until later Fixes #721. --- README.md | 2 ++ src/cocoa_window.m | 3 +++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index e329fb29c..db0686832 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,8 @@ does not find Doxygen, the documentation will not be generated. - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault - [Cocoa] Bugfix: Modifier flags cache was not updated when window became key - [Cocoa] Bugfix: Dead key character composition did not work + - [Cocoa] Bugfix: The CGL context was not released until the autorelease pool + was drained by another function - [X11] Bugfix: Monitor connection and disconnection events were not reported - [X11] Bugfix: Decoding of UTF-8 text from XIM could continue past the end - [X11] Bugfix: An XKB structure was leaked during `glfwInit` diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 99920d030..152bae69f 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1038,6 +1038,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) [window->ns.object close]; window->ns.object = nil; + + [_glfw.ns.autoreleasePool drain]; + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) From 728a088cd7d8fe5884ed1e30f8dadf1f73cf6e96 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 18 Mar 2016 12:08:43 +0100 Subject: [PATCH 102/156] Fix event processing guide section --- docs/input.dox | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/input.dox b/docs/input.dox index 89587d3db..c426e8873 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -33,8 +33,10 @@ information. GLFW needs to communicate regularly with the window system both in order to receive events and to show that the application hasn't locked up. Event -processing must be done regularly while you have visible windows and is normally -done each frame after [buffer swapping](@ref buffer_swap). +processing must be done regularly while you have any windows and is normally +done each frame after [buffer swapping](@ref buffer_swap). Even when you have +no windows, event polling needs to be done in order to receive monitor +connection events. There are two functions for processing pending events. @ref glfwPollEvents, processes only those events that have already been received and then returns From 3503cba5d9df2976fa94eeaf852e15f987a00fa0 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 24 Mar 2016 21:20:33 +0100 Subject: [PATCH 103/156] Fix Ctrl+Pause reported as unknown key on Win32 Fixes #730 --- README.md | 1 + src/win32_init.c | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index db0686832..14a9a81fe 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ does not find Doxygen, the documentation will not be generated. - [Win32] Bugfix: Activating or deactivating displays in software did not trigger monitor callback - [Win32] Bugfix: No monitors were listed on headless and VMware guest systems + - [Win32] Bugfix: Pressing Ctrl+Pause would report `GLFW_KEY_UNKNOWN` - [Cocoa] Removed support for OS X 10.6 - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault diff --git a/src/win32_init.c b/src/win32_init.c index 57acdb3ae..f993064f5 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -196,6 +196,7 @@ static void createKeyTables(void) _glfw.win32.publicKeys[0x151] = GLFW_KEY_PAGE_DOWN; _glfw.win32.publicKeys[0x149] = GLFW_KEY_PAGE_UP; _glfw.win32.publicKeys[0x045] = GLFW_KEY_PAUSE; + _glfw.win32.publicKeys[0x146] = GLFW_KEY_PAUSE; _glfw.win32.publicKeys[0x039] = GLFW_KEY_SPACE; _glfw.win32.publicKeys[0x00F] = GLFW_KEY_TAB; _glfw.win32.publicKeys[0x03A] = GLFW_KEY_CAPS_LOCK; From c1e4c45c7ae7094345a1eef1bbc68021f484b095 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 27 Mar 2016 21:20:31 +0200 Subject: [PATCH 104/156] Replace Win32 window long with window property Related to #25. --- src/win32_window.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/win32_window.c b/src/win32_window.c index b120ec4ee..5c9f87384 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -369,20 +369,13 @@ static void releaseMonitor(_GLFWwindow* window) static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - _GLFWwindow* window = (_GLFWwindow*) GetWindowLongPtrW(hWnd, 0); + _GLFWwindow* window = (_GLFWwindow*) GetPropW(hWnd, L"GLFW"); if (!window) { // This is the message handling for the hidden helper window switch (uMsg) { - case WM_NCCREATE: - { - CREATESTRUCTW* cs = (CREATESTRUCTW*) lParam; - SetWindowLongPtrW(hWnd, 0, (LONG_PTR) cs->lpCreateParams); - break; - } - case WM_DISPLAYCHANGE: { _glfwInputMonitorChange(); @@ -815,7 +808,7 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) NULL, // No parent window NULL, // No window menu GetModuleHandleW(NULL), - window); // Pass object to WM_CREATE + NULL); free(wideTitle); @@ -825,6 +818,8 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) return GLFW_FALSE; } + SetPropW(window->win32.handle, L"GLFW", window); + if (_glfw_ChangeWindowMessageFilterEx) { _glfw_ChangeWindowMessageFilterEx(window->win32.handle, @@ -846,6 +841,7 @@ static void destroyWindow(_GLFWwindow* window) { if (window->win32.handle) { + RemovePropW(window->win32.handle, L"GLFW"); DestroyWindow(window->win32.handle); window->win32.handle = NULL; } @@ -866,7 +862,6 @@ GLFWbool _glfwRegisterWindowClassWin32(void) wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC) windowProc; - wc.cbWndExtra = sizeof(void*) + sizeof(int); // Make room for one pointer wc.hInstance = GetModuleHandleW(NULL); wc.hCursor = LoadCursorW(NULL, IDC_ARROW); wc.lpszClassName = _GLFW_WNDCLASSNAME; From 5eb2e83c821787503e7146c176234e5fda9434f8 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 20 Mar 2016 09:39:53 +0100 Subject: [PATCH 105/156] Cleanup --- src/context.c | 37 +++++++++++++++---------------------- src/internal.h | 9 --------- src/window.c | 8 -------- 3 files changed, 15 insertions(+), 39 deletions(-) diff --git a/src/context.c b/src/context.c index c06018962..7d868a0dc 100644 --- a/src/context.c +++ b/src/context.c @@ -370,6 +370,21 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) return GLFW_FALSE; } + if (window->context.major < ctxconfig->major || + (window->context.major == ctxconfig->major && + window->context.minor < ctxconfig->minor)) + { + // The desired OpenGL version is greater than the actual version + // This only happens if the machine lacks {GLX|WGL}_ARB_create_context + // /and/ the user has requested an OpenGL version greater than 1.0 + + // For API consistency, we emulate the behavior of the + // {GLX|WGL}_ARB_create_context extension and fail here + + _glfwInputError(GLFW_VERSION_UNAVAILABLE, NULL); + return GLFW_FALSE; + } + if (window->context.major >= 3) { // OpenGL 3.0+ uses a different function for extension string retrieval @@ -490,28 +505,6 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) return GLFW_TRUE; } -GLFWbool _glfwIsValidContext(const _GLFWctxconfig* ctxconfig) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - if (window->context.major < ctxconfig->major || - (window->context.major == ctxconfig->major && - window->context.minor < ctxconfig->minor)) - { - // The desired OpenGL version is greater than the actual version - // This only happens if the machine lacks {GLX|WGL}_ARB_create_context - // /and/ the user has requested an OpenGL version greater than 1.0 - - // For API consistency, we emulate the behavior of the - // {GLX|WGL}_ARB_create_context extension and fail here - - _glfwInputError(GLFW_VERSION_UNAVAILABLE, NULL); - return GLFW_FALSE; - } - - return GLFW_TRUE; -} - GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions) { const char* start = extensions; diff --git a/src/internal.h b/src/internal.h index ebcd8b31a..42835d143 100644 --- a/src/internal.h +++ b/src/internal.h @@ -1009,15 +1009,6 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig); */ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig); -/*! @brief Checks whether the current context fulfils the specified hard - * constraints. - * @param[in] ctxconfig The desired context attributes. - * @return `GLFW_TRUE` if the context fulfils the hard constraints, or - * `GLFW_FALSE` otherwise. - * @ingroup utility - */ -GLFWbool _glfwIsValidContext(const _GLFWctxconfig* ctxconfig); - /*! @ingroup utility */ void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size); diff --git a/src/window.c b/src/window.c index c10f9acfe..bc2f600b1 100644 --- a/src/window.c +++ b/src/window.c @@ -210,14 +210,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, return NULL; } - // Verify the context against the requested parameters - if (!_glfwIsValidContext(&ctxconfig)) - { - glfwDestroyWindow((GLFWwindow*) window); - _glfwPlatformMakeContextCurrent(previous); - return NULL; - } - // Restore the previously current context (or NULL) _glfwPlatformMakeContextCurrent(previous); } From 5661d03be875d28ee72e44a037b653250de24a53 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 23 Mar 2016 10:09:07 +0100 Subject: [PATCH 106/156] Replace GLFWuint64 with uint64_t C99 stdint.h is provided by VS 2010 and later. GLFW has not provided testing or binaries for VS 2008 for several releases. For earlier versions of VS there are third-party alternatives: https://msinttypes.googlecode.com/svn/trunk/stdint.h http://www.azillionmonkeys.com/qed/pstdint.h This change does not affect the ABI. --- README.md | 1 - docs/input.dox | 4 ++-- include/GLFW/glfw3.h | 18 +++--------------- src/cocoa_platform.h | 2 +- src/cocoa_time.c | 4 ++-- src/input.c | 6 +++--- src/internal.h | 8 ++++---- src/posix_time.c | 4 ++-- src/posix_time.h | 2 +- src/win32_platform.h | 2 +- src/win32_time.c | 10 +++++----- src/x11_window.c | 2 +- 12 files changed, 25 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 14a9a81fe..4b331e249 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,6 @@ does not find Doxygen, the documentation will not be generated. - Added `glfwWaitEventsTimeout` for waiting for events for a set amount of time - Added `glfwSetWindowIcon` for setting the icon of a window - Added `glfwGetTimerValue` and `glfwGetTimerFrequency` for raw timer access - - Added `GLFWuint64` for platform-independent 64-bit unsigned values - Added `GLFW_NO_API` for creating window without contexts - Added `GLFW_CONTEXT_NO_ERROR` context hint for `GL_KHR_no_error` support - Added `GLFW_INCLUDE_VULKAN` for including the Vulkan header diff --git a/docs/input.dox b/docs/input.dox index c426e8873..8e4ff7eaa 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -571,7 +571,7 @@ You can also access the raw timer value, measured in 1 / frequency seconds, with @ref glfwGetTimerValue. @code -GLFWuint64 value = glfwGetTimerValue(); +uint64_t value = glfwGetTimerValue(); @endcode The frequency of the raw timer varies depending on what time sources are @@ -579,7 +579,7 @@ available on the machine. You can query its frequency, in Hz, with @ref glfwGetTimerFrequency. @code -GLFWuint64 freqency = glfwGetTimerFrequency(); +uint64_t freqency = glfwGetTimerFrequency(); @endcode diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index d88e108af..809e21530 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -120,6 +120,7 @@ extern "C" { * Include it unconditionally to avoid surprising side-effects. */ #include +#include /* Include the chosen client API headers. */ @@ -728,19 +729,6 @@ extern "C" { * GLFW API types *************************************************************************/ -/*! @brief 64-bit unsigned integer. - * - * 64-bit unsigned integer. - * - * @since Added in version 3.2. - */ -#if defined(_MSC_VER) && (_MSC_VER < 1600) -typedef unsigned __int64 GLFWuint64; -#else - #include -typedef uint64_t GLFWuint64; -#endif - /*! @brief Client API function pointer type. * * Generic function pointer used for returning client API function pointers @@ -3735,7 +3723,7 @@ GLFWAPI void glfwSetTime(double time); * * @ingroup input */ -GLFWAPI GLFWuint64 glfwGetTimerValue(void); +GLFWAPI uint64_t glfwGetTimerValue(void); /*! @brief Returns the frequency, in Hz, of the raw timer. * @@ -3755,7 +3743,7 @@ GLFWAPI GLFWuint64 glfwGetTimerValue(void); * * @ingroup input */ -GLFWAPI GLFWuint64 glfwGetTimerFrequency(void); +GLFWAPI uint64_t glfwGetTimerFrequency(void); /*! @brief Makes the context of the specified window current for the calling * thread. diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index bb52252d7..eeeb47271 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -118,7 +118,7 @@ typedef struct _GLFWcursorNS // typedef struct _GLFWtimeNS { - GLFWuint64 frequency; + uint64_t frequency; } _GLFWtimeNS; diff --git a/src/cocoa_time.c b/src/cocoa_time.c index 20b938d78..f8db04e97 100644 --- a/src/cocoa_time.c +++ b/src/cocoa_time.c @@ -48,12 +48,12 @@ void _glfwInitTimerNS(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWuint64 _glfwPlatformGetTimerValue(void) +uint64_t _glfwPlatformGetTimerValue(void) { return mach_absolute_time(); } -GLFWuint64 _glfwPlatformGetTimerFrequency(void) +uint64_t _glfwPlatformGetTimerFrequency(void) { return _glfw.ns_time.frequency; } diff --git a/src/input.c b/src/input.c index 368a55696..584f858e2 100644 --- a/src/input.c +++ b/src/input.c @@ -660,16 +660,16 @@ GLFWAPI void glfwSetTime(double time) } _glfw.timerOffset = _glfwPlatformGetTimerValue() - - (GLFWuint64) (time * _glfwPlatformGetTimerFrequency()); + (uint64_t) (time * _glfwPlatformGetTimerFrequency()); } -GLFWAPI GLFWuint64 glfwGetTimerValue(void) +GLFWAPI uint64_t glfwGetTimerValue(void) { _GLFW_REQUIRE_INIT_OR_RETURN(0); return _glfwPlatformGetTimerValue(); } -GLFWAPI GLFWuint64 glfwGetTimerFrequency(void) +GLFWAPI uint64_t glfwGetTimerFrequency(void) { _GLFW_REQUIRE_INIT_OR_RETURN(0); return _glfwPlatformGetTimerFrequency(); diff --git a/src/internal.h b/src/internal.h index 42835d143..fc33b0de5 100644 --- a/src/internal.h +++ b/src/internal.h @@ -91,7 +91,7 @@ typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint); typedef void* VkInstance; typedef void* VkPhysicalDevice; -typedef GLFWuint64 VkSurfaceKHR; +typedef uint64_t VkSurfaceKHR; typedef unsigned int VkFlags; typedef unsigned int VkBool32; @@ -431,7 +431,7 @@ struct _GLFWlibrary _GLFWmonitor** monitors; int monitorCount; - GLFWuint64 timerOffset; + uint64_t timerOffset; struct { GLFWbool available; @@ -600,12 +600,12 @@ const char* _glfwPlatformGetJoystickName(int joy); /*! @copydoc glfwGetTimerValue * @ingroup platform */ -GLFWuint64 _glfwPlatformGetTimerValue(void); +uint64_t _glfwPlatformGetTimerValue(void); /*! @copydoc glfwGetTimerFrequency * @ingroup platform */ -GLFWuint64 _glfwPlatformGetTimerFrequency(void); +uint64_t _glfwPlatformGetTimerFrequency(void); /*! @ingroup platform */ diff --git a/src/posix_time.c b/src/posix_time.c index 228f2f7e0..7b2d1ab29 100644 --- a/src/posix_time.c +++ b/src/posix_time.c @@ -60,7 +60,7 @@ void _glfwInitTimerPOSIX(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWuint64 _glfwPlatformGetTimerValue(void) +uint64_t _glfwPlatformGetTimerValue(void) { #if defined(CLOCK_MONOTONIC) if (_glfw.posix_time.monotonic) @@ -78,7 +78,7 @@ GLFWuint64 _glfwPlatformGetTimerValue(void) } } -GLFWuint64 _glfwPlatformGetTimerFrequency(void) +uint64_t _glfwPlatformGetTimerFrequency(void) { return _glfw.posix_time.frequency; } diff --git a/src/posix_time.h b/src/posix_time.h index 31591737d..237db3a99 100644 --- a/src/posix_time.h +++ b/src/posix_time.h @@ -38,7 +38,7 @@ typedef struct _GLFWtimePOSIX { GLFWbool monotonic; - GLFWuint64 frequency; + uint64_t frequency; } _GLFWtimePOSIX; diff --git a/src/win32_platform.h b/src/win32_platform.h index 36e3ead24..b94b0b0dd 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -275,7 +275,7 @@ typedef struct _GLFWcursorWin32 typedef struct _GLFWtimeWin32 { GLFWbool hasPC; - GLFWuint64 frequency; + uint64_t frequency; } _GLFWtimeWin32; diff --git a/src/win32_time.c b/src/win32_time.c index ec6294dbb..43e673512 100644 --- a/src/win32_time.c +++ b/src/win32_time.c @@ -36,7 +36,7 @@ // void _glfwInitTimerWin32(void) { - GLFWuint64 frequency; + uint64_t frequency; if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) { @@ -55,19 +55,19 @@ void _glfwInitTimerWin32(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWuint64 _glfwPlatformGetTimerValue(void) +uint64_t _glfwPlatformGetTimerValue(void) { if (_glfw.win32_time.hasPC) { - GLFWuint64 value; + uint64_t value; QueryPerformanceCounter((LARGE_INTEGER*) &value); return value; } else - return (GLFWuint64) _glfw_timeGetTime(); + return (uint64_t) _glfw_timeGetTime(); } -GLFWuint64 _glfwPlatformGetTimerFrequency(void) +uint64_t _glfwPlatformGetTimerFrequency(void) { return _glfw.win32_time.frequency; } diff --git a/src/x11_window.c b/src/x11_window.c index aaefcd818..9e004010d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1763,7 +1763,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, if (!_glfwPlatformWindowVisible(window) && _glfw.x11.NET_REQUEST_FRAME_EXTENTS) { - GLFWuint64 base; + uint64_t base; XEvent event; // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to From 7ab7d8b4b121d6a733af0a12495161a6e384a578 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 23 Mar 2016 10:24:01 +0100 Subject: [PATCH 107/156] Make use of uint32_t where appropriate This change does not affect the ABI. --- docs/vulkan.dox | 2 +- include/GLFW/glfw3.h | 2 +- src/cocoa_window.m | 4 ++-- src/internal.h | 14 +++++++------- src/mir_window.c | 4 ++-- src/vulkan.c | 6 +++--- src/win32_window.c | 4 ++-- src/wl_window.c | 4 ++-- src/x11_window.c | 4 ++-- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/vulkan.dox b/docs/vulkan.dox index a54000324..988c2b84b 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -127,7 +127,7 @@ To query the instance extensions required, call @ref glfwGetRequiredInstanceExtensions. @code -unsigned int count; +uint32_t count; const char** extensions = glfwGetRequiredInstanceExtensions(&count); @endcode diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 809e21530..ebd7eb26f 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4029,7 +4029,7 @@ GLFWAPI int glfwVulkanSupported(void); * * @ingroup vulkan */ -GLFWAPI const char** glfwGetRequiredInstanceExtensions(unsigned int* count); +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); #if defined(VK_VERSION_1_0) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 152bae69f..6f514392b 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1577,7 +1577,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return _glfw.ns.clipboardString; } -char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) { *count = 0; return NULL; @@ -1585,7 +1585,7 @@ char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, - unsigned int queuefamily) + uint32_t queuefamily) { return GLFW_FALSE; } diff --git a/src/internal.h b/src/internal.h index fc33b0de5..ae66c0bed 100644 --- a/src/internal.h +++ b/src/internal.h @@ -92,8 +92,8 @@ typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint); typedef void* VkInstance; typedef void* VkPhysicalDevice; typedef uint64_t VkSurfaceKHR; -typedef unsigned int VkFlags; -typedef unsigned int VkBool32; +typedef uint32_t VkFlags; +typedef uint32_t VkBool32; typedef enum VkStructureType { @@ -138,12 +138,12 @@ typedef struct VkAllocationCallbacks VkAllocationCallbacks; typedef struct VkExtensionProperties { char extensionName[256]; - unsigned int specVersion; + uint32_t specVersion; } VkExtensionProperties; typedef void (APIENTRY * PFN_vkVoidFunction)(void); typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*); -typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,unsigned int*,VkExtensionProperties*); +typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*); #define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties #define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr @@ -437,7 +437,7 @@ struct _GLFWlibrary GLFWbool available; void* handle; char** extensions; - unsigned int extensionCount; + uint32_t extensionCount; PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; PFN_vkGetInstanceProcAddr GetInstanceProcAddr; GLFWbool KHR_surface; @@ -799,11 +799,11 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); /*! @ingroup platform */ -char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count); +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count); /*! @ingroup platform */ -int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, unsigned int queuefamily); +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); /*! @ingroup platform */ diff --git a/src/mir_window.c b/src/mir_window.c index 8e6ceb896..6b6f44679 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -754,7 +754,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return NULL; } -char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) { char** extensions; @@ -773,7 +773,7 @@ char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, - unsigned int queuefamily) + uint32_t queuefamily) { PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR = (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR) diff --git a/src/vulkan.c b/src/vulkan.c index b4712127c..fb62a18fd 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -40,7 +40,7 @@ void _glfwInitVulkan(void) { VkResult err; VkExtensionProperties* ep; - unsigned int i, count; + uint32_t i, count; #if defined(_GLFW_WIN32) const char* name = "vulkan-1.dll"; #else @@ -120,7 +120,7 @@ void _glfwInitVulkan(void) void _glfwTerminateVulkan(void) { - unsigned int i; + uint32_t i; for (i = 0; i < _glfw.vk.extensionCount; i++) free(_glfw.vk.extensions[i]); @@ -196,7 +196,7 @@ GLFWAPI int glfwVulkanSupported(void) return _glfw.vk.available; } -GLFWAPI const char** glfwGetRequiredInstanceExtensions(unsigned int* count) +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count) { *count = 0; diff --git a/src/win32_window.c b/src/win32_window.c index 5c9f87384..2ffa70a4d 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1601,7 +1601,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return _glfw.win32.clipboardString; } -char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) { char** extensions; @@ -1620,7 +1620,7 @@ char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, - unsigned int queuefamily) + uint32_t queuefamily) { PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) diff --git a/src/wl_window.c b/src/wl_window.c index 0deef6d58..6a86f9e9c 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -847,7 +847,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return NULL; } -char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) { char** extensions; @@ -866,7 +866,7 @@ char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, - unsigned int queuefamily) + uint32_t queuefamily) { PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) diff --git a/src/x11_window.c b/src/x11_window.c index 9e004010d..2250ec2eb 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2273,7 +2273,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) return _glfw.x11.clipboardString; } -char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) { char** extensions; @@ -2299,7 +2299,7 @@ char** _glfwPlatformGetRequiredInstanceExtensions(unsigned int* count) int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, - unsigned int queuefamily) + uint32_t queuefamily) { VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display, _glfw.x11.screen)); From 925208d28ffc6f79994887c4d3c1e479b0459370 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 23 Mar 2016 10:24:59 +0100 Subject: [PATCH 108/156] Fix copypaste mistake --- src/x11_window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 2250ec2eb..ff38a82d4 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -210,9 +210,9 @@ static void updateNormalHints(_GLFWwindow* window) if (window->resizable) { if (window->minwidth != GLFW_DONT_CARE && - window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE && window->maxwidth != GLFW_DONT_CARE && - window->maxwidth != GLFW_DONT_CARE) + window->maxheight != GLFW_DONT_CARE) { hints->flags |= (PMinSize | PMaxSize); hints->min_width = window->minwidth; From f96d865b93b113543d36edfa5d605f970e53b890 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 28 Mar 2016 20:11:22 +0200 Subject: [PATCH 109/156] Cleanup --- src/egl_context.c | 6 +++--- src/egl_context.h | 1 - src/glx_context.c | 6 +++--- src/glx_context.h | 1 - src/internal.h | 4 +--- src/nsgl_context.h | 1 - src/wgl_context.c | 4 ++-- src/wgl_context.h | 1 - 8 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/egl_context.c b/src/egl_context.c index 827ccbfd3..74067fc0a 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -155,18 +155,18 @@ static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, u->samples = getConfigAttrib(n, EGL_SAMPLES); u->doublebuffer = GLFW_TRUE; - u->egl = n; + u->handle = (uintptr_t) n; usableCount++; } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) - *result = closest->egl; + *result = (EGLConfig) closest->handle; free(nativeConfigs); free(usableConfigs); - return closest ? GLFW_TRUE : GLFW_FALSE; + return closest != NULL; } diff --git a/src/egl_context.h b/src/egl_context.h index 15d5a1258..0b0b4dcba 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -149,7 +149,6 @@ typedef GLFWglproc (EGLAPIENTRY * PFNEGLGETPROCADDRESSPROC)(const char*); #define eglQueryString _glfw.egl.QueryString #define eglGetProcAddress _glfw.egl.GetProcAddress -#define _GLFW_PLATFORM_FBCONFIG EGLConfig egl #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl diff --git a/src/glx_context.c b/src/glx_context.c index 22ec7e10a..5fde5b05c 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -115,18 +115,18 @@ static GLFWbool chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB) u->sRGB = getFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); - u->glx = n; + u->handle = (uintptr_t) n; usableCount++; } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) - *result = closest->glx; + *result = (GLXFBConfig) closest->handle; XFree(nativeConfigs); free(usableConfigs); - return closest ? GLFW_TRUE : GLFW_FALSE; + return closest != NULL; } // Create the OpenGL context using legacy API diff --git a/src/glx_context.h b/src/glx_context.h index dc54c7973..c60186a64 100644 --- a/src/glx_context.h +++ b/src/glx_context.h @@ -108,7 +108,6 @@ typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); #define glXCreateWindow _glfw.glx.CreateWindow #define glXDestroyWindow _glfw.glx.DestroyWindow -#define _GLFW_PLATFORM_FBCONFIG GLXFBConfig glx #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx diff --git a/src/internal.h b/src/internal.h index ae66c0bed..d9d037c61 100644 --- a/src/internal.h +++ b/src/internal.h @@ -296,9 +296,7 @@ struct _GLFWfbconfig int samples; GLFWbool sRGB; GLFWbool doublebuffer; - - // This is defined in the context API's context.h - _GLFW_PLATFORM_FBCONFIG; + uintptr_t handle; }; diff --git a/src/nsgl_context.h b/src/nsgl_context.h index 6a0a22fd0..ab4cf3dfe 100644 --- a/src/nsgl_context.h +++ b/src/nsgl_context.h @@ -27,7 +27,6 @@ #ifndef _glfw3_nsgl_context_h_ #define _glfw3_nsgl_context_h_ -#define _GLFW_PLATFORM_FBCONFIG #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl diff --git a/src/wgl_context.c b/src/wgl_context.c index afc85bab1..608587c7a 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -236,7 +236,7 @@ static GLFWbool choosePixelFormat(_GLFWwindow* window, u->doublebuffer = GLFW_TRUE; } - u->wgl = n; + u->handle = n; usableCount++; } @@ -259,7 +259,7 @@ static GLFWbool choosePixelFormat(_GLFWwindow* window, return GLFW_FALSE; } - *result = closest->wgl; + *result = (int) closest->handle; free(usableConfigs); return GLFW_TRUE; diff --git a/src/wgl_context.h b/src/wgl_context.h index bc8968b4e..cca55e03a 100644 --- a/src/wgl_context.h +++ b/src/wgl_context.h @@ -96,7 +96,6 @@ typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC); #define _GLFW_RECREATION_REQUIRED 1 #define _GLFW_RECREATION_IMPOSSIBLE 2 -#define _GLFW_PLATFORM_FBCONFIG int wgl #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl From 33c68a24a063ad19e95e521d0b5b1489ef8f886f Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 28 Mar 2016 20:17:37 +0200 Subject: [PATCH 110/156] Formatting [ci skip] --- src/glx_context.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/glx_context.c b/src/glx_context.c index 5fde5b05c..0a5b8336d 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -163,7 +163,6 @@ GLFWbool _glfwInitGLX(void) NULL }; - for (i = 0; sonames[i]; i++) { _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); From bc713dabc435551e2e8f99e2f2ede4c44a12f33f Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 29 Mar 2016 10:45:06 +0200 Subject: [PATCH 111/156] Documentation work [ci skip] --- docs/window.dox | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/window.dox b/docs/window.dox index 1b25c553a..953e2eab3 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -912,9 +912,9 @@ window's context supports robustness, or `GLFW_NO_ROBUSTNESS` otherwise. @subsubsection window_attribs_fb Framebuffer related attributes -The attributes of the default framebuffer (i.e. the framebuffer attached to the -window) are not provided by this function but can be queried with both OpenGL -and OpenGL ES. +GLFW does not expose attributes of the default framebuffer (i.e. the framebuffer +attached to the window) as these can be queried directly with either OpenGL, +OpenGL ES or Vulkan. If you are using version 3.0 or later of OpenGL or OpenGL ES, the `glGetFramebufferAttachmentParameteriv` function can be used to retrieve the @@ -936,8 +936,8 @@ Stencil bits | `GL_STENCIL_BITS` | `GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE` MSAA samples | `GL_SAMPLES` | _Not provided by this function_ When calling `glGetFramebufferAttachmentParameteriv`, the red, green, blue and -alpha sizes can be queried from the `GL_BACK_LEFT`, while the depth and stencil -sizes can be queried from the `GL_DEPTH` and `GL_STENCIL` attachments, +alpha sizes are queried from the `GL_BACK_LEFT`, while the depth and stencil +sizes are queried from the `GL_DEPTH` and `GL_STENCIL` attachments, respectively. From 29e232f4b2d9849c21020880f3790739871090e3 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 29 Mar 2016 10:49:34 +0200 Subject: [PATCH 112/156] Improved error messages --- src/context.c | 28 ++++++++++++++++++---------- src/input.c | 23 +++++++++++------------ src/monitor.c | 2 +- src/window.c | 15 +++++++-------- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/context.c b/src/context.c index 7d868a0dc..eb8a561b7 100644 --- a/src/context.c +++ b/src/context.c @@ -57,7 +57,7 @@ static GLFWbool parseVersionString(int* api, int* major, int* minor, int* rev) if (!version) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Failed to retrieve context version string"); + "Client API version string retrieval is broken"); return GLFW_FALSE; } @@ -76,7 +76,7 @@ static GLFWbool parseVersionString(int* api, int* major, int* minor, int* rev) if (!sscanf(version, "%d.%d.%d", major, minor, rev)) { _glfwInputError(GLFW_PLATFORM_ERROR, - "No version found in context version string"); + "No version found in client API version string"); return GLFW_FALSE; } @@ -94,7 +94,9 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->api != GLFW_OPENGL_API && ctxconfig->api != GLFW_OPENGL_ES_API) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid client API"); + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid client API %i", + ctxconfig->api); return GLFW_FALSE; } @@ -123,7 +125,8 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid OpenGL profile"); + "Invalid OpenGL profile %i", + ctxconfig->profile); return GLFW_FALSE; } @@ -171,7 +174,8 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid context robustness mode"); + "Invalid context robustness mode %i", + ctxconfig->robustness); return GLFW_FALSE; } } @@ -182,7 +186,8 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid context release behavior"); + "Invalid context release behavior %i", + ctxconfig->release); return GLFW_FALSE; } } @@ -381,7 +386,10 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) // For API consistency, we emulate the behavior of the // {GLX|WGL}_ARB_create_context extension and fail here - _glfwInputError(GLFW_VERSION_UNAVAILABLE, NULL); + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "Requested client API version %i.%i, got version %i.%i", + ctxconfig->major, ctxconfig->minor, + window->context.major, window->context.minor); return GLFW_FALSE; } @@ -603,7 +611,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) if (*extension == '\0') { - _glfwInputError(GLFW_INVALID_VALUE, NULL); + _glfwInputError(GLFW_INVALID_VALUE, "Extension name is empty string"); return GLFW_FALSE; } @@ -623,7 +631,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) if (!en) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Failed to retrieve extension string %i", i); + "Extension string retrieval is broken"); return GLFW_FALSE; } @@ -640,7 +648,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) if (!extensions) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Failed to retrieve extension string"); + "Extension string retrieval is broken"); return GLFW_FALSE; } diff --git a/src/input.c b/src/input.c index 584f858e2..4ca83f871 100644 --- a/src/input.c +++ b/src/input.c @@ -44,7 +44,7 @@ static void setCursorMode(_GLFWwindow* window, int newMode) newMode != GLFW_CURSOR_HIDDEN && newMode != GLFW_CURSOR_DISABLED) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid cursor mode"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid cursor mode %i", newMode); return; } @@ -253,7 +253,7 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) case GLFW_STICKY_MOUSE_BUTTONS: return window->stickyMouseButtons; default: - _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode); return 0; } } @@ -277,7 +277,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) setStickyMouseButtons(window, value ? GLFW_TRUE : GLFW_FALSE); break; default: - _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode); break; } } @@ -297,7 +297,7 @@ GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) if (key < 0 || key > GLFW_KEY_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid key"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); return GLFW_RELEASE; } @@ -320,8 +320,7 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, - "Invalid mouse button"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button); return GLFW_RELEASE; } @@ -415,7 +414,7 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) shape != GLFW_HRESIZE_CURSOR && shape != GLFW_VRESIZE_CURSOR) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor %i", shape); return NULL; } @@ -570,7 +569,7 @@ GLFWAPI int glfwJoystickPresent(int joy) if (joy < 0 || joy > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy); return 0; } @@ -586,7 +585,7 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count) if (joy < 0 || joy > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy); return NULL; } @@ -602,7 +601,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count) if (joy < 0 || joy > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy); return NULL; } @@ -615,7 +614,7 @@ GLFWAPI const char* glfwGetJoystickName(int joy) if (joy < 0 || joy > GLFW_JOYSTICK_LAST) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy); return NULL; } @@ -655,7 +654,7 @@ GLFWAPI void glfwSetTime(double time) if (time != time || time < 0.0 || time > 18446744073.0) { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid time"); + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); return; } diff --git a/src/monitor.c b/src/monitor.c index 2ba4ceeee..f63aff9be 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -409,7 +409,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX) { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value"); + _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma); return; } diff --git a/src/window.c b/src/window.c index bc2f600b1..8aec74b8c 100644 --- a/src/window.c +++ b/src/window.c @@ -137,7 +137,10 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, if (width <= 0 || height <= 0) { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size"); + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window size %ix%i", + width, height); + return NULL; } @@ -372,7 +375,7 @@ GLFWAPI void glfwWindowHint(int hint, int value) _glfw.hints.refreshRate = value; break; default: - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint %i", hint); break; } } @@ -477,11 +480,7 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) _GLFW_REQUIRE_INIT(); if (window->monitor) - { - _glfwInputError(GLFW_INVALID_VALUE, - "Full screen windows cannot be moved"); return; - } _glfwPlatformSetWindowPos(window, xpos, ypos); } @@ -698,7 +697,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->context.noerror; } - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute"); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute %i", attrib); return 0; } @@ -849,7 +848,7 @@ GLFWAPI void glfwWaitEventsTimeout(double timeout) if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX) { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid time"); + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout); return; } From 20574fa81f5b8f9412dc6aedc27b535ea686767e Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 29 Mar 2016 11:05:42 +0200 Subject: [PATCH 113/156] Fix VC++ warnings --- 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 2ffa70a4d..ed822b427 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1225,14 +1225,14 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, if (monitor) { GLFWvidmode mode; - DWORD style = GetWindowLongPtrW(window->win32.handle, GWL_STYLE); + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; if (window->decorated) { style &= ~WS_OVERLAPPEDWINDOW; style |= getWindowStyle(window); - SetWindowLongPtrW(window->win32.handle, GWL_STYLE, style); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); flags |= SWP_FRAMECHANGED; } @@ -1250,14 +1250,14 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, { HWND after; RECT rect = { xpos, ypos, xpos + width, ypos + height }; - DWORD style = GetWindowLongPtrW(window->win32.handle, GWL_STYLE); + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; if (window->decorated) { style &= ~WS_POPUP; style |= getWindowStyle(window); - SetWindowLongPtrW(window->win32.handle, GWL_STYLE, style); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); flags |= SWP_FRAMECHANGED; } From c234a1942359dc5f2f7c2b8971bdb43b3bcb8ace Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 29 Mar 2016 11:09:03 +0200 Subject: [PATCH 114/156] Fix invalid EGL display being terminated --- src/egl_context.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/egl_context.c b/src/egl_context.c index 74067fc0a..26df4566d 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -269,9 +269,14 @@ GLFWbool _glfwInitEGL(void) // void _glfwTerminateEGL(void) { - if (_glfw.egl.handle) + if (_glfw.egl.display) { eglTerminate(_glfw.egl.display); + _glfw.egl.display = EGL_NO_DISPLAY; + } + + if (_glfw.egl.handle) + { _glfw_dlclose(_glfw.egl.handle); _glfw.egl.handle = NULL; } From 13e2ad2840e81478aad5a49239b602550c5ec5d6 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 29 Mar 2016 11:26:37 +0200 Subject: [PATCH 115/156] Documentation work --- docs/intro.dox | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/intro.dox b/docs/intro.dox index 301185c4e..6f0a22919 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -197,6 +197,7 @@ function: - @ref glfwDestroyCursor - @ref glfwPollEvents - @ref glfwWaitEvents + - @ref glfwWaitEventsTimeout - @ref glfwTerminate These functions may be made reentrant in future minor or patch releases, but @@ -242,8 +243,15 @@ may be called from any thread: - @ref glfwExtensionSupported - @ref glfwGetProcAddress -The timer may be accessed from any thread, but this is not synchronized by GLFW. -The following timer related functions may be called from any thread: +The raw timer may be queried from any thread. The following raw timer related +functions may be called from any thread: + + - @ref glfwGetTimerFrequency + - @ref glfwGetTimerValue + +The regular timer may be queried from any thread, but this is not synchronized +by GLFW with calls to @ref glfwSetTime. The following timer related functions +may be called from any thread: - @ref glfwGetTime From ae4ece840da41f0e3486f2aebbdbd3fc2f848b05 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Wed, 23 Mar 2016 16:11:34 -0600 Subject: [PATCH 116/156] Remove redundant OS X joystick polling Closes #729. --- src/cocoa_joystick.m | 56 +++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 5c584f6dc..9c7ccc42e 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -192,9 +192,35 @@ static void removeJoystick(_GLFWjoydeviceNS* joystick) memset(joystick, 0, sizeof(_GLFWjoydeviceNS)); } -// Polls for joystick events and updates GLFW state +// Polls for joystick axis events and updates GLFW state // -static GLFWbool pollJoystickEvents(_GLFWjoydeviceNS* joystick) +static GLFWbool pollJoystickAxisEvents(_GLFWjoydeviceNS* joystick) +{ + CFIndex i; + + if (!joystick->present) + return GLFW_FALSE; + + for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++) + { + _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) + CFArrayGetValueAtIndex(joystick->axisElements, i); + + long value = getElementValue(joystick, axis); + long readScale = axis->maxReport - axis->minReport; + + if (readScale == 0) + joystick->axes[i] = value; + else + joystick->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f; + } + + return GLFW_TRUE; +} + +// Polls for joystick button events and updates GLFW state +// +static GLFWbool pollJoystickButtonEvents(_GLFWjoydeviceNS* joystick) { CFIndex i; int buttonIndex = 0; @@ -213,20 +239,6 @@ static GLFWbool pollJoystickEvents(_GLFWjoydeviceNS* joystick) joystick->buttons[buttonIndex++] = GLFW_RELEASE; } - for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++) - { - _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) - CFArrayGetValueAtIndex(joystick->axisElements, i); - - long value = getElementValue(joystick, axis); - long readScale = axis->maxReport - axis->minReport; - - if (readScale == 0) - joystick->axes[i] = value; - else - joystick->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f; - } - for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++) { _GLFWjoyelementNS* hat = (_GLFWjoyelementNS*) @@ -469,13 +481,13 @@ void _glfwTerminateJoysticksNS(void) int _glfwPlatformJoystickPresent(int joy) { _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - return pollJoystickEvents(joystick); + return joystick->present ? GLFW_TRUE : GLFW_FALSE; } const float* _glfwPlatformGetJoystickAxes(int joy, int* count) { _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - if (!pollJoystickEvents(joystick)) + if (!pollJoystickAxisEvents(joystick)) return NULL; *count = (int) CFArrayGetCount(joystick->axisElements); @@ -485,7 +497,7 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count) const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) { _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - if (!pollJoystickEvents(joystick)) + if (!pollJoystickButtonEvents(joystick)) return NULL; *count = (int) CFArrayGetCount(joystick->buttonElements) + @@ -496,9 +508,9 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) const char* _glfwPlatformGetJoystickName(int joy) { _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - if (!pollJoystickEvents(joystick)) + if (joystick->present) + return joystick->name; + else return NULL; - - return joystick->name; } From c580949417bf0d8f41815007a71c7fd7f40c425d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 29 Mar 2016 13:42:11 +0200 Subject: [PATCH 117/156] Cleanup --- src/cocoa_joystick.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 9c7ccc42e..29264f490 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -481,7 +481,7 @@ void _glfwTerminateJoysticksNS(void) int _glfwPlatformJoystickPresent(int joy) { _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - return joystick->present ? GLFW_TRUE : GLFW_FALSE; + return joystick->present; } const float* _glfwPlatformGetJoystickAxes(int joy, int* count) @@ -508,9 +508,9 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) const char* _glfwPlatformGetJoystickName(int joy) { _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - if (joystick->present) - return joystick->name; - else + if (!joystick->present) return NULL; + + return joystick->name; } From 608a33f72bd34a848f83ec60becc20ebb0e8cc4d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 29 Mar 2016 14:00:44 +0200 Subject: [PATCH 118/156] Add credit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4b331e249..bc6ab59b9 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,7 @@ skills. - heromyth - Lucas Hinderberger - Paul Holden + - IntellectualKitty - Aaron Jacobs - Toni Jovanoski - Arseny Kapoulkine From 9f1474c1d04e641fd36cf721b1787e239e2d6170 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 29 Mar 2016 13:05:30 +0200 Subject: [PATCH 119/156] Add Unix full screen key chord for no reason --- examples/boing.c | 8 ++++++-- tests/iconify.c | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/boing.c b/examples/boing.c index e55d8d1c4..45c867fd1 100644 --- a/examples/boing.c +++ b/examples/boing.c @@ -237,9 +237,13 @@ void reshape( GLFWwindow* window, int w, int h ) void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods ) { - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + if (action != GLFW_PRESS) + return; + + if (key == GLFW_KEY_ESCAPE && mods == 0) glfwSetWindowShouldClose(window, GLFW_TRUE); - if (key == GLFW_KEY_ENTER && action == GLFW_PRESS && mods == GLFW_MOD_ALT) + if ((key == GLFW_KEY_ENTER && mods == GLFW_MOD_ALT) || + (key == GLFW_KEY_F11 && mods == GLFW_MOD_ALT)) { if (glfwGetWindowMonitor(window)) { diff --git a/tests/iconify.c b/tests/iconify.c index 7990c08f1..870345987 100644 --- a/tests/iconify.c +++ b/tests/iconify.c @@ -76,6 +76,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GLFW_TRUE); break; + case GLFW_KEY_F11: case GLFW_KEY_ENTER: { if (mods != GLFW_MOD_ALT) From eb3577c1ebca161c7d603d1c757fb62168711106 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Fri, 15 Aug 2014 15:08:09 +0200 Subject: [PATCH 120/156] Add initial XInput support --- src/win32_init.c | 53 +++++++- src/win32_joystick.c | 301 +++++++++++++++++++++++++++++-------------- src/win32_joystick.h | 9 +- src/win32_platform.h | 52 ++++++-- src/win32_window.c | 29 ++++- 5 files changed, 323 insertions(+), 121 deletions(-) diff --git a/src/win32_init.c b/src/win32_init.c index f993064f5..0a83c0e19 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -30,6 +30,8 @@ #include #include +#include +DEFINE_GUID(GUID_DEVINTERFACE_HID,0x4d1e55b2,0xf16f,0x11cf,0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30); #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) @@ -69,12 +71,6 @@ static GLFWbool loadLibraries(void) return GLFW_FALSE; } - _glfw.win32.winmm.joyGetDevCaps = (JOYGETDEVCAPS_T) - GetProcAddress(_glfw.win32.winmm.instance, "joyGetDevCapsW"); - _glfw.win32.winmm.joyGetPos = (JOYGETPOS_T) - GetProcAddress(_glfw.win32.winmm.instance, "joyGetPos"); - _glfw.win32.winmm.joyGetPosEx = (JOYGETPOSEX_T) - GetProcAddress(_glfw.win32.winmm.instance, "joyGetPosEx"); _glfw.win32.winmm.timeGetTime = (TIMEGETTIME_T) GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime"); @@ -90,6 +86,33 @@ static GLFWbool loadLibraries(void) _glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T) GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); + { + int i; + const char* names[] = + { + "xinput1_4.dll", + "xinput1_3.dll", + "xinput9_1_0.dll", + "xinput1_2.dll", + "xinput1_1.dll", + NULL + }; + + for (i = 0; names[i]; i++) + { + _glfw.win32.xinput.instance = LoadLibraryA(names[i]); + if (_glfw.win32.xinput.instance) + { + _glfw.win32.xinput.XInputGetCapabilities = (XINPUTGETCAPABILITIES_T) + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities"); + _glfw.win32.xinput.XInputGetState = (XINPUTGETSTATE_T) + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState"); + + break; + } + } + } + _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); if (_glfw.win32.dwmapi.instance) { @@ -113,6 +136,9 @@ static GLFWbool loadLibraries(void) // static void freeLibraries(void) { + if (_glfw.win32.xinput.instance) + FreeLibrary(_glfw.win32.xinput.instance); + if (_glfw.win32.winmm.instance) FreeLibrary(_glfw.win32.winmm.instance); @@ -283,7 +309,20 @@ static HWND createHelperWindow(void) return NULL; } - return window; + // Register for HID device notifications + { + DEV_BROADCAST_DEVICEINTERFACE_W dbi; + ZeroMemory(&dbi, sizeof(dbi)); + dbi.dbcc_size = sizeof(dbi); + dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; + + RegisterDeviceNotificationW(window, + (DEV_BROADCAST_HDR*) &dbi, + DEVICE_NOTIFY_WINDOW_HANDLE); + } + + return window; } diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 854dfe7d3..9184e80a9 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.2 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2010 Camilla Berglund +// Copyright (c) 2006-2015 Camilla Berglund // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -27,22 +27,169 @@ #include "internal.h" -#include +#include + +#define _GLFW_UPDATE_BUTTONS 1 +#define _GLFW_UPDATE_AXES 2 -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -// Convert axis value to the [-1,1] range +// Returns a description fitting the specified XInput capabilities // -static float normalizeAxis(DWORD pos, DWORD min, DWORD max) +static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic) { - float fpos = (float) pos; - float fmin = (float) min; - float fmax = (float) max; + switch (xic->SubType) + { + case XINPUT_DEVSUBTYPE_WHEEL: + return "XInput Wheel"; + case XINPUT_DEVSUBTYPE_ARCADE_STICK: + return "XInput Arcade Stick"; + case XINPUT_DEVSUBTYPE_FLIGHT_STICK: + return "XInput Flight Stick"; + case XINPUT_DEVSUBTYPE_DANCE_PAD: + return "XInput Dance Pad"; + case XINPUT_DEVSUBTYPE_GUITAR: + return "XInput Guitar"; + case XINPUT_DEVSUBTYPE_DRUM_KIT: + return "XInput Drum Kit"; + case XINPUT_DEVSUBTYPE_GAMEPAD: + { + if (xic->Flags & XINPUT_CAPS_WIRELESS) + return "Wireless Xbox 360 Controller"; + else + return "Xbox 360 Controller"; + } + } - return (2.f * (fpos - fmin) / (fmax - fmin)) - 1.f; + return "Unknown XInput Device"; +} + +// Attempt to open the specified joystick device +// TODO: Pack state arrays for non-gamepad devices +// +static GLFWbool openJoystickDevice(DWORD index) +{ + int joy; + XINPUT_CAPABILITIES xic; + _GLFWjoystickWin32* js; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (_glfw.win32_js[joy].present && _glfw.win32_js[joy].index == index) + return GLFW_FALSE; + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.win32_js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return GLFW_FALSE; + + if (_glfw_XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS) + return GLFW_FALSE; + + js = _glfw.win32_js + joy; + js->axisCount = 6; + js->buttonCount = 14; + js->present = GLFW_TRUE; + js->name = strdup(getDeviceDescription(&xic)); + js->index = index; + + return GLFW_TRUE; +} + +// Polls for and processes events the specified joystick +// +static GLFWbool pollJoystickEvents(_GLFWjoystickWin32* js, int flags) +{ + XINPUT_STATE xis; + DWORD result; + + if (!_glfw.win32.xinput.instance) + return GLFW_FALSE; + + if (!js->present) + return GLFW_FALSE; + + result = _glfw_XInputGetState(js->index, &xis); + if (result != ERROR_SUCCESS) + { + if (result == ERROR_DEVICE_NOT_CONNECTED) + { + free(js->name); + memset(js, 0, sizeof(_GLFWjoystickWin32)); + } + + return GLFW_FALSE; + } + + if (flags & _GLFW_UPDATE_AXES) + { + if (sqrtf((float) (xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX + + xis.Gamepad.sThumbLY * xis.Gamepad.sThumbLY)) > + (float) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) + { + js->axes[0] = (xis.Gamepad.sThumbLX + 0.5f) / 32767.f; + js->axes[1] = (xis.Gamepad.sThumbLY + 0.5f) / 32767.f; + } + else + { + js->axes[0] = 0.f; + js->axes[1] = 0.f; + } + + if (sqrtf((float) (xis.Gamepad.sThumbRX * xis.Gamepad.sThumbRX + + xis.Gamepad.sThumbRY * xis.Gamepad.sThumbRY)) > + (float) XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) + { + js->axes[2] = (xis.Gamepad.sThumbRX + 0.5f) / 32767.f; + js->axes[3] = (xis.Gamepad.sThumbRY + 0.5f) / 32767.f; + } + else + { + js->axes[2] = 0.f; + js->axes[3] = 0.f; + } + + if (xis.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + js->axes[4] = xis.Gamepad.bLeftTrigger / 127.5f - 1.f; + else + js->axes[4] = -1.f; + + if (xis.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + js->axes[5] = xis.Gamepad.bRightTrigger / 127.5f - 1.f; + else + js->axes[5] = -1.f; + } + + if (flags & _GLFW_UPDATE_BUTTONS) + { + int i; + const WORD buttons[14] = + { + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_BACK, + XINPUT_GAMEPAD_START, + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB, + XINPUT_GAMEPAD_DPAD_UP, + XINPUT_GAMEPAD_DPAD_RIGHT, + XINPUT_GAMEPAD_DPAD_DOWN, + XINPUT_GAMEPAD_DPAD_LEFT + }; + + for (i = 0; i < 14; i++) + js->buttons[i] = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0; + } + + return GLFW_TRUE; } @@ -54,16 +201,43 @@ static float normalizeAxis(DWORD pos, DWORD min, DWORD max) // void _glfwInitJoysticksWin32(void) { + _glfwDetectJoystickConnectionWin32(); } // Close all opened joystick handles // void _glfwTerminateJoysticksWin32(void) { - int i; + int joy; - for (i = 0; i < GLFW_JOYSTICK_LAST; i++) - free(_glfw.win32_js[i].name); + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + free(_glfw.win32_js[joy].name); +} + +// Looks for new joysticks +// +void _glfwDetectJoystickConnectionWin32(void) +{ + DWORD i; + + if (!_glfw.win32.xinput.instance) + return; + + for (i = 0; i < XUSER_MAX_COUNT; i++) + openJoystickDevice(i); +} + +// Checks if any current joystick has been disconnected +// +void _glfwDetectJoystickDisconnectionWin32(void) +{ + DWORD i; + + if (!_glfw.win32.xinput.instance) + return; + + for (i = 0; i < XUSER_MAX_COUNT; i++) + pollJoystickEvents(_glfw.win32_js + i, 0); } @@ -73,105 +247,36 @@ void _glfwTerminateJoysticksWin32(void) int _glfwPlatformJoystickPresent(int joy) { - JOYINFO ji; - - if (_glfw_joyGetPos(joy, &ji) != JOYERR_NOERROR) - return GLFW_FALSE; - - return GLFW_TRUE; + _GLFWjoystickWin32* js = _glfw.win32_js + joy; + return pollJoystickEvents(js, 0); } const float* _glfwPlatformGetJoystickAxes(int joy, int* count) { - JOYCAPS jc; - JOYINFOEX ji; - float* axes = _glfw.win32_js[joy].axes; - - if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) + _GLFWjoystickWin32* js = _glfw.win32_js + joy; + if (!pollJoystickEvents(js, _GLFW_UPDATE_AXES)) return NULL; - ji.dwSize = sizeof(JOYINFOEX); - ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | - JOY_RETURNR | JOY_RETURNU | JOY_RETURNV; - if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR) - return NULL; - - axes[(*count)++] = normalizeAxis(ji.dwXpos, jc.wXmin, jc.wXmax); - axes[(*count)++] = normalizeAxis(ji.dwYpos, jc.wYmin, jc.wYmax); - - if (jc.wCaps & JOYCAPS_HASZ) - axes[(*count)++] = normalizeAxis(ji.dwZpos, jc.wZmin, jc.wZmax); - - if (jc.wCaps & JOYCAPS_HASR) - axes[(*count)++] = normalizeAxis(ji.dwRpos, jc.wRmin, jc.wRmax); - - if (jc.wCaps & JOYCAPS_HASU) - axes[(*count)++] = normalizeAxis(ji.dwUpos, jc.wUmin, jc.wUmax); - - if (jc.wCaps & JOYCAPS_HASV) - axes[(*count)++] = normalizeAxis(ji.dwVpos, jc.wVmin, jc.wVmax); - - return axes; + *count = js->axisCount; + return js->axes; } const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) { - JOYCAPS jc; - JOYINFOEX ji; - unsigned char* buttons = _glfw.win32_js[joy].buttons; - - if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) + _GLFWjoystickWin32* js = _glfw.win32_js + joy; + if (!pollJoystickEvents(js, _GLFW_UPDATE_BUTTONS)) return NULL; - ji.dwSize = sizeof(JOYINFOEX); - ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV; - if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR) - return NULL; - - while (*count < (int) jc.wNumButtons) - { - buttons[*count] = (unsigned char) - (ji.dwButtons & (1UL << *count) ? GLFW_PRESS : GLFW_RELEASE); - (*count)++; - } - - // Virtual buttons - Inject data from hats - // Each hat is exposed as 4 buttons which exposes 8 directions with - // concurrent button presses - // NOTE: this API exposes only one hat - - if ((jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR)) - { - int i, value = ji.dwPOV / 100 / 45; - - // Bit fields of button presses for each direction, including nil - const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; - - if (value < 0 || value > 8) - value = 8; - - for (i = 0; i < 4; i++) - { - if (directions[value] & (1 << i)) - buttons[(*count)++] = GLFW_PRESS; - else - buttons[(*count)++] = GLFW_RELEASE; - } - } - - return buttons; + *count = js->buttonCount; + return js->buttons; } const char* _glfwPlatformGetJoystickName(int joy) { - JOYCAPS jc; - - if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) + _GLFWjoystickWin32* js = _glfw.win32_js + joy; + if (!pollJoystickEvents(js, 0)) return NULL; - free(_glfw.win32_js[joy].name); - _glfw.win32_js[joy].name = _glfwCreateUTF8FromWideStringWin32(jc.szPname); - - return _glfw.win32_js[joy].name; + return js->name; } diff --git a/src/win32_joystick.h b/src/win32_joystick.h index ea999cd87..e57d16ea4 100644 --- a/src/win32_joystick.h +++ b/src/win32_joystick.h @@ -30,18 +30,23 @@ #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ _GLFWjoystickWin32 win32_js[GLFW_JOYSTICK_LAST + 1] - // Win32-specific per-joystick data // typedef struct _GLFWjoystickWin32 { + GLFWbool present; float axes[6]; - unsigned char buttons[36]; // 32 buttons plus one hat + int axisCount; + unsigned char buttons[14]; + int buttonCount; char* name; + DWORD index; } _GLFWjoystickWin32; void _glfwInitJoysticksWin32(void); 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 b94b0b0dd..6ec69c6e4 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -63,6 +63,7 @@ #include #include +#include #include #if defined(_MSC_VER) @@ -120,16 +121,42 @@ typedef enum PROCESS_DPI_AWARENESS } PROCESS_DPI_AWARENESS; #endif /*DPI_ENUMS_DECLARED*/ +// HACK: Define macros that some older xinput.h variants don't +#ifndef XINPUT_CAPS_WIRELESS + #define XINPUT_CAPS_WIRELESS 0x0002 +#endif +#ifndef XINPUT_DEVSUBTYPE_WHEEL + #define XINPUT_DEVSUBTYPE_WHEEL 0x02 +#endif +#ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK + #define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 +#endif +#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK + #define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04 +#endif +#ifndef XINPUT_DEVSUBTYPE_DANCE_PAD + #define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 +#endif +#ifndef XINPUT_DEVSUBTYPE_GUITAR + #define XINPUT_DEVSUBTYPE_GUITAR 0x06 +#endif +#ifndef XINPUT_DEVSUBTYPE_DRUM_KIT + #define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 +#endif +#ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD + #define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13 +#endif + // winmm.dll function pointer typedefs -typedef MMRESULT (WINAPI * JOYGETDEVCAPS_T)(UINT,LPJOYCAPS,UINT); -typedef MMRESULT (WINAPI * JOYGETPOS_T)(UINT,LPJOYINFO); -typedef MMRESULT (WINAPI * JOYGETPOSEX_T)(UINT,LPJOYINFOEX); typedef DWORD (WINAPI * TIMEGETTIME_T)(void); -#define _glfw_joyGetDevCaps _glfw.win32.winmm.joyGetDevCaps -#define _glfw_joyGetPos _glfw.win32.winmm.joyGetPos -#define _glfw_joyGetPosEx _glfw.win32.winmm.joyGetPosEx #define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime +// xinput.dll function pointer typedefs +typedef DWORD (WINAPI * XINPUTGETCAPABILITIES_T)(DWORD,DWORD,XINPUT_CAPABILITIES*); +typedef DWORD (WINAPI * XINPUTGETSTATE_T)(DWORD,XINPUT_STATE*); +#define _glfw_XInputGetCapabilities _glfw.win32.xinput.XInputGetCapabilities +#define _glfw_XInputGetState _glfw.win32.xinput.XInputGetState + // user32.dll function pointer typedefs typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void); typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); @@ -217,16 +244,19 @@ typedef struct _GLFWlibraryWin32 // winmm.dll struct { HINSTANCE instance; - JOYGETDEVCAPS_T joyGetDevCaps; - JOYGETPOS_T joyGetPos; - JOYGETPOSEX_T joyGetPosEx; TIMEGETTIME_T timeGetTime; } winmm; // user32.dll struct { - HINSTANCE instance; - SETPROCESSDPIAWARE_T SetProcessDPIAware; + HINSTANCE instance; + XINPUTGETCAPABILITIES_T XInputGetCapabilities; + XINPUTGETSTATE_T XInputGetState; + } xinput; + + struct { + HINSTANCE instance; + SETPROCESSDPIAWARE_T SetProcessDPIAware; CHANGEWINDOWMESSAGEFILTEREX_T ChangeWindowMessageFilterEx; } user32; diff --git a/src/win32_window.c b/src/win32_window.c index ed822b427..ed6bbe7f6 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -376,10 +376,33 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, switch (uMsg) { - case WM_DISPLAYCHANGE: + case WM_DEVICECHANGE: { - _glfwInputMonitorChange(); - return 0; + if (wParam == DBT_DEVNODES_CHANGED) + { + _glfwInputMonitorChange(); + return TRUE; + } + else if (wParam == DBT_DEVICEARRIVAL) + { + DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; + if (dbh) + { + if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickConnectionWin32(); + } + } + else if (wParam == DBT_DEVICEREMOVECOMPLETE) + { + DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; + if (dbh) + { + if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickDisconnectionWin32(); + } + } + + break; } } From 3bbc8e31916e63b145dac228d32a43db9bacdcbf Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 31 Mar 2016 10:45:40 +0200 Subject: [PATCH 121/156] Hack for msvcrt and mintty --- tests/joysticks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/joysticks.c b/tests/joysticks.c index 7eaf52383..5397ba7f8 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -229,6 +229,9 @@ int main(void) glfwSwapBuffers(window); glfwPollEvents(); + + // Workaround for an issue with msvcrt and mintty + fflush(stdout); } glfwTerminate(); From bdd17c337fef4e8b29734d6d289dd5eaa23a5e31 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 8 Feb 2016 16:39:08 +0100 Subject: [PATCH 122/156] Make helper window child of HWND_MESSAGE --- src/win32_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32_init.c b/src/win32_init.c index 0a83c0e19..23dbfa01a 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -299,7 +299,7 @@ static HWND createHelperWindow(void) L"GLFW helper window", WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 1, 1, - NULL, NULL, + HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); if (!window) From 8a7fa306cecbccb64e8e38f2f9712d815590953d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 13 Dec 2015 17:38:50 +0100 Subject: [PATCH 123/156] Add glfwSetJoystickCallback --- README.md | 2 + docs/input.dox | 27 ++++++++ include/GLFW/glfw3.h | 40 ++++++++++++ src/cocoa_joystick.m | 4 ++ src/input.c | 13 ++++ src/internal.h | 8 +++ src/linux_joystick.c | 48 +++++++++------ src/linux_joystick.h | 2 + src/win32_joystick.c | 3 + src/x11_window.c | 14 ++++- tests/events.c | 24 ++++++++ tests/joysticks.c | 142 ++++++++++++++++++------------------------- 12 files changed, 223 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index bc6ab59b9..292ccecbb 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ does not find Doxygen, the documentation will not be generated. - Added `glfwWaitEventsTimeout` for waiting for events for a set amount of time - Added `glfwSetWindowIcon` for setting the icon of a window - Added `glfwGetTimerValue` and `glfwGetTimerFrequency` for raw timer access + - Added `glfwSetJoystickCallback` and `GLFWjoystickfun` for joystick connection + and disconnection events - Added `GLFW_NO_API` for creating window without contexts - Added `GLFW_CONTEXT_NO_ERROR` context hint for `GL_KHR_no_error` support - Added `GLFW_INCLUDE_VULKAN` for including the Vulkan header diff --git a/docs/input.dox b/docs/input.dox index 8e4ff7eaa..7ac3f2292 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -547,6 +547,33 @@ and make may have the same name. Only the [joystick token](@ref joysticks) is guaranteed to be unique, and only until that joystick is disconnected. +@subsection joystick_event Joystick configuration changes + +If you wish to be notified when a joystick is connected or disconnected, set +a joystick callback. + +@code +glfwSetJoystickCallback(joystick_callback); +@endcode + +The callback function receives the ID of the joystick that has been connected +and disconnected and the event that occurred. + +@code +void joystick_callback(int joy, int event) +{ + if (event == GLFW_CONNECTED) + { + // The joystick was connected + } + else if (event == GLFW_DISCONNECTED) + { + // The joystick was disconnected + } +} +@endcode + + @section time Time input GLFW provides high-resolution time input, in seconds, with @ref glfwGetTime. diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index ebd7eb26f..f8ca3d61a 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1097,6 +1097,23 @@ typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); */ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); +/*! @brief The function signature for joystick configuration callbacks. + * + * This is the function signature for joystick configuration callback + * functions. + * + * @param[in] joy The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa @ref joystick_event + * @sa glfwSetJoystickCallback + * + * @since Added in version 3.2. + * + * @ingroup input + */ +typedef void (* GLFWjoystickfun)(int,int); + /*! @brief Video mode type. * * This describes a single video mode. @@ -3596,6 +3613,29 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); */ GLFWAPI const char* glfwGetJoystickName(int joy); +/*! @brief Sets the joystick configuration callback. + * + * This function sets the joystick configuration callback, or removes the + * currently set callback. This is called when a joystick is connected to or + * disconnected from the system. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_event + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); + /*! @brief Sets the clipboard to the specified string. * * This function sets the system clipboard to the specified, UTF-8 encoded diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 29264f490..71ead6d10 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -190,6 +190,8 @@ static void removeJoystick(_GLFWjoydeviceNS* joystick) free(joystick->buttons); memset(joystick, 0, sizeof(_GLFWjoydeviceNS)); + + _glfwInputJoystickChange(joystick - _glfw.ns_js.devices, GLFW_DISCONNECTED); } // Polls for joystick axis events and updates GLFW state @@ -329,6 +331,8 @@ static void matchCallback(void* context, sizeof(float)); joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) + CFArrayGetCount(joystick->hatElements) * 4, 1); + + _glfwInputJoystickChange(joy, GLFW_CONNECTED); } // Callback for user-initiated joystick removal diff --git a/src/input.c b/src/input.c index 4ca83f871..287dab3cc 100644 --- a/src/input.c +++ b/src/input.c @@ -220,6 +220,12 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) window->callbacks.drop((GLFWwindow*) window, count, paths); } +void _glfwInputJoystickChange(int joy, int event) +{ + if (_glfw.callbacks.joystick) + _glfw.callbacks.joystick(joy, event); +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -621,6 +627,13 @@ GLFWAPI const char* glfwGetJoystickName(int joy) return _glfwPlatformGetJoystickName(joy); } +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun); + return cbfun; +} + GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/internal.h b/src/internal.h index d9d037c61..e83047706 100644 --- a/src/internal.h +++ b/src/internal.h @@ -448,6 +448,7 @@ struct _GLFWlibrary struct { GLFWmonitorfun monitor; + GLFWjoystickfun joystick; } callbacks; // This is defined in the window API's platform.h @@ -947,6 +948,13 @@ void _glfwInputError(int error, const char* format, ...); */ void _glfwInputDrop(_GLFWwindow* window, int count, const char** names); +/*! @brief Notifies shared code of a joystick connection/disconnection event. + * @param[in] joy The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * @ingroup event + */ +void _glfwInputJoystickChange(int joy, int event); + //======================================================================== // Utility functions diff --git a/src/linux_joystick.c b/src/linux_joystick.c index e3f8bb38c..3342e0fef 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -100,6 +100,8 @@ static GLFWbool openJoystickDevice(const char* path) ioctl(fd, JSIOCGBUTTONS, &buttonCount); js->buttonCount = (int) buttonCount; js->buttons = calloc(buttonCount, 1); + + _glfwInputJoystickChange(joy, GLFW_CONNECTED); #endif // __linux__ return GLFW_TRUE; } @@ -109,25 +111,7 @@ static GLFWbool openJoystickDevice(const char* path) static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js) { #if defined(__linux__) - ssize_t offset = 0; - char buffer[16384]; - - const ssize_t size = read(_glfw.linux_js.inotify, buffer, sizeof(buffer)); - - while (size > offset) - { - regmatch_t match; - const struct inotify_event* e = (struct inotify_event*) (buffer + offset); - - if (regexec(&_glfw.linux_js.regex, e->name, 1, &match, 0) == 0) - { - char path[20]; - snprintf(path, sizeof(path), "/dev/input/%s", e->name); - openJoystickDevice(path); - } - - offset += sizeof(struct inotify_event) + e->len; - } + _glfwPollJoystickEvents(); if (!js->present) return GLFW_FALSE; @@ -149,6 +133,9 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js) free(js->path); memset(js, 0, sizeof(_GLFWjoystickLinux)); + + _glfwInputJoystickChange(js - _glfw.linux_js.js, + GLFW_DISCONNECTED); } break; @@ -285,6 +272,29 @@ void _glfwTerminateJoysticksLinux(void) #endif // __linux__ } +void _glfwPollJoystickEvents(void) +{ + ssize_t offset = 0; + char buffer[16384]; + + const ssize_t size = read(_glfw.linux_js.inotify, buffer, sizeof(buffer)); + + while (size > offset) + { + regmatch_t match; + const struct inotify_event* e = (struct inotify_event*) (buffer + offset); + + if (regexec(&_glfw.linux_js.regex, e->name, 1, &match, 0) == 0) + { + char path[20]; + snprintf(path, sizeof(path), "/dev/input/%s", e->name); + openJoystickDevice(path); + } + + offset += sizeof(struct inotify_event) + e->len; + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// diff --git a/src/linux_joystick.h b/src/linux_joystick.h index 6f34d5760..c949e81d6 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -64,4 +64,6 @@ typedef struct _GLFWjoylistLinux GLFWbool _glfwInitJoysticksLinux(void); void _glfwTerminateJoysticksLinux(void); +void _glfwPollJoystickEvents(void); + #endif // _glfw3_linux_joystick_h_ diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 9184e80a9..b3eab7072 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -97,6 +97,8 @@ static GLFWbool openJoystickDevice(DWORD index) js->name = strdup(getDeviceDescription(&xic)); js->index = index; + _glfwInputJoystickChange(joy, GLFW_CONNECTED); + return GLFW_TRUE; } @@ -120,6 +122,7 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickWin32* js, int flags) { free(js->name); memset(js, 0, sizeof(_GLFWjoystickWin32)); + _glfwInputJoystickChange((int) (js - _glfw.win32_js), GLFW_DISCONNECTED); } return GLFW_FALSE; diff --git a/src/x11_window.c b/src/x11_window.c index ff38a82d4..0f8053247 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -54,11 +54,19 @@ void selectDisplayConnection(struct timeval* timeout) { fd_set fds; - int result; + int result, count; const int fd = ConnectionNumber(_glfw.x11.display); FD_ZERO(&fds); FD_SET(fd, &fds); +#if defined(__linux__) + FD_SET(_glfw.linux_js.inotify, &fds); +#endif + + if (fd > _glfw.linux_js.inotify) + count = fd + 1; + else + count = _glfw.linux_js.inotify + 1; // NOTE: We use select instead of an X function like XNextEvent, as the // wait inside those are guarded by the mutex protecting the display @@ -68,7 +76,7 @@ void selectDisplayConnection(struct timeval* timeout) // TODO: Update timeout value manually do { - result = select(fd + 1, &fds, NULL, NULL, timeout); + result = select(count, &fds, NULL, NULL, timeout); } while (result == -1 && errno == EINTR && timeout == NULL); } @@ -1999,6 +2007,8 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) void _glfwPlatformPollEvents(void) { + _glfwPollJoystickEvents(); + int count = XPending(_glfw.x11.display); while (count--) { diff --git a/tests/events.c b/tests/events.c index 3d4a81065..5e697f973 100644 --- a/tests/events.c +++ b/tests/events.c @@ -451,6 +451,29 @@ static void monitor_callback(GLFWmonitor* monitor, int event) } } +static void joystick_callback(int joy, int event) +{ + if (event == GLFW_CONNECTED) + { + int axisCount, buttonCount; + + glfwGetJoystickAxes(joy, &axisCount); + glfwGetJoystickButtons(joy, &buttonCount); + + printf("%08x at %0.3f: Joystick %i (%s) was connected with %i axes and %i buttons\n", + counter++, glfwGetTime(), + joy, + glfwGetJoystickName(joy), + axisCount, + buttonCount); + } + else + { + printf("%08x at %0.3f: Joystick %i was disconnected\n", + counter++, glfwGetTime(), joy); + } +} + int main(int argc, char** argv) { Slot* slots; @@ -467,6 +490,7 @@ int main(int argc, char** argv) printf("Library initialized\n"); glfwSetMonitorCallback(monitor_callback); + glfwSetJoystickCallback(joystick_callback); while ((ch = getopt(argc, argv, "hfn:")) != -1) { diff --git a/tests/joysticks.c b/tests/joysticks.c index 5397ba7f8..04b578e90 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -39,17 +39,7 @@ #define strdup(x) _strdup(x) #endif -typedef struct Joystick -{ - int present; - char* name; - float* axes; - unsigned char* buttons; - int axis_count; - int button_count; -} Joystick; - -static Joystick joysticks[GLFW_JOYSTICK_LAST - GLFW_JOYSTICK_1 + 1]; +static int joysticks[GLFW_JOYSTICK_LAST + 1]; static int joystick_count = 0; static void error_callback(int error, const char* description) @@ -62,19 +52,23 @@ static void framebuffer_size_callback(GLFWwindow* window, int width, int height) glViewport(0, 0, width, height); } -static void draw_joystick(Joystick* j, int x, int y, int width, int height) +static void draw_joystick(int index, int x, int y, int width, int height) { int i; + int axis_count, button_count; + const float* axes; + const unsigned char* buttons; const int axis_height = 3 * height / 4; const int button_height = height / 4; - if (j->axis_count) + axes = glfwGetJoystickAxes(joysticks[index], &axis_count); + if (axis_count) { - const int axis_width = width / j->axis_count; + const int axis_width = width / axis_count; - for (i = 0; i < j->axis_count; i++) + for (i = 0; i < axis_count; i++) { - float value = j->axes[i] / 2.f + 0.5f; + float value = axes[i] / 2.f + 0.5f; glColor3f(0.3f, 0.3f, 0.3f); glRecti(x + i * axis_width, @@ -90,13 +84,14 @@ static void draw_joystick(Joystick* j, int x, int y, int width, int height) } } - if (j->button_count) + buttons = glfwGetJoystickButtons(joysticks[index], &button_count); + if (button_count) { - const int button_width = width / j->button_count; + const int button_width = width / button_count; - for (i = 0; i < j->button_count; i++) + for (i = 0; i < button_count; i++) { - if (j->buttons[i]) + if (buttons[i]) glColor3f(1.f, 1.f, 1.f); else glColor3f(0.3f, 0.3f, 0.3f); @@ -120,79 +115,58 @@ static void draw_joysticks(GLFWwindow* window) glOrtho(0.f, width, height, 0.f, 1.f, -1.f); glMatrixMode(GL_MODELVIEW); - for (i = 0; i < sizeof(joysticks) / sizeof(Joystick); i++) + for (i = 0; i < joystick_count; i++) { - Joystick* j = joysticks + i; - - if (j->present) - { - draw_joystick(j, - 0, offset * height / joystick_count, - width, height / joystick_count); - offset++; - } + draw_joystick(i, + 0, offset * height / joystick_count, + width, height / joystick_count); + offset++; } } -static void refresh_joysticks(void) +static void joystick_callback(int joy, int event) { - int i; - - for (i = 0; i < sizeof(joysticks) / sizeof(Joystick); i++) + if (event == GLFW_CONNECTED) { - Joystick* j = joysticks + i; + int axis_count, button_count; - if (glfwJoystickPresent(GLFW_JOYSTICK_1 + i)) + glfwGetJoystickAxes(joy, &axis_count); + glfwGetJoystickButtons(joy, &button_count); + + printf("Found joystick %i named \'%s\' with %i axes, %i buttons\n", + joy + 1, + glfwGetJoystickName(joy), + axis_count, + button_count); + + joysticks[joystick_count++] = joy; + } + else if (event == GLFW_DISCONNECTED) + { + int i; + + for (i = 0; i < joystick_count; i++) { - const float* axes; - const unsigned char* buttons; - int axis_count, button_count; - - free(j->name); - j->name = strdup(glfwGetJoystickName(GLFW_JOYSTICK_1 + i)); - - axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1 + i, &axis_count); - if (axis_count != j->axis_count) - { - j->axis_count = axis_count; - j->axes = realloc(j->axes, j->axis_count * sizeof(float)); - } - - memcpy(j->axes, axes, axis_count * sizeof(float)); - - buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1 + i, &button_count); - if (button_count != j->button_count) - { - j->button_count = button_count; - j->buttons = realloc(j->buttons, j->button_count); - } - - memcpy(j->buttons, buttons, button_count * sizeof(unsigned char)); - - if (!j->present) - { - printf("Found joystick %i named \'%s\' with %i axes, %i buttons\n", - i + 1, j->name, j->axis_count, j->button_count); - - joystick_count++; - } - - j->present = GLFW_TRUE; + if (joysticks[i] == joy) + break; } - else - { - if (j->present) - { - printf("Lost joystick %i named \'%s\'\n", i + 1, j->name); - free(j->name); - free(j->axes); - free(j->buttons); - memset(j, 0, sizeof(Joystick)); + for (i = i + 1; i < joystick_count; i++) + joysticks[i - 1] = joysticks[i]; - joystick_count--; - } - } + printf("Lost joystick %i\n", joy + 1); + joystick_count--; + } +} + +static void find_joysticks(void) +{ + int joy; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (glfwJoystickPresent(joy)) + joystick_callback(joy, GLFW_CONNECTED); } } @@ -207,6 +181,9 @@ int main(void) if (!glfwInit()) exit(EXIT_FAILURE); + find_joysticks(); + glfwSetJoystickCallback(joystick_callback); + window = glfwCreateWindow(640, 480, "Joystick Test", NULL, NULL); if (!window) { @@ -224,7 +201,6 @@ int main(void) { glClear(GL_COLOR_BUFFER_BIT); - refresh_joysticks(); draw_joysticks(window); glfwSwapBuffers(window); From 3aebb0bfe3ecd9362139b35ec65eddd81e4c2536 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 8 Feb 2016 09:32:48 +0100 Subject: [PATCH 124/156] Cleanup --- src/cocoa_joystick.h | 2 +- src/cocoa_joystick.m | 169 ++++++++++++++++++++----------------------- 2 files changed, 81 insertions(+), 90 deletions(-) diff --git a/src/cocoa_joystick.h b/src/cocoa_joystick.h index f1ea1532f..48d82b85b 100644 --- a/src/cocoa_joystick.h +++ b/src/cocoa_joystick.h @@ -56,7 +56,7 @@ typedef struct _GLFWjoydeviceNS // typedef struct _GLFWjoystickNS { - _GLFWjoydeviceNS devices[GLFW_JOYSTICK_LAST + 1]; + _GLFWjoydeviceNS js[GLFW_JOYSTICK_LAST + 1]; IOHIDManagerRef managerRef; } _GLFWjoystickNS; diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 71ead6d10..0e0a20f5b 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -38,9 +38,8 @@ #include -//------------------------------------------------------------------------ // Joystick element information -//------------------------------------------------------------------------ +// typedef struct _GLFWjoyelementNS { IOHIDElementRef elementRef; @@ -58,7 +57,7 @@ static void getElementsCFArrayHandler(const void* value, void* parameter); // Adds an element to the specified joystick // -static void addJoystickElement(_GLFWjoydeviceNS* joystick, +static void addJoystickElement(_GLFWjoydeviceNS* js, IOHIDElementRef elementRef) { IOHIDElementType elementType; @@ -91,10 +90,10 @@ static void addJoystickElement(_GLFWjoydeviceNS* joystick, case kHIDUsage_GD_Slider: case kHIDUsage_GD_Dial: case kHIDUsage_GD_Wheel: - elementsArray = joystick->axisElements; + elementsArray = js->axisElements; break; case kHIDUsage_GD_Hatswitch: - elementsArray = joystick->hatElements; + elementsArray = js->hatElements; break; } @@ -102,7 +101,7 @@ static void addJoystickElement(_GLFWjoydeviceNS* joystick, } case kHIDPage_Button: - elementsArray = joystick->buttonElements; + elementsArray = js->buttonElements; break; default: break; @@ -134,15 +133,15 @@ static void getElementsCFArrayHandler(const void* value, void* parameter) // Returns the value of the specified element of the specified joystick // -static long getElementValue(_GLFWjoydeviceNS* joystick, _GLFWjoyelementNS* element) +static long getElementValue(_GLFWjoydeviceNS* js, _GLFWjoyelementNS* element) { IOReturn result = kIOReturnSuccess; IOHIDValueRef valueRef; long value = 0; - if (joystick && element && joystick->deviceRef) + if (js && element && js->deviceRef) { - result = IOHIDDeviceGetValue(joystick->deviceRef, + result = IOHIDDeviceGetValue(js->deviceRef, element->elementRef, &valueRef); @@ -164,57 +163,57 @@ static long getElementValue(_GLFWjoydeviceNS* joystick, _GLFWjoyelementNS* eleme // Removes the specified joystick // -static void removeJoystick(_GLFWjoydeviceNS* joystick) +static void removeJoystick(_GLFWjoydeviceNS* js) { int i; - if (!joystick->present) + if (!js->present) return; - for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++) - free((void*) CFArrayGetValueAtIndex(joystick->axisElements, i)); - CFArrayRemoveAllValues(joystick->axisElements); - CFRelease(joystick->axisElements); + for (i = 0; i < CFArrayGetCount(js->axisElements); i++) + free((void*) CFArrayGetValueAtIndex(js->axisElements, i)); + CFArrayRemoveAllValues(js->axisElements); + CFRelease(js->axisElements); - for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++) - free((void*) CFArrayGetValueAtIndex(joystick->buttonElements, i)); - CFArrayRemoveAllValues(joystick->buttonElements); - CFRelease(joystick->buttonElements); + for (i = 0; i < CFArrayGetCount(js->buttonElements); i++) + free((void*) CFArrayGetValueAtIndex(js->buttonElements, i)); + CFArrayRemoveAllValues(js->buttonElements); + CFRelease(js->buttonElements); - for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++) - free((void*) CFArrayGetValueAtIndex(joystick->hatElements, i)); - CFArrayRemoveAllValues(joystick->hatElements); - CFRelease(joystick->hatElements); + for (i = 0; i < CFArrayGetCount(js->hatElements); i++) + free((void*) CFArrayGetValueAtIndex(js->hatElements, i)); + CFArrayRemoveAllValues(js->hatElements); + CFRelease(js->hatElements); - free(joystick->axes); - free(joystick->buttons); + free(js->axes); + free(js->buttons); - memset(joystick, 0, sizeof(_GLFWjoydeviceNS)); + memset(js, 0, sizeof(_GLFWjoydeviceNS)); - _glfwInputJoystickChange(joystick - _glfw.ns_js.devices, GLFW_DISCONNECTED); + _glfwInputJoystickChange(js - _glfw.ns_js.js, GLFW_DISCONNECTED); } // Polls for joystick axis events and updates GLFW state // -static GLFWbool pollJoystickAxisEvents(_GLFWjoydeviceNS* joystick) +static GLFWbool pollJoystickAxisEvents(_GLFWjoydeviceNS* js) { CFIndex i; - if (!joystick->present) + if (!js->present) return GLFW_FALSE; - for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++) + for (i = 0; i < CFArrayGetCount(js->axisElements); i++) { _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) - CFArrayGetValueAtIndex(joystick->axisElements, i); + CFArrayGetValueAtIndex(js->axisElements, i); - long value = getElementValue(joystick, axis); + long value = getElementValue(js, axis); long readScale = axis->maxReport - axis->minReport; if (readScale == 0) - joystick->axes[i] = value; + js->axes[i] = value; else - joystick->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f; + js->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f; } return GLFW_TRUE; @@ -222,43 +221,43 @@ static GLFWbool pollJoystickAxisEvents(_GLFWjoydeviceNS* joystick) // Polls for joystick button events and updates GLFW state // -static GLFWbool pollJoystickButtonEvents(_GLFWjoydeviceNS* joystick) +static GLFWbool pollJoystickButtonEvents(_GLFWjoydeviceNS* js) { CFIndex i; int buttonIndex = 0; - if (!joystick->present) + if (!js->present) return GLFW_FALSE; - for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++) + for (i = 0; i < CFArrayGetCount(js->buttonElements); i++) { _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) - CFArrayGetValueAtIndex(joystick->buttonElements, i); + CFArrayGetValueAtIndex(js->buttonElements, i); - if (getElementValue(joystick, button)) - joystick->buttons[buttonIndex++] = GLFW_PRESS; + if (getElementValue(js, button)) + js->buttons[buttonIndex++] = GLFW_PRESS; else - joystick->buttons[buttonIndex++] = GLFW_RELEASE; + js->buttons[buttonIndex++] = GLFW_RELEASE; } - for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++) + for (i = 0; i < CFArrayGetCount(js->hatElements); i++) { _GLFWjoyelementNS* hat = (_GLFWjoyelementNS*) - CFArrayGetValueAtIndex(joystick->hatElements, i); + CFArrayGetValueAtIndex(js->hatElements, i); // Bit fields of button presses for each direction, including nil const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; - long j, value = getElementValue(joystick, hat); + long j, value = getElementValue(js, hat); if (value < 0 || value > 8) value = 8; for (j = 0; j < 4; j++) { if (directions[value] & (1 << j)) - joystick->buttons[buttonIndex++] = GLFW_PRESS; + js->buttons[buttonIndex++] = GLFW_PRESS; else - joystick->buttons[buttonIndex++] = GLFW_RELEASE; + js->buttons[buttonIndex++] = GLFW_RELEASE; } } @@ -272,49 +271,43 @@ static void matchCallback(void* context, void* sender, IOHIDDeviceRef deviceRef) { - _GLFWjoydeviceNS* joystick; + _GLFWjoydeviceNS* js; int joy; for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) { - joystick = _glfw.ns_js.devices + joy; - - if (!joystick->present) - continue; - - if (joystick->deviceRef == deviceRef) + if (!_glfw.ns_js.js[joy].present && _glfw.ns_js.js[joy].deviceRef == deviceRef) return; } for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) { - joystick = _glfw.ns_js.devices + joy; - - if (!joystick->present) + if (!_glfw.ns_js.js[joy].present) break; } if (joy > GLFW_JOYSTICK_LAST) return; - joystick->present = GLFW_TRUE; - joystick->deviceRef = deviceRef; + js = _glfw.ns_js.js + joy; + js->present = GLFW_TRUE; + js->deviceRef = deviceRef; CFStringRef name = IOHIDDeviceGetProperty(deviceRef, CFSTR(kIOHIDProductKey)); if (name) { CFStringGetCString(name, - joystick->name, - sizeof(joystick->name), + js->name, + sizeof(js->name), kCFStringEncodingUTF8); } else - strncpy(joystick->name, "Unknown", sizeof(joystick->name)); + strncpy(js->name, "Unknown", sizeof(js->name)); - joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL); - joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL); - joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL); + js->axisElements = CFArrayCreateMutable(NULL, 0, NULL); + js->buttonElements = CFArrayCreateMutable(NULL, 0, NULL); + js->hatElements = CFArrayCreateMutable(NULL, 0, NULL); CFArrayRef arrayRef = IOHIDDeviceCopyMatchingElements(deviceRef, NULL, @@ -323,14 +316,13 @@ static void matchCallback(void* context, CFArrayApplyFunction(arrayRef, range, getElementsCFArrayHandler, - (void*) joystick); + (void*) js); CFRelease(arrayRef); - joystick->axes = calloc(CFArrayGetCount(joystick->axisElements), - sizeof(float)); - joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) + - CFArrayGetCount(joystick->hatElements) * 4, 1); + js->axes = calloc(CFArrayGetCount(js->axisElements), sizeof(float)); + js->buttons = calloc(CFArrayGetCount(js->buttonElements) + + CFArrayGetCount(js->hatElements) * 4, 1); _glfwInputJoystickChange(joy, GLFW_CONNECTED); } @@ -346,10 +338,9 @@ static void removeCallback(void* context, for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) { - _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - if (joystick->deviceRef == deviceRef) + if (_glfw.ns_js.js[joy].deviceRef == deviceRef) { - removeJoystick(joystick); + removeJoystick(_glfw.ns_js.js + joy); break; } } @@ -467,10 +458,10 @@ void _glfwTerminateJoysticksNS(void) { int joy; - for (joy = 0; joy <= GLFW_JOYSTICK_LAST; joy++) + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) { - _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - removeJoystick(joystick); + _GLFWjoydeviceNS* js = _glfw.ns_js.js + joy; + removeJoystick(js); } CFRelease(_glfw.ns_js.managerRef); @@ -484,37 +475,37 @@ void _glfwTerminateJoysticksNS(void) int _glfwPlatformJoystickPresent(int joy) { - _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - return joystick->present; + _GLFWjoydeviceNS* js = _glfw.ns_js.js + joy; + return js->present; } const float* _glfwPlatformGetJoystickAxes(int joy, int* count) { - _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - if (!pollJoystickAxisEvents(joystick)) + _GLFWjoydeviceNS* js = _glfw.ns_js.js + joy; + if (!pollJoystickAxisEvents(js)) return NULL; - *count = (int) CFArrayGetCount(joystick->axisElements); - return joystick->axes; + *count = (int) CFArrayGetCount(js->axisElements); + return js->axes; } const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) { - _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - if (!pollJoystickButtonEvents(joystick)) + _GLFWjoydeviceNS* js = _glfw.ns_js.js + joy; + if (!pollJoystickButtonEvents(js)) return NULL; - *count = (int) CFArrayGetCount(joystick->buttonElements) + - (int) CFArrayGetCount(joystick->hatElements) * 4; - return joystick->buttons; + *count = (int) CFArrayGetCount(js->buttonElements) + + (int) CFArrayGetCount(js->hatElements) * 4; + return js->buttons; } const char* _glfwPlatformGetJoystickName(int joy) { - _GLFWjoydeviceNS* joystick = _glfw.ns_js.devices + joy; - if (!joystick->present) + _GLFWjoydeviceNS* js = _glfw.ns_js.js + joy; + if (!js->present) return NULL; - return joystick->name; + return js->name; } From 7cbdae1bed69d21a29f69ec3d476e6ac31339569 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 16 Feb 2016 23:06:29 +0100 Subject: [PATCH 125/156] Add initial DirectInput 8 support Fixes #232. --- README.md | 1 + src/win32_init.c | 10 + src/win32_joystick.c | 602 ++++++++++++++++++++++++++++++++++++++----- src/win32_joystick.h | 26 +- src/win32_platform.h | 27 +- 5 files changed, 591 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 292ccecbb..d58659ad7 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ does not find Doxygen, the documentation will not be generated. - Removed `_GLFW_USE_OPENGL`, `_GLFW_USE_GLESV1` and `_GLFW_USE_GLESV2` configuration macros - [Win32] Added support for Windows 8.1 per-monitor DPI + - [Win32] Replaced winmm with XInput and DirectInput for joystick input - [Win32] Bugfix: Window creation would segfault if video mode setting required the system to be restarted - [Win32] Bugfix: MinGW import library lacked the `lib` prefix diff --git a/src/win32_init.c b/src/win32_init.c index 23dbfa01a..521f0452d 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -86,6 +86,13 @@ static GLFWbool loadLibraries(void) _glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T) GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); + _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); + if (_glfw.win32.dinput8.instance) + { + _glfw.win32.dinput8.DirectInput8Create = (DIRECTINPUT8CREATE_T) + GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create"); + } + { int i; const char* names[] = @@ -139,6 +146,9 @@ static void freeLibraries(void) if (_glfw.win32.xinput.instance) FreeLibrary(_glfw.win32.xinput.instance); + if (_glfw.win32.dinput8.instance) + FreeLibrary(_glfw.win32.dinput8.instance); + if (_glfw.win32.winmm.instance) FreeLibrary(_glfw.win32.winmm.instance); diff --git a/src/win32_joystick.c b/src/win32_joystick.c index b3eab7072..43336a31f 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -29,9 +29,104 @@ #include -#define _GLFW_UPDATE_BUTTONS 1 -#define _GLFW_UPDATE_AXES 2 +#include +#define _GLFW_PRESENCE_ONLY 1 +#define _GLFW_UPDATE_STATE 2 + +#define _GLFW_TYPE_AXIS 0 +#define _GLFW_TYPE_SLIDER 1 +#define _GLFW_TYPE_BUTTON 2 +#define _GLFW_TYPE_POV 3 + +// Data produced with DirectInput device object enumeration +// +typedef struct _GLFWobjenumWin32 +{ + IDirectInputDevice8W* device; + _GLFWjoyobjectWin32* objects; + int objectCount; + int axisCount; + int sliderCount; + int buttonCount; + int povCount; +} _GLFWobjenumWin32; + +// Define only the necessary GUIDs (it's bad enough that we're exporting these) +// +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); + +// Object data array for our clone of c_dfDIJoystick +// Generated with https://github.com/elmindreda/c_dfDIJoystick2 +// +static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] = +{ + { &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, +}; + +// Our clone of c_dfDIJoystick +// +static const DIDATAFORMAT _glfwDataFormat = +{ + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDFT_ABSAXIS, + sizeof(DIJOYSTATE), + sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT), + _glfwObjectDataFormats +}; // Returns a description fitting the specified XInput capabilities // @@ -63,10 +158,294 @@ static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic) return "Unknown XInput Device"; } +// Lexically compare device objects +// +static int compareJoystickObjects(const void* first, const void* second) +{ + const _GLFWjoyobjectWin32* fo = first; + const _GLFWjoyobjectWin32* so = second; + + if (fo->type != so->type) + return fo->type - so->type; + + return fo->offset - so->offset; +} + +// Checks whether the specified device supports XInput +// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom +// +static GLFWbool supportsXInput(const GUID* guid) +{ + UINT i, count; + RAWINPUTDEVICELIST* ridl; + GLFWbool result = GLFW_FALSE; + + if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0) + return GLFW_FALSE; + + ridl = calloc(count, sizeof(RAWINPUTDEVICELIST)); + + if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == -1) + { + free(ridl); + return GLFW_FALSE; + } + + for (i = 0; i < count; i++) + { + RID_DEVICE_INFO rdi; + char name[256]; + UINT size; + + if (ridl[i].dwType != RIM_TYPEHID) + continue; + + ZeroMemory(&rdi, sizeof(rdi)); + rdi.cbSize = sizeof(rdi); + size = sizeof(rdi); + + if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice, + RIDI_DEVICEINFO, + &rdi, &size) == -1) + { + continue; + } + + if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != guid->Data1) + continue; + + memset(name, 0, sizeof(name)); + size = sizeof(name); + + if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice, + RIDI_DEVICENAME, + name, &size) == -1) + { + break; + } + + name[sizeof(name) - 1] = '\0'; + if (strstr(name, "IG_")) + { + result = GLFW_TRUE; + break; + } + } + + free(ridl); + return result; +} + +// Frees all resources associated with the specified joystick +// +static void closeJoystick(_GLFWjoystickWin32* js) +{ + if (js->device) + { + IDirectInputDevice8_Unacquire(js->device); + IDirectInputDevice8_Release(js->device); + } + + free(js->name); + free(js->axes); + free(js->buttons); + free(js->objects); + memset(js, 0, sizeof(_GLFWjoystickWin32)); + + _glfwInputJoystickChange((int) (js - _glfw.win32_js), GLFW_DISCONNECTED); +} + +// DirectInput device object enumeration callback +// Insights gleaned from SDL2 +// +static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi, + void* user) +{ + _GLFWobjenumWin32* data = user; + _GLFWjoyobjectWin32* object = data->objects + data->objectCount; + + if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS) + { + DIPROPRANGE dipr; + + if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0) + object->offset = DIJOFS_SLIDER(data->sliderCount); + else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_X; + else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_Y; + else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_Z; + else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RX; + else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RY; + else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RZ; + else + return DIENUM_CONTINUE; + + ZeroMemory(&dipr, sizeof(dipr)); + dipr.diph.dwSize = sizeof(dipr); + dipr.diph.dwHeaderSize = sizeof(dipr.diph); + dipr.diph.dwObj = doi->dwType; + dipr.diph.dwHow = DIPH_BYID; + dipr.lMin = -32768; + dipr.lMax = 32767; + + if (FAILED(IDirectInputDevice8_SetProperty(data->device, + DIPROP_RANGE, + &dipr.diph))) + { + return DIENUM_CONTINUE; + } + + if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0) + { + object->type = _GLFW_TYPE_SLIDER; + data->sliderCount++; + } + else + { + object->type = _GLFW_TYPE_AXIS; + data->axisCount++; + } + } + else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON) + { + object->offset = DIJOFS_BUTTON(data->buttonCount); + object->type = _GLFW_TYPE_BUTTON; + data->buttonCount++; + } + else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV) + { + object->offset = DIJOFS_POV(data->povCount); + object->type = _GLFW_TYPE_POV; + data->povCount++; + } + + data->objectCount++; + return DIENUM_CONTINUE; +} + +// DirectInput device enumeration callback +// +static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) +{ + int joy = 0; + DIDEVCAPS dc; + DIPROPDWORD dipd; + IDirectInputDevice8* device; + _GLFWobjenumWin32 data; + _GLFWjoystickWin32* js; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (memcmp(&_glfw.win32_js[joy].guid, &di->guidInstance, sizeof(GUID)) == 0) + return DIENUM_CONTINUE; + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.win32_js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return DIENUM_STOP; + + if (supportsXInput(&di->guidProduct)) + return DIENUM_CONTINUE; + + if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api, + &di->guidInstance, + &device, + NULL))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "DI: Failed to create device"); + return DIENUM_CONTINUE; + } + + if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to set device data format"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + ZeroMemory(&dc, sizeof(dc)); + dc.dwSize = sizeof(dc); + + if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to query device capabilities"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + ZeroMemory(&dipd, sizeof(dipd)); + dipd.diph.dwSize = sizeof(dipd); + dipd.diph.dwHeaderSize = sizeof(dipd.diph); + dipd.diph.dwHow = DIPH_DEVICE; + dipd.dwData = DIPROPAXISMODE_ABS; + + if (FAILED(IDirectInputDevice8_SetProperty(device, + DIPROP_AXISMODE, + &dipd.diph))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to set device axis mode"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + memset(&data, 0, sizeof(data)); + data.device = device; + data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs, + sizeof(_GLFWjoyobjectWin32)); + + if (FAILED(IDirectInputDevice8_EnumObjects(device, + deviceObjectCallback, + &data, + DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to enumerate device objects"); + + IDirectInputDevice8_Release(device); + free(data.objects); + return DIENUM_CONTINUE; + } + + qsort(data.objects, data.objectCount, + sizeof(_GLFWjoyobjectWin32), + compareJoystickObjects); + + js = _glfw.win32_js + joy; + js->device = device; + js->guid = di->guidInstance; + js->axisCount = data.axisCount + data.sliderCount; + js->axes = calloc(js->axisCount, sizeof(float)); + js->buttonCount += data.buttonCount + data.povCount * 4; + js->buttons = calloc(js->buttonCount, 1); + js->objects = data.objects; + js->objectCount = data.objectCount; + js->name = _glfwCreateUTF8FromWideStringWin32(di->tszInstanceName); + js->present = GLFW_TRUE; + + _glfwInputJoystickChange(joy, GLFW_CONNECTED); + return DIENUM_CONTINUE; +} + // Attempt to open the specified joystick device // TODO: Pack state arrays for non-gamepad devices // -static GLFWbool openJoystickDevice(DWORD index) +static GLFWbool openXinputDevice(DWORD index) { int joy; XINPUT_CAPABILITIES xic; @@ -74,8 +453,12 @@ static GLFWbool openJoystickDevice(DWORD index) for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) { - if (_glfw.win32_js[joy].present && _glfw.win32_js[joy].index == index) + if (_glfw.win32_js[joy].present && + _glfw.win32_js[joy].device == NULL && + _glfw.win32_js[joy].index == index) + { return GLFW_FALSE; + } } for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) @@ -92,7 +475,9 @@ static GLFWbool openJoystickDevice(DWORD index) js = _glfw.win32_js + joy; js->axisCount = 6; + js->axes = calloc(js->axisCount, sizeof(float)); js->buttonCount = 14; + js->buttons = calloc(js->buttonCount, 1); js->present = GLFW_TRUE; js->name = strdup(getDeviceDescription(&xic)); js->index = index; @@ -104,32 +489,120 @@ static GLFWbool openJoystickDevice(DWORD index) // Polls for and processes events the specified joystick // -static GLFWbool pollJoystickEvents(_GLFWjoystickWin32* js, int flags) +static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) { - XINPUT_STATE xis; - DWORD result; - - if (!_glfw.win32.xinput.instance) - return GLFW_FALSE; - if (!js->present) return GLFW_FALSE; - result = _glfw_XInputGetState(js->index, &xis); - if (result != ERROR_SUCCESS) + if (js->device) { - if (result == ERROR_DEVICE_NOT_CONNECTED) + int i, j, ai = 0, bi = 0; + HRESULT result; + DIJOYSTATE state; + + IDirectInputDevice8_Poll(js->device); + result = IDirectInputDevice8_GetDeviceState(js->device, + sizeof(state), + &state); + if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST) { - free(js->name); - memset(js, 0, sizeof(_GLFWjoystickWin32)); - _glfwInputJoystickChange((int) (js - _glfw.win32_js), GLFW_DISCONNECTED); + IDirectInputDevice8_Acquire(js->device); + IDirectInputDevice8_Poll(js->device); + result = IDirectInputDevice8_GetDeviceState(js->device, + sizeof(state), + &state); } - return GLFW_FALSE; - } + if (FAILED(result)) + { + closeJoystick(js); + return GLFW_FALSE; + } - if (flags & _GLFW_UPDATE_AXES) + if (mode == _GLFW_PRESENCE_ONLY) + return GLFW_TRUE; + + for (i = 0; i < js->objectCount; i++) + { + const void* data = (char*) &state + js->objects[i].offset; + + switch (js->objects[i].type) + { + case _GLFW_TYPE_AXIS: + case _GLFW_TYPE_SLIDER: + { + js->axes[ai++] = (*((LONG*) data) + 0.5f) / 32767.5f; + break; + } + + case _GLFW_TYPE_BUTTON: + { + if (*((BYTE*) data) & 0x80) + js->buttons[bi++] = GLFW_PRESS; + else + js->buttons[bi++] = GLFW_RELEASE; + + break; + } + + case _GLFW_TYPE_POV: + { + const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + // Screams of horror are appropriate at this point + int value = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); + if (value < 0 || value > 8) + value = 8; + + for (j = 0; j < 4; j++) + { + if (directions[value] & (1 << j)) + js->buttons[bi++] = GLFW_PRESS; + else + js->buttons[bi++] = GLFW_RELEASE; + } + + break; + } + } + } + + return GLFW_TRUE; + } + else { + int i; + DWORD result; + XINPUT_STATE xis; + const WORD buttons[14] = + { + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_BACK, + XINPUT_GAMEPAD_START, + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB, + XINPUT_GAMEPAD_DPAD_UP, + XINPUT_GAMEPAD_DPAD_RIGHT, + XINPUT_GAMEPAD_DPAD_DOWN, + XINPUT_GAMEPAD_DPAD_LEFT + }; + + result = _glfw_XInputGetState(js->index, &xis); + if (result != ERROR_SUCCESS) + { + if (result == ERROR_DEVICE_NOT_CONNECTED) + closeJoystick(js); + + return GLFW_FALSE; + } + + if (mode == _GLFW_PRESENCE_ONLY) + return GLFW_TRUE; + if (sqrtf((float) (xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX + xis.Gamepad.sThumbLY * xis.Gamepad.sThumbLY)) > (float) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) @@ -165,34 +638,12 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickWin32* js, int flags) js->axes[5] = xis.Gamepad.bRightTrigger / 127.5f - 1.f; else js->axes[5] = -1.f; - } - - if (flags & _GLFW_UPDATE_BUTTONS) - { - int i; - const WORD buttons[14] = - { - XINPUT_GAMEPAD_A, - XINPUT_GAMEPAD_B, - XINPUT_GAMEPAD_X, - XINPUT_GAMEPAD_Y, - XINPUT_GAMEPAD_LEFT_SHOULDER, - XINPUT_GAMEPAD_RIGHT_SHOULDER, - XINPUT_GAMEPAD_BACK, - XINPUT_GAMEPAD_START, - XINPUT_GAMEPAD_LEFT_THUMB, - XINPUT_GAMEPAD_RIGHT_THUMB, - XINPUT_GAMEPAD_DPAD_UP, - XINPUT_GAMEPAD_DPAD_RIGHT, - XINPUT_GAMEPAD_DPAD_DOWN, - XINPUT_GAMEPAD_DPAD_LEFT - }; for (i = 0; i < 14; i++) js->buttons[i] = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0; - } - return GLFW_TRUE; + return GLFW_TRUE; + } } @@ -204,6 +655,19 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickWin32* js, int flags) // void _glfwInitJoysticksWin32(void) { + if (_glfw.win32.dinput8.instance) + { + if (FAILED(_glfw_DirectInput8Create(GetModuleHandle(NULL), + DIRECTINPUT_VERSION, + &IID_IDirectInput8W, + (void**) &_glfw.win32.dinput8.api, + NULL))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to create interface"); + } + } + _glfwDetectJoystickConnectionWin32(); } @@ -214,33 +678,47 @@ void _glfwTerminateJoysticksWin32(void) int joy; for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) - free(_glfw.win32_js[joy].name); + closeJoystick(_glfw.win32_js + joy); + + if (_glfw.win32.dinput8.api) + IDirectInput8_Release(_glfw.win32.dinput8.api); } -// Looks for new joysticks +// Checks for new joysticks after DBT_DEVICEARRIVAL // void _glfwDetectJoystickConnectionWin32(void) { - DWORD i; + if (_glfw.win32.xinput.instance) + { + DWORD i; - if (!_glfw.win32.xinput.instance) - return; + for (i = 0; i < XUSER_MAX_COUNT; i++) + openXinputDevice(i); + } - for (i = 0; i < XUSER_MAX_COUNT; i++) - openJoystickDevice(i); + if (_glfw.win32.dinput8.api) + { + if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api, + DI8DEVCLASS_GAMECTRL, + deviceCallback, + NULL, + DIEDFL_ALLDEVICES))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to enumerate DirectInput8 devices"); + return; + } + } } -// Checks if any current joystick has been disconnected +// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE // void _glfwDetectJoystickDisconnectionWin32(void) { - DWORD i; + int joy; - if (!_glfw.win32.xinput.instance) - return; - - for (i = 0; i < XUSER_MAX_COUNT; i++) - pollJoystickEvents(_glfw.win32_js + i, 0); + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + pollJoystickState(_glfw.win32_js + joy, _GLFW_PRESENCE_ONLY); } @@ -251,13 +729,13 @@ void _glfwDetectJoystickDisconnectionWin32(void) int _glfwPlatformJoystickPresent(int joy) { _GLFWjoystickWin32* js = _glfw.win32_js + joy; - return pollJoystickEvents(js, 0); + return pollJoystickState(js, _GLFW_PRESENCE_ONLY); } const float* _glfwPlatformGetJoystickAxes(int joy, int* count) { _GLFWjoystickWin32* js = _glfw.win32_js + joy; - if (!pollJoystickEvents(js, _GLFW_UPDATE_AXES)) + if (!pollJoystickState(js, _GLFW_UPDATE_STATE)) return NULL; *count = js->axisCount; @@ -267,7 +745,7 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count) const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) { _GLFWjoystickWin32* js = _glfw.win32_js + joy; - if (!pollJoystickEvents(js, _GLFW_UPDATE_BUTTONS)) + if (!pollJoystickState(js, _GLFW_UPDATE_STATE)) return NULL; *count = js->buttonCount; @@ -277,7 +755,7 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) const char* _glfwPlatformGetJoystickName(int joy) { _GLFWjoystickWin32* js = _glfw.win32_js + joy; - if (!pollJoystickEvents(js, 0)) + if (!pollJoystickState(js, _GLFW_PRESENCE_ONLY)) return NULL; return js->name; diff --git a/src/win32_joystick.h b/src/win32_joystick.h index e57d16ea4..c6faeda0d 100644 --- a/src/win32_joystick.h +++ b/src/win32_joystick.h @@ -30,17 +30,29 @@ #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ _GLFWjoystickWin32 win32_js[GLFW_JOYSTICK_LAST + 1] +// Spoo +// +typedef struct _GLFWjoyobjectWin32 +{ + int offset; + int type; +} _GLFWjoyobjectWin32; + // Win32-specific per-joystick data // typedef struct _GLFWjoystickWin32 { - GLFWbool present; - float axes[6]; - int axisCount; - unsigned char buttons[14]; - int buttonCount; - char* name; - DWORD index; + GLFWbool present; + float* axes; + int axisCount; + unsigned char* buttons; + int buttonCount; + _GLFWjoyobjectWin32* objects; + int objectCount; + char* name; + IDirectInputDevice8W* device; + DWORD index; + GUID guid; } _GLFWjoystickWin32; diff --git a/src/win32_platform.h b/src/win32_platform.h index 6ec69c6e4..932accf8b 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -61,8 +61,12 @@ #define _WIN32_WINNT 0x0501 #endif +// GLFW uses DirectInput8 interfaces +#define DIRECTINPUT_VERSION 0x0800 + #include #include +#include #include #include @@ -71,7 +75,7 @@ #define strdup _strdup #endif -// HACK: Define macros that some older windows.h variants don't +// HACK: Define macros that some windows.h variants don't #ifndef WM_MOUSEHWHEEL #define WM_MOUSEHWHEEL 0x020E #endif @@ -121,7 +125,7 @@ typedef enum PROCESS_DPI_AWARENESS } PROCESS_DPI_AWARENESS; #endif /*DPI_ENUMS_DECLARED*/ -// HACK: Define macros that some older xinput.h variants don't +// HACK: Define macros that some xinput.h variants don't #ifndef XINPUT_CAPS_WIRELESS #define XINPUT_CAPS_WIRELESS 0x0002 #endif @@ -147,6 +151,11 @@ typedef enum PROCESS_DPI_AWARENESS #define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13 #endif +// HACK: Define macros that some dinput.h variants don't +#ifndef DIDFT_OPTIONAL + #define DIDFT_OPTIONAL 0x80000000 +#endif + // winmm.dll function pointer typedefs typedef DWORD (WINAPI * TIMEGETTIME_T)(void); #define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime @@ -157,6 +166,10 @@ typedef DWORD (WINAPI * XINPUTGETSTATE_T)(DWORD,XINPUT_STATE*); #define _glfw_XInputGetCapabilities _glfw.win32.xinput.XInputGetCapabilities #define _glfw_XInputGetState _glfw.win32.xinput.XInputGetState +// dinput8.dll function pointer typedefs +typedef HRESULT (WINAPI * DIRECTINPUT8CREATE_T)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN); +#define _glfw_DirectInput8Create _glfw.win32.dinput8.DirectInput8Create + // user32.dll function pointer typedefs typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void); typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); @@ -241,13 +254,17 @@ typedef struct _GLFWlibraryWin32 short int publicKeys[512]; short int nativeKeys[GLFW_KEY_LAST + 1]; - // winmm.dll struct { HINSTANCE instance; TIMEGETTIME_T timeGetTime; } winmm; - // user32.dll + struct { + HINSTANCE instance; + DIRECTINPUT8CREATE_T DirectInput8Create; + IDirectInput8W* api; + } dinput8; + struct { HINSTANCE instance; XINPUTGETCAPABILITIES_T XInputGetCapabilities; @@ -260,14 +277,12 @@ typedef struct _GLFWlibraryWin32 CHANGEWINDOWMESSAGEFILTEREX_T ChangeWindowMessageFilterEx; } user32; - // dwmapi.dll struct { HINSTANCE instance; DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled; DWMFLUSH_T DwmFlush; } dwmapi; - // shcore.dll struct { HINSTANCE instance; SETPROCESSDPIAWARENESS_T SetProcessDpiAwareness; From c2fd61fa016995b18106ee22498aaff2c6989b66 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 30 Mar 2016 23:26:09 +0200 Subject: [PATCH 126/156] Remove unused variable in timeout test --- tests/timeout.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/timeout.c b/tests/timeout.c index d1a9491e4..83f18998e 100644 --- a/tests/timeout.c +++ b/tests/timeout.c @@ -53,7 +53,6 @@ static float nrand(void) int main(void) { - int result; GLFWwindow* window; srand((unsigned int) time(NULL)); From 9e35bc7daef99b1b9ad2dce8af3f4af9ea38ba64 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 31 Mar 2016 10:54:54 +0200 Subject: [PATCH 127/156] Update changelog --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d58659ad7..a1eabd44b 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ does not find Doxygen, the documentation will not be generated. trigger monitor callback - [Win32] Bugfix: No monitors were listed on headless and VMware guest systems - [Win32] Bugfix: Pressing Ctrl+Pause would report `GLFW_KEY_UNKNOWN` + - [Cocoa] Made joystick polling more efficient - [Cocoa] Removed support for OS X 10.6 - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault @@ -123,6 +124,7 @@ does not find Doxygen, the documentation will not be generated. - [X11] Bugfix: An XKB structure was leaked during `glfwInit` - [X11] Bugfix: XInput2 `XI_Motion` events interfered with the Steam overlay - [POSIX] Bugfix: An unrelated TLS key could be deleted by `glfwTerminate` + - [Linux] Made joystick polling more efficient - [WGL] Changed extension loading to only be performed once - [WGL] Removed dependency on external WGL headers - [GLX] Replaced legacy drawable with `GLXWindow` From c41b029ca407f750ea453b596117913ecae54b98 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 31 Mar 2016 12:40:41 +0200 Subject: [PATCH 128/156] Update changelog --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1eabd44b..30f9ba2ca 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,6 @@ does not find Doxygen, the documentation will not be generated. - Added `GLFW_CONTEXT_NO_ERROR` context hint for `GL_KHR_no_error` support - Added `GLFW_INCLUDE_VULKAN` for including the Vulkan header - Added `GLFW_TRUE` and `GLFW_FALSE` as client API independent boolean values - - Added `glfwGetGLXWindow` to query the `GLXWindow` of a window - Added icons to examples on Windows and OS X - Relaxed rules for native access header macros - Removed dependency on external OpenGL or OpenGL ES headers @@ -127,6 +126,7 @@ does not find Doxygen, the documentation will not be generated. - [Linux] Made joystick polling more efficient - [WGL] Changed extension loading to only be performed once - [WGL] Removed dependency on external WGL headers + - [GLX] Added `glfwGetGLXWindow` to query the `GLXWindow` of a window - [GLX] Replaced legacy drawable with `GLXWindow` - [GLX] Removed dependency on external GLX headers - [GLX] Bugfix: NetBSD does not provide `libGL.so.1` From bd345164d3692005447fac2b89f5308c275aa22d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 31 Mar 2016 13:07:06 +0200 Subject: [PATCH 129/156] Fix missing constant on VC++ 2010 --- src/win32_platform.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/win32_platform.h b/src/win32_platform.h index 932accf8b..d0dac96d7 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -150,6 +150,9 @@ typedef enum PROCESS_DPI_AWARENESS #ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD #define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13 #endif +#ifndef XUSER_MAX_COUNT + #define XUSER_MAX_COUNT 4 +#endif // HACK: Define macros that some dinput.h variants don't #ifndef DIDFT_OPTIONAL From 135ed7feb4c5c7d5a3493d7f7889549088d7587b Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 31 Mar 2016 14:22:54 +0200 Subject: [PATCH 130/156] Fix build on legacy MinGW --- src/win32_joystick.c | 8 ++++---- src/win32_platform.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 43336a31f..0268e0514 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -603,9 +603,9 @@ static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) if (mode == _GLFW_PRESENCE_ONLY) return GLFW_TRUE; - if (sqrtf((float) (xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX + + if (sqrt((double) (xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX + xis.Gamepad.sThumbLY * xis.Gamepad.sThumbLY)) > - (float) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) + (double) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { js->axes[0] = (xis.Gamepad.sThumbLX + 0.5f) / 32767.f; js->axes[1] = (xis.Gamepad.sThumbLY + 0.5f) / 32767.f; @@ -616,9 +616,9 @@ static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) js->axes[1] = 0.f; } - if (sqrtf((float) (xis.Gamepad.sThumbRX * xis.Gamepad.sThumbRX + + if (sqrt((double) (xis.Gamepad.sThumbRX * xis.Gamepad.sThumbRX + xis.Gamepad.sThumbRY * xis.Gamepad.sThumbRY)) > - (float) XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) + (double) XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { js->axes[2] = (xis.Gamepad.sThumbRX + 0.5f) / 32767.f; js->axes[3] = (xis.Gamepad.sThumbRY + 0.5f) / 32767.f; diff --git a/src/win32_platform.h b/src/win32_platform.h index d0dac96d7..d44ca3b9c 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -64,6 +64,7 @@ // GLFW uses DirectInput8 interfaces #define DIRECTINPUT_VERSION 0x0800 +#include #include #include #include From e2d5071e59f18b7d73113de90f928e4ea55ea854 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 31 Mar 2016 16:56:43 +0200 Subject: [PATCH 131/156] Fix typo --- docs/build.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build.dox b/docs/build.dox index 7fccf8737..fde65add1 100644 --- a/docs/build.dox +++ b/docs/build.dox @@ -241,7 +241,7 @@ target_link_libraries(myapp ${OPENGL_glu_LIBRARY}) @subsection build_link_pkgconfig With makefiles and pkg-config on Unix GLFW supports [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/), -and the `glfw3.pc` pkf-config file is generated when the GLFW library is built +and the `glfw3.pc` pkg-config file is generated when the GLFW library is built and is installed along with it. A pkg-config file describes all necessary compile-time and link-time flags and dependencies needed to use a library. When they are updated or if they differ between systems, you will get the correct From 95439ba5290caf7489c1ddb1981b346f9714f113 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 4 Apr 2016 12:52:08 +0200 Subject: [PATCH 132/156] Merge downstream FreeBSD fix --- deps/tinycthread.h | 1 + 1 file changed, 1 insertion(+) diff --git a/deps/tinycthread.h b/deps/tinycthread.h index 86a908046..6da30d703 100644 --- a/deps/tinycthread.h +++ b/deps/tinycthread.h @@ -78,6 +78,7 @@ freely, subject to the following restrictions: /* Platform specific includes */ #if defined(_TTHREAD_POSIX_) + #include #include #elif defined(_TTHREAD_WIN32_) #ifndef WIN32_LEAN_AND_MEAN From 99dc2c48bdaa07a4aa892c5ff2af215eca3698a7 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 17 Apr 2016 13:44:07 +0200 Subject: [PATCH 133/156] Fix setting of GLFW_MAXIMIZED hint Caused by a bad rebase. Fixes #738. --- src/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.c b/src/window.c index 8aec74b8c..104c703e1 100644 --- a/src/window.c +++ b/src/window.c @@ -339,7 +339,7 @@ GLFWAPI void glfwWindowHint(int hint, int value) _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE; break; case GLFW_MAXIMIZED: - _glfw.hints.window.maximized = hint ? GLFW_TRUE : GLFW_FALSE; + _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE; break; case GLFW_VISIBLE: _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; From d97044d9acc0c76433edda5a75b3196957906ca5 Mon Sep 17 00:00:00 2001 From: Erlend Sogge Heggen Date: Wed, 20 Apr 2016 12:40:56 +0200 Subject: [PATCH 134/156] Update forum link Closes #743. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 30f9ba2ca..f0f827ddf 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ can find the latest version of GLFW, as well as news, documentation and other information about the project. If you have questions related to the use of GLFW, we have a -[support forum](https://sourceforge.net/p/glfw/discussion/247562/), and the IRC +[support forum](http://discourse.glfw.org/), and the IRC channel `#glfw` on [Freenode](http://freenode.net/). If you have a bug to report, a patch to submit or a feature you'd like to From 3b0b5dacf526a185dfdbbc6a026ebeb6fbe8b574 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Wed, 27 Apr 2016 06:04:16 -0600 Subject: [PATCH 135/156] Fix test for joystick presence in matchCallback The matchCallback function has an initial loop to filter out redundant joystick additions based on matching deviceRef values. However, the if statement incorrectly combines this test with the condition that the joystick is not present, which is obviously incorrect. Closes #753. --- src/cocoa_joystick.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 0e0a20f5b..674004235 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -276,7 +276,7 @@ static void matchCallback(void* context, for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) { - if (!_glfw.ns_js.js[joy].present && _glfw.ns_js.js[joy].deviceRef == deviceRef) + if (_glfw.ns_js.js[joy].present && _glfw.ns_js.js[joy].deviceRef == deviceRef) return; } From 0b6a4313dd6074cb4e2614e14389961c135076d3 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Sun, 1 May 2016 22:54:02 +0200 Subject: [PATCH 136/156] Create EWMH and XDND atoms on demand --- src/x11_init.c | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 7f7587c9b..2e7f7a725 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -356,16 +356,13 @@ static Atom getSupportedAtom(Atom* supportedAtoms, unsigned long atomCount, const char* atomName) { - Atom atom = XInternAtom(_glfw.x11.display, atomName, True); - if (atom != None) - { - unsigned long i; + unsigned long i; + const Atom atom = XInternAtom(_glfw.x11.display, atomName, False); - for (i = 0; i < atomCount; i++) - { - if (supportedAtoms[i] == atom) - return atom; - } + for (i = 0; i < atomCount; i++) + { + if (supportedAtoms[i] == atom) + return atom; } return None; @@ -378,13 +375,11 @@ static void detectEWMH(void) Window* windowFromRoot = NULL; Window* windowFromChild = NULL; - // First we need a couple of atoms, which should already be there - Atom supportingWmCheck = - XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", True); - Atom wmSupported = - XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", True); - if (supportingWmCheck == None || wmSupported == None) - return; + // First we need a couple of atoms + const Atom supportingWmCheck = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); + const Atom wmSupported = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); // Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window if (_glfwGetWindowPropertyX11(_glfw.x11.root, @@ -611,15 +606,15 @@ static GLFWbool initExtensions(void) XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); // Find Xdnd (drag and drop) atoms, if available - _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True); - _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True); - _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", True); - _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", True); - _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", True); - _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", True); - _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", True); - _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", True); - _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", True); + _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False); + _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); + _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); + _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); return GLFW_TRUE; } From f0f5d9f644641b0a79050cebf80d43e23fab751c Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 9 Apr 2016 00:42:58 +0100 Subject: [PATCH 137/156] wayland: Implement size limits and aspect ratio --- include/GLFW/glfw3.h | 2 +- src/wl_window.c | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index f8ca3d61a..cedecfcbb 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2049,7 +2049,7 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); /*! @brief Sets the size limits of the specified window. * * This function sets the size limits of the client area of the specified - * window. If the window is full screen, the size limits only take effect if + * window. If the window is full screen, the size limits only take effect * once it is made windowed. If the window is not resizable, this function * does nothing. * diff --git a/src/wl_window.c b/src/wl_window.c index 6a86f9e9c..1c85772e5 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -55,7 +55,32 @@ static void handleConfigure(void* data, int32_t height) { _GLFWwindow* window = data; - _glfwInputFramebufferSize(window, width, height); + float aspectRatio; + float targetRatio; + + if (!window->monitor) + { + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) + { + aspectRatio = (float)width / (float)height; + targetRatio = (float)window->numer / (float)window->denom; + if (aspectRatio < targetRatio) + height = width / targetRatio; + else if (aspectRatio > targetRatio) + width = height * targetRatio; + } + + if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth) + width = window->minwidth; + else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth) + width = window->maxwidth; + + if (window->minheight != GLFW_DONT_CARE && height < window->minheight) + height = window->minheight; + else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight) + height = window->maxheight; + } + _glfwInputWindowSize(window, width, height); _glfwPlatformSetWindowSize(window, width, height); _glfwInputWindowDamage(window); @@ -429,14 +454,14 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { - // TODO - fprintf(stderr, "_glfwPlatformSetWindowSizeLimits not implemented yet\n"); + // TODO: find out how to trigger a resize. + // The actual limits are checked in the wl_shell_surface::configure handler. } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { - // TODO - fprintf(stderr, "_glfwPlatformSetWindowAspectRatio not implemented yet\n"); + // TODO: find out how to trigger a resize. + // The actual limits are checked in the wl_shell_surface::configure handler. } void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) From 5034c6c65e645285e962116cf38d3a24d4f3d2f8 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 9 Apr 2016 00:51:48 +0100 Subject: [PATCH 138/156] wayland: Handle hidden window as no shell surface --- src/wl_platform.h | 2 ++ src/wl_window.c | 69 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index 100b12bc0..c538936c5 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -91,6 +91,8 @@ typedef struct _GLFWwindowWayland _GLFWcursor* currentCursor; double cursorPosX, cursorPosY; + char* title; + // We need to track the monitors the window spans on to calculate the // optimal scaling factor. int scale; diff --git a/src/wl_window.c b/src/wl_window.c index 1c85772e5..033e11e40 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -193,6 +193,15 @@ static GLFWbool createSurface(_GLFWwindow* window, if (!window->wl.native) return GLFW_FALSE; + window->wl.width = wndconfig->width; + window->wl.height = wndconfig->height; + window->wl.scale = 1; + + return GLFW_TRUE; +} + +static GLFWbool createShellSurface(_GLFWwindow* window) +{ window->wl.shell_surface = wl_shell_get_shell_surface(_glfw.wl.shell, window->wl.surface); if (!window->wl.shell_surface) @@ -202,9 +211,21 @@ static GLFWbool createSurface(_GLFWwindow* window, &shellSurfaceListener, window); - window->wl.width = wndconfig->width; - window->wl.height = wndconfig->height; - window->wl.scale = 1; + if (window->wl.title) + wl_shell_surface_set_title(window->wl.shell_surface, window->wl.title); + + if (window->monitor) + { + wl_shell_surface_set_fullscreen( + window->wl.shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + 0, + window->monitor->wl.output); + } + else + { + wl_shell_surface_set_toplevel(window->wl.shell_surface); + } return GLFW_TRUE; } @@ -354,17 +375,20 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, return GLFW_FALSE; } - if (window->monitor) + if (wndconfig->title) + window->wl.title = strdup(wndconfig->title); + + if (wndconfig->visible) { - wl_shell_surface_set_fullscreen( - window->wl.shell_surface, - WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, - 0, - window->monitor->wl.output); + if (!createShellSurface(window)) + return GLFW_FALSE; + + window->wl.visible = GLFW_TRUE; } else { - wl_shell_surface_set_toplevel(window->wl.shell_surface); + window->wl.shell_surface = NULL; + window->wl.visible = GLFW_FALSE; } window->wl.currentCursor = NULL; @@ -400,12 +424,17 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->wl.surface) wl_surface_destroy(window->wl.surface); + free(window->wl.title); free(window->wl.monitors); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { - wl_shell_surface_set_title(window->wl.shell_surface, title); + if (window->wl.title) + free(window->wl.title); + window->wl.title = strdup(title); + if (window->wl.shell_surface) + wl_shell_surface_set_title(window->wl.shell_surface, title); } void _glfwPlatformSetWindowIcon(_GLFWwindow* window, @@ -499,13 +528,22 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window) { - wl_shell_surface_set_toplevel(window->wl.shell_surface); + if (!window->monitor) + { + if (!window->wl.shell_surface) + createShellSurface(window); + window->wl.visible = GLFW_TRUE; + } } void _glfwPlatformHideWindow(_GLFWwindow* window) { - wl_surface_attach(window->wl.surface, NULL, 0, 0); - wl_surface_commit(window->wl.surface); + if (!window->monitor) + { + if (window->wl.shell_surface) + wl_shell_surface_destroy(window->wl.shell_surface); + window->wl.visible = GLFW_FALSE; + } } void _glfwPlatformFocusWindow(_GLFWwindow* window) @@ -538,8 +576,7 @@ int _glfwPlatformWindowIconified(_GLFWwindow* window) int _glfwPlatformWindowVisible(_GLFWwindow* window) { - // TODO - return GLFW_FALSE; + return window->wl.visible; } int _glfwPlatformWindowMaximized(_GLFWwindow* window) From 71cedc6cfe2fd0c4707946e91abea5cd1ab32fb9 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 9 Apr 2016 00:53:03 +0100 Subject: [PATCH 139/156] wayland: Implement glfwSetWindowMonitor --- src/wl_window.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 033e11e40..c254f41b4 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -558,8 +558,19 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, int width, int height, int refreshRate) { - // TODO - fprintf(stderr, "_glfwPlatformSetWindowMonitor not implemented yet\n"); + if (monitor) + { + wl_shell_surface_set_fullscreen( + window->wl.shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + refreshRate * 1000, // Convert Hz to mHz. + monitor->wl.output); + } + else + { + wl_shell_surface_set_toplevel(window->wl.shell_surface); + } + _glfwInputWindowMonitorChange(window, monitor); } int _glfwPlatformWindowFocused(_GLFWwindow* window) From e673bdc617b59e4924d2b4f8889a3d75f5018ebe Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 9 Apr 2016 00:54:23 +0100 Subject: [PATCH 140/156] wayland: Implement maximized state --- src/wl_platform.h | 1 + src/wl_window.c | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index c538936c5..d75c025e5 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -83,6 +83,7 @@ typedef struct _GLFWwindowWayland { int width, height; GLFWbool visible; + GLFWbool maximized; struct wl_surface* surface; struct wl_egl_window* native; struct wl_shell_surface* shell_surface; diff --git a/src/wl_window.c b/src/wl_window.c index c254f41b4..085863009 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -222,6 +222,10 @@ static GLFWbool createShellSurface(_GLFWwindow* window) 0, window->monitor->wl.output); } + else if (window->wl.maximized) + { + wl_shell_surface_set_maximized(window->wl.shell_surface, NULL); + } else { wl_shell_surface_set_toplevel(window->wl.shell_surface); @@ -516,14 +520,27 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window) void _glfwPlatformRestoreWindow(_GLFWwindow* window) { - // TODO - fprintf(stderr, "_glfwPlatformRestoreWindow not implemented yet\n"); + // TODO: also do the same for iconified. + if (window->monitor || window->wl.maximized) + { + if (window->wl.shell_surface) + wl_shell_surface_set_toplevel(window->wl.shell_surface); + + window->wl.maximized = GLFW_FALSE; + } } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { - // TODO - fprintf(stderr, "_glfwPlatformMaximizeWindow not implemented yet\n"); + if (!window->monitor && !window->wl.maximized) + { + if (window->wl.shell_surface) + { + // Let the compositor select the best output. + wl_shell_surface_set_maximized(window->wl.shell_surface, NULL); + } + window->wl.maximized = GLFW_TRUE; + } } void _glfwPlatformShowWindow(_GLFWwindow* window) @@ -592,8 +609,7 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window) int _glfwPlatformWindowMaximized(_GLFWwindow* window) { - // TODO - return GLFW_FALSE; + return window->wl.maximized; } void _glfwPlatformPollEvents(void) From c301a1e51ae470580d51df4558a4a6c313064289 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 9 Apr 2016 00:55:03 +0100 Subject: [PATCH 141/156] wayland: Implement remaining attribute getters --- src/wl_window.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 085863009..e4f4c6857 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -508,8 +508,8 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { - // TODO - fprintf(stderr, "_glfwPlatformGetWindowFrameSize not implemented yet\n"); + // TODO: will need a proper implementation once decorations are + // implemented, but for now just leave everything as 0. } void _glfwPlatformIconifyWindow(_GLFWwindow* window) @@ -592,13 +592,12 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, int _glfwPlatformWindowFocused(_GLFWwindow* window) { - // TODO - return GLFW_FALSE; + return _glfw.wl.keyboardFocus == window; } int _glfwPlatformWindowIconified(_GLFWwindow* window) { - // TODO + // TODO: move to xdg_shell, wl_shell doesn't have any iconified concept. return GLFW_FALSE; } From 1e82832737167cfa569b1a74d44ff208f0b5cef5 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 9 Apr 2016 00:47:55 +0100 Subject: [PATCH 142/156] wayland: Report unsupported operations as errors --- src/wl_monitor.c | 6 ++++-- src/wl_window.c | 23 +++++++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/wl_monitor.c b/src/wl_monitor.c index 7c58c8f84..3b2b95fed 100644 --- a/src/wl_monitor.c +++ b/src/wl_monitor.c @@ -244,13 +244,15 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { // TODO - fprintf(stderr, "_glfwPlatformGetGammaRamp not implemented yet\n"); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Gamma ramp getting not supported yet"); } void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { // TODO - fprintf(stderr, "_glfwPlatformSetGammaRamp not implemented yet\n"); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Gamma ramp setting not supported yet"); } diff --git a/src/wl_window.c b/src/wl_window.c index e4f4c6857..194c0ecab 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -444,8 +444,8 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images) { - // TODO - fprintf(stderr, "_glfwPlatformSetWindowIcon not implemented yet\n"); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Setting window icon not supported"); } void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) @@ -514,8 +514,9 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, void _glfwPlatformIconifyWindow(_GLFWwindow* window) { - // TODO - fprintf(stderr, "_glfwPlatformIconifyWindow not implemented yet\n"); + // TODO: move to xdg_shell instead of wl_shell. + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Iconify window not supported"); } void _glfwPlatformRestoreWindow(_GLFWwindow* window) @@ -565,8 +566,8 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformFocusWindow(_GLFWwindow* window) { - // TODO - fprintf(stderr, "_glfwPlatformFocusWindow not implemented yet\n"); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Focusing a window requires user interaction"); } void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, @@ -677,7 +678,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, if (fd < 0) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Creating a buffer file for %d B failed: %m\n", + "Wayland: Creating a buffer file for %d B failed: %m", length); return GLFW_FALSE; } @@ -686,7 +687,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, if (data == MAP_FAILED) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Cursor mmap failed: %m\n"); + "Wayland: Cursor mmap failed: %m"); close(fd); return GLFW_FALSE; } @@ -925,13 +926,15 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) { // TODO - fprintf(stderr, "_glfwPlatformSetClipboardString not implemented yet\n"); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Clipboard setting not implemented yet"); } const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) { // TODO - fprintf(stderr, "_glfwPlatformGetClipboardString not implemented yet\n"); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Clipboard getting not implemented yet"); return NULL; } From f000b5dafff1cddd7b5b989bafed368fc75df244 Mon Sep 17 00:00:00 2001 From: bschaefer Date: Sat, 16 Apr 2016 16:27:42 -0700 Subject: [PATCH 143/156] Mir: Fix window/context creation order Need to create the native window before creating the context as creating the context creates the EGL surface. --- src/mir_window.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mir_window.c b/src/mir_window.c index 6b6f44679..93a82624a 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -345,12 +345,6 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - if (ctxconfig->api != GLFW_NO_API) - { - if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; - } - if (window->monitor) { GLFWvidmode mode; @@ -377,6 +371,12 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, window->mir.window = mir_buffer_stream_get_egl_native_window( mir_surface_get_buffer_stream(window->mir.surface)); + if (ctxconfig->api != GLFW_NO_API) + { + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + return GLFW_TRUE; } From e44fd87fa3abe4abb86a7ffe366aec548d89defc Mon Sep 17 00:00:00 2001 From: bschaefer Date: Sun, 17 Apr 2016 13:48:10 -0700 Subject: [PATCH 144/156] Mir: Fix button states --- src/mir_window.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/mir_window.c b/src/mir_window.c index 93a82624a..8ab4a4f68 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -160,10 +160,15 @@ static void handlePointerButton(_GLFWwindow* window, int pressed, const MirPointerEvent* pointer_event) { - MirPointerButton button = mir_pointer_event_buttons (pointer_event); int mods = mir_pointer_event_modifiers(pointer_event); const int publicMods = mirModToGLFWMod(mods); - int publicButton; + MirPointerButton button = mir_pointer_button_primary; + static uint32_t oldButtonStates = 0; + uint32_t newButtonStates = mir_pointer_event_buttons(pointer_event); + int publicButton = GLFW_MOUSE_BUTTON_LEFT; + + // XOR our old button states our new states to figure out what was added or removed + button = newButtonStates ^ oldButtonStates; switch (button) { @@ -188,6 +193,8 @@ static void handlePointerButton(_GLFWwindow* window, break; } + oldButtonStates = newButtonStates; + _glfwInputMouseClick(window, publicButton, pressed, publicMods); } From 078bd8ef40bb82915eb2183028aa4094e8c3147d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 2 May 2016 23:03:10 +0200 Subject: [PATCH 145/156] Update Vulkan headers to 1.0.11 SDK --- deps/vulkan/vk_platform.h | 31 ++++----- deps/vulkan/vulkan.h | 136 +++++++++++++++++++++++++++----------- 2 files changed, 110 insertions(+), 57 deletions(-) diff --git a/deps/vulkan/vk_platform.h b/deps/vulkan/vk_platform.h index a53e725a9..5d0fc766e 100644 --- a/deps/vulkan/vk_platform.h +++ b/deps/vulkan/vk_platform.h @@ -4,29 +4,22 @@ /* ** Copyright (c) 2014-2015 The Khronos Group Inc. ** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. +** http://www.apache.org/licenses/LICENSE-2.0 ** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. */ -#ifndef __VK_PLATFORM_H__ -#define __VK_PLATFORM_H__ +#ifndef VK_PLATFORM_H_ +#define VK_PLATFORM_H_ #ifdef __cplusplus extern "C" @@ -124,4 +117,4 @@ extern "C" #include #endif -#endif // __VK_PLATFORM_H__ +#endif diff --git a/deps/vulkan/vulkan.h b/deps/vulkan/vulkan.h index cd6a71ac1..eb8343e26 100644 --- a/deps/vulkan/vulkan.h +++ b/deps/vulkan/vulkan.h @@ -1,5 +1,5 @@ -#ifndef __vulkan_h_ -#define __vulkan_h_ 1 +#ifndef VULKAN_H_ +#define VULKAN_H_ 1 #ifdef __cplusplus extern "C" { @@ -8,24 +8,17 @@ extern "C" { /* ** Copyright (c) 2015-2016 The Khronos Group Inc. ** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. +** http://www.apache.org/licenses/LICENSE-2.0 ** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. */ /* @@ -40,12 +33,18 @@ extern "C" { #define VK_MAKE_VERSION(major, minor, patch) \ (((major) << 22) | ((minor) << 12) | (patch)) -// Vulkan API version supported by this file -#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 3) +// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. +//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) + +// Vulkan 1.0 version number +#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0) #define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) +// Version of this file +#define VK_HEADER_VERSION 11 + #define VK_NULL_HANDLE 0 @@ -142,6 +141,7 @@ typedef enum VkResult { VK_ERROR_OUT_OF_DATE_KHR = -1000001004, VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, + VK_ERROR_INVALID_SHADER_NV = -1000012000, VK_RESULT_BEGIN_RANGE = VK_ERROR_FORMAT_NOT_SUPPORTED, VK_RESULT_END_RANGE = VK_INCOMPLETE, VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FORMAT_NOT_SUPPORTED + 1), @@ -209,7 +209,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, - VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = 1000011000, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1), @@ -679,6 +679,7 @@ typedef enum VkDynamicState { typedef enum VkFilter { VK_FILTER_NEAREST = 0, VK_FILTER_LINEAR = 1, + VK_FILTER_CUBIC_IMG = 1000015000, VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST, VK_FILTER_END_RANGE = VK_FILTER_LINEAR, VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1), @@ -701,8 +702,8 @@ typedef enum VkSamplerAddressMode { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT, - VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, - VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), + VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerAddressMode; @@ -808,6 +809,8 @@ typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, + VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFormatFeatureFlagBits; typedef VkFlags VkFormatFeatureFlags; @@ -820,6 +823,7 @@ typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, + VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageUsageFlagBits; typedef VkFlags VkImageUsageFlags; @@ -829,6 +833,7 @@ typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, + VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageCreateFlagBits; typedef VkFlags VkImageCreateFlags; @@ -840,6 +845,7 @@ typedef enum VkSampleCountFlagBits { VK_SAMPLE_COUNT_16_BIT = 0x00000010, VK_SAMPLE_COUNT_32_BIT = 0x00000020, VK_SAMPLE_COUNT_64_BIT = 0x00000040, + VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSampleCountFlagBits; typedef VkFlags VkSampleCountFlags; @@ -848,6 +854,7 @@ typedef enum VkQueueFlagBits { VK_QUEUE_COMPUTE_BIT = 0x00000002, VK_QUEUE_TRANSFER_BIT = 0x00000004, VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, + VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueueFlagBits; typedef VkFlags VkQueueFlags; @@ -857,11 +864,13 @@ typedef enum VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, + VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryPropertyFlagBits; typedef VkFlags VkMemoryPropertyFlags; typedef enum VkMemoryHeapFlagBits { VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryHeapFlagBits; typedef VkFlags VkMemoryHeapFlags; typedef VkFlags VkDeviceCreateFlags; @@ -885,6 +894,7 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineStageFlagBits; typedef VkFlags VkPipelineStageFlags; typedef VkFlags VkMemoryMapFlags; @@ -894,6 +904,7 @@ typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageAspectFlagBits; typedef VkFlags VkImageAspectFlags; @@ -901,16 +912,19 @@ typedef enum VkSparseImageFormatFlagBits { VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, + VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSparseImageFormatFlagBits; typedef VkFlags VkSparseImageFormatFlags; typedef enum VkSparseMemoryBindFlagBits { VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, + VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSparseMemoryBindFlagBits; typedef VkFlags VkSparseMemoryBindFlags; typedef enum VkFenceCreateFlagBits { VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, + VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFenceCreateFlagBits; typedef VkFlags VkFenceCreateFlags; typedef VkFlags VkSemaphoreCreateFlags; @@ -929,6 +943,7 @@ typedef enum VkQueryPipelineStatisticFlagBits { VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, + VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryPipelineStatisticFlagBits; typedef VkFlags VkQueryPipelineStatisticFlags; @@ -937,6 +952,7 @@ typedef enum VkQueryResultFlagBits { VK_QUERY_RESULT_WAIT_BIT = 0x00000002, VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, + VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryResultFlagBits; typedef VkFlags VkQueryResultFlags; @@ -944,6 +960,7 @@ typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferCreateFlagBits; typedef VkFlags VkBufferCreateFlags; @@ -957,6 +974,7 @@ typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferUsageFlagBits; typedef VkFlags VkBufferUsageFlags; typedef VkFlags VkBufferViewCreateFlags; @@ -968,6 +986,7 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, + VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCreateFlagBits; typedef VkFlags VkPipelineCreateFlags; typedef VkFlags VkPipelineShaderStageCreateFlags; @@ -979,8 +998,9 @@ typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, - VK_SHADER_STAGE_ALL_GRAPHICS = 0x1F, + VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, VK_SHADER_STAGE_ALL = 0x7FFFFFFF, + VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkShaderStageFlagBits; typedef VkFlags VkPipelineVertexInputStateCreateFlags; typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; @@ -992,7 +1012,8 @@ typedef enum VkCullModeFlagBits { VK_CULL_MODE_NONE = 0, VK_CULL_MODE_FRONT_BIT = 0x00000001, VK_CULL_MODE_BACK_BIT = 0x00000002, - VK_CULL_MODE_FRONT_AND_BACK = 0x3, + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, + VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCullModeFlagBits; typedef VkFlags VkCullModeFlags; typedef VkFlags VkPipelineMultisampleStateCreateFlags; @@ -1004,6 +1025,7 @@ typedef enum VkColorComponentFlagBits { VK_COLOR_COMPONENT_G_BIT = 0x00000002, VK_COLOR_COMPONENT_B_BIT = 0x00000004, VK_COLOR_COMPONENT_A_BIT = 0x00000008, + VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkColorComponentFlagBits; typedef VkFlags VkColorComponentFlags; typedef VkFlags VkPipelineDynamicStateCreateFlags; @@ -1014,6 +1036,7 @@ typedef VkFlags VkDescriptorSetLayoutCreateFlags; typedef enum VkDescriptorPoolCreateFlagBits { VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, + VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorPoolCreateFlagBits; typedef VkFlags VkDescriptorPoolCreateFlags; typedef VkFlags VkDescriptorPoolResetFlags; @@ -1022,6 +1045,7 @@ typedef VkFlags VkRenderPassCreateFlags; typedef enum VkAttachmentDescriptionFlagBits { VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, + VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAttachmentDescriptionFlagBits; typedef VkFlags VkAttachmentDescriptionFlags; typedef VkFlags VkSubpassDescriptionFlags; @@ -1044,22 +1068,26 @@ typedef enum VkAccessFlagBits { VK_ACCESS_HOST_WRITE_BIT = 0x00004000, VK_ACCESS_MEMORY_READ_BIT = 0x00008000, VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAccessFlagBits; typedef VkFlags VkAccessFlags; typedef enum VkDependencyFlagBits { VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, + VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDependencyFlagBits; typedef VkFlags VkDependencyFlags; typedef enum VkCommandPoolCreateFlagBits { VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, + VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolCreateFlagBits; typedef VkFlags VkCommandPoolCreateFlags; typedef enum VkCommandPoolResetFlagBits { VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolResetFlagBits; typedef VkFlags VkCommandPoolResetFlags; @@ -1067,23 +1095,27 @@ typedef enum VkCommandBufferUsageFlagBits { VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, + VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferUsageFlagBits; typedef VkFlags VkCommandBufferUsageFlags; typedef enum VkQueryControlFlagBits { VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, + VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryControlFlagBits; typedef VkFlags VkQueryControlFlags; typedef enum VkCommandBufferResetFlagBits { VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferResetFlagBits; typedef VkFlags VkCommandBufferResetFlags; typedef enum VkStencilFaceFlagBits { VK_STENCIL_FACE_FRONT_BIT = 0x00000001, VK_STENCIL_FACE_BACK_BIT = 0x00000002, - VK_STENCIL_FRONT_AND_BACK = 0x3, + VK_STENCIL_FRONT_AND_BACK = 0x00000003, + VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkStencilFaceFlagBits; typedef VkFlags VkStencilFaceFlags; @@ -3140,10 +3172,10 @@ VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) typedef enum VkColorSpaceKHR { VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0, - VK_COLORSPACE_BEGIN_RANGE = VK_COLORSPACE_SRGB_NONLINEAR_KHR, - VK_COLORSPACE_END_RANGE = VK_COLORSPACE_SRGB_NONLINEAR_KHR, - VK_COLORSPACE_RANGE_SIZE = (VK_COLORSPACE_SRGB_NONLINEAR_KHR - VK_COLORSPACE_SRGB_NONLINEAR_KHR + 1), - VK_COLORSPACE_MAX_ENUM = 0x7FFFFFFF + VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLORSPACE_SRGB_NONLINEAR_KHR, + VK_COLOR_SPACE_END_RANGE_KHR = VK_COLORSPACE_SRGB_NONLINEAR_KHR, + VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLORSPACE_SRGB_NONLINEAR_KHR - VK_COLORSPACE_SRGB_NONLINEAR_KHR + 1), + VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF } VkColorSpaceKHR; typedef enum VkPresentModeKHR { @@ -3151,10 +3183,10 @@ typedef enum VkPresentModeKHR { VK_PRESENT_MODE_MAILBOX_KHR = 1, VK_PRESENT_MODE_FIFO_KHR = 2, VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, - VK_PRESENT_MODE_BEGIN_RANGE = VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_END_RANGE = VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_RANGE_SIZE = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), - VK_PRESENT_MODE_MAX_ENUM = 0x7FFFFFFF + VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF } VkPresentModeKHR; @@ -3168,6 +3200,7 @@ typedef enum VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, + VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSurfaceTransformFlagBitsKHR; typedef VkFlags VkSurfaceTransformFlagsKHR; @@ -3176,6 +3209,7 @@ typedef enum VkCompositeAlphaFlagBitsKHR { VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, + VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkCompositeAlphaFlagBitsKHR; typedef VkFlags VkCompositeAlphaFlagsKHR; @@ -3237,7 +3271,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( #define VK_KHR_swapchain 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) -#define VK_KHR_SWAPCHAIN_SPEC_VERSION 67 +#define VK_KHR_SWAPCHAIN_SPEC_VERSION 68 #define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" typedef VkFlags VkSwapchainCreateFlagsKHR; @@ -3325,9 +3359,10 @@ typedef enum VkDisplayPlaneAlphaFlagBitsKHR { VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, + VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkDisplayPlaneAlphaFlagBitsKHR; -typedef VkFlags VkDisplayModeCreateFlagsKHR; typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +typedef VkFlags VkDisplayModeCreateFlagsKHR; typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; typedef struct VkDisplayPropertiesKHR { @@ -3392,7 +3427,7 @@ typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhys typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR*pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); @@ -3667,11 +3702,17 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( #endif #endif /* VK_USE_PLATFORM_WIN32_KHR */ +#define VK_KHR_sampler_mirror_clamp_to_edge 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" + + #define VK_EXT_debug_report 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 1 +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" +#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT typedef enum VkDebugReportObjectTypeEXT { @@ -3704,11 +3745,19 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28, + VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), + VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportObjectTypeEXT; typedef enum VkDebugReportErrorEXT { VK_DEBUG_REPORT_ERROR_NONE_EXT = 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1, + VK_DEBUG_REPORT_ERROR_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_ERROR_NONE_EXT, + VK_DEBUG_REPORT_ERROR_END_RANGE_EXT = VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, + VK_DEBUG_REPORT_ERROR_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT - VK_DEBUG_REPORT_ERROR_NONE_EXT + 1), + VK_DEBUG_REPORT_ERROR_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportErrorEXT; @@ -3718,6 +3767,7 @@ typedef enum VkDebugReportFlagBitsEXT { VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, + VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportFlagBitsEXT; typedef VkFlags VkDebugReportFlagsEXT; @@ -3768,6 +3818,16 @@ VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( const char* pMessage); #endif +#define VK_NV_glsl_shader 1 +#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 +#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" + + +#define VK_IMG_filter_cubic 1 +#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 +#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" + + #ifdef __cplusplus } #endif From 3f25610d2f30014382ddc508882adcd374fb3aa3 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 2 May 2016 23:03:43 +0200 Subject: [PATCH 146/156] Fix uses of deprecated Vulkan symbol --- tests/glfwinfo.c | 2 +- tests/vulkan.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index 806763550..01d8ac0cb 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -816,7 +816,7 @@ int main(int argc, char** argv) ai.applicationVersion = GLFW_VERSION_MAJOR; ai.pEngineName = "GLFW"; ai.engineVersion = GLFW_VERSION_MAJOR; - ai.apiVersion = VK_API_VERSION; + ai.apiVersion = VK_API_VERSION_1_0; ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; ici.pApplicationInfo = &ai; diff --git a/tests/vulkan.c b/tests/vulkan.c index cacba9c05..1b62d6814 100644 --- a/tests/vulkan.c +++ b/tests/vulkan.c @@ -1778,7 +1778,7 @@ static void demo_init_vk(struct demo *demo) { .applicationVersion = 0, .pEngineName = APP_SHORT_NAME, .engineVersion = 0, - .apiVersion = VK_API_VERSION, + .apiVersion = VK_API_VERSION_1_0, }; VkInstanceCreateInfo inst_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, From 6fcedb5396d1c7af0e41e2e15402e563e042f313 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 3 May 2016 11:28:23 +0200 Subject: [PATCH 147/156] Fix GLFW_RESIZABLE on X11 when exiting full screen The WM normal hints were set with the wrong window dimensions. Fixes #737. --- src/x11_window.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 0f8053247..f3730c252 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -209,7 +209,7 @@ static void sendEventToWM(_GLFWwindow* window, Atom type, // Updates the normal hints according to the window settings // -static void updateNormalHints(_GLFWwindow* window) +static void updateNormalHints(_GLFWwindow* window, int width, int height) { XSizeHints* hints = XAllocSizeHints(); @@ -239,9 +239,6 @@ static void updateNormalHints(_GLFWwindow* window) } else { - int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); - hints->flags |= (PMinSize | PMaxSize); hints->min_width = hints->max_width = width; hints->min_height = hints->max_height = height; @@ -256,8 +253,6 @@ static void updateNormalHints(_GLFWwindow* window) // static void updateWindowMode(_GLFWwindow* window) { - updateNormalHints(window); - if (window->monitor) { if (_glfw.x11.xinerama.available && @@ -556,7 +551,7 @@ static GLFWbool createWindow(_GLFWwindow* window, XFree(hints); } - updateNormalHints(window); + updateNormalHints(window, wndconfig->width, wndconfig->height); // Set ICCCM WM_CLASS property // HACK: Until a mechanism for specifying the application name is added, the @@ -1729,7 +1724,7 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) else { if (!window->resizable) - updateNormalHints(window); + updateNormalHints(window, width, height); XResizeWindow(_glfw.x11.display, window->x11.handle, width, height); } @@ -1741,13 +1736,17 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { - updateNormalHints(window); + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { - updateNormalHints(window); + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); XFlush(_glfw.x11.display); } @@ -1943,6 +1942,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, releaseMonitor(window); _glfwInputWindowMonitorChange(window, monitor); + updateNormalHints(window, width, height); updateWindowMode(window); if (window->monitor) From 211bdab51f5879c3cc9e8cadb9a221324ad7c03a Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 3 May 2016 11:38:45 +0200 Subject: [PATCH 148/156] Fix NET_WM_STATE clobbering at creation --- src/x11_window.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index f3730c252..dfa7af309 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -464,32 +464,32 @@ static GLFWbool createWindow(_GLFWwindow* window, sizeof(hints) / sizeof(long)); } - if (wndconfig->floating) + if (_glfw.x11.NET_WM_STATE && !window->monitor) { - if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE) + Atom states[3]; + int count = 0; + + if (wndconfig->floating) { - Atom value = _glfw.x11.NET_WM_STATE_ABOVE; - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) &value, 1); + if (_glfw.x11.NET_WM_STATE_ABOVE) + states[count++] = _glfw.x11.NET_WM_STATE_ABOVE; } - } - if (wndconfig->maximized && !window->monitor) - { - if (_glfw.x11.NET_WM_STATE && - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + if (wndconfig->maximized) { - const Atom states[2] = + if (_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) { - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ - }; + states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT; + states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ; + } + } + if (count) + { XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) &states, 2); + PropModeReplace, (unsigned char*) &states, count); } } From 932a161d44386987ab8af7fa92173044246da872 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 3 May 2016 11:58:25 +0200 Subject: [PATCH 149/156] Unconditionally use some EWMH atoms These window properties do no harm if they're declared even if the WM doesn't support them. This makes GLFW slightly more tolerant of WM changes as well as things like Ubuntu Unity reading _NET_WM_ICON without declaring support for it. --- src/x11_init.c | 30 +++++++++++++++------------ src/x11_window.c | 53 ++++++++++++++++-------------------------------- 2 files changed, 35 insertions(+), 48 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 2e7f7a725..522bf6635 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -445,16 +445,6 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); _glfw.x11.NET_WM_FULLSCREEN_MONITORS = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); - _glfw.x11.NET_WM_NAME = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME"); - _glfw.x11.NET_WM_ICON_NAME = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON_NAME"); - _glfw.x11.NET_WM_ICON = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON"); - _glfw.x11.NET_WM_PID = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PID"); - _glfw.x11.NET_WM_PING = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PING"); _glfw.x11.NET_WM_WINDOW_TYPE = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = @@ -465,8 +455,6 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); _glfw.x11.NET_REQUEST_FRAME_EXTENTS = getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); - _glfw.x11.NET_WM_BYPASS_COMPOSITOR = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_BYPASS_COMPOSITOR"); XFree(supportedAtoms); } @@ -475,7 +463,8 @@ static void detectEWMH(void) // static GLFWbool initExtensions(void) { - // Find or create window manager atoms + // ICCCM window property and protocol atoms + // Always intern these as they can be set safely even without WM support _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False); @@ -487,6 +476,21 @@ static GLFWbool initExtensions(void) "_MOTIF_WM_HINTS", False); + // EWMH window property and protocol atoms + // Always intern these as they can be set safely even without WM support + _glfw.x11.NET_WM_ICON = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); + _glfw.x11.NET_WM_PING = + XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); + _glfw.x11.NET_WM_PID = + XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); + _glfw.x11.NET_WM_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); + _glfw.x11.NET_WM_ICON_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); + _glfw.x11.NET_WM_BYPASS_COMPOSITOR = + XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); + #if defined(_GLFW_HAS_XF86VM) // Check for XF86VidMode extension _glfw.x11.vidmode.available = diff --git a/src/x11_window.c b/src/x11_window.c index dfa7af309..fbe36f1da 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -295,7 +295,7 @@ static void updateWindowMode(_GLFWwindow* window) window->x11.overrideRedirect = GLFW_TRUE; } - if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) + // Enable compositor bypass { const unsigned long value = 1; @@ -333,7 +333,7 @@ static void updateWindowMode(_GLFWwindow* window) window->x11.overrideRedirect = GLFW_FALSE; } - if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) + // Disable compositor bypass { XDeleteProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_BYPASS_COMPOSITOR); @@ -495,28 +495,17 @@ static GLFWbool createWindow(_GLFWwindow* window, // Declare the WM protocols supported by GLFW { - int count = 0; - Atom protocols[2]; - - // The WM_DELETE_WINDOW ICCCM protocol - // Basic window close notification protocol - if (_glfw.x11.WM_DELETE_WINDOW) - protocols[count++] = _glfw.x11.WM_DELETE_WINDOW; - - // The _NET_WM_PING EWMH protocol - // Tells the WM to ping the GLFW window and flag the application as - // unresponsive if the WM doesn't get a reply within a few seconds - if (_glfw.x11.NET_WM_PING) - protocols[count++] = _glfw.x11.NET_WM_PING; - - if (count > 0) + Atom protocols[] = { - XSetWMProtocols(_glfw.x11.display, window->x11.handle, - protocols, count); - } + _glfw.x11.WM_DELETE_WINDOW, + _glfw.x11.NET_WM_PING + }; + + XSetWMProtocols(_glfw.x11.display, window->x11.handle, + protocols, sizeof(protocols) / sizeof(Atom)); } - if (_glfw.x11.NET_WM_PID) + // Declare our PID { const pid_t pid = getpid(); @@ -1591,21 +1580,15 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) NULL, NULL, NULL); #endif - if (_glfw.x11.NET_WM_NAME) - { - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, - PropModeReplace, - (unsigned char*) title, strlen(title)); - } + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + (unsigned char*) title, strlen(title)); - if (_glfw.x11.NET_WM_ICON_NAME) - { - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, - PropModeReplace, - (unsigned char*) title, strlen(title)); - } + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + (unsigned char*) title, strlen(title)); XFlush(_glfw.x11.display); } From 11d051b69a30df89d34d540d5f1eae394bf62666 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 3 May 2016 12:00:16 +0200 Subject: [PATCH 150/156] Formatting --- src/x11_init.c | 62 +++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 522bf6635..b81afcc7c 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -463,34 +463,6 @@ static void detectEWMH(void) // static GLFWbool initExtensions(void) { - // ICCCM window property and protocol atoms - // Always intern these as they can be set safely even without WM support - _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display, - "WM_PROTOCOLS", - False); - _glfw.x11.WM_STATE = XInternAtom(_glfw.x11.display, "WM_STATE", False); - _glfw.x11.WM_DELETE_WINDOW = XInternAtom(_glfw.x11.display, - "WM_DELETE_WINDOW", - False); - _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, - "_MOTIF_WM_HINTS", - False); - - // EWMH window property and protocol atoms - // Always intern these as they can be set safely even without WM support - _glfw.x11.NET_WM_ICON = - XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); - _glfw.x11.NET_WM_PING = - XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); - _glfw.x11.NET_WM_PID = - XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); - _glfw.x11.NET_WM_NAME = - XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); - _glfw.x11.NET_WM_ICON_NAME = - XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); - _glfw.x11.NET_WM_BYPASS_COMPOSITOR = - XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); - #if defined(_GLFW_HAS_XF86VM) // Check for XF86VidMode extension _glfw.x11.vidmode.available = @@ -586,7 +558,7 @@ static GLFWbool initExtensions(void) // Detect whether an EWMH-conformant window manager is running detectEWMH(); - // Find or create string format atoms + // String format atoms _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False); @@ -594,22 +566,22 @@ static GLFWbool initExtensions(void) XInternAtom(_glfw.x11.display, "COMPOUND_STRING", False); _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); - // Find or create selection property atom + // Custom selection property atom _glfw.x11.GLFW_SELECTION = XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); - // Find or create standard clipboard atoms + // ICCCM standard clipboard atoms _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); - // Find or create clipboard manager atoms + // Clipboard manager atoms _glfw.x11.CLIPBOARD_MANAGER = XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); _glfw.x11.SAVE_TARGETS = XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); - // Find Xdnd (drag and drop) atoms, if available + // Xdnd (drag and drop) atoms _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False); _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); @@ -620,6 +592,30 @@ static GLFWbool initExtensions(void) _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); + // ICCCM, EWMH and Motif window property atoms + // These can be set safely even without WM support + // The EWMH atoms that require WM support are handled in detectEWMH + _glfw.x11.WM_PROTOCOLS = + XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False); + _glfw.x11.WM_STATE = + XInternAtom(_glfw.x11.display, "WM_STATE", False); + _glfw.x11.WM_DELETE_WINDOW = + XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False); + _glfw.x11.NET_WM_ICON = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); + _glfw.x11.NET_WM_PING = + XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); + _glfw.x11.NET_WM_PID = + XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); + _glfw.x11.NET_WM_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); + _glfw.x11.NET_WM_ICON_NAME = + 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.MOTIF_WM_HINTS = + XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + return GLFW_TRUE; } From e640d840b710c79074cc99766222f86bda94f417 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 4 May 2016 16:04:26 +0200 Subject: [PATCH 151/156] Fix Win32 window size event race condition The old window size was reported after re-entering full screen and setting and reporting the new window size. Fixes #740. --- README.md | 2 ++ src/win32_window.c | 25 ++++++++++++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f0f827ddf..0321e2ccd 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,8 @@ does not find Doxygen, the documentation will not be generated. trigger monitor callback - [Win32] Bugfix: No monitors were listed on headless and VMware guest systems - [Win32] Bugfix: Pressing Ctrl+Pause would report `GLFW_KEY_UNKNOWN` + - [Win32] Bugfix: Window size events would be reported in wrong order when + restoring a full screen window - [Cocoa] Made joystick polling more efficient - [Cocoa] Removed support for OS X 10.6 - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned diff --git a/src/win32_window.c b/src/win32_window.c index ed6bbe7f6..944bff66c 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -613,32 +613,39 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_SIZE: { + const GLFWbool iconified = + !window->win32.iconified && wParam == SIZE_MINIMIZED; + const GLFWbool restored = + window->win32.iconified && + (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED); + if (_glfw.cursorWindow == window) { if (window->cursorMode == GLFW_CURSOR_DISABLED) updateClipRect(window); } - if (!window->win32.iconified && wParam == SIZE_MINIMIZED) + if (iconified) + _glfwInputWindowIconify(window, GLFW_TRUE); + else if (restored) + _glfwInputWindowIconify(window, GLFW_FALSE); + + _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); + _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); + + if (iconified) { window->win32.iconified = GLFW_TRUE; if (window->monitor) releaseMonitor(window); - - _glfwInputWindowIconify(window, GLFW_TRUE); } - else if (window->win32.iconified && - (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)) + else if (restored) { window->win32.iconified = GLFW_FALSE; if (window->monitor) acquireMonitor(window); - - _glfwInputWindowIconify(window, GLFW_FALSE); } - _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); - _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); return 0; } From 12a695696ddfe395e1e94e7eaceec7b40046d93d Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 4 May 2016 16:28:08 +0200 Subject: [PATCH 152/156] Add validation of size limit and aspect ratio args --- include/GLFW/glfw3.h | 7 +++++-- src/window.c | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index cedecfcbb..06c722cab 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2056,6 +2056,9 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); * The size limits are applied immediately to a windowed mode window and may * cause it to be resized. * + * The maximum dimensions must be greater than or equal to the minimum + * dimensions and all must be greater than or equal to zero. + * * @param[in] window The window to set limits for. * @param[in] minwidth The minimum width, in screen coordinates, of the client * area, or `GLFW_DONT_CARE`. @@ -2066,8 +2069,8 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); * @param[in] maxheight The maximum height, in screen coordinates, of the * client area, or `GLFW_DONT_CARE`. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @remark If you set size limits and an aspect ratio that conflict, the * results are undefined. diff --git a/src/window.c b/src/window.c index 104c703e1..fee08b257 100644 --- a/src/window.c +++ b/src/window.c @@ -521,6 +521,13 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, _GLFW_REQUIRE_INIT(); + if (minwidth < 0 || minheight < 0 || + maxwidth < minwidth || maxheight < minheight) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size limits"); + return; + } + window->minwidth = minwidth; window->minheight = minheight; window->maxwidth = maxwidth; @@ -541,18 +548,18 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) _GLFW_REQUIRE_INIT(); + if (numer <= 0 || denom <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid window aspect ratio"); + return; + } + window->numer = numer; window->denom = denom; if (window->monitor || !window->resizable) return; - if (!denom) - { - _glfwInputError(GLFW_INVALID_VALUE, "Denominator cannot be zero"); - return; - } - _glfwPlatformSetWindowAspectRatio(window, numer, denom); } From 9d50a346f052ae105840d92600c10a168aeac2e9 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 4 May 2016 16:56:17 +0200 Subject: [PATCH 153/156] Fix X11 build on non-Linux systems --- src/linux_joystick.c | 8 ++++++-- src/x11_window.c | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 3342e0fef..e3e03cf17 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -45,9 +45,9 @@ // Attempt to open the specified joystick device // +#if defined(__linux__) static GLFWbool openJoystickDevice(const char* path) { -#if defined(__linux__) char axisCount, buttonCount; char name[256]; int joy, fd, version; @@ -102,9 +102,9 @@ static GLFWbool openJoystickDevice(const char* path) js->buttons = calloc(buttonCount, 1); _glfwInputJoystickChange(joy, GLFW_CONNECTED); -#endif // __linux__ return GLFW_TRUE; } +#endif // __linux__ // Polls for and processes events the specified joystick // @@ -155,12 +155,14 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js) // Lexically compare joysticks, used by quicksort // +#if defined(__linux__) static int compareJoysticks(const void* fp, const void* sp) { const _GLFWjoystickLinux* fj = fp; const _GLFWjoystickLinux* sj = sp; return strcmp(fj->path, sj->path); } +#endif // __linux__ ////////////////////////////////////////////////////////////////////////// @@ -274,6 +276,7 @@ void _glfwTerminateJoysticksLinux(void) void _glfwPollJoystickEvents(void) { +#if defined(__linux__) ssize_t offset = 0; char buffer[16384]; @@ -293,6 +296,7 @@ void _glfwPollJoystickEvents(void) offset += sizeof(struct inotify_event) + e->len; } +#endif } diff --git a/src/x11_window.c b/src/x11_window.c index fbe36f1da..7cf26ce30 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -57,16 +57,16 @@ void selectDisplayConnection(struct timeval* timeout) int result, count; const int fd = ConnectionNumber(_glfw.x11.display); + count = fd + 1; + FD_ZERO(&fds); FD_SET(fd, &fds); #if defined(__linux__) FD_SET(_glfw.linux_js.inotify, &fds); -#endif - if (fd > _glfw.linux_js.inotify) - count = fd + 1; - else + if (fd < _glfw.linux_js.inotify) count = _glfw.linux_js.inotify + 1; +#endif // NOTE: We use select instead of an X function like XNextEvent, as the // wait inside those are guarded by the mutex protecting the display From ef80beab812ee3282493e87f2d7ad8cf10cb8a95 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 28 Mar 2016 13:19:31 +0200 Subject: [PATCH 154/156] Add run-time context creation API selection Fixes #145. --- CMakeLists.txt | 32 +---- README.md | 6 +- docs/compile.dox | 37 ++--- docs/context.dox | 7 +- docs/news.dox | 6 + docs/window.dox | 24 ++++ include/GLFW/glfw3.h | 4 + src/CMakeLists.txt | 41 +++--- src/cocoa_init.m | 5 +- src/cocoa_platform.h | 10 +- src/cocoa_window.m | 20 ++- src/context.c | 67 ++++++--- src/egl_context.c | 257 +++++++++++++++++----------------- src/egl_context.h | 5 +- src/glfw_config.h.in | 9 -- src/glx_context.c | 232 ++++++++++++++++--------------- src/internal.h | 49 +++---- src/mir_platform.h | 10 +- src/mir_window.c | 5 +- src/nsgl_context.m | 130 ++++++++--------- src/wgl_context.c | 324 ++++++++++++++++++++++--------------------- src/wgl_context.h | 1 - src/win32_init.c | 16 +-- src/win32_platform.h | 15 +- src/win32_window.c | 101 +++++++------- src/window.c | 32 +++-- src/wl_platform.h | 10 +- src/wl_window.c | 5 +- src/x11_init.c | 17 +-- src/x11_platform.h | 15 +- src/x11_window.c | 48 +++---- tests/glfwinfo.c | 70 ++++++---- 32 files changed, 806 insertions(+), 804 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 070beae49..02040dd06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,13 +35,11 @@ if (APPLE) option(GLFW_USE_CHDIR "Make glfwInit chdir to Contents/Resources" ON) option(GLFW_USE_MENUBAR "Populate the menu bar on first window creation" ON) option(GLFW_USE_RETINA "Use the full resolution of Retina displays" ON) -else() - option(GLFW_USE_EGL "Use EGL for context creation" OFF) endif() if (UNIX AND NOT APPLE) - option(GLFW_USE_WAYLAND "Use Wayland for context creation (implies EGL as well)" OFF) - option(GLFW_USE_MIR "Use Mir for context creation (implies EGL as well)" OFF) + option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF) + option(GLFW_USE_MIR "Use Mir for window creation" OFF) endif() if (MSVC) @@ -59,12 +57,6 @@ else() set(GLFW_LIB_NAME glfw3) endif() -if (GLFW_USE_WAYLAND) - set(GLFW_USE_EGL ON) -elseif (GLFW_USE_MIR) - set(GLFW_USE_EGL ON) -endif() - set(CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules") find_package(Threads REQUIRED) @@ -129,19 +121,9 @@ endif() if (WIN32) set(_GLFW_WIN32 1) message(STATUS "Using Win32 for window creation") - - if (GLFW_USE_EGL) - set(_GLFW_EGL 1) - message(STATUS "Using EGL for context creation") - else() - set(_GLFW_WGL 1) - message(STATUS "Using WGL for context creation") - endif() elseif (APPLE) set(_GLFW_COCOA 1) message(STATUS "Using Cocoa for window creation") - set(_GLFW_NSGL 1) - message(STATUS "Using NSGL for context creation") elseif (UNIX) if (GLFW_USE_WAYLAND) set(_GLFW_WAYLAND 1) @@ -153,14 +135,6 @@ elseif (UNIX) set(_GLFW_X11 1) message(STATUS "Using X11 for window creation") endif() - - if (GLFW_USE_EGL) - set(_GLFW_EGL 1) - message(STATUS "Using EGL for context creation") - else() - set(_GLFW_GLX 1) - message(STATUS "Using GLX for context creation") - endif() else() message(FATAL_ERROR "No supported platform was detected") endif() @@ -306,7 +280,7 @@ endif() #-------------------------------------------------------------------- # Use Cocoa for window creation and NSOpenGL for context creation #-------------------------------------------------------------------- -if (_GLFW_COCOA AND _GLFW_NSGL) +if (_GLFW_COCOA) if (GLFW_USE_MENUBAR) set(_GLFW_USE_MENUBAR 1) diff --git a/README.md b/README.md index 0321e2ccd..aa72d5e70 100644 --- a/README.md +++ b/README.md @@ -93,12 +93,14 @@ does not find Doxygen, the documentation will not be generated. - Added `GLFW_NO_API` for creating window without contexts - Added `GLFW_CONTEXT_NO_ERROR` context hint for `GL_KHR_no_error` support - Added `GLFW_INCLUDE_VULKAN` for including the Vulkan header + - Added `GLFW_CONTEXT_CREATION_API`, `GLFW_NATIVE_CONTEXT_API` and + `GLFW_EGL_CONTEXT_API` for run-time context creation API selection - Added `GLFW_TRUE` and `GLFW_FALSE` as client API independent boolean values - Added icons to examples on Windows and OS X - Relaxed rules for native access header macros - Removed dependency on external OpenGL or OpenGL ES headers - - Removed `_GLFW_USE_OPENGL`, `_GLFW_USE_GLESV1` and `_GLFW_USE_GLESV2` - configuration macros + - Removed `_GLFW_USE_OPENGL`, `_GLFW_USE_GLESV1`, `_GLFW_USE_GLESV2`, + `_GLFW_WGL`, `_GLFW_NSGL`, `_GLFW_GLX` and `_GLFW_EGL` configuration macros - [Win32] Added support for Windows 8.1 per-monitor DPI - [Win32] Replaced winmm with XInput and DirectInput for joystick input - [Win32] Bugfix: Window creation would segfault if video mode setting required diff --git a/docs/compile.dox b/docs/compile.dox index e1646711b..adadf7793 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -225,19 +225,13 @@ need to be exported by the EXE to be detected by the driver, so the override will not work if GLFW is built as a DLL. -@subsubsection compile_options_egl EGL specific CMake options - -`GLFW_USE_EGL` determines whether to use EGL instead of the platform-specific -context creation API. Note that EGL is not yet provided on all supported -platforms. - - @section compile_manual Compiling GLFW manually If you wish to compile GLFW without its CMake build environment then you will have to do at least some of the platform detection yourself. GLFW needs -a number of configuration macros to be defined in order to know what it's being -compiled for and has many optional, platform-specific ones for various features. +a configuration macro to be defined in order to know what window system it's +being compiled for and also has optional, platform-specific ones for various +features. When building with CMake, the `glfw_config.h` configuration header is generated based on the current platform and CMake options. The GLFW CMake environment @@ -245,10 +239,6 @@ defines `_GLFW_USE_CONFIG_H`, which causes this header to be included by `internal.h`. Without this macro, GLFW will expect the necessary configuration macros to be defined on the command-line. -Three macros _must_ be defined when compiling GLFW: one selecting the window -creation API and one selecting the context creation API. Exactly one of each -kind must be defined for GLFW to compile and link. - The window creation API is used to create windows, handle input, monitors, gamma ramps and clipboard. The options are: @@ -258,19 +248,14 @@ ramps and clipboard. The options are: - `_GLFW_WAYLAND` to use the Wayland API (experimental and incomplete) - `_GLFW_MIR` to use the Mir API (experimental and incomplete) -The context creation API is used to enumerate pixel formats / framebuffer -configurations and to create contexts. The options are: - - - `_GLFW_NSGL` to use the Cocoa OpenGL framework - - `_GLFW_WGL` to use the Win32 WGL API - - `_GLFW_GLX` to use the X11 GLX API - - `_GLFW_EGL` to use the EGL API - -Wayland and Mir both require the EGL backend. - If you are building GLFW as a shared library / dynamic library / DLL then you must also define `_GLFW_BUILD_DLL`. Otherwise, you must not define it. +For the EGL context creation API, the following options are available: + + - `_GLFW_USE_EGLPLATFORM_H` to use `EGL/eglplatform.h` for native handle + definitions (fallback) + If you are using the X11 window creation API, support for the following X11 extensions can be enabled: @@ -287,12 +272,6 @@ available: - `_GLFW_USE_RETINA` to have windows use the full resolution of Retina displays (recommended) -If you are using the EGL context creation API, the following options are -available: - - - `_GLFW_USE_EGLPLATFORM_H` to use `EGL/eglplatform.h` for native handle - definitions (fallback) - @note None of the @ref build_macros may be defined during the compilation of GLFW. If you define any of these in your build files, make sure they are not applied to the GLFW sources. diff --git a/docs/context.dox b/docs/context.dox index 62bbc61fb..7cc1f120c 100644 --- a/docs/context.dox +++ b/docs/context.dox @@ -177,9 +177,10 @@ python main.py --generator c --no-loader --out-path output @endcode The `--no-loader` option is added because GLFW already provides a function for -loading OpenGL and OpenGL ES function pointers and glad can call this instead of -having to implement its own. There are several other command-line options as -well. See the glad documentation for details. +loading OpenGL and OpenGL ES function pointers, one that automatically uses the +selected context creation API, and glad can call this instead of having to +implement its own. There are several other command-line options as well. See +the glad documentation for details. Add the generated `output/src/glad.c`, `output/include/glad/glad.h` and `output/include/KHR/khrplatform.h` files to your build. Then you need to diff --git a/docs/news.dox b/docs/news.dox index dae843090..e0fb5f80c 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -61,6 +61,12 @@ GLFW now supports waiting for events for a set amount of time with @ref glfwWaitEventsTimeout. +@subsection news_32_contextapi Run-time context creation API selection + +GLFW now supports selecting the context creation API at run-time with +[GLFW_CONTEXT_CREATION_API](@ref window_hints_ctx). + + @section news_31 New features in 3.1 These are the release highlights. For a full list of changes see the diff --git a/docs/window.dox b/docs/window.dox index 953e2eab3..b66874bb9 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -159,6 +159,7 @@ The following hints are always hard constraints: - `GLFW_STEREO` - `GLFW_DOUBLEBUFFER` - `GLFW_CLIENT_API` +- `GLFW_CONTEXT_CREATION_API` The following additional hints are hard constraints when requesting an OpenGL context, but are ignored when requesting an OpenGL ES context: @@ -249,6 +250,24 @@ This hint is ignored for windowed mode windows. Possible values are `GLFW_OPENGL_API`, `GLFW_OPENGL_ES_API` and `GLFW_NO_API`. This is a hard constraint. +`GLFW_CONTEXT_CREATION_API` specifies which context creation API to use to +create the context. Possible values are `GLFW_NATIVE_CONTEXT_API` and +`GLFW_EGL_CONTEXT_API`. This is a hard constraint. If no client API is +requested, this hint is ignored. + +@par +__OS X:__ The EGL API is not available on this platform and requests to use it +will fail. + +@par +__Wayland, Mir:__ The EGL API _is_ the native context creation API, so this hint +will have no effect. + +@note An OpenGL extension loader library that assumes it knows which context +creation API is used on a given platform may fail if you change this hint. This +can be resolved by having it load via @ref glfwGetProcAddress, which always uses +the selected API. + `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. @@ -362,6 +381,7 @@ Window hint | Default value | Supported values `GLFW_SRGB_CAPABLE` | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` `GLFW_DOUBLEBUFFER` | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` `GLFW_CLIENT_API` | `GLFW_OPENGL_API` | `GLFW_OPENGL_API`, `GLFW_OPENGL_ES_API` or `GLFW_NO_API` +`GLFW_CONTEXT_CREATION_API` | `GLFW_NATIVE_CONTEXT_API` | `GLFW_NATIVE_CONTEXT_API` or `GLFW_EGL_CONTEXT_API` `GLFW_CONTEXT_VERSION_MAJOR` | 1 | Any valid major version number of the chosen client API `GLFW_CONTEXT_VERSION_MINOR` | 0 | Any valid minor version number of the chosen client API `GLFW_CONTEXT_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS`, `GLFW_NO_RESET_NOTIFICATION` or `GLFW_LOSE_CONTEXT_ON_RESET` @@ -889,6 +909,10 @@ topmost or always-on-top. This is controlled by the `GLFW_CLIENT_API` indicates the client API provided by the window's context; either `GLFW_OPENGL_API`, `GLFW_OPENGL_ES_API` or `GLFW_NO_API`. +`GLFW_CONTEXT_CREATION_API` indicates the context creation API used to create +the window's context; either `GLFW_NATIVE_CONTEXT_API` or +`GLFW_EGL_CONTEXT_API`. + `GLFW_CONTEXT_VERSION_MAJOR`, `GLFW_CONTEXT_VERSION_MINOR` and `GLFW_CONTEXT_REVISION` indicate the client API version of the window's context. diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 06c722cab..4e4bdcd3d 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -655,6 +655,7 @@ extern "C" { #define GLFW_OPENGL_PROFILE 0x00022008 #define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 #define GLFW_CONTEXT_NO_ERROR 0x0002200A +#define GLFW_CONTEXT_CREATION_API 0x0002200B #define GLFW_NO_API 0 #define GLFW_OPENGL_API 0x00030001 @@ -680,6 +681,9 @@ extern "C" { #define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 #define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 +#define GLFW_NATIVE_CONTEXT_API 0x00036001 +#define GLFW_EGL_CONTEXT_API 0x00036002 + /*! @defgroup shapes Standard cursor shapes * * See [standard cursor creation](@ref cursor_standard) for how these are used. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dab94ef12..5042aba38 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,23 +7,29 @@ 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) + posix_tls.h nsgl_context.h) 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_tls.c + nsgl_context.m) elseif (_GLFW_WIN32) - set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h) + set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h + wgl_context.h egl_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_tls.c win32_window.c + wgl_context.c egl_context.c) elseif (_GLFW_X11) set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h - linux_joystick.h posix_time.h posix_tls.h) + linux_joystick.h posix_time.h posix_tls.h glx_context.h + egl_context.h) set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c - xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c) + xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c + glx_context.c egl_context.c) elseif (_GLFW_WAYLAND) set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h - posix_time.h posix_tls.h xkb_unicode.h) + posix_time.h posix_tls.h xkb_unicode.h egl_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_tls.c xkb_unicode.c + egl_context.c) ecm_add_wayland_client_protocol(glfw_SOURCES PROTOCOL @@ -35,23 +41,10 @@ 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) + posix_time.h posix_tls.h xkb_unicode.h egl_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) -endif() - -if (_GLFW_EGL) - list(APPEND glfw_HEADERS ${common_HEADERS} egl_context.h) - list(APPEND glfw_SOURCES ${common_SOURCES} egl_context.c) -elseif (_GLFW_NSGL) - list(APPEND glfw_HEADERS ${common_HEADERS} nsgl_context.h) - list(APPEND glfw_SOURCES ${common_SOURCES} nsgl_context.m) -elseif (_GLFW_WGL) - list(APPEND glfw_HEADERS ${common_HEADERS} wgl_context.h) - list(APPEND glfw_SOURCES ${common_SOURCES} wgl_context.c) -elseif (_GLFW_X11) - list(APPEND glfw_HEADERS ${common_HEADERS} glx_context.h) - list(APPEND glfw_SOURCES ${common_SOURCES} glx_context.c) + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c + egl_context.c) endif() if (APPLE) diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 16b8c9f9f..9b6434d5b 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -280,10 +280,7 @@ void _glfwPlatformTerminate(void) const char* _glfwPlatformGetVersionString(void) { - return _GLFW_VERSION_NUMBER " Cocoa" -#if defined(_GLFW_NSGL) - " NSGL" -#endif + return _GLFW_VERSION_NUMBER " Cocoa NSGL" #if defined(_GLFW_USE_CHDIR) " chdir" #endif diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index eeeb47271..95eae62bc 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -41,12 +41,7 @@ typedef void* id; #include "posix_tls.h" #include "cocoa_joystick.h" - -#if defined(_GLFW_NSGL) - #include "nsgl_context.h" -#else - #error "The Cocoa backend depends on NSGL platform support" -#endif +#include "nsgl_context.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -58,6 +53,9 @@ typedef void* id; #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns +#define _GLFW_EGL_CONTEXT_STATE +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE + // Cocoa-specific per-window data // diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 6f514392b..f5e992893 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -209,7 +209,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidResize:(NSNotification *)notification { - if (window->context.api != GLFW_NO_API) + if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; if (_glfw.cursorWindow == window && @@ -227,7 +227,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidMove:(NSNotification *)notification { - if (window->context.api != GLFW_NO_API) + if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; if (_glfw.cursorWindow == window && @@ -1002,10 +1002,18 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!createWindow(window, wndconfig)) return GLFW_FALSE; - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { - if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig)) + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Cocoa: EGL not available"); return GLFW_FALSE; + } } if (window->monitor) @@ -1026,8 +1034,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->monitor) releaseMonitor(window); - if (window->context.api != GLFW_NO_API) - _glfwDestroyContextNSGL(window); + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); [window->ns.object setDelegate:nil]; [window->ns.delegate release]; diff --git a/src/context.c b/src/context.c index eb8a561b7..5f4a08c33 100644 --- a/src/context.c +++ b/src/context.c @@ -90,17 +90,26 @@ static GLFWbool parseVersionString(int* api, int* major, int* minor, int* rev) GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) { - if (ctxconfig->api != GLFW_NO_API && - ctxconfig->api != GLFW_OPENGL_API && - ctxconfig->api != GLFW_OPENGL_ES_API) + if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API && + ctxconfig->source != GLFW_EGL_CONTEXT_API) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid client API %i", - ctxconfig->api); + "Invalid context creation API %i", + ctxconfig->source); return GLFW_FALSE; } - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client != GLFW_NO_API && + ctxconfig->client != GLFW_OPENGL_API && + ctxconfig->client != GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid client API %i", + ctxconfig->client); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_API) { if ((ctxconfig->major < 1 || ctxconfig->minor < 0) || (ctxconfig->major == 1 && ctxconfig->minor > 5) || @@ -150,7 +159,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) return GLFW_FALSE; } } - else if (ctxconfig->api == GLFW_OPENGL_ES_API) + else if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (ctxconfig->major < 1 || ctxconfig->minor < 0 || (ctxconfig->major == 1 && ctxconfig->minor > 1) || @@ -366,8 +375,13 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) glfwGetProcAddress("glGetIntegerv"); window->context.GetString = (PFNGLGETSTRINGPROC) glfwGetProcAddress("glGetString"); + if (!window->context.GetIntegerv || !window->context.GetString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); + return GLFW_FALSE; + } - if (!parseVersionString(&window->context.api, + if (!parseVersionString(&window->context.client, &window->context.major, &window->context.minor, &window->context.revision)) @@ -375,6 +389,8 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) return GLFW_FALSE; } + window->context.source = ctxconfig->source; + if (window->context.major < ctxconfig->major || (window->context.major == ctxconfig->major && window->context.minor < ctxconfig->minor)) @@ -409,7 +425,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) } } - if (window->context.api == GLFW_OPENGL_API) + if (window->context.client == GLFW_OPENGL_API) { // Read back context flags (OpenGL 3.0 and above) if (window->context.major >= 3) @@ -507,7 +523,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) { PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) glfwGetProcAddress("glClear"); glClear(GL_COLOR_BUFFER_BIT); - _glfwPlatformSwapBuffers(window); + window->context.swapBuffers(window); } return GLFW_TRUE; @@ -547,16 +563,24 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFWwindow* previous = _glfwPlatformGetCurrentContext(); _GLFW_REQUIRE_INIT(); - if (window && window->context.api == GLFW_NO_API) + if (window && window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return; } - _glfwPlatformMakeContextCurrent(window); + if (previous) + { + if (!window || window->context.source != previous->context.source) + previous->context.makeContextCurrent(NULL); + } + + if (window) + window->context.makeContextCurrent(window); } GLFWAPI GLFWwindow* glfwGetCurrentContext(void) @@ -572,26 +596,29 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) _GLFW_REQUIRE_INIT(); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return; } - _glfwPlatformSwapBuffers(window); + window->context.swapBuffers(window); } GLFWAPI void glfwSwapInterval(int interval) { + _GLFWwindow* window; + _GLFW_REQUIRE_INIT(); - if (!_glfwPlatformGetCurrentContext()) + window = _glfwPlatformGetCurrentContext(); + if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); return; } - _glfwPlatformSwapInterval(interval); + window->context.swapInterval(interval); } GLFWAPI int glfwExtensionSupported(const char* extension) @@ -657,21 +684,23 @@ GLFWAPI int glfwExtensionSupported(const char* extension) } // Check if extension is in the platform-specific string - return _glfwPlatformExtensionSupported(extension); + return window->context.extensionSupported(extension); } GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) { + _GLFWwindow* window; assert(procname != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (!_glfwPlatformGetCurrentContext()) + window = _glfwPlatformGetCurrentContext(); + if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); return NULL; } - return _glfwPlatformGetProcAddress(procname); + return window->context.getProcAddress(procname); } diff --git a/src/egl_context.c b/src/egl_context.c index 26df4566d..062030276 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -125,7 +125,7 @@ static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, continue; #endif // _GLFW_X11 - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (ctxconfig->major == 1) { @@ -138,7 +138,7 @@ static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, continue; } } - else if (ctxconfig->api == GLFW_OPENGL_API) + else if (ctxconfig->client == GLFW_OPENGL_API) { if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) continue; @@ -169,6 +169,110 @@ static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, return closest != NULL; } +static void makeContextCurrent(_GLFWwindow* window) +{ + if (window) + { + if (!eglMakeCurrent(_glfw.egl.display, + window->context.egl.surface, + window->context.egl.surface, + window->context.egl.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to make context current: %s", + getErrorString(eglGetError())); + return; + } + } + else + { + if (!eglMakeCurrent(_glfw.egl.display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to clear current context: %s", + getErrorString(eglGetError())); + return; + } + } + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffers(_GLFWwindow* window) +{ + if (window != _glfwPlatformGetCurrentContext()) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: The context must be current on the calling thread when swapping buffers"); + return; + } + + eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); +} + +static void swapInterval(int interval) +{ + eglSwapInterval(_glfw.egl.display, interval); +} + +static int extensionSupported(const char* extension) +{ + const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddress(const char* procname) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (window->context.egl.client) + { + GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, + procname); + if (proc) + return proc; + } + + return eglGetProcAddress(procname); +} + +static void destroyContext(_GLFWwindow* window) +{ +#if defined(_GLFW_X11) + // NOTE: Do not unload libGL.so.1 while the X11 display is still open, + // as it will make XCloseDisplay segfault + if (window->context.client != GLFW_OPENGL_API) +#endif // _GLFW_X11 + { + if (window->context.egl.client) + { + _glfw_dlclose(window->context.egl.client); + window->context.egl.client = NULL; + } + } + + if (window->context.egl.surface) + { + eglDestroySurface(_glfw.egl.display, window->context.egl.surface); + window->context.egl.surface = EGL_NO_SURFACE; + } + + if (window->context.egl.handle) + { + eglDestroyContext(_glfw.egl.display, window->context.egl.handle); + window->context.egl.handle = EGL_NO_CONTEXT; + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -200,10 +304,7 @@ GLFWbool _glfwInitEGL(void) } if (!_glfw.egl.handle) - { - _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to load EGL"); return GLFW_FALSE; - } _glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); @@ -244,6 +345,8 @@ GLFWbool _glfwInitEGL(void) _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to get EGL display: %s", getErrorString(eglGetError())); + + _glfwTerminateEGL(); return GLFW_FALSE; } @@ -252,15 +355,17 @@ GLFWbool _glfwInitEGL(void) _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to initialize EGL: %s", getErrorString(eglGetError())); + + _glfwTerminateEGL(); return GLFW_FALSE; } _glfw.egl.KHR_create_context = - _glfwPlatformExtensionSupported("EGL_KHR_create_context"); + extensionSupported("EGL_KHR_create_context"); _glfw.egl.KHR_create_context_no_error = - _glfwPlatformExtensionSupported("EGL_KHR_create_context_no_error"); + extensionSupported("EGL_KHR_create_context_no_error"); _glfw.egl.KHR_gl_colorspace = - _glfwPlatformExtensionSupported("EGL_KHR_gl_colorspace"); + extensionSupported("EGL_KHR_gl_colorspace"); return GLFW_TRUE; } @@ -299,6 +404,12 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, EGLConfig config; EGLContext share = NULL; + if (!_glfw.egl.display) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available"); + return GLFW_FALSE; + } + if (ctxconfig->share) share = ctxconfig->share->context.egl.handle; @@ -309,7 +420,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, return GLFW_FALSE; } - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (!eglBindAPI(EGL_OPENGL_ES_API)) { @@ -334,7 +445,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { int index = 0, mask = 0, flags = 0; - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; @@ -388,7 +499,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { int index = 0; - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); setEGLattrib(EGL_NONE, EGL_NONE); @@ -477,7 +588,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, NULL }; - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (ctxconfig->major == 1) sonames = es1sonames; @@ -502,41 +613,18 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, } } + window->context.makeContextCurrent = makeContextCurrent; + window->context.swapBuffers = swapBuffers; + window->context.swapInterval = swapInterval; + window->context.extensionSupported = extensionSupported; + window->context.getProcAddress = getProcAddress; + window->context.destroyContext = destroyContext; + return GLFW_TRUE; } #undef setEGLattrib -// Destroy the OpenGL context -// -void _glfwDestroyContextEGL(_GLFWwindow* window) -{ -#if defined(_GLFW_X11) - // NOTE: Do not unload libGL.so.1 while the X11 display is still open, - // as it will make XCloseDisplay segfault - if (window->context.api != GLFW_OPENGL_API) -#endif // _GLFW_X11 - { - if (window->context.egl.client) - { - _glfw_dlclose(window->context.egl.client); - window->context.egl.client = NULL; - } - } - - if (window->context.egl.surface) - { - eglDestroySurface(_glfw.egl.display, window->context.egl.surface); - window->context.egl.surface = EGL_NO_SURFACE; - } - - if (window->context.egl.handle) - { - eglDestroyContext(_glfw.egl.display, window->context.egl.handle); - window->context.egl.handle = EGL_NO_CONTEXT; - } -} - // Returns the Visual and depth of the chosen EGLConfig // #if defined(_GLFW_X11) @@ -580,87 +668,6 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, #endif // _GLFW_X11 -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) -{ - if (window) - { - if (!eglMakeCurrent(_glfw.egl.display, - window->context.egl.surface, - window->context.egl.surface, - window->context.egl.handle)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "EGL: Failed to make context current: %s", - getErrorString(eglGetError())); - return; - } - } - else - { - if (!eglMakeCurrent(_glfw.egl.display, - EGL_NO_SURFACE, - EGL_NO_SURFACE, - EGL_NO_CONTEXT)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "EGL: Failed to clear current context: %s", - getErrorString(eglGetError())); - return; - } - } - - _glfwPlatformSetCurrentContext(window); -} - -void _glfwPlatformSwapBuffers(_GLFWwindow* window) -{ - if (window != _glfwPlatformGetCurrentContext()) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "EGL: The context must be current on the calling thread when swapping buffers"); - return; - } - - eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); -} - -void _glfwPlatformSwapInterval(int interval) -{ - eglSwapInterval(_glfw.egl.display, interval); -} - -int _glfwPlatformExtensionSupported(const char* extension) -{ - const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - - return GLFW_FALSE; -} - -GLFWglproc _glfwPlatformGetProcAddress(const char* procname) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - if (window->context.egl.client) - { - GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, - procname); - if (proc) - return proc; - } - - return eglGetProcAddress(procname); -} - - ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// @@ -676,7 +683,7 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_CONTEXT; @@ -690,7 +697,7 @@ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_SURFACE; diff --git a/src/egl_context.h b/src/egl_context.h index 0b0b4dcba..aed8a255d 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -149,8 +149,8 @@ typedef GLFWglproc (EGLAPIENTRY * PFNEGLGETPROCADDRESSPROC)(const char*); #define eglQueryString _glfw.egl.QueryString #define eglGetProcAddress _glfw.egl.GetProcAddress -#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl -#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl +#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl // EGL-specific per-context data @@ -204,7 +204,6 @@ void _glfwTerminateEGL(void); GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyContextEGL(_GLFWwindow* window); #if defined(_GLFW_X11) GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index ab57dd59d..aed7f7a91 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in @@ -45,15 +45,6 @@ // Define this to 1 if building GLFW for Mir #cmakedefine _GLFW_MIR -// Define this to 1 if building GLFW for EGL -#cmakedefine _GLFW_EGL -// Define this to 1 if building GLFW for GLX -#cmakedefine _GLFW_GLX -// Define this to 1 if building GLFW for WGL -#cmakedefine _GLFW_WGL -// Define this to 1 if building GLFW for NSGL -#cmakedefine _GLFW_NSGL - // Define this to 1 if building as a shared library / dynamic library / DLL #cmakedefine _GLFW_BUILD_DLL diff --git a/src/glx_context.c b/src/glx_context.c index 0a5b8336d..1760582b8 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -142,6 +142,96 @@ static GLXContext createLegacyContext(_GLFWwindow* window, True); } +static void makeContextCurrent(_GLFWwindow* window) +{ + if (window) + { + if (!glXMakeCurrent(_glfw.x11.display, + window->context.glx.window, + window->context.glx.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to make context current"); + return; + } + } + else + { + if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to clear current context"); + return; + } + } + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffers(_GLFWwindow* window) +{ + glXSwapBuffers(_glfw.x11.display, window->context.glx.window); +} + +static void swapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (_glfw.glx.EXT_swap_control) + { + _glfw.glx.SwapIntervalEXT(_glfw.x11.display, + window->context.glx.window, + interval); + } + else if (_glfw.glx.MESA_swap_control) + _glfw.glx.SwapIntervalMESA(interval); + else if (_glfw.glx.SGI_swap_control) + { + if (interval > 0) + _glfw.glx.SwapIntervalSGI(interval); + } +} + +static int extensionSupported(const char* extension) +{ + const char* extensions = + glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddress(const char* procname) +{ + if (_glfw.glx.GetProcAddress) + return _glfw.glx.GetProcAddress((const GLubyte*) procname); + else if (_glfw.glx.GetProcAddressARB) + return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); + else + return dlsym(_glfw.glx.handle, procname); +} + +// Destroy the OpenGL context +// +static void destroyContext(_GLFWwindow* window) +{ + if (window->context.glx.window) + { + glXDestroyWindow(_glfw.x11.display, window->context.glx.window); + window->context.glx.window = None; + } + + if (window->context.glx.handle) + { + glXDestroyContext(_glfw.x11.display, window->context.glx.handle); + window->context.glx.handle = NULL; + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -229,61 +319,61 @@ GLFWbool _glfwInitGLX(void) return GLFW_FALSE; } - if (_glfwPlatformExtensionSupported("GLX_EXT_swap_control")) + if (extensionSupported("GLX_EXT_swap_control")) { _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) - _glfwPlatformGetProcAddress("glXSwapIntervalEXT"); + getProcAddress("glXSwapIntervalEXT"); if (_glfw.glx.SwapIntervalEXT) _glfw.glx.EXT_swap_control = GLFW_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_SGI_swap_control")) + if (extensionSupported("GLX_SGI_swap_control")) { _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) - _glfwPlatformGetProcAddress("glXSwapIntervalSGI"); + getProcAddress("glXSwapIntervalSGI"); if (_glfw.glx.SwapIntervalSGI) _glfw.glx.SGI_swap_control = GLFW_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_MESA_swap_control")) + if (extensionSupported("GLX_MESA_swap_control")) { _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) - _glfwPlatformGetProcAddress("glXSwapIntervalMESA"); + getProcAddress("glXSwapIntervalMESA"); if (_glfw.glx.SwapIntervalMESA) _glfw.glx.MESA_swap_control = GLFW_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_ARB_multisample")) + if (extensionSupported("GLX_ARB_multisample")) _glfw.glx.ARB_multisample = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_ARB_framebuffer_sRGB")) + if (extensionSupported("GLX_ARB_framebuffer_sRGB")) _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_EXT_framebuffer_sRGB")) + if (extensionSupported("GLX_EXT_framebuffer_sRGB")) _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_ARB_create_context")) + if (extensionSupported("GLX_ARB_create_context")) { _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) - _glfwPlatformGetProcAddress("glXCreateContextAttribsARB"); + getProcAddress("glXCreateContextAttribsARB"); if (_glfw.glx.CreateContextAttribsARB) _glfw.glx.ARB_create_context = GLFW_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_robustness")) + if (extensionSupported("GLX_ARB_create_context_robustness")) _glfw.glx.ARB_create_context_robustness = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_profile")) + if (extensionSupported("GLX_ARB_create_context_profile")) _glfw.glx.ARB_create_context_profile = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_EXT_create_context_es2_profile")) + if (extensionSupported("GLX_EXT_create_context_es2_profile")) _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_ARB_context_flush_control")) + if (extensionSupported("GLX_ARB_context_flush_control")) _glfw.glx.ARB_context_flush_control = GLFW_TRUE; return GLFW_TRUE; @@ -330,7 +420,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, return GLFW_FALSE; } - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile || @@ -369,7 +459,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { int index = 0, mask = 0, flags = 0; - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; @@ -454,7 +544,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (!window->context.glx.handle) { if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && - ctxconfig->api == GLFW_OPENGL_API && + ctxconfig->client == GLFW_OPENGL_API && ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && ctxconfig->forward == GLFW_FALSE) { @@ -482,28 +572,18 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, return GLFW_FALSE; } + window->context.makeContextCurrent = makeContextCurrent; + window->context.swapBuffers = swapBuffers; + window->context.swapInterval = swapInterval; + window->context.extensionSupported = extensionSupported; + window->context.getProcAddress = getProcAddress; + window->context.destroyContext = destroyContext; + return GLFW_TRUE; } #undef setGLXattrib -// Destroy the OpenGL context -// -void _glfwDestroyContextGLX(_GLFWwindow* window) -{ - if (window->context.glx.window) - { - glXDestroyWindow(_glfw.x11.display, window->context.glx.window); - window->context.glx.window = None; - } - - if (window->context.glx.handle) - { - glXDestroyContext(_glfw.x11.display, window->context.glx.handle); - window->context.glx.handle = NULL; - } -} - // Returns the Visual and depth of the chosen GLXFBConfig // GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, @@ -536,84 +616,6 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, } -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) -{ - if (window) - { - if (!glXMakeCurrent(_glfw.x11.display, - window->context.glx.window, - window->context.glx.handle)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "GLX: Failed to make context current"); - return; - } - } - else - { - if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "GLX: Failed to clear current context"); - return; - } - } - - _glfwPlatformSetCurrentContext(window); -} - -void _glfwPlatformSwapBuffers(_GLFWwindow* window) -{ - glXSwapBuffers(_glfw.x11.display, window->context.glx.window); -} - -void _glfwPlatformSwapInterval(int interval) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - if (_glfw.glx.EXT_swap_control) - { - _glfw.glx.SwapIntervalEXT(_glfw.x11.display, - window->context.glx.window, - interval); - } - else if (_glfw.glx.MESA_swap_control) - _glfw.glx.SwapIntervalMESA(interval); - else if (_glfw.glx.SGI_swap_control) - { - if (interval > 0) - _glfw.glx.SwapIntervalSGI(interval); - } -} - -int _glfwPlatformExtensionSupported(const char* extension) -{ - const char* extensions = - glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - - return GLFW_FALSE; -} - -GLFWglproc _glfwPlatformGetProcAddress(const char* procname) -{ - if (_glfw.glx.GetProcAddress) - return _glfw.glx.GetProcAddress((const GLubyte*) procname); - else if (_glfw.glx.GetProcAddressARB) - return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); - else - return dlsym(_glfw.glx.handle, procname); -} - - ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// @@ -623,7 +625,7 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; @@ -637,7 +639,7 @@ GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return None; diff --git a/src/internal.h b/src/internal.h index e83047706..6c084f8d6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -58,6 +58,13 @@ typedef struct _GLFWlibrary _GLFWlibrary; typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; +typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); +typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); +typedef void (* _GLFWswapintervalfun)(int); +typedef int (* _GLFWextensionsupportedfun)(const char*); +typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*); +typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*); + #define GL_VERSION 0x1f02 #define GL_NONE 0 #define GL_COLOR_BUFFER_BIT 0x00004000 @@ -258,7 +265,8 @@ struct _GLFWwndconfig */ struct _GLFWctxconfig { - int api; + int client; + int source; int major; int minor; GLFWbool forward; @@ -304,7 +312,8 @@ struct _GLFWfbconfig */ struct _GLFWcontext { - int api; + int client; + int source; int major, minor, revision; GLFWbool forward, debug, noerror; int profile; @@ -315,8 +324,17 @@ struct _GLFWcontext PFNGLGETINTEGERVPROC GetIntegerv; PFNGLGETSTRINGPROC GetString; + _GLFWmakecontextcurrentfun makeContextCurrent; + _GLFWswapbuffersfun swapBuffers; + _GLFWswapintervalfun swapInterval; + _GLFWextensionsupportedfun extensionSupported; + _GLFWgetprocaddressfun getProcAddress; + _GLFWdestroycontextfun destroyContext; + // This is defined in the context API's context.h _GLFW_PLATFORM_CONTEXT_STATE; + // This is defined in egl_context.h + _GLFW_EGL_CONTEXT_STATE; }; @@ -461,6 +479,8 @@ struct _GLFWlibrary _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; }; @@ -742,11 +762,6 @@ void _glfwPlatformWaitEventsTimeout(double timeout); */ void _glfwPlatformPostEmptyEvent(void); -/*! @copydoc glfwMakeContextCurrent - * @ingroup platform - */ -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window); - /*! @ingroup platform */ void _glfwPlatformSetCurrentContext(_GLFWwindow* context); @@ -756,26 +771,6 @@ void _glfwPlatformSetCurrentContext(_GLFWwindow* context); */ _GLFWwindow* _glfwPlatformGetCurrentContext(void); -/*! @copydoc glfwSwapBuffers - * @ingroup platform - */ -void _glfwPlatformSwapBuffers(_GLFWwindow* window); - -/*! @copydoc glfwSwapInterval - * @ingroup platform - */ -void _glfwPlatformSwapInterval(int interval); - -/*! @copydoc glfwExtensionSupported - * @ingroup platform - */ -int _glfwPlatformExtensionSupported(const char* extension); - -/*! @copydoc glfwGetProcAddress - * @ingroup platform - */ -GLFWglproc _glfwPlatformGetProcAddress(const char* procname); - /*! @copydoc glfwCreateCursor * @ingroup platform */ diff --git a/src/mir_platform.h b/src/mir_platform.h index 5d328c208..66c6776db 100644 --- a/src/mir_platform.h +++ b/src/mir_platform.h @@ -51,12 +51,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(Vk #include "posix_time.h" #include "linux_joystick.h" #include "xkb_unicode.h" - -#if defined(_GLFW_EGL) - #include "egl_context.h" -#else - #error "The Mir backend depends on EGL platform support" -#endif +#include "egl_context.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -70,6 +65,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(Vk #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + // Mir-specific Event Queue // diff --git a/src/mir_window.c b/src/mir_window.c index 8ab4a4f68..26ee52621 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -378,7 +378,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, window->mir.window = mir_buffer_stream_get_egl_native_window( mir_surface_get_buffer_stream(window->mir.surface)); - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; @@ -395,7 +395,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) window->mir.surface = NULL; } - _glfwDestroyContextEGL(window); + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 714d5272e..1b515cb32 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -27,6 +27,63 @@ #include "internal.h" +static void makeContextCurrent(_GLFWwindow* window) +{ + if (window) + [window->context.nsgl.object makeCurrentContext]; + else + [NSOpenGLContext clearCurrentContext]; + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffers(_GLFWwindow* window) +{ + // ARP appears to be unnecessary, but this is future-proof + [window->context.nsgl.object flushBuffer]; +} + +static void swapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + GLint sync = interval; + [window->context.nsgl.object setValues:&sync + forParameter:NSOpenGLCPSwapInterval]; +} + +static int extensionSupported(const char* extension) +{ + // There are no NSGL extensions + return GLFW_FALSE; +} + +static GLFWglproc getProcAddress(const char* procname) +{ + CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, + procname, + kCFStringEncodingASCII); + + GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, + symbolName); + + CFRelease(symbolName); + + return symbol; +} + +// Destroy the OpenGL context +// +static void destroyContext(_GLFWwindow* window) +{ + [window->context.nsgl.pixelFormat release]; + window->context.nsgl.pixelFormat = nil; + + [window->context.nsgl.object release]; + window->context.nsgl.object = nil; +} + + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -61,7 +118,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, { unsigned int attributeCount = 0; - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_API_UNAVAILABLE, "NSGL: OpenGL ES is not available on OS X"); @@ -216,70 +273,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, } [window->context.nsgl.object setView:window->ns.view]; + + window->context.makeContextCurrent = makeContextCurrent; + window->context.swapBuffers = swapBuffers; + window->context.swapInterval = swapInterval; + window->context.extensionSupported = extensionSupported; + window->context.getProcAddress = getProcAddress; + window->context.destroyContext = destroyContext; + return GLFW_TRUE; } -// Destroy the OpenGL context -// -void _glfwDestroyContextNSGL(_GLFWwindow* window) -{ - [window->context.nsgl.pixelFormat release]; - window->context.nsgl.pixelFormat = nil; - - [window->context.nsgl.object release]; - window->context.nsgl.object = nil; -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) -{ - if (window) - [window->context.nsgl.object makeCurrentContext]; - else - [NSOpenGLContext clearCurrentContext]; - - _glfwPlatformSetCurrentContext(window); -} - -void _glfwPlatformSwapBuffers(_GLFWwindow* window) -{ - // ARP appears to be unnecessary, but this is future-proof - [window->context.nsgl.object flushBuffer]; -} - -void _glfwPlatformSwapInterval(int interval) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - GLint sync = interval; - [window->context.nsgl.object setValues:&sync - forParameter:NSOpenGLCPSwapInterval]; -} - -int _glfwPlatformExtensionSupported(const char* extension) -{ - // There are no NSGL extensions - return GLFW_FALSE; -} - -GLFWglproc _glfwPlatformGetProcAddress(const char* procname) -{ - CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, - procname, - kCFStringEncodingASCII); - - GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, - symbolName); - - CFRelease(symbolName); - - return symbol; -} - ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// @@ -290,7 +294,7 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(nil); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; diff --git a/src/wgl_context.c b/src/wgl_context.c index 608587c7a..55399cb1c 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -32,55 +32,6 @@ #include -// Initialize WGL-specific extensions -// -static void loadExtensions(void) -{ - // Functions for WGL_EXT_extension_string - // NOTE: These are needed by _glfwPlatformExtensionSupported - _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) - wglGetProcAddress("wglGetExtensionsStringEXT"); - _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) - wglGetProcAddress("wglGetExtensionsStringARB"); - - // Functions for WGL_ARB_create_context - _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) - wglGetProcAddress("wglCreateContextAttribsARB"); - - // Functions for WGL_EXT_swap_control - _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) - wglGetProcAddress("wglSwapIntervalEXT"); - - // Functions for WGL_ARB_pixel_format - _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) - wglGetProcAddress("wglGetPixelFormatAttribivARB"); - - // This needs to include every extension used below except for - // WGL_ARB_extensions_string and WGL_EXT_extensions_string - _glfw.wgl.ARB_multisample = - _glfwPlatformExtensionSupported("WGL_ARB_multisample"); - _glfw.wgl.ARB_framebuffer_sRGB = - _glfwPlatformExtensionSupported("WGL_ARB_framebuffer_sRGB"); - _glfw.wgl.EXT_framebuffer_sRGB = - _glfwPlatformExtensionSupported("WGL_EXT_framebuffer_sRGB"); - _glfw.wgl.ARB_create_context = - _glfwPlatformExtensionSupported("WGL_ARB_create_context"); - _glfw.wgl.ARB_create_context_profile = - _glfwPlatformExtensionSupported("WGL_ARB_create_context_profile"); - _glfw.wgl.EXT_create_context_es2_profile = - _glfwPlatformExtensionSupported("WGL_EXT_create_context_es2_profile"); - _glfw.wgl.ARB_create_context_robustness = - _glfwPlatformExtensionSupported("WGL_ARB_create_context_robustness"); - _glfw.wgl.EXT_swap_control = - _glfwPlatformExtensionSupported("WGL_EXT_swap_control"); - _glfw.wgl.ARB_pixel_format = - _glfwPlatformExtensionSupported("WGL_ARB_pixel_format"); - _glfw.wgl.ARB_context_flush_control = - _glfwPlatformExtensionSupported("WGL_ARB_context_flush_control"); - - _glfw.wgl.extensionsLoaded = GLFW_TRUE; -} - // Returns the specified attribute of the specified pixel format // static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib) @@ -280,6 +231,157 @@ static GLFWbool isCompositionEnabled(void) return enabled; } +static void makeContextCurrent(_GLFWwindow* window) +{ + if (window) + { + if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) + _glfwPlatformSetCurrentContext(window); + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to make context current"); + _glfwPlatformSetCurrentContext(NULL); + } + } + else + { + if (!wglMakeCurrent(NULL, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to clear current context"); + } + + _glfwPlatformSetCurrentContext(NULL); + } +} + +static void swapBuffers(_GLFWwindow* window) +{ + // HACK: Use DwmFlush when desktop composition is enabled + if (isCompositionEnabled() && !window->monitor) + { + int count = abs(window->context.wgl.interval); + while (count--) + _glfw_DwmFlush(); + } + + SwapBuffers(window->context.wgl.dc); +} + +static void swapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + window->context.wgl.interval = interval; + + // HACK: Disable WGL swap interval when desktop composition is enabled to + // avoid interfering with DWM vsync + if (isCompositionEnabled() && !window->monitor) + interval = 0; + + if (_glfw.wgl.EXT_swap_control) + _glfw.wgl.SwapIntervalEXT(interval); +} + +static int extensionSupported(const char* extension) +{ + const char* extensions; + + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (_glfw.wgl.GetExtensionsStringEXT) + { + extensions = _glfw.wgl.GetExtensionsStringEXT(); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + } + + if (_glfw.wgl.GetExtensionsStringARB) + { + extensions = _glfw.wgl.GetExtensionsStringARB(window->context.wgl.dc); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddress(const char* procname) +{ + const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname); + if (proc) + return proc; + + return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); +} + +// Destroy the OpenGL context +// +static void destroyContext(_GLFWwindow* window) +{ + if (window->context.wgl.handle) + { + wglDeleteContext(window->context.wgl.handle); + window->context.wgl.handle = NULL; + } +} + +// Initialize WGL-specific extensions +// +static void loadExtensions(void) +{ + // Functions for WGL_EXT_extension_string + // NOTE: These are needed by extensionSupported + _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) + wglGetProcAddress("wglGetExtensionsStringEXT"); + _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) + wglGetProcAddress("wglGetExtensionsStringARB"); + + // Functions for WGL_ARB_create_context + _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) + wglGetProcAddress("wglCreateContextAttribsARB"); + + // Functions for WGL_EXT_swap_control + _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) + wglGetProcAddress("wglSwapIntervalEXT"); + + // Functions for WGL_ARB_pixel_format + _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) + wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + // This needs to include every extension used below except for + // WGL_ARB_extensions_string and WGL_EXT_extensions_string + _glfw.wgl.ARB_multisample = + extensionSupported("WGL_ARB_multisample"); + _glfw.wgl.ARB_framebuffer_sRGB = + extensionSupported("WGL_ARB_framebuffer_sRGB"); + _glfw.wgl.EXT_framebuffer_sRGB = + extensionSupported("WGL_EXT_framebuffer_sRGB"); + _glfw.wgl.ARB_create_context = + extensionSupported("WGL_ARB_create_context"); + _glfw.wgl.ARB_create_context_profile = + extensionSupported("WGL_ARB_create_context_profile"); + _glfw.wgl.EXT_create_context_es2_profile = + extensionSupported("WGL_EXT_create_context_es2_profile"); + _glfw.wgl.ARB_create_context_robustness = + extensionSupported("WGL_ARB_create_context_robustness"); + _glfw.wgl.EXT_swap_control = + extensionSupported("WGL_EXT_swap_control"); + _glfw.wgl.ARB_pixel_format = + extensionSupported("WGL_ARB_pixel_format"); + _glfw.wgl.ARB_context_flush_control = + extensionSupported("WGL_ARB_context_flush_control"); + + _glfw.wgl.extensionsLoaded = GLFW_TRUE; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -336,7 +438,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, PIXELFORMATDESCRIPTOR pfd; HGLRC share = NULL; - if (ctxconfig->api == GLFW_NO_API) + if (ctxconfig->client == GLFW_NO_API) return GLFW_TRUE; if (ctxconfig->share) @@ -372,7 +474,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { int index = 0, mask = 0, flags = 0; - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; @@ -474,22 +576,18 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } } + window->context.makeContextCurrent = makeContextCurrent; + window->context.swapBuffers = swapBuffers; + window->context.swapInterval = swapInterval; + window->context.extensionSupported = extensionSupported; + window->context.getProcAddress = getProcAddress; + window->context.destroyContext = destroyContext; + return GLFW_TRUE; } #undef setWGLattrib -// Destroy the OpenGL context -// -void _glfwDestroyContextWGL(_GLFWwindow* window) -{ - if (window->context.wgl.handle) - { - wglDeleteContext(window->context.wgl.handle); - window->context.wgl.handle = NULL; - } -} - // Analyzes the specified context for possible recreation // int _glfwAnalyzeContextWGL(_GLFWwindow* window, @@ -501,10 +599,10 @@ int _glfwAnalyzeContextWGL(_GLFWwindow* window, if (_glfw.wgl.extensionsLoaded) return _GLFW_RECREATION_NOT_NEEDED; - _glfwPlatformMakeContextCurrent(window); + makeContextCurrent(window); loadExtensions(); - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) { @@ -587,102 +685,6 @@ int _glfwAnalyzeContextWGL(_GLFWwindow* window, } -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) -{ - if (window) - { - if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) - _glfwPlatformSetCurrentContext(window); - else - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to make context current"); - _glfwPlatformSetCurrentContext(NULL); - } - } - else - { - if (!wglMakeCurrent(NULL, NULL)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to clear current context"); - } - - _glfwPlatformSetCurrentContext(NULL); - } -} - -void _glfwPlatformSwapBuffers(_GLFWwindow* window) -{ - // HACK: Use DwmFlush when desktop composition is enabled - if (isCompositionEnabled() && !window->monitor) - { - int count = abs(window->context.wgl.interval); - while (count--) - _glfw_DwmFlush(); - } - - SwapBuffers(window->context.wgl.dc); -} - -void _glfwPlatformSwapInterval(int interval) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - window->context.wgl.interval = interval; - - // HACK: Disable WGL swap interval when desktop composition is enabled to - // avoid interfering with DWM vsync - if (isCompositionEnabled() && !window->monitor) - interval = 0; - - if (_glfw.wgl.EXT_swap_control) - _glfw.wgl.SwapIntervalEXT(interval); -} - -int _glfwPlatformExtensionSupported(const char* extension) -{ - const char* extensions; - - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - if (_glfw.wgl.GetExtensionsStringEXT) - { - extensions = _glfw.wgl.GetExtensionsStringEXT(); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - } - - if (_glfw.wgl.GetExtensionsStringARB) - { - extensions = _glfw.wgl.GetExtensionsStringARB(window->context.wgl.dc); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - } - - return GLFW_FALSE; -} - -GLFWglproc _glfwPlatformGetProcAddress(const char* procname) -{ - const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname); - if (proc) - return proc; - - return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); -} - - ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// @@ -692,7 +694,7 @@ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; diff --git a/src/wgl_context.h b/src/wgl_context.h index cca55e03a..f1e653c8d 100644 --- a/src/wgl_context.h +++ b/src/wgl_context.h @@ -148,7 +148,6 @@ void _glfwTerminateWGL(void); GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyContextWGL(_GLFWwindow* window); int _glfwAnalyzeContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); diff --git a/src/win32_init.c b/src/win32_init.c index 521f0452d..0bfe34c7c 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -421,14 +421,10 @@ int _glfwPlatformInit(void) _glfwPlatformPollEvents(); -#if defined(_GLFW_WGL) if (!_glfwInitWGL()) return GLFW_FALSE; -#elif defined(_GLFW_EGL) - if (!_glfwInitEGL()) - return GLFW_FALSE; -#endif + _glfwInitEGL(); _glfwInitTimerWin32(); _glfwInitJoysticksWin32(); @@ -449,11 +445,8 @@ void _glfwPlatformTerminate(void) free(_glfw.win32.clipboardString); -#if defined(_GLFW_WGL) _glfwTerminateWGL(); -#elif defined(_GLFW_EGL) _glfwTerminateEGL(); -#endif _glfwTerminateJoysticksWin32(); _glfwTerminateThreadLocalStorageWin32(); @@ -463,12 +456,7 @@ void _glfwPlatformTerminate(void) const char* _glfwPlatformGetVersionString(void) { - return _GLFW_VERSION_NUMBER " Win32" -#if defined(_GLFW_WGL) - " WGL" -#elif defined(_GLFW_EGL) - " EGL" -#endif + return _GLFW_VERSION_NUMBER " Win32 WGL EGL" #if defined(__MINGW32__) " MinGW" #elif defined(_MSC_VER) diff --git a/src/win32_platform.h b/src/win32_platform.h index d44ca3b9c..f3570bcc2 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -205,16 +205,8 @@ typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin3 typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t); #include "win32_joystick.h" - -#if defined(_GLFW_WGL) - #include "wgl_context.h" -#elif defined(_GLFW_EGL) - #define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle) - #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY - #include "egl_context.h" -#else - #error "No supported context creation API selected" -#endif +#include "wgl_context.h" +#include "egl_context.h" #define _GLFW_WNDCLASSNAME L"GLFW30" @@ -222,6 +214,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)( #define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) #define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle) +#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY + #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 #define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time diff --git a/src/win32_window.c b/src/win32_window.c index 944bff66c..b5c03ea3f 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -940,55 +940,58 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!createWindow(window, wndconfig)) return GLFW_FALSE; - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { -#if defined(_GLFW_WGL) - if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; - - status = _glfwAnalyzeContextWGL(window, ctxconfig, fbconfig); - - if (status == _GLFW_RECREATION_IMPOSSIBLE) - return GLFW_FALSE; - - if (status == _GLFW_RECREATION_REQUIRED) + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) { - // Some window hints require us to re-create the context using WGL - // extensions retrieved through the current context, as we cannot - // check for WGL extensions or retrieve WGL entry points before we - // have a current context (actually until we have implicitly loaded - // the vendor ICD) - - // Yes, this is strange, and yes, this is the proper way on WGL - - // As Windows only allows you to set the pixel format once for - // a window, we need to destroy the current window and create a new - // one to be able to use the new pixel format - - // Technically, it may be possible to keep the old window around if - // we're just creating an OpenGL 3.0+ context with the same pixel - // format, but it's not worth the added code complexity - - // First we clear the current context (the one we just created) - // This is usually done by glfwDestroyWindow, but as we're not doing - // full GLFW window destruction, it's duplicated here - _glfwPlatformMakeContextCurrent(NULL); - - // Next destroy the Win32 window and WGL context (without resetting - // or destroying the GLFW window object) - _glfwDestroyContextWGL(window); - destroyWindow(window); - - // ...and then create them again, this time with better APIs - if (!createWindow(window, wndconfig)) - return GLFW_FALSE; if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; + + status = _glfwAnalyzeContextWGL(window, ctxconfig, fbconfig); + + if (status == _GLFW_RECREATION_IMPOSSIBLE) + return GLFW_FALSE; + + if (status == _GLFW_RECREATION_REQUIRED) + { + // Some window hints require us to re-create the context using WGL + // extensions retrieved through the current context, as we cannot + // check for WGL extensions or retrieve WGL entry points before we + // have a current context (actually until we have implicitly loaded + // the vendor ICD) + + // Yes, this is strange, and yes, this is the proper way on WGL + + // As Windows only allows you to set the pixel format once for + // a window, we need to destroy the current window and create a new + // one to be able to use the new pixel format + + // Technically, it may be possible to keep the old window around if + // we're just creating an OpenGL 3.0+ context with the same pixel + // format, but it's not worth the added code complexity + + // First we clear the current context (the one we just created) + // This is usually done by glfwDestroyWindow, but as we're not doing + // full GLFW window destruction, it's duplicated here + window->context.makeContextCurrent(NULL); + + // Next destroy the Win32 window and WGL context (without resetting + // or destroying the GLFW window object) + window->context.destroyContext(window); + destroyWindow(window); + + // ...and then create them again, this time with better APIs + if (!createWindow(window, wndconfig)) + return GLFW_FALSE; + if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + else + { + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; } -#elif defined(_GLFW_EGL) - if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; -#endif } if (window->monitor) @@ -1007,14 +1010,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->monitor) releaseMonitor(window); - if (window->context.api != GLFW_NO_API) - { -#if defined(_GLFW_WGL) - _glfwDestroyContextWGL(window); -#elif defined(_GLFW_EGL) - _glfwDestroyContextEGL(window); -#endif - } + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); destroyWindow(window); diff --git a/src/window.c b/src/window.c index fee08b257..89b0189a3 100644 --- a/src/window.c +++ b/src/window.c @@ -155,7 +155,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, if (ctxconfig.share) { - if (ctxconfig.share->context.api == GLFW_NO_API) + if (ctxconfig.share->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; @@ -192,29 +192,31 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, // Save the currently current context so it can be restored later previous = _glfwPlatformGetCurrentContext(); + if (ctxconfig.client != GLFW_NO_API) + glfwMakeContextCurrent(NULL); // Open the actual window and create its context if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { + glfwMakeContextCurrent((GLFWwindow*) previous); glfwDestroyWindow((GLFWwindow*) window); - _glfwPlatformMakeContextCurrent(previous); return NULL; } - if (ctxconfig.api != GLFW_NO_API) + if (ctxconfig.client != GLFW_NO_API) { - _glfwPlatformMakeContextCurrent(window); + window->context.makeContextCurrent(window); // Retrieve the actual (as opposed to requested) context attributes if (!_glfwRefreshContextAttribs(&ctxconfig)) { + glfwMakeContextCurrent((GLFWwindow*) previous); glfwDestroyWindow((GLFWwindow*) window); - _glfwPlatformMakeContextCurrent(previous); return NULL; } // Restore the previously current context (or NULL) - _glfwPlatformMakeContextCurrent(previous); + glfwMakeContextCurrent((GLFWwindow*) previous); } if (window->monitor) @@ -247,9 +249,10 @@ void glfwDefaultWindowHints(void) memset(&_glfw.hints, 0, sizeof(_glfw.hints)); // The default is OpenGL with minimum version 1.0 - _glfw.hints.context.api = GLFW_OPENGL_API; - _glfw.hints.context.major = 1; - _glfw.hints.context.minor = 0; + _glfw.hints.context.client = GLFW_OPENGL_API; + _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API; + _glfw.hints.context.major = 1; + _glfw.hints.context.minor = 0; // The default is a focused, visible, resizable window with decorations _glfw.hints.window.resizable = GLFW_TRUE; @@ -345,7 +348,10 @@ GLFWAPI void glfwWindowHint(int hint, int value) _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; break; case GLFW_CLIENT_API: - _glfw.hints.context.api = value; + _glfw.hints.context.client = value; + break; + case GLFW_CONTEXT_CREATION_API: + _glfw.hints.context.source = value; break; case GLFW_CONTEXT_VERSION_MAJOR: _glfw.hints.context.major = value; @@ -396,7 +402,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()) - _glfwPlatformMakeContextCurrent(NULL); + glfwMakeContextCurrent(NULL); // Clear the focused window pointer if this is the focused window if (_glfw.cursorWindow == window) @@ -683,7 +689,9 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) case GLFW_FLOATING: return window->floating; case GLFW_CLIENT_API: - return window->context.api; + return window->context.client; + case GLFW_CONTEXT_CREATION_API: + return window->context.source; case GLFW_CONTEXT_VERSION_MAJOR: return window->context.major; case GLFW_CONTEXT_VERSION_MINOR: diff --git a/src/wl_platform.h b/src/wl_platform.h index d75c025e5..221108ed0 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -49,12 +49,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "posix_time.h" #include "linux_joystick.h" #include "xkb_unicode.h" - -#if defined(_GLFW_EGL) - #include "egl_context.h" -#else - #error "The Wayland backend depends on EGL platform support" -#endif +#include "egl_context.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" @@ -71,6 +66,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + // Wayland-specific video mode data // diff --git a/src/wl_window.c b/src/wl_window.c index 194c0ecab..5ff999093 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -373,7 +373,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!createSurface(window, wndconfig)) return GLFW_FALSE; - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; @@ -417,7 +417,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) _glfwInputWindowFocus(window, GLFW_FALSE); } - _glfwDestroyContextEGL(window); + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); if (window->wl.native) wl_egl_window_destroy(window->wl.native); diff --git a/src/x11_init.c b/src/x11_init.c index b81afcc7c..112e4547d 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -766,17 +766,13 @@ int _glfwPlatformInit(void) if (!_glfwInitThreadLocalStoragePOSIX()) return GLFW_FALSE; -#if defined(_GLFW_GLX) if (!_glfwInitGLX()) return GLFW_FALSE; -#elif defined(_GLFW_EGL) - if (!_glfwInitEGL()) - return GLFW_FALSE; -#endif if (!_glfwInitJoysticksLinux()) return GLFW_FALSE; + _glfwInitEGL(); _glfwInitTimerPOSIX(); return GLFW_TRUE; @@ -804,9 +800,7 @@ void _glfwPlatformTerminate(void) _glfw.x11.im = NULL; } -#if defined(_GLFW_EGL) _glfwTerminateEGL(); -#endif if (_glfw.x11.display) { @@ -816,9 +810,7 @@ void _glfwPlatformTerminate(void) // NOTE: This needs to be done after XCloseDisplay, as libGL registers // cleanup callbacks that get called by it -#if defined(_GLFW_GLX) _glfwTerminateGLX(); -#endif _glfwTerminateJoysticksLinux(); _glfwTerminateThreadLocalStoragePOSIX(); @@ -826,12 +818,7 @@ void _glfwPlatformTerminate(void) const char* _glfwPlatformGetVersionString(void) { - return _GLFW_VERSION_NUMBER " X11" -#if defined(_GLFW_GLX) - " GLX" -#elif defined(_GLFW_EGL) - " EGL" -#endif + return _GLFW_VERSION_NUMBER " X11 GLX EGL" #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) " clock_gettime" #else diff --git a/src/x11_platform.h b/src/x11_platform.h index a12374aac..9c76d1898 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -87,21 +87,16 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk #include "posix_time.h" #include "linux_joystick.h" #include "xkb_unicode.h" - -#if defined(_GLFW_GLX) - #include "glx_context.h" -#elif defined(_GLFW_EGL) - #define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle) - #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) - #include "egl_context.h" -#else - #error "No supported context creation API selected" -#endif +#include "glx_context.h" +#include "egl_context.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle) +#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_MONITOR_STATE _GLFWmonitorX11 x11 diff --git a/src/x11_window.c b/src/x11_window.c index 7cf26ce30..19b9d2469 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1478,34 +1478,40 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, Visual* visual; int depth; - if (ctxconfig->api == GLFW_NO_API) + if (ctxconfig->client == GLFW_NO_API) { visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); } else { -#if defined(_GLFW_GLX) - if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth)) - return GLFW_FALSE; -#elif defined(_GLFW_EGL) - if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) - return GLFW_FALSE; -#endif + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } + else + { + if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } } if (!createWindow(window, wndconfig, visual, depth)) return GLFW_FALSE; - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { -#if defined(_GLFW_GLX) - if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig)) - return GLFW_FALSE; -#elif defined(_GLFW_EGL) - if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; -#endif + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } } if (window->monitor) @@ -1530,14 +1536,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) window->x11.ic = NULL; } - if (window->context.api != GLFW_NO_API) - { -#if defined(_GLFW_GLX) - _glfwDestroyContextGLX(window); -#elif defined(_GLFW_EGL) - _glfwDestroyContextEGL(window); -#endif - } + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); if (window->x11.handle) { diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index 01d8ac0cb..e85b38585 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -41,6 +41,9 @@ #define API_NAME_OPENGL "gl" #define API_NAME_OPENGL_ES "es" +#define API_NAME_NATIVE "native" +#define API_NAME_EGL "egl" + #define PROFILE_NAME_CORE "core" #define PROFILE_NAME_COMPAT "compat" @@ -60,6 +63,9 @@ static void usage(void) printf(" -b, --behavior=BEHAVIOR the release behavior to use (" BEHAVIOR_NAME_NONE " or " BEHAVIOR_NAME_FLUSH ")\n"); + printf(" -c, --context-api=API the context creation API to use (" + API_NAME_NATIVE " or " + API_NAME_EGL ")\n"); printf(" -d, --debug request a debug context\n"); printf(" -f, --forward require a forward-compatible context\n"); printf(" -h, --help show this help\n"); @@ -165,15 +171,15 @@ static const char* get_strategy_name_glfw(int strategy) return "unknown"; } -static void list_context_extensions(int api, int major, int minor) +static void list_context_extensions(int client, int major, int minor) { int i; GLint count; const GLubyte* extensions; - printf("%s context extensions:\n", get_api_name(api)); + printf("%s context extensions:\n", get_api_name(client)); - if (api == GLFW_OPENGL_API && major > 2) + if (client == GLFW_OPENGL_API && major > 2) { glGetIntegerv(GL_NUM_EXTENSIONS, &count); @@ -351,13 +357,13 @@ static void print_version(void) int main(int argc, char** argv) { - int ch, api, major, minor, revision, profile; + int ch, client, context, major, minor, revision, profile; GLint redbits, greenbits, bluebits, alphabits, depthbits, stencilbits; int list_extensions = GLFW_FALSE, list_layers = GLFW_FALSE; GLenum error; GLFWwindow* window; - enum { API, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS, LAYERS, + enum { CLIENT, CONTEXT, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS, LAYERS, MAJOR, MINOR, PROFILE, ROBUSTNESS, VERSION, REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS, ACCUMREDBITS, ACCUMGREENBITS, ACCUMBLUEBITS, ACCUMALPHABITS, @@ -365,7 +371,8 @@ int main(int argc, char** argv) const struct option options[] = { { "behavior", 1, NULL, BEHAVIOR }, - { "client-api", 1, NULL, API }, + { "client-api", 1, NULL, CLIENT }, + { "context-api", 1, NULL, CONTEXT }, { "debug", 0, NULL, DEBUG }, { "forward", 0, NULL, FORWARD }, { "help", 0, NULL, HELP }, @@ -410,7 +417,7 @@ int main(int argc, char** argv) switch (ch) { case 'a': - case API: + case CLIENT: if (strcasecmp(optarg, API_NAME_OPENGL) == 0) glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); else if (strcasecmp(optarg, API_NAME_OPENGL_ES) == 0) @@ -439,6 +446,18 @@ int main(int argc, char** argv) exit(EXIT_FAILURE); } break; + case 'c': + case CONTEXT: + if (strcasecmp(optarg, API_NAME_NATIVE) == 0) + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); + else if (strcasecmp(optarg, API_NAME_EGL) == 0) + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); + else + { + usage(); + exit(EXIT_FAILURE); + } + break; case 'd': case DEBUG: glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); @@ -616,30 +635,31 @@ int main(int argc, char** argv) // Report client API version - api = glfwGetWindowAttrib(window, GLFW_CLIENT_API); + client = glfwGetWindowAttrib(window, GLFW_CLIENT_API); + context = glfwGetWindowAttrib(window, GLFW_CONTEXT_CREATION_API); major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); revision = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION); profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE); printf("%s context version string: \"%s\"\n", - get_api_name(api), + get_api_name(client), glGetString(GL_VERSION)); printf("%s context version parsed by GLFW: %u.%u.%u\n", - get_api_name(api), + get_api_name(client), major, minor, revision); // Report client API context properties - if (api == GLFW_OPENGL_API) + if (client == GLFW_OPENGL_API) { if (major >= 3) { GLint flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags); - printf("%s context flags (0x%08x):", get_api_name(api), flags); + printf("%s context flags (0x%08x):", get_api_name(client), flags); if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) printf(" forward-compatible"); @@ -651,7 +671,7 @@ int main(int argc, char** argv) printf(" no-error"); putchar('\n'); - printf("%s context flags parsed by GLFW:", get_api_name(api)); + printf("%s context flags parsed by GLFW:", get_api_name(client)); if (glfwGetWindowAttrib(window, GLFW_OPENGL_FORWARD_COMPAT)) printf(" forward-compatible"); @@ -670,12 +690,12 @@ int main(int argc, char** argv) glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); printf("%s profile mask (0x%08x): %s\n", - get_api_name(api), + get_api_name(client), mask, get_profile_name_gl(mask)); printf("%s profile mask parsed by GLFW: %s\n", - get_api_name(api), + get_api_name(client), get_profile_name_glfw(profile)); } @@ -686,33 +706,33 @@ int main(int argc, char** argv) glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); printf("%s robustness strategy (0x%08x): %s\n", - get_api_name(api), + get_api_name(client), strategy, get_strategy_name_gl(strategy)); printf("%s robustness strategy parsed by GLFW: %s\n", - get_api_name(api), + get_api_name(client), get_strategy_name_glfw(robustness)); } } printf("%s context renderer string: \"%s\"\n", - get_api_name(api), + get_api_name(client), glGetString(GL_RENDERER)); printf("%s context vendor string: \"%s\"\n", - get_api_name(api), + get_api_name(client), glGetString(GL_VENDOR)); if (major >= 2) { printf("%s context shading language version: \"%s\"\n", - get_api_name(api), + get_api_name(client), glGetString(GL_SHADING_LANGUAGE_VERSION)); } - printf("%s framebuffer:\n", get_api_name(api)); + printf("%s framebuffer:\n", get_api_name(client)); - if (api == GLFW_OPENGL_API && profile == GLFW_OPENGL_CORE_PROFILE) + if (client == GLFW_OPENGL_API && profile == GLFW_OPENGL_CORE_PROFILE) { glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_BACK_LEFT, @@ -752,7 +772,7 @@ int main(int argc, char** argv) printf(" red: %u green: %u blue: %u alpha: %u depth: %u stencil: %u\n", redbits, greenbits, bluebits, alphabits, depthbits, stencilbits); - if (api == GLFW_OPENGL_ES_API || + if (client == GLFW_OPENGL_ES_API || glfwExtensionSupported("GL_ARB_multisample") || major > 1 || minor >= 3) { @@ -763,7 +783,7 @@ int main(int argc, char** argv) printf(" samples: %u sample buffers: %u\n", samples, samplebuffers); } - if (api == GLFW_OPENGL_API && profile != GLFW_OPENGL_CORE_PROFILE) + if (client == GLFW_OPENGL_API && profile != GLFW_OPENGL_CORE_PROFILE) { GLint accumredbits, accumgreenbits, accumbluebits, accumalphabits; GLint auxbuffers; @@ -779,7 +799,7 @@ int main(int argc, char** argv) } if (list_extensions) - list_context_extensions(api, major, minor); + list_context_extensions(client, major, minor); printf("Vulkan loader: %s\n", glfwVulkanSupported() ? "available" : "missing"); From a5021520755d24008e55cb7647a3569934853bff Mon Sep 17 00:00:00 2001 From: linkmauve Date: Thu, 5 May 2016 13:15:44 +0100 Subject: [PATCH 155/156] wayland: Always make the window surface opaque --- src/wl_window.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/wl_window.c b/src/wl_window.c index 5ff999093..58a721fd9 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -174,6 +174,21 @@ static const struct wl_surface_listener surfaceListener = { handleLeave }; +// Makes the surface considered as XRGB instead of ARGB. +static void setOpaqueRegion(_GLFWwindow* window) +{ + struct wl_region* region; + + region = wl_compositor_create_region(_glfw.wl.compositor); + if (!region) + return; + + wl_region_add(region, 0, 0, window->wl.width, window->wl.height); + wl_surface_set_opaque_region(window->wl.surface, region); + wl_surface_commit(window->wl.surface); + wl_region_destroy(region); +} + static GLFWbool createSurface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { @@ -197,6 +212,9 @@ 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); + return GLFW_TRUE; } @@ -481,6 +499,7 @@ 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); _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); } From 4eb7cbac47c7d40e2c1469016b54f9323aa36d8f Mon Sep 17 00:00:00 2001 From: Brandon Schaefer Date: Thu, 5 May 2016 05:22:57 -0700 Subject: [PATCH 156/156] Mir: Remove workaround for LP bug 1477285 Closes #756. --- src/mir_window.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/mir_window.c b/src/mir_window.c index 26ee52621..ddc70fa63 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -709,11 +709,6 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf)); if (cursor->mir.custom_cursor) { - /* FIXME Bug https://bugs.launchpad.net/mir/+bug/1477285 - Requires a triple buffer swap to get the cursor buffer on top! (since mir is tripled buffered) - */ - mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor); - mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor); mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor); } }