From 2298e66fa00f4b79dcebc94da5044f2404cbfe7e Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Sun, 16 Feb 2020 14:00:41 -0500 Subject: [PATCH 1/2] v3.3/glfw: delete unneeded files in glfw directory This change follows the steps documented in the "Updating GLFW C source" section at https://github.com/go-gl/glfw/wiki/Development#updating-glfw-c-source and removes some unneeded files. Two addition files were deemed unneeded and added to the instructions in https://github.com/go-gl/glfw/wiki/Development/_compare/a6202c21a91fc5a6e1c1d66056ddbbf98badd0c1...b5cfb810447f9236bca5c575ec6deb15de972039. They were .gitattributes and .mailmap. This is in preparation of updating to GLFW 3.3.2. --- v3.3/glfw/glfw/src/CMakeLists.txt | 184 ------------------------ v3.3/glfw/glfw/src/glfw3.pc.in | 13 -- v3.3/glfw/glfw/src/glfw3Config.cmake.in | 1 - v3.3/glfw/glfw/src/glfw_config.h.in | 60 -------- v3.3/glfw/glfw/src/mappings.h.in | 73 ---------- 5 files changed, 331 deletions(-) delete mode 100644 v3.3/glfw/glfw/src/CMakeLists.txt delete mode 100644 v3.3/glfw/glfw/src/glfw3.pc.in delete mode 100644 v3.3/glfw/glfw/src/glfw3Config.cmake.in delete mode 100644 v3.3/glfw/glfw/src/glfw_config.h.in delete mode 100644 v3.3/glfw/glfw/src/mappings.h.in diff --git a/v3.3/glfw/glfw/src/CMakeLists.txt b/v3.3/glfw/glfw/src/CMakeLists.txt deleted file mode 100644 index 6cbeed6d..00000000 --- a/v3.3/glfw/glfw/src/CMakeLists.txt +++ /dev/null @@ -1,184 +0,0 @@ - -set(common_HEADERS internal.h mappings.h - "${GLFW_BINARY_DIR}/src/glfw_config.h" - "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" - "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") -set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c) - -if (_GLFW_COCOA) - set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h - posix_thread.h nsgl_context.h egl_context.h osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m - cocoa_monitor.m cocoa_window.m cocoa_time.c posix_thread.c - nsgl_context.m egl_context.c osmesa_context.c) -elseif (_GLFW_WIN32) - set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h - wgl_context.h egl_context.h osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c - win32_monitor.c win32_time.c win32_thread.c win32_window.c - wgl_context.c egl_context.c osmesa_context.c) -elseif (_GLFW_X11) - set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h posix_time.h - posix_thread.h glx_context.h egl_context.h osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c - xkb_unicode.c posix_time.c posix_thread.c glx_context.c - egl_context.c osmesa_context.c) -elseif (_GLFW_WAYLAND) - set(glfw_HEADERS ${common_HEADERS} wl_platform.h - posix_time.h posix_thread.h xkb_unicode.h egl_context.h - osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c - posix_time.c posix_thread.c xkb_unicode.c - egl_context.c osmesa_context.c) - - ecm_add_wayland_client_protocol(glfw_SOURCES - PROTOCOL - "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml" - BASENAME xdg-shell) - ecm_add_wayland_client_protocol(glfw_SOURCES - PROTOCOL - "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" - BASENAME xdg-decoration) - ecm_add_wayland_client_protocol(glfw_SOURCES - PROTOCOL - "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml" - BASENAME viewporter) - 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) - ecm_add_wayland_client_protocol(glfw_SOURCES - PROTOCOL - "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" - BASENAME idle-inhibit-unstable-v1) -elseif (_GLFW_OSMESA) - set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h - posix_time.h posix_thread.h osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} null_init.c null_monitor.c null_window.c - null_joystick.c posix_time.c posix_thread.c osmesa_context.c) -endif() - -if (_GLFW_X11 OR _GLFW_WAYLAND) - if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - set(glfw_HEADERS ${glfw_HEADERS} linux_joystick.h) - set(glfw_SOURCES ${glfw_SOURCES} linux_joystick.c) - else() - set(glfw_HEADERS ${glfw_HEADERS} null_joystick.h) - set(glfw_SOURCES ${glfw_SOURCES} null_joystick.c) - endif() -endif() - -if (APPLE) - # For some reason, CMake doesn't know about .m - set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) -endif() - -# Make GCC and Clang warn about declarations that VS 2010 and 2012 won't accept -# for all source files that VS will build -if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR - "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR - "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") - - if (WIN32) - set(windows_SOURCES ${glfw_SOURCES}) - else() - set(windows_SOURCES ${common_SOURCES}) - endif() - set_source_files_properties(${windows_SOURCES} PROPERTIES - COMPILE_FLAGS -Wdeclaration-after-statement) -endif() - -add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) -set_target_properties(glfw PROPERTIES - OUTPUT_NAME ${GLFW_LIB_NAME} - VERSION ${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR} - SOVERSION ${GLFW_VERSION_MAJOR} - POSITION_INDEPENDENT_CODE ON - FOLDER "GLFW3") - -if (${CMAKE_VERSION} VERSION_EQUAL "3.1.0" OR - ${CMAKE_VERSION} VERSION_GREATER "3.1.0") - - set_target_properties(glfw PROPERTIES C_STANDARD 99) -else() - # Remove this fallback when removing support for CMake version less than 3.1 - target_compile_options(glfw PRIVATE - "$<$:-std=c99>" - "$<$:-std=c99>" - "$<$:-std=c99>") -endif() - -target_compile_definitions(glfw PRIVATE _GLFW_USE_CONFIG_H) -target_include_directories(glfw PUBLIC - "$" - "$") -target_include_directories(glfw PRIVATE - "${GLFW_SOURCE_DIR}/src" - "${GLFW_BINARY_DIR}/src" - ${glfw_INCLUDE_DIRS}) - -# HACK: When building on MinGW, WINVER and UNICODE need to be defined before -# the inclusion of stddef.h (by glfw3.h), which is itself included before -# win32_platform.h. We define them here until a saner solution can be found -# NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. -target_compile_definitions(glfw PRIVATE - "$<$:UNICODE;WINVER=0x0501>") - -# Enable a reasonable set of warnings (no, -Wextra is not reasonable) -target_compile_options(glfw PRIVATE - "$<$:-Wall>" - "$<$:-Wall>" - "$<$:-Wall>") - -if (BUILD_SHARED_LIBS) - if (WIN32) - if (MINGW) - # Remove the dependency on the shared version of libgcc - # NOTE: MinGW-w64 has the correct default but MinGW needs this - target_link_options(glfw PRIVATE "-static-libgcc") - - # Remove the lib prefix on the DLL (but not the import library) - set_target_properties(glfw PROPERTIES PREFIX "") - - # Add a suffix to the import library to avoid naming conflicts - set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.a") - else() - # Add a suffix to the import library to avoid naming conflicts - set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") - endif() - - target_compile_definitions(glfw INTERFACE GLFW_DLL) - elseif (APPLE) - # Add -fno-common to work around a bug in Apple's GCC - target_compile_options(glfw PRIVATE "-fno-common") - - set_target_properties(glfw PROPERTIES - INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}") - endif() - - if (UNIX) - # Hide symbols not explicitly tagged for export from the shared library - target_compile_options(glfw PRIVATE "-fvisibility=hidden") - endif() - - target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES}) -else() - target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES}) -endif() - -if (MSVC) - target_compile_definitions(glfw PRIVATE _CRT_SECURE_NO_WARNINGS) -endif() - -if (GLFW_INSTALL) - install(TARGETS glfw - EXPORT glfwTargets - RUNTIME DESTINATION "bin" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") -endif() - diff --git a/v3.3/glfw/glfw/src/glfw3.pc.in b/v3.3/glfw/glfw/src/glfw3.pc.in deleted file mode 100644 index f74298d4..00000000 --- a/v3.3/glfw/glfw/src/glfw3.pc.in +++ /dev/null @@ -1,13 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ -libdir=@CMAKE_INSTALL_FULL_LIBDIR@ - -Name: GLFW -Description: A multi-platform library for OpenGL, window and input -Version: @GLFW_VERSION@ -URL: https://www.glfw.org/ -Requires.private: @GLFW_PKG_DEPS@ -Libs: -L${libdir} -l@GLFW_LIB_NAME@ -Libs.private: @GLFW_PKG_LIBS@ -Cflags: -I${includedir} diff --git a/v3.3/glfw/glfw/src/glfw3Config.cmake.in b/v3.3/glfw/glfw/src/glfw3Config.cmake.in deleted file mode 100644 index 1fa200e2..00000000 --- a/v3.3/glfw/glfw/src/glfw3Config.cmake.in +++ /dev/null @@ -1 +0,0 @@ -include("${CMAKE_CURRENT_LIST_DIR}/glfw3Targets.cmake") diff --git a/v3.3/glfw/glfw/src/glfw_config.h.in b/v3.3/glfw/glfw/src/glfw_config.h.in deleted file mode 100644 index f418c995..00000000 --- a/v3.3/glfw/glfw/src/glfw_config.h.in +++ /dev/null @@ -1,60 +0,0 @@ -//======================================================================== -// GLFW 3.3 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2010-2016 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== -// As glfw_config.h.in, this file is used by CMake to produce the -// glfw_config.h configuration header file. If you are adding a feature -// requiring conditional compilation, this is where to add the macro. -//======================================================================== -// As glfw_config.h, this file defines compile-time option macros for a -// specific platform and development environment. If you are using the -// GLFW CMake files, modify glfw_config.h.in instead of this file. If you -// are using your own build system, make this file define the appropriate -// macros in whatever way is suitable. -//======================================================================== - -// Define this to 1 if building GLFW for X11 -#cmakedefine _GLFW_X11 -// Define this to 1 if building GLFW for Win32 -#cmakedefine _GLFW_WIN32 -// Define this to 1 if building GLFW for Cocoa -#cmakedefine _GLFW_COCOA -// Define this to 1 if building GLFW for Wayland -#cmakedefine _GLFW_WAYLAND -// Define this to 1 if building GLFW for OSMesa -#cmakedefine _GLFW_OSMESA - -// Define this to 1 if building as a shared library / dynamic library / DLL -#cmakedefine _GLFW_BUILD_DLL -// Define this to 1 to use Vulkan loader linked statically into application -#cmakedefine _GLFW_VULKAN_STATIC - -// Define this to 1 to force use of high-performance GPU on hybrid systems -#cmakedefine _GLFW_USE_HYBRID_HPG - -// Define this to 1 if xkbcommon supports the compose key -#cmakedefine HAVE_XKBCOMMON_COMPOSE_H -// Define this to 1 if the libc supports memfd_create() -#cmakedefine HAVE_MEMFD_CREATE - diff --git a/v3.3/glfw/glfw/src/mappings.h.in b/v3.3/glfw/glfw/src/mappings.h.in deleted file mode 100644 index 72460b0d..00000000 --- a/v3.3/glfw/glfw/src/mappings.h.in +++ /dev/null @@ -1,73 +0,0 @@ -//======================================================================== -// GLFW 3.3 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2006-2018 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== -// As mappings.h.in, this file is used by CMake to produce the mappings.h -// header file. If you are adding a GLFW specific gamepad mapping, this is -// where to put it. -//======================================================================== -// As mappings.h, this provides all pre-defined gamepad mappings, including -// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad -// mappings not specific to GLFW should be submitted to SDL_GameControllerDB. -// This file can be re-generated from mappings.h.in and the upstream -// gamecontrollerdb.txt with the GenerateMappings.cmake script. -//======================================================================== - -// All gamepad mappings not labeled GLFW are copied from the -// SDL_GameControllerDB project under the following license: -// -// Simple DirectMedia Layer -// Copyright (C) 1997-2013 Sam Lantinga -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the -// use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. - -const char* _glfwDefaultMappings[] = -{ -@GLFW_GAMEPAD_MAPPINGS@ -"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", -NULL -}; - From 76ac4531e99b9a11a284b24dbf17b2ad69e34092 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Sun, 16 Feb 2020 14:17:55 -0500 Subject: [PATCH 2/2] v3.3/glfw: update to GLFW 3.3.2 GLFW 3.3.2 was released on January 20, 2020. See https://github.com/glfw/glfw/releases/tag/3.3.2. Done using steps from https://github.com/go-gl/glfw/wiki/Development#updating-glfw-c-source: rm -rf ./glfw/ git clone --depth 1 --branch latest https://github.com/glfw/glfw # 'latest' branch points to latest stable release. cd ./glfw/ git rev-parse HEAD > ../GLFW_C_REVISION.txt # Only keep the needed sources files in ./src, ./include and ./deps. rm -rf ./.git rm -rf ./.gitignore rm -rf ./.gitattributes rm -rf ./.mailmap rm -rf ./.appveyor.yml rm -rf ./.github rm -rf ./.travis.yml rm -rf ./CMake rm -rf ./CMakeLists.txt rm -rf ./src/CMakeLists.txt rm -rf ./src/*.in rm -rf ./README.md rm -rf ./cmake_uninstall.cmake.in rm -rf ./docs rm -rf ./examples rm -rf ./tests Fixes #262. --- v3.3/glfw/GLFW_C_REVISION.txt | 2 +- v3.3/glfw/glfw/include/GLFW/glfw3.h | 7 +- v3.3/glfw/glfw/src/cocoa_init.m | 35 +++- v3.3/glfw/glfw/src/cocoa_joystick.m | 2 +- v3.3/glfw/glfw/src/cocoa_monitor.m | 96 ++++++++--- v3.3/glfw/glfw/src/cocoa_platform.h | 15 +- v3.3/glfw/glfw/src/cocoa_window.m | 109 +++++++++---- v3.3/glfw/glfw/src/egl_context.c | 29 ++-- v3.3/glfw/glfw/src/internal.h | 2 + v3.3/glfw/glfw/src/nsgl_context.h | 5 - v3.3/glfw/glfw/src/nsgl_context.m | 100 ++++-------- v3.3/glfw/glfw/src/vulkan.c | 4 + v3.3/glfw/glfw/src/win32_monitor.c | 1 + v3.3/glfw/glfw/src/win32_window.c | 179 ++++++++++----------- v3.3/glfw/glfw/src/wl_init.c | 32 ++-- v3.3/glfw/glfw/src/wl_platform.h | 1 + v3.3/glfw/glfw/src/wl_window.c | 2 +- v3.3/glfw/glfw/src/x11_monitor.c | 24 ++- v3.3/glfw/glfw/src/x11_platform.h | 1 + v3.3/glfw/glfw/src/x11_window.c | 238 +++++++++++++++++++--------- 20 files changed, 532 insertions(+), 352 deletions(-) diff --git a/v3.3/glfw/GLFW_C_REVISION.txt b/v3.3/glfw/GLFW_C_REVISION.txt index 79d2fc38..6a8efe19 100644 --- a/v3.3/glfw/GLFW_C_REVISION.txt +++ b/v3.3/glfw/GLFW_C_REVISION.txt @@ -1 +1 @@ -2bac7ee8da526257d808bd026b027246c98e4f2f +0a49ef0a00baa3ab520ddc452f0e3b1e099c5589 diff --git a/v3.3/glfw/glfw/include/GLFW/glfw3.h b/v3.3/glfw/glfw/include/GLFW/glfw3.h index 671ba725..66dff649 100644 --- a/v3.3/glfw/glfw/include/GLFW/glfw3.h +++ b/v3.3/glfw/glfw/include/GLFW/glfw3.h @@ -270,7 +270,7 @@ extern "C" { * API changes. * @ingroup init */ -#define GLFW_VERSION_REVISION 1 +#define GLFW_VERSION_REVISION 2 /*! @} */ /*! @brief One. @@ -5677,8 +5677,9 @@ GLFWAPI int glfwVulkanSupported(void); * returned array, as it is an error to specify an extension more than once in * the `VkInstanceCreateInfo` struct. * - * @remark @macos This function currently only supports the - * `VK_MVK_macos_surface` extension from MoltenVK. + * @remark @macos This function currently supports either the + * `VK_MVK_macos_surface` extension from MoltenVK or `VK_EXT_metal_surface` + * extension. * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is guaranteed to be valid only until the diff --git a/v3.3/glfw/glfw/src/cocoa_init.m b/v3.3/glfw/glfw/src/cocoa_init.m index 62a3cfab..579b6e6c 100644 --- a/v3.3/glfw/glfw/src/cocoa_init.m +++ b/v3.3/glfw/glfw/src/cocoa_init.m @@ -431,9 +431,8 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notification // In case we are unbundled, make us a proper UI application [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - // Menu bar setup must go between sharedApplication above and - // finishLaunching below, in order to properly emulate the behavior - // of NSApplicationMain + // Menu bar setup must go between sharedApplication and finishLaunching + // in order to properly emulate the behavior of NSApplicationMain if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) { @@ -448,9 +447,9 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notification - (void)applicationDidFinishLaunching:(NSNotification *)notification { - [NSApp stop:nil]; - + _glfw.ns.finishedLaunching = GLFW_TRUE; _glfwPlatformPostEmptyEvent(); + [NSApp stop:nil]; } - (void)applicationDidHide:(NSNotification *)notification @@ -464,6 +463,32 @@ - (void)applicationDidHide:(NSNotification *)notification @end // GLFWApplicationDelegate +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void* _glfwLoadLocalVulkanLoaderNS(void) +{ + CFBundleRef bundle = CFBundleGetMainBundle(); + if (!bundle) + return NULL; + + CFURLRef url = + CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib")); + if (!url) + return NULL; + + char path[PATH_MAX]; + void* handle = NULL; + + if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1)) + handle = _glfw_dlopen(path); + + CFRelease(url); + return handle; +} + + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// diff --git a/v3.3/glfw/glfw/src/cocoa_joystick.m b/v3.3/glfw/glfw/src/cocoa_joystick.m index a8121e85..2c8d82d9 100644 --- a/v3.3/glfw/glfw/src/cocoa_joystick.m +++ b/v3.3/glfw/glfw/src/cocoa_joystick.m @@ -331,7 +331,7 @@ void _glfwInitJoysticksNS(void) return; } - for (int i = 0; i < sizeof(usages) / sizeof(long); i++) + for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++) { const long page = kHIDPage_GenericDesktop; diff --git a/v3.3/glfw/glfw/src/cocoa_monitor.m b/v3.3/glfw/glfw/src/cocoa_monitor.m index bb526732..8ef94a3b 100644 --- a/v3.3/glfw/glfw/src/cocoa_monitor.m +++ b/v3.3/glfw/glfw/src/cocoa_monitor.m @@ -144,7 +144,7 @@ static GLFWbool modeIsGood(CGDisplayModeRef mode) // Convert Core Graphics display mode to GLFW video mode // static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode, - CVDisplayLinkRef link) + double fallbackRefreshRate) { GLFWvidmode result; result.width = (int) CGDisplayModeGetWidth(mode); @@ -152,11 +152,7 @@ static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode, result.refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode)); if (result.refreshRate == 0) - { - const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); - if (!(time.flags & kCVTimeIsIndefinite)) - result.refreshRate = (int) (time.timeScale / (double) time.timeValue); - } + result.refreshRate = (int) round(fallbackRefreshRate); #if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); @@ -238,6 +234,68 @@ static GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor) return GLFW_FALSE; } +// Returns the display refresh rate queried from the I/O registry +// +static double getFallbackRefreshRate(CGDirectDisplayID displayID) +{ + double refreshRate = 60.0; + + io_iterator_t it; + io_service_t service; + + if (IOServiceGetMatchingServices(kIOMasterPortDefault, + IOServiceMatching("IOFramebuffer"), + &it) != 0) + { + return refreshRate; + } + + while ((service = IOIteratorNext(it)) != 0) + { + const CFNumberRef indexRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFramebufferOpenGLIndex"), + kCFAllocatorDefault, + kNilOptions); + if (!indexRef) + continue; + + uint32_t index = 0; + CFNumberGetValue(indexRef, kCFNumberIntType, &index); + CFRelease(indexRef); + + if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID) + continue; + + const CFNumberRef clockRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFBCurrentPixelClock"), + kCFAllocatorDefault, + kNilOptions); + const CFNumberRef countRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFBCurrentPixelCount"), + kCFAllocatorDefault, + kNilOptions); + if (!clockRef || !countRef) + break; + + uint32_t clock = 0, count = 0; + CFNumberGetValue(clockRef, kCFNumberIntType, &clock); + CFNumberGetValue(countRef, kCFNumberIntType, &count); + CFRelease(clockRef); + CFRelease(countRef); + + if (clock > 0 && count > 0) + refreshRate = clock / (double) count; + + break; + } + + IOObjectRelease(it); + return refreshRate; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -294,6 +352,11 @@ void _glfwPollMonitorsNS(void) free(name); + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]); + if (CGDisplayModeGetRefreshRate(mode) == 0.0) + monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]); + CGDisplayModeRelease(mode); + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } @@ -318,9 +381,6 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) if (_glfwCompareVideoModes(¤t, best) == 0) return; - CVDisplayLinkRef link; - CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); - CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); const CFIndex count = CFArrayGetCount(modes); CGDisplayModeRef native = NULL; @@ -331,7 +391,8 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) if (!modeIsGood(dm)) continue; - const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + const GLFWvidmode mode = + vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate); if (_glfwCompareVideoModes(best, &mode) == 0) { native = dm; @@ -350,7 +411,6 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) } CFRelease(modes); - CVDisplayLinkRelease(link); } // Restore the previously saved (original) video mode @@ -440,9 +500,6 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, *count = 0; - CVDisplayLinkRef link; - CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); - CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); const CFIndex found = CFArrayGetCount(modes); GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode)); @@ -453,7 +510,8 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, if (!modeIsGood(dm)) continue; - const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + const GLFWvidmode mode = + vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate); CFIndex j; for (j = 0; j < *count; j++) @@ -471,7 +529,6 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, } CFRelease(modes); - CVDisplayLinkRelease(link); return result; } // autoreleasepool @@ -481,15 +538,10 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode) { @autoreleasepool { - CVDisplayLinkRef link; - CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); - CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID); - *mode = vidmodeFromCGDisplayMode(native, link); + *mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate); CGDisplayModeRelease(native); - CVDisplayLinkRelease(link); - } // autoreleasepool } diff --git a/v3.3/glfw/glfw/src/cocoa_platform.h b/v3.3/glfw/glfw/src/cocoa_platform.h index b29b64c8..15c21696 100644 --- a/v3.3/glfw/glfw/src/cocoa_platform.h +++ b/v3.3/glfw/glfw/src/cocoa_platform.h @@ -28,8 +28,6 @@ #include #include -#include -#include // NOTE: All of NSGL was deprecated in the 10.14 SDK // This disables the pointless warnings for every symbol we use @@ -63,6 +61,7 @@ typedef void* id; #endif typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; +typedef VkFlags VkMetalSurfaceCreateFlagsEXT; typedef struct VkMacOSSurfaceCreateInfoMVK { @@ -72,7 +71,16 @@ typedef struct VkMacOSSurfaceCreateInfoMVK const void* pView; } VkMacOSSurfaceCreateInfoMVK; +typedef struct VkMetalSurfaceCreateInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkMetalSurfaceCreateFlagsEXT flags; + const void* pLayer; +} VkMetalSurfaceCreateInfoEXT; + typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMetalSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*); #include "posix_thread.h" #include "cocoa_joystick.h" @@ -170,6 +178,7 @@ typedef struct _GLFWmonitorNS CGDisplayModeRef previousMode; uint32_t unitNumber; id screen; + double fallbackRefreshRate; } _GLFWmonitorNS; @@ -198,3 +207,5 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor); float _glfwTransformYNS(float y); +void* _glfwLoadLocalVulkanLoaderNS(void); + diff --git a/v3.3/glfw/glfw/src/cocoa_window.m b/v3.3/glfw/glfw/src/cocoa_window.m index 61321805..129e975e 100644 --- a/v3.3/glfw/glfw/src/cocoa_window.m +++ b/v3.3/glfw/glfw/src/cocoa_window.m @@ -322,12 +322,6 @@ - (void)windowDidResignKey:(NSNotification *)notification _glfwInputWindowFocus(window, GLFW_FALSE); } -- (void)windowDidChangeScreen:(NSNotification *)notification -{ - if (window->context.source == GLFW_NATIVE_CONTEXT_API) - _glfwUpdateDisplayLinkDisplayNSGL(window); -} - @end @@ -891,10 +885,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, @autoreleasepool { if (!_glfw.ns.finishedLaunching) - { [NSApp run]; - _glfw.ns.finishedLaunching = GLFW_TRUE; - } if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; @@ -967,13 +958,14 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) } // autoreleasepool } -void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { @autoreleasepool { - [window->ns.object setTitle:@(title)]; + NSString* string = @(title); + [window->ns.object setTitle:string]; // HACK: Set the miniwindow title explicitly as setTitle: doesn't update it // if the window lacks NSWindowStyleMaskTitled - [window->ns.object setMiniwindowTitle:@(title)]; + [window->ns.object setMiniwindowTitle:string]; } // autoreleasepool } @@ -1385,6 +1377,9 @@ void _glfwPlatformPollEvents(void) { @autoreleasepool { + if (!_glfw.ns.finishedLaunching) + [NSApp run]; + for (;;) { NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny @@ -1404,6 +1399,9 @@ void _glfwPlatformWaitEvents(void) { @autoreleasepool { + if (!_glfw.ns.finishedLaunching) + [NSApp run]; + // I wanted to pass NO to dequeue:, and rely on PollEvents to // dequeue and send. For reasons not at all clear to me, passing // NO to dequeue: causes this method never to return. @@ -1422,6 +1420,9 @@ void _glfwPlatformWaitEventsTimeout(double timeout) { @autoreleasepool { + if (!_glfw.ns.finishedLaunching) + [NSApp run]; + NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout]; NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:date @@ -1439,6 +1440,9 @@ void _glfwPlatformPostEmptyEvent(void) { @autoreleasepool { + if (!_glfw.ns.finishedLaunching) + [NSApp run]; + NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 @@ -1512,6 +1516,13 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { @autoreleasepool { + if (scancode < 0 || scancode > 0xff || + _glfw.ns.keycodes[scancode] == GLFW_KEY_UNKNOWN) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); + return NULL; + } + const int key = _glfw.ns.keycodes[scancode]; UInt32 deadKeyState = 0; @@ -1685,11 +1696,16 @@ void _glfwPlatformSetClipboardString(const char* string) void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { - if (!_glfw.vk.KHR_surface || !_glfw.vk.MVK_macos_surface) - return; - - extensions[0] = "VK_KHR_surface"; - extensions[1] = "VK_MVK_macos_surface"; + if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface) + { + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_EXT_metal_surface"; + } + else if (_glfw.vk.KHR_surface && _glfw.vk.MVK_macos_surface) + { + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_MVK_macos_surface"; + } } int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, @@ -1707,19 +1723,6 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, @autoreleasepool { #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 - VkResult err; - VkMacOSSurfaceCreateInfoMVK sci; - PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; - - vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK) - vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK"); - if (!vkCreateMacOSSurfaceMVK) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "Cocoa: Vulkan instance missing VK_MVK_macos_surface extension"); - return VK_ERROR_EXTENSION_NOT_PRESENT; - } - // HACK: Dynamically load Core Animation to avoid adding an extra // dependency for the majority who don't use MoltenVK NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"]; @@ -1745,11 +1748,49 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, [window->ns.view setLayer:window->ns.layer]; [window->ns.view setWantsLayer:YES]; - memset(&sci, 0, sizeof(sci)); - sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; - sci.pView = window->ns.view; + VkResult err; + + if (_glfw.vk.EXT_metal_surface) + { + VkMetalSurfaceCreateInfoEXT sci; + + PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; + vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT) + vkGetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT"); + if (!vkCreateMetalSurfaceEXT) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Cocoa: Vulkan instance missing VK_EXT_metal_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; + sci.pLayer = window->ns.layer; + + err = vkCreateMetalSurfaceEXT(instance, &sci, allocator, surface); + } + else + { + VkMacOSSurfaceCreateInfoMVK sci; + + PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; + vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK) + vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK"); + if (!vkCreateMacOSSurfaceMVK) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Cocoa: Vulkan instance missing VK_MVK_macos_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + sci.pView = window->ns.view; + + err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface); + } - err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface); if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/v3.3/glfw/glfw/src/egl_context.c b/v3.3/glfw/glfw/src/egl_context.c index 0b93e72d..e458bfb8 100644 --- a/v3.3/glfw/glfw/src/egl_context.c +++ b/v3.3/glfw/glfw/src/egl_context.c @@ -123,23 +123,24 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, continue; #if defined(_GLFW_X11) - XVisualInfo vi = {0}; + { + XVisualInfo vi = {0}; - // Only consider EGLConfigs with associated Visuals - vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); - if (!vi.visualid) - continue; + // Only consider EGLConfigs with associated Visuals + vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!vi.visualid) + continue; - if (desired->transparent) - { - int count; - XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display, - VisualIDMask, &vi, - &count); - if (vis) + if (desired->transparent) { - u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); - XFree(vis); + int count; + XVisualInfo* vis = + XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count); + if (vis) + { + u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); + XFree(vis); + } } } #endif // _GLFW_X11 diff --git a/v3.3/glfw/glfw/src/internal.h b/v3.3/glfw/glfw/src/internal.h index 81f12dc1..92b9497a 100644 --- a/v3.3/glfw/glfw/src/internal.h +++ b/v3.3/glfw/glfw/src/internal.h @@ -128,6 +128,7 @@ typedef enum VkStructureType VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, + VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; @@ -556,6 +557,7 @@ struct _GLFWlibrary GLFWbool KHR_win32_surface; #elif defined(_GLFW_COCOA) GLFWbool MVK_macos_surface; + GLFWbool EXT_metal_surface; #elif defined(_GLFW_X11) GLFWbool KHR_xlib_surface; GLFWbool KHR_xcb_surface; diff --git a/v3.3/glfw/glfw/src/nsgl_context.h b/v3.3/glfw/glfw/src/nsgl_context.h index 432d200e..a772b511 100644 --- a/v3.3/glfw/glfw/src/nsgl_context.h +++ b/v3.3/glfw/glfw/src/nsgl_context.h @@ -44,10 +44,6 @@ typedef struct _GLFWcontextNSGL { id pixelFormat; id object; - CVDisplayLinkRef displayLink; - atomic_int swapInterval; - int swapIntervalsPassed; - id swapIntervalCond; } _GLFWcontextNSGL; @@ -67,5 +63,4 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextNSGL(_GLFWwindow* window); -void _glfwUpdateDisplayLinkDisplayNSGL(_GLFWwindow* window); diff --git a/v3.3/glfw/glfw/src/nsgl_context.m b/v3.3/glfw/glfw/src/nsgl_context.m index 9cfa4276..3bcfafcc 100644 --- a/v3.3/glfw/glfw/src/nsgl_context.m +++ b/v3.3/glfw/glfw/src/nsgl_context.m @@ -28,29 +28,8 @@ #include "internal.h" -// Display link callback for manual swap interval implementation -// This is based on a similar workaround added to SDL2 -// -static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, - const CVTimeStamp* now, - const CVTimeStamp* outputTime, - CVOptionFlags flagsIn, - CVOptionFlags* flagsOut, - void* userInfo) -{ - _GLFWwindow* window = (_GLFWwindow *) userInfo; - - const int interval = atomic_load(&window->context.nsgl.swapInterval); - if (interval > 0) - { - [window->context.nsgl.swapIntervalCond lock]; - window->context.nsgl.swapIntervalsPassed++; - [window->context.nsgl.swapIntervalCond signal]; - [window->context.nsgl.swapIntervalCond unlock]; - } - - return kCVReturnSuccess; -} +#include +#include static void makeContextCurrentNSGL(_GLFWwindow* window) { @@ -70,19 +49,28 @@ static void swapBuffersNSGL(_GLFWwindow* window) { @autoreleasepool { - const int interval = atomic_load(&window->context.nsgl.swapInterval); - if (interval > 0) + // HACK: Simulate vsync with usleep as NSGL swap interval does not apply to + // windows with a non-visible occlusion state + if (!([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)) { - [window->context.nsgl.swapIntervalCond lock]; - do + int interval = 0; + [window->context.nsgl.object getValues:&interval + forParameter:NSOpenGLContextParameterSwapInterval]; + + if (interval > 0) { - [window->context.nsgl.swapIntervalCond wait]; - } while (window->context.nsgl.swapIntervalsPassed % interval != 0); - window->context.nsgl.swapIntervalsPassed = 0; - [window->context.nsgl.swapIntervalCond unlock]; + const double framerate = 60.0; + const uint64_t frequency = _glfwPlatformGetTimerFrequency(); + const uint64_t value = _glfwPlatformGetTimerValue(); + + const double elapsed = value / (double) frequency; + const double period = 1.0 / framerate; + const double delay = period - fmod(elapsed, period); + + usleep(floorl(delay * 1e6)); + } } - // ARP appears to be unnecessary, but this is future-proof [window->context.nsgl.object flushBuffer]; } // autoreleasepool @@ -91,11 +79,14 @@ static void swapBuffersNSGL(_GLFWwindow* window) static void swapIntervalNSGL(int interval) { @autoreleasepool { + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); - atomic_store(&window->context.nsgl.swapInterval, interval); - [window->context.nsgl.swapIntervalCond lock]; - window->context.nsgl.swapIntervalsPassed = 0; - [window->context.nsgl.swapIntervalCond unlock]; + if (window) + { + [window->context.nsgl.object setValues:&interval + forParameter:NSOpenGLContextParameterSwapInterval]; + } + } // autoreleasepool } @@ -123,17 +114,6 @@ static void destroyContextNSGL(_GLFWwindow* window) { @autoreleasepool { - if (window->context.nsgl.displayLink) - { - if (CVDisplayLinkIsRunning(window->context.nsgl.displayLink)) - CVDisplayLinkStop(window->context.nsgl.displayLink); - - CVDisplayLinkRelease(window->context.nsgl.displayLink); - } - - [window->context.nsgl.swapIntervalCond release]; - window->context.nsgl.swapIntervalCond = nil; - [window->context.nsgl.pixelFormat release]; window->context.nsgl.pixelFormat = nil; @@ -361,17 +341,10 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, forParameter:NSOpenGLContextParameterSurfaceOpacity]; } - if (window->ns.retina) - [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; - - GLint interval = 0; - [window->context.nsgl.object setValues:&interval - forParameter:NSOpenGLContextParameterSwapInterval]; + [window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina]; [window->context.nsgl.object setView:window->ns.view]; - window->context.nsgl.swapIntervalCond = [NSCondition new]; - window->context.makeCurrent = makeContextCurrentNSGL; window->context.swapBuffers = swapBuffersNSGL; window->context.swapInterval = swapIntervalNSGL; @@ -379,26 +352,9 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, window->context.getProcAddress = getProcAddressNSGL; window->context.destroy = destroyContextNSGL; - CVDisplayLinkCreateWithActiveCGDisplays(&window->context.nsgl.displayLink); - CVDisplayLinkSetOutputCallback(window->context.nsgl.displayLink, - &displayLinkCallback, - window); - CVDisplayLinkStart(window->context.nsgl.displayLink); - - _glfwUpdateDisplayLinkDisplayNSGL(window); return GLFW_TRUE; } -void _glfwUpdateDisplayLinkDisplayNSGL(_GLFWwindow* window) -{ - CGDirectDisplayID displayID = - [[[window->ns.object screen] deviceDescription][@"NSScreenNumber"] unsignedIntValue]; - if (!displayID) - return; - - CVDisplayLinkSetCurrentCGDisplay(window->context.nsgl.displayLink, displayID); -} - ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// diff --git a/v3.3/glfw/glfw/src/vulkan.c b/v3.3/glfw/glfw/src/vulkan.c index 7f9ed862..22c54e4a 100644 --- a/v3.3/glfw/glfw/src/vulkan.c +++ b/v3.3/glfw/glfw/src/vulkan.c @@ -57,6 +57,8 @@ GLFWbool _glfwInitVulkan(int mode) _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); #elif defined(_GLFW_COCOA) _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib"); + if (!_glfw.vk.handle) + _glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS(); #else _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); #endif @@ -130,6 +132,8 @@ GLFWbool _glfwInitVulkan(int mode) #elif defined(_GLFW_COCOA) else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0) _glfw.vk.MVK_macos_surface = GLFW_TRUE; + else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0) + _glfw.vk.EXT_metal_surface = GLFW_TRUE; #elif defined(_GLFW_X11) else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0) _glfw.vk.KHR_xlib_surface = GLFW_TRUE; diff --git a/v3.3/glfw/glfw/src/win32_monitor.c b/v3.3/glfw/glfw/src/win32_monitor.c index 03496411..4f5af36a 100644 --- a/v3.3/glfw/glfw/src/win32_monitor.c +++ b/v3.3/glfw/glfw/src/win32_monitor.c @@ -33,6 +33,7 @@ #include #include #include +#include // Callback for EnumDisplayMonitors in createMonitor diff --git a/v3.3/glfw/glfw/src/win32_window.c b/v3.3/glfw/glfw/src/win32_window.c index cdb1fe87..0ce22ee7 100644 --- a/v3.3/glfw/glfw/src/win32_window.c +++ b/v3.3/glfw/glfw/src/win32_window.c @@ -36,8 +36,6 @@ #include #include -#define _GLFW_KEY_INVALID -2 - // Returns the window style for the specified window // static DWORD getWindowStyle(const _GLFWwindow* window) @@ -448,77 +446,6 @@ static int getKeyMods(void) return mods; } -// Retrieves and translates modifier keys -// -static int getAsyncKeyMods(void) -{ - int mods = 0; - - if (GetAsyncKeyState(VK_SHIFT) & 0x8000) - mods |= GLFW_MOD_SHIFT; - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - mods |= GLFW_MOD_CONTROL; - if (GetAsyncKeyState(VK_MENU) & 0x8000) - mods |= GLFW_MOD_ALT; - if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000) - mods |= GLFW_MOD_SUPER; - if (GetAsyncKeyState(VK_CAPITAL) & 1) - mods |= GLFW_MOD_CAPS_LOCK; - if (GetAsyncKeyState(VK_NUMLOCK) & 1) - mods |= GLFW_MOD_NUM_LOCK; - - return mods; -} - -// Translates a Windows key to the corresponding GLFW key -// -static int translateKey(WPARAM wParam, LPARAM lParam) -{ - // The Ctrl keys require special handling - if (wParam == VK_CONTROL) - { - MSG next; - DWORD time; - - // Right side keys have the extended key bit set - if (HIWORD(lParam) & KF_EXTENDED) - return GLFW_KEY_RIGHT_CONTROL; - - // HACK: Alt Gr sends Left Ctrl and then Right Alt in close sequence - // We only want the Right Alt message, so if the next message is - // Right Alt we ignore this (synthetic) Left Ctrl message - time = GetMessageTime(); - - if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) - { - if (next.message == WM_KEYDOWN || - next.message == WM_SYSKEYDOWN || - next.message == WM_KEYUP || - next.message == WM_SYSKEYUP) - { - if (next.wParam == VK_MENU && - (HIWORD(next.lParam) & KF_EXTENDED) && - next.time == time) - { - // Next message is Right Alt down so discard this - return _GLFW_KEY_INVALID; - } - } - } - - return GLFW_KEY_LEFT_CONTROL; - } - - if (wParam == VK_PROCESSKEY) - { - // IME notifies that keys have been filtered by setting the virtual - // key-code to VK_PROCESSKEY - return _GLFW_KEY_INVALID; - } - - return _glfw.win32.keycodes[HIWORD(lParam) & 0x1FF]; -} - static void fitToMonitor(_GLFWwindow* window) { MONITORINFO mi = { sizeof(mi) }; @@ -739,13 +666,64 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_KEYUP: case WM_SYSKEYUP: { - const int key = translateKey(wParam, lParam); - const int scancode = (HIWORD(lParam) & 0x1ff); + int key, scancode; const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS; const int mods = getKeyMods(); - if (key == _GLFW_KEY_INVALID) + scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); + if (!scancode) + { + // NOTE: Some synthetic key messages have a scancode of zero + // HACK: Map the virtual key back to a usable scancode + scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC); + } + + key = _glfw.win32.keycodes[scancode]; + + // The Ctrl keys require special handling + if (wParam == VK_CONTROL) + { + if (HIWORD(lParam) & KF_EXTENDED) + { + // Right side keys have the extended key bit set + key = GLFW_KEY_RIGHT_CONTROL; + } + else + { + // NOTE: Alt Gr sends Left Ctrl followed by Right Alt + // HACK: We only want one event for Alt Gr, so if we detect + // this sequence we discard this Left Ctrl message now + // and later report Right Alt normally + MSG next; + const DWORD time = GetMessageTime(); + + if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) + { + if (next.message == WM_KEYDOWN || + next.message == WM_SYSKEYDOWN || + next.message == WM_KEYUP || + next.message == WM_SYSKEYUP) + { + if (next.wParam == VK_MENU && + (HIWORD(next.lParam) & KF_EXTENDED) && + next.time == time) + { + // Next message is Right Alt down so discard this + break; + } + } + } + + // This is a regular Left Ctrl message + key = GLFW_KEY_LEFT_CONTROL; + } + } + else if (wParam == VK_PROCESSKEY) + { + // IME notifies that keys have been filtered by setting the + // virtual key-code to VK_PROCESSKEY break; + } if (action == GLFW_RELEASE && wParam == VK_SHIFT) { @@ -1924,30 +1902,40 @@ void _glfwPlatformPollEvents(void) } } + // HACK: Release modifier keys that the system did not emit KEYUP for + // NOTE: Shift keys on Windows tend to "stick" when both are pressed as + // no key up message is generated by the first key release + // NOTE: Windows key is not reported as released by the Win+V hotkey + // Other Win hotkeys are handled implicitly by _glfwInputWindowFocus + // because they change the input focus + // NOTE: The other half of this is in the WM_*KEY* handler in windowProc handle = GetActiveWindow(); if (handle) { - // NOTE: Shift keys on Windows tend to "stick" when both are pressed as - // no key up message is generated by the first key release - // The other half of this is in the handling of WM_KEYUP - // HACK: Query actual key state and synthesize release events as needed window = GetPropW(handle, L"GLFW"); if (window) { - const GLFWbool lshift = (GetAsyncKeyState(VK_LSHIFT) & 0x8000) != 0; - const GLFWbool rshift = (GetAsyncKeyState(VK_RSHIFT) & 0x8000) != 0; - - if (!lshift && window->keys[GLFW_KEY_LEFT_SHIFT] == GLFW_PRESS) + int i; + const int keys[4][2] = { - const int mods = getAsyncKeyMods(); - const int scancode = _glfw.win32.scancodes[GLFW_KEY_LEFT_SHIFT]; - _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods); - } - else if (!rshift && window->keys[GLFW_KEY_RIGHT_SHIFT] == GLFW_PRESS) + { VK_LSHIFT, GLFW_KEY_LEFT_SHIFT }, + { VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT }, + { VK_LWIN, GLFW_KEY_LEFT_SUPER }, + { VK_RWIN, GLFW_KEY_RIGHT_SUPER } + }; + + for (i = 0; i < 4; i++) { - const int mods = getAsyncKeyMods(); - const int scancode = _glfw.win32.scancodes[GLFW_KEY_RIGHT_SHIFT]; - _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods); + const int vk = keys[i][0]; + const int key = keys[i][1]; + const int scancode = _glfw.win32.scancodes[key]; + + if ((GetKeyState(vk) & 0x8000)) + continue; + if (window->keys[key] != GLFW_PRESS) + continue; + + _glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods()); } } } @@ -2029,6 +2017,13 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) const char* _glfwPlatformGetScancodeName(int scancode) { + if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) || + _glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); + return NULL; + } + return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]]; } diff --git a/v3.3/glfw/glfw/src/wl_init.c b/v3.3/glfw/glfw/src/wl_init.c index 292de1c3..97b53673 100644 --- a/v3.3/glfw/glfw/src/wl_init.c +++ b/v3.3/glfw/glfw/src/wl_init.c @@ -125,6 +125,7 @@ static void pointerHandleLeave(void* data, _glfw.wl.serial = serial; _glfw.wl.pointerFocus = NULL; _glfwInputCursorEnter(window, GLFW_FALSE); + _glfw.wl.cursorPreviousName = NULL; } static void setCursor(_GLFWwindow* window, const char* name) @@ -169,6 +170,7 @@ static void setCursor(_GLFWwindow* window, const char* name) wl_surface_damage(surface, 0, 0, image->width, image->height); wl_surface_commit(surface); + _glfw.wl.cursorPreviousName = name; } static void pointerHandleMotion(void* data, @@ -178,48 +180,47 @@ static void pointerHandleMotion(void* data, wl_fixed_t sy) { _GLFWwindow* window = _glfw.wl.pointerFocus; - const char* cursorName; + const char* cursorName = NULL; + double x, y; if (!window) return; if (window->cursorMode == GLFW_CURSOR_DISABLED) return; - else - { - window->wl.cursorPosX = wl_fixed_to_double(sx); - window->wl.cursorPosY = wl_fixed_to_double(sy); - } + x = wl_fixed_to_double(sx); + y = wl_fixed_to_double(sy); switch (window->wl.decorations.focus) { case mainWindow: - _glfwInputCursorPos(window, - wl_fixed_to_double(sx), - wl_fixed_to_double(sy)); + window->wl.cursorPosX = x; + window->wl.cursorPosY = y; + _glfwInputCursorPos(window, x, y); + _glfw.wl.cursorPreviousName = NULL; return; case topDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + if (y < _GLFW_DECORATION_WIDTH) cursorName = "n-resize"; else cursorName = "left_ptr"; break; case leftDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + if (y < _GLFW_DECORATION_WIDTH) cursorName = "nw-resize"; else cursorName = "w-resize"; break; case rightDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + if (y < _GLFW_DECORATION_WIDTH) cursorName = "ne-resize"; else cursorName = "e-resize"; break; case bottomDecoration: - if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH) + if (x < _GLFW_DECORATION_WIDTH) cursorName = "sw-resize"; - else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH) + else if (x > window->wl.width + _GLFW_DECORATION_WIDTH) cursorName = "se-resize"; else cursorName = "s-resize"; @@ -227,7 +228,8 @@ static void pointerHandleMotion(void* data, default: assert(0); } - setCursor(window, cursorName); + if (_glfw.wl.cursorPreviousName != cursorName) + setCursor(window, cursorName); } static void pointerHandleButton(void* data, diff --git a/v3.3/glfw/glfw/src/wl_platform.h b/v3.3/glfw/glfw/src/wl_platform.h index 940e57ee..41a7fdfa 100644 --- a/v3.3/glfw/glfw/src/wl_platform.h +++ b/v3.3/glfw/glfw/src/wl_platform.h @@ -249,6 +249,7 @@ typedef struct _GLFWlibraryWayland struct wl_cursor_theme* cursorTheme; struct wl_cursor_theme* cursorThemeHiDPI; struct wl_surface* cursorSurface; + const char* cursorPreviousName; int cursorTimerfd; uint32_t serial; diff --git a/v3.3/glfw/glfw/src/wl_window.c b/v3.3/glfw/glfw/src/wl_window.c index 07fe64eb..a9025718 100644 --- a/v3.3/glfw/glfw/src/wl_window.c +++ b/v3.3/glfw/glfw/src/wl_window.c @@ -904,7 +904,7 @@ static char *translateCursorShape(int shape) case GLFW_CROSSHAIR_CURSOR: return "crosshair"; case GLFW_HAND_CURSOR: - return "grabbing"; + return "hand2"; case GLFW_HRESIZE_CURSOR: return "sb_h_double_arrow"; case GLFW_VRESIZE_CURSOR: diff --git a/v3.3/glfw/glfw/src/x11_monitor.c b/v3.3/glfw/glfw/src/x11_monitor.c index 412f9f40..1f804aeb 100644 --- a/v3.3/glfw/glfw/src/x11_monitor.c +++ b/v3.3/glfw/glfw/src/x11_monitor.c @@ -322,12 +322,16 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); - if (xpos) - *xpos = ci->x; - if (ypos) - *ypos = ci->y; + if (ci) + { + if (xpos) + *xpos = ci->x; + if (ypos) + *ypos = ci->y; + + XRRFreeCrtcInfo(ci); + } - XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); } } @@ -493,9 +497,15 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); - *mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci); + if (ci) + { + const XRRModeInfo* mi = getModeInfo(sr, ci->mode); + if (mi) // mi can be NULL if the monitor has been disconnected + *mode = vidmodeFromModeInfo(mi, ci); + + XRRFreeCrtcInfo(ci); + } - XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); } else diff --git a/v3.3/glfw/glfw/src/x11_platform.h b/v3.3/glfw/glfw/src/x11_platform.h index d34bc587..7377b2c0 100644 --- a/v3.3/glfw/glfw/src/x11_platform.h +++ b/v3.3/glfw/glfw/src/x11_platform.h @@ -180,6 +180,7 @@ typedef struct _GLFWwindowX11 { Colormap colormap; Window handle; + Window parent; XIC ic; GLFWbool overrideRedirect; diff --git a/v3.3/glfw/glfw/src/x11_window.c b/v3.3/glfw/glfw/src/x11_window.c index 85d548a6..271e1080 100644 --- a/v3.3/glfw/glfw/src/x11_window.c +++ b/v3.3/glfw/glfw/src/x11_window.c @@ -613,46 +613,41 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, window->x11.transparent = _glfwIsVisualTransparentX11(visual); - // Create the actual window - { - XSetWindowAttributes wa; - const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask; - - wa.colormap = window->x11.colormap; - wa.border_pixel = 0; - wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | - PointerMotionMask | ButtonPressMask | ButtonReleaseMask | - ExposureMask | FocusChangeMask | VisibilityChangeMask | - EnterWindowMask | LeaveWindowMask | PropertyChangeMask; - - _glfwGrabErrorHandlerX11(); - - window->x11.handle = XCreateWindow(_glfw.x11.display, - _glfw.x11.root, - 0, 0, - width, height, - 0, // Border width - depth, // Color depth - InputOutput, - visual, - wamask, - &wa); - - _glfwReleaseErrorHandlerX11(); - - if (!window->x11.handle) - { - _glfwInputErrorX11(GLFW_PLATFORM_ERROR, - "X11: Failed to create window"); - return GLFW_FALSE; - } - - XSaveContext(_glfw.x11.display, - window->x11.handle, - _glfw.x11.context, - (XPointer) window); + XSetWindowAttributes wa = { 0 }; + wa.colormap = window->x11.colormap; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask | + EnterWindowMask | LeaveWindowMask | PropertyChangeMask; + + _glfwGrabErrorHandlerX11(); + + window->x11.parent = _glfw.x11.root; + window->x11.handle = XCreateWindow(_glfw.x11.display, + _glfw.x11.root, + 0, 0, // Position + width, height, + 0, // Border width + depth, // Color depth + InputOutput, + visual, + CWBorderPixel | CWColormap | CWEventMask, + &wa); + + _glfwReleaseErrorHandlerX11(); + + if (!window->x11.handle) + { + _glfwInputErrorX11(GLFW_PLATFORM_ERROR, + "X11: Failed to create window"); + return GLFW_FALSE; } + XSaveContext(_glfw.x11.display, + window->x11.handle, + _glfw.x11.context, + (XPointer) window); + if (!wndconfig->decorated) _glfwPlatformSetWindowDecorated(window, GLFW_FALSE); @@ -682,7 +677,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, { XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) &states, count); + PropModeReplace, (unsigned char*) states, count); } } @@ -787,6 +782,13 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, NULL); } + if (window->x11.ic) + { + unsigned long filter = 0; + if (XGetICValues(window->x11.ic, XNFilterEvents, &filter, NULL) == NULL) + XSelectInput(_glfw.x11.display, window->x11.handle, wa.event_mask | filter); + } + _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); @@ -1257,6 +1259,12 @@ static void processEvent(XEvent *event) switch (event->type) { + case ReparentNotify: + { + window->x11.parent = event->xreparent.parent; + return; + } + case KeyPress: { const int key = translateKey(keycode); @@ -1541,18 +1549,28 @@ static void processEvent(XEvent *event) window->x11.height = event->xconfigure.height; } - if (event->xconfigure.x != window->x11.xpos || - event->xconfigure.y != window->x11.ypos) + int xpos = event->xconfigure.x; + int ypos = event->xconfigure.y; + + // NOTE: ConfigureNotify events from the server are in local + // coordinates, so if we are reparented we need to translate + // the position into root (screen) coordinates + if (!event->xany.send_event && window->x11.parent != _glfw.x11.root) { - if (window->x11.overrideRedirect || event->xany.send_event) - { - _glfwInputWindowPos(window, - event->xconfigure.x, - event->xconfigure.y); + Window dummy; + XTranslateCoordinates(_glfw.x11.display, + window->x11.parent, + _glfw.x11.root, + xpos, ypos, + &xpos, &ypos, + &dummy); + } - window->x11.xpos = event->xconfigure.x; - window->x11.ypos = event->xconfigure.y; - } + if (xpos != window->x11.xpos || ypos != window->x11.ypos) + { + _glfwInputWindowPos(window, xpos, ypos); + window->x11.xpos = xpos; + window->x11.ypos = ypos; } return; @@ -2340,18 +2358,67 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { - if (_glfw.x11.NET_WM_STATE && - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + if (!_glfw.x11.NET_WM_STATE || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + return; + } + + if (_glfwPlatformWindowVisible(window)) { 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); + _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); } + else + { + Atom* states = NULL; + unsigned long count = + _glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + (unsigned char**) &states); + + // NOTE: We don't check for failure as this property may not exist yet + // and that's fine (and we'll create it implicitly with append) + + Atom missing[2] = + { + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ + }; + unsigned long missingCount = 2; + + for (unsigned long i = 0; i < count; i++) + { + for (unsigned long j = 0; j < missingCount; j++) + { + if (states[i] == missing[j]) + { + missing[j] = missing[missingCount - 1]; + missingCount--; + } + } + } + + if (states) + XFree(states); + + if (!missingCount) + return; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeAppend, + (unsigned char*) missing, + missingCount); + } + + XFlush(_glfw.x11.display); } void _glfwPlatformShowWindow(_GLFWwindow* window) @@ -2371,6 +2438,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { + if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION) + return; + sendEventToWM(window, _glfw.x11.NET_WM_STATE, _NET_WM_STATE_ADD, @@ -2382,7 +2452,7 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW) sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); - else + else if (_glfwPlatformWindowVisible(window)) { XRaiseWindow(_glfw.x11.display, window->x11.handle); XSetInputFocus(_glfw.x11.display, window->x11.handle, @@ -2567,7 +2637,7 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) if (_glfwPlatformWindowVisible(window)) { - const Atom action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + const long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; sendEventToWM(window, _glfw.x11.NET_WM_STATE, action, @@ -2576,15 +2646,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) } else { - Atom* states; + Atom* states = NULL; unsigned long i, count; count = _glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, (unsigned char**) &states); - if (!states) - return; + + // NOTE: We don't check for failure as this property may not exist yet + // and that's fine (and we'll create it implicitly with append) if (enabled) { @@ -2594,32 +2665,36 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) break; } - if (i == count) - { - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeAppend, - (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, - 1); - } + if (i < count) + return; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeAppend, + (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, + 1); } - else + else if (states) { for (i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) - { - states[i] = states[count - 1]; - count--; - } + break; } + if (i == count) + return; + + states[i] = states[count - 1]; + count--; + XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) &states, count); + PropModeReplace, (unsigned char*) states, count); } - XFree(states); + if (states) + XFree(states); } XFlush(_glfw.x11.display); @@ -2787,6 +2862,13 @@ const char* _glfwPlatformGetScancodeName(int scancode) if (!_glfw.x11.xkb.available) return NULL; + if (scancode < 0 || scancode > 0xff || + _glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); + return NULL; + } + const int key = _glfw.x11.keycodes[scancode]; const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0);