diff --git a/.gitignore b/.gitignore index 2f580b8a0..428e7334c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,16 +8,20 @@ _ReSharper* *.dir *.vcxproj* *.sln -.vs/ +.vs +CMakeSettings.json Win32 x64 Debug Release MinSizeRel RelWithDebInfo -*.xcodeproj *.opensdf +# Xcode clutter +GLFW.build +GLFW.xcodeproj + # macOS clutter .DS_Store diff --git a/.travis.yml b/.travis.yml index 9b37ebfd3..5f3b73936 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,12 +75,14 @@ matrix: env: - BUILD_SHARED_LIBS=ON - CFLAGS=-Werror + - MACOSX_DEPLOYMENT_TARGET=10.8 - os: osx sudo: false name: "Cocoa static library" env: - BUILD_SHARED_LIBS=OFF - CFLAGS=-Werror + - MACOSX_DEPLOYMENT_TARGET=10.8 script: - if grep -Inr '\s$' src include docs tests examples CMake *.md .gitattributes .gitignore; then echo Trailing whitespace found, aborting; diff --git a/CMake/MacOSXBundleInfo.plist.in b/CMake/Info.plist.in similarity index 100% rename from CMake/MacOSXBundleInfo.plist.in rename to CMake/Info.plist.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c7ac8192..8d8719da3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.1) project(GLFW VERSION 3.4.0 LANGUAGES C) @@ -37,10 +37,6 @@ cmake_dependent_option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF cmake_dependent_option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON "MSVC" OFF) -if (BUILD_SHARED_LIBS) - set(_GLFW_BUILD_DLL 1) -endif() - if (BUILD_SHARED_LIBS AND UNIX) # On Unix-like systems, shared libraries can use the soname system. set(GLFW_LIB_NAME glfw) @@ -75,7 +71,7 @@ if (MSVC) include(CheckIncludeFile) check_include_file(dinput.h DINPUT_H_FOUND) if (NOT DINPUT_H_FOUND) - message(FATAL_ERROR "DirectX 9 SDK not found") + message(FATAL_ERROR "DirectX 9 headers not found; install DirectX 9 SDK") endif() # Workaround for VS 2008 not shipping with stdint.h list(APPEND glfw_INCLUDE_DIRS "${GLFW_SOURCE_DIR}/deps/vs2008") @@ -203,38 +199,32 @@ if (_GLFW_X11) # Set up library and include paths list(APPEND glfw_INCLUDE_DIRS "${X11_X11_INCLUDE_PATH}") - list(APPEND glfw_LIBRARIES "${X11_X11_LIB}" "${CMAKE_THREAD_LIBS_INIT}") + list(APPEND glfw_LIBRARIES "${X11_X11_LIB}") # Check for XRandR (modern resolution switching and gamma control) if (NOT X11_Xrandr_INCLUDE_PATH) - message(FATAL_ERROR "The RandR headers were not found") + message(FATAL_ERROR "RandR headers not found; install libxrandr development package") endif() # Check for Xinerama (legacy multi-monitor support) if (NOT X11_Xinerama_INCLUDE_PATH) - message(FATAL_ERROR "The Xinerama headers were not found") + message(FATAL_ERROR "Xinerama headers not found; install libxinerama development package") endif() # Check for Xkb (X keyboard extension) if (NOT X11_Xkb_INCLUDE_PATH) - message(FATAL_ERROR "The X keyboard extension headers were not found") + message(FATAL_ERROR "XKB headers not found; install X11 development package") endif() # Check for Xcursor (cursor creation from RGBA images) if (NOT X11_Xcursor_INCLUDE_PATH) - message(FATAL_ERROR "The Xcursor headers were not found") + message(FATAL_ERROR "Xcursor headers not found; install libxcursor development package") endif() # Check for XInput (modern HID input) if (NOT X11_Xi_INCLUDE_PATH) - message(FATAL_ERROR "The XInput headers were not found") + message(FATAL_ERROR "XInput headers not found; install libxi development package") endif() - - list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}" - "${X11_Xinerama_INCLUDE_PATH}" - "${X11_Xkb_INCLUDE_PATH}" - "${X11_Xcursor_INCLUDE_PATH}" - "${X11_Xi_INCLUDE_PATH}") endif() #-------------------------------------------------------------------- @@ -251,7 +241,7 @@ if (_GLFW_WAYLAND) list(APPEND glfw_PKG_DEPS "wayland-egl") list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIRS}") - list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") + list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}") find_package(XKBCommon REQUIRED) list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") @@ -275,7 +265,6 @@ endif() #-------------------------------------------------------------------- if (_GLFW_OSMESA) find_package(OSMesa REQUIRED) - list(APPEND glfw_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") endif() #-------------------------------------------------------------------- @@ -286,11 +275,10 @@ if (_GLFW_COCOA) list(APPEND glfw_LIBRARIES "-framework Cocoa" "-framework IOKit" - "-framework CoreFoundation" - "-framework CoreVideo") + "-framework CoreFoundation") set(glfw_PKG_DEPS "") - set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo") + set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation") endif() #-------------------------------------------------------------------- @@ -326,8 +314,6 @@ write_basic_package_version_file(src/glfw3ConfigVersion.cmake VERSION ${GLFW_VERSION} COMPATIBILITY SameMajorVersion) -configure_file(src/glfw_config.h.in src/glfw_config.h @ONLY) - configure_file(src/glfw3.pc.in src/glfw3.pc @ONLY) #-------------------------------------------------------------------- @@ -365,6 +351,11 @@ if (GLFW_INSTALL) install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + if (GLFW_BUILD_DOCS) + install(DIRECTORY "${GLFW_BINARY_DIR}/docs/html" + DESTINATION "${CMAKE_INSTALL_DOCDIR}") + endif() + # Only generate this target if no higher-level project already has if (NOT TARGET uninstall) configure_file(CMake/cmake_uninstall.cmake.in diff --git a/README.md b/README.md index ad41c133e..d3cf5da1a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ application development. It provides a simple, platform-independent API for creating windows, contexts and surfaces, reading input, handling events, etc. GLFW natively supports Windows, macOS and Linux and other Unix-like systems. On -Linux both X11 and Wayland is supported. +Linux both X11 and Wayland are supported. GLFW is licensed under the [zlib/libpng license](http://www.glfw.org/license.html). @@ -85,10 +85,11 @@ in the documentation for more information. ## Dependencies -GLFW itself depends only on the headers and libraries for your window system. +GLFW itself needs only CMake 3.1 or later and the headers and libraries for your +OS and window system. The (experimental) Wayland backend also depends on the `extra-cmake-modules` -package, which is used to generated Wayland protocol headers. +package, which is used to generate Wayland protocol headers. The examples and test programs depend on a number of tiny libraries. These are located in the `deps/` directory. @@ -118,28 +119,53 @@ information on what to include when reporting a bug. ## Changelog + - Added `GLFW_RESIZE_NWSE_CURSOR`, `GLFW_RESIZE_NESW_CURSOR`, + `GLFW_RESIZE_ALL_CURSOR` and `GLFW_NOT_ALLOWED_CURSOR` cursor shapes (#427) + - Added `GLFW_RESIZE_EW_CURSOR` alias for `GLFW_HRESIZE_CURSOR` (#427) + - Added `GLFW_RESIZE_NS_CURSOR` alias for `GLFW_VRESIZE_CURSOR` (#427) + - Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427) + - Updated the minimum required CMake version to 3.1 - Disabled tests and examples by default when built as a CMake subdirectory - Bugfix: The CMake config-file package used an absolute path and was not relocatable (#1470) - Bugfix: Video modes with a duplicate screen area were discarded (#1555,#1556) - Bugfix: Compiling with -Wextra-semi caused warnings (#1440) + - Bugfix: Built-in mappings failed because some OEMs re-used VID/PID (#1583) - [Win32] Added the `GLFW_WIN32_KEYBOARD_MENU` window hint for enabling access to the window menu + - [Win32] Added a version info resource to the GLFW DLL - [Win32] Bugfix: `GLFW_INCLUDE_VULKAN` plus `VK_USE_PLATFORM_WIN32_KHR` caused symbol redefinition (#1524) - [Win32] Bugfix: The cursor position event was emitted before its cursor enter event (#1490) - [Win32] Bugfix: The window hint `GLFW_MAXIMIZED` did not move or resize the window (#1499) + - [Win32] Bugfix: Disabled cursor mode interfered with some non-client actions + - [Cocoa] Removed dependency on the CoreVideo framework - [Cocoa] Bugfix: `glfwSetWindowSize` used a bottom-left anchor point (#1553) - [Cocoa] Bugfix: Window remained on screen after destruction until event poll (#1412) + - [Cocoa] Bugfix: Event processing before window creation would assert (#1543) + - [Cocoa] Bugfix: Undecorated windows could not be iconified on recent macOS - [X11] Bugfix: The CMake files did not check for the XInput headers (#1480) - [X11] Bugfix: Key names were not updated when the keyboard layout changed (#1462,#1528) - [X11] Bugfix: Decorations could not be enabled after window creation (#1566) - [X11] Bugfix: Content scale fallback value could be inconsistent (#1578) + - [X11] Bugfix: `glfwMaximizeWindow` had no effect on hidden windows + - [X11] Bugfix: Clearing `GLFW_FLOATING` on a hidden window caused invalid read + - [X11] Bugfix: Changing `GLFW_FLOATING` on a hidden window could silently fail + - [X11] Bugfix: Disabled cursor mode was interrupted by indicator windows + - [X11] Bugfix: Monitor physical dimensions could be reported as zero mm + - [X11] Bugfix: Window position events were not emitted during resizing (#1613) + - [Wayland] Removed support for `wl_shell` (#1443) + - [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432) + - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled + - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [NSGL] Removed enforcement of forward-compatible flag for core contexts + - [NSGL] Bugfix: `GLFW_COCOA_RETINA_FRAMEBUFFER` had no effect on newer + macOS versions (#1442) + - [NSGL] Bugfix: Workaround for swap interval on 10.14 broke on 10.12 (#1483) ## Contact @@ -212,6 +238,7 @@ skills. - GeO4d - Marcus Geelnard - Charles Giessen + - Ryan C. Gordon - Stephen Gowen - Kovid Goyal - Eloi Marín Gratacós @@ -292,6 +319,7 @@ skills. - Alexandre Pretyman - Pablo Prietz - przemekmirek + - pthom - Guillaume Racicot - Philip Rideout - Eddie Ringle diff --git a/docs/build.dox b/docs/build.dox index 127c9f063..7c3b8ae2e 100644 --- a/docs/build.dox +++ b/docs/build.dox @@ -344,8 +344,8 @@ If you are using the dynamic library version of GLFW, add it to the project dependencies. If you are using the static library version of GLFW, add it and the Cocoa, -OpenGL, IOKit and CoreVideo frameworks to the project as dependencies. They can -all be found in `/System/Library/Frameworks`. +OpenGL and IOKit frameworks to the project as dependencies. They can all be +found in `/System/Library/Frameworks`. @subsection build_link_osx With command-line on macOS @@ -359,7 +359,7 @@ the `-l` and `-framework` switches. If you are using the dynamic GLFW library, which is named `libglfw.3.dylib`, do: @code{.sh} -cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo +cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit @endcode If you are using the static library, named `libglfw3.a`, substitute `-lglfw3` diff --git a/docs/compat.dox b/docs/compat.dox index 77ba63b46..c437e3508 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -85,6 +85,13 @@ transparent window framebuffers. If the running X server does not support this extension or there is no running compositing manager, the `GLFW_TRANSPARENT_FRAMEBUFFER` framebuffer hint will have no effect. +GLFW uses both the Xcursor extension and the freedesktop cursor conventions to +provide an expanded set of standard cursor shapes. If the running X server does +not support this extension or the current cursor theme does not support the +conventions, the `GLFW_RESIZE_NWSE_CURSOR`, `GLFW_RESIZE_NESW_CURSOR` and +`GLFW_NOT_ALLOWED_CURSOR` shapes will not be available and other shapes may use +legacy images. + @section compat_wayland Wayland protocols and IPC standards diff --git a/docs/input.dox b/docs/input.dox index dea648774..331f97183 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -373,12 +373,15 @@ A cursor with a [standard shape](@ref shapes) from the current system cursor theme can be can be created with @ref glfwCreateStandardCursor. @code -GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); +GLFWcursor* url_cursor = glfwCreateStandardCursor(GLFW_POINTING_HAND_CURSOR); @endcode These cursor objects behave in the exact same way as those created with @ref glfwCreateCursor except that the system cursor theme provides the actual image. +A few of these shapes are not available everywhere. If a shape is unavailable, +`NULL` is returned. See @ref glfwCreateStandardCursor for details. + @subsubsection cursor_destruction Cursor destruction diff --git a/docs/news.dox b/docs/news.dox index 39f190310..81af3d1dd 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -9,6 +9,24 @@ @subsection features_34 New features in version 3.4 +@subsubsection standard_cursors_34 More standard cursors + +GLFW now provides the standard cursor shapes @ref GLFW_RESIZE_NWSE_CURSOR and +@ref GLFW_RESIZE_NESW_CURSOR for diagonal resizing, @ref GLFW_RESIZE_ALL_CURSOR +for omni-directional resizing and @ref GLFW_NOT_ALLOWED_CURSOR for showing an +action is not allowed. + +Unlike the original set, these shapes may not be available everywhere and +creation will then fail with the new @ref GLFW_CURSOR_UNAVAILABLE error. + +The cursors for horizontal and vertical resizing are now referred to as @ref +GLFW_RESIZE_EW_CURSOR and @ref GLFW_RESIZE_NS_CURSOR, and the pointing hand +cursor is now referred to as @ref GLFW_POINTING_HAND_CURSOR. The older names +are still available. + +For more information see @ref cursor_standard. + + @subsubsection features_34_win32_keymenu Support for keyboard access to Windows window menu GLFW now provides the @@ -34,6 +52,12 @@ add_subdirectory(path/to/glfw) @endcode +@subsubsection corevideo_34 CoreVideo dependency has been removed + +GLFW no longer depends on the CoreVideo framework on macOS and it no longer +needs to be specified during compilation or linking. + + @subsection deprecations_34 Deprecations in version 3.4 @subsection removals_34 Removals in 3.4 @@ -44,6 +68,14 @@ add_subdirectory(path/to/glfw) @subsubsection types_34 New types in version 3.4 @subsubsection constants_34 New constants in version 3.4 + - @ref GLFW_POINTING_HAND_CURSOR + - @ref GLFW_RESIZE_EW_CURSOR + - @ref GLFW_RESIZE_NS_CURSOR + - @ref GLFW_RESIZE_NWSE_CURSOR + - @ref GLFW_RESIZE_NESW_CURSOR + - @ref GLFW_RESIZE_ALL_CURSOR + - @ref GLFW_NOT_ALLOWED_CURSOR + - @ref GLFW_CURSOR_UNAVAILABLE - @ref GLFW_WIN32_KEYBOARD_MENU diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 597c1e134..867f5bcf0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,7 +1,7 @@ link_libraries(glfw) -include_directories(${glfw_INCLUDE_DIRS} "${GLFW_SOURCE_DIR}/deps") +include_directories("${GLFW_SOURCE_DIR}/deps") if (MATH_LIBRARY) link_libraries("${MATH_LIBRARY}") @@ -11,27 +11,10 @@ if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() -if (GLFW_USE_OSMESA) - add_definitions(-DUSE_NATIVE_OSMESA) -endif() - if (WIN32) set(ICON glfw.rc) elseif (APPLE) set(ICON glfw.icns) - set_source_files_properties(glfw.icns PROPERTIES - MACOSX_PACKAGE_LOCATION "Resources") -endif() - -if (${CMAKE_VERSION} VERSION_EQUAL "3.1.0" OR - ${CMAKE_VERSION} VERSION_GREATER "3.1.0") - set(CMAKE_C_STANDARD 99) -else() - # Remove this fallback when removing support for CMake version less than 3.1 - add_compile_options("$<$:-std=c99>" - "$<$:-std=c99>" - "$<$:-std=c99>") - endif() set(GLAD_GL "${GLFW_SOURCE_DIR}/deps/glad/gl.h" @@ -51,20 +34,26 @@ add_executable(splitview WIN32 MACOSX_BUNDLE splitview.c ${ICON} ${GLAD_GL}) add_executable(triangle-opengl WIN32 MACOSX_BUNDLE triangle-opengl.c ${ICON} ${GLAD_GL}) add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD_GL}) -target_link_libraries(particles "${CMAKE_THREAD_LIBS_INIT}") +target_link_libraries(particles Threads::Threads) if (RT_LIBRARY) target_link_libraries(particles "${RT_LIBRARY}") endif() -set(WINDOWS_BINARIES boing gears heightmap particles sharing splitview triangle-opengl wave) +set(GUI_ONLY_BINARIES boing gears heightmap particles sharing splitview + triangle-opengl wave) set(CONSOLE_BINARIES offscreen) -set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES +set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES + C_STANDARD 99 FOLDER "GLFW3/Examples") +if (GLFW_USE_OSMESA) + target_compile_definitions(offscreen PRIVATE USE_NATIVE_OSMESA) +endif() + if (MSVC) # Tell MSVC to use main instead of WinMain for Windows subsystem executables - set_target_properties(${WINDOWS_BINARIES} PROPERTIES + set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES LINK_FLAGS "/ENTRY:mainCRTStartup") endif() @@ -78,11 +67,12 @@ if (APPLE) set_target_properties(splitview PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "SplitView") set_target_properties(wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave") - set_target_properties(${WINDOWS_BINARIES} PROPERTIES - RESOURCE glfw.icns + set_source_files_properties(glfw.icns PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources") + set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION} MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION} MACOSX_BUNDLE_ICON_FILE glfw.icns - MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/MacOSXBundleInfo.plist.in") + MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/Info.plist.in") endif() diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 0b6031603..d6843f689 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -757,6 +757,17 @@ extern "C" { * @analysis Application programmer error. Fix the offending call. */ #define GLFW_NO_WINDOW_CONTEXT 0x0001000A +/*! @brief The specified cursor shape is not available. + * + * The specified standard cursor shape is not available, either because the + * current system cursor theme does not provide it or because it is not + * available on the platform. + * + * @analysis Platform or system settings limitation. Pick another + * [standard cursor shape](@ref shapes) or create a + * [custom cursor](@ref cursor_custom). + */ +#define GLFW_CURSOR_UNAVAILABLE 0x0001000B /*! @} */ /*! @addtogroup window @@ -1039,14 +1050,15 @@ extern "C" { /*! @defgroup shapes Standard cursor shapes * @brief Standard system cursor shapes. * - * See [standard cursor creation](@ref cursor_standard) for how these are used. + * These are the [standard cursor shapes](@ref cursor_standard) that can be + * requested from the window system. * * @ingroup input * @{ */ /*! @brief The regular arrow cursor shape. * - * The regular arrow cursor. + * The regular arrow cursor shape. */ #define GLFW_ARROW_CURSOR 0x00036001 /*! @brief The text input I-beam cursor shape. @@ -1054,26 +1066,91 @@ extern "C" { * The text input I-beam cursor shape. */ #define GLFW_IBEAM_CURSOR 0x00036002 -/*! @brief The crosshair shape. +/*! @brief The crosshair cursor shape. * - * The crosshair shape. + * The crosshair cursor shape. */ #define GLFW_CROSSHAIR_CURSOR 0x00036003 -/*! @brief The hand shape. +/*! @brief The pointing hand cursor shape. * - * The hand shape. + * The pointing hand cursor shape. */ -#define GLFW_HAND_CURSOR 0x00036004 -/*! @brief The horizontal resize arrow shape. +#define GLFW_POINTING_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize/move arrow shape. * - * The horizontal resize arrow shape. + * The horizontal resize/move arrow shape. This is usually a horizontal + * double-headed arrow. */ -#define GLFW_HRESIZE_CURSOR 0x00036005 -/*! @brief The vertical resize arrow shape. +#define GLFW_RESIZE_EW_CURSOR 0x00036005 +/*! @brief The vertical resize/move arrow shape. * - * The vertical resize arrow shape. + * The vertical resize/move shape. This is usually a vertical double-headed + * arrow. */ -#define GLFW_VRESIZE_CURSOR 0x00036006 +#define GLFW_RESIZE_NS_CURSOR 0x00036006 +/*! @brief The top-left to bottom-right diagonal resize/move arrow shape. + * + * The top-left to bottom-right diagonal resize/move shape. This is usually + * a diagonal double-headed arrow. + * + * @note @macos This shape is provided by a private system API and may fail + * with @ref GLFW_CURSOR_UNAVAILABLE in the future. + * + * @note @x11 This shape is provided by a newer standard not supported by all + * cursor themes. + * + * @note @wayland This shape is provided by a newer standard not supported by + * all cursor themes. + */ +#define GLFW_RESIZE_NWSE_CURSOR 0x00036007 +/*! @brief The top-right to bottom-left diagonal resize/move arrow shape. + * + * The top-right to bottom-left diagonal resize/move shape. This is usually + * a diagonal double-headed arrow. + * + * @note @macos This shape is provided by a private system API and may fail + * with @ref GLFW_CURSOR_UNAVAILABLE in the future. + * + * @note @x11 This shape is provided by a newer standard not supported by all + * cursor themes. + * + * @note @wayland This shape is provided by a newer standard not supported by + * all cursor themes. + */ +#define GLFW_RESIZE_NESW_CURSOR 0x00036008 +/*! @brief The omni-directional resize/move cursor shape. + * + * The omni-directional resize cursor/move shape. This is usually either + * a combined horizontal and vertical double-headed arrow or a grabbing hand. + */ +#define GLFW_RESIZE_ALL_CURSOR 0x00036009 +/*! @brief The operation-not-allowed shape. + * + * The operation-not-allowed shape. This is usually a circle with a diagonal + * line through it. + * + * @note @x11 This shape is provided by a newer standard not supported by all + * cursor themes. + * + * @note @wayland This shape is provided by a newer standard not supported by + * all cursor themes. + */ +#define GLFW_NOT_ALLOWED_CURSOR 0x0003600A +/*! @brief Legacy name for compatibility. + * + * This is an alias for compatibility with earlier versions. + */ +#define GLFW_HRESIZE_CURSOR GLFW_RESIZE_EW_CURSOR +/*! @brief Legacy name for compatibility. + * + * This is an alias for compatibility with earlier versions. + */ +#define GLFW_VRESIZE_CURSOR GLFW_RESIZE_NS_CURSOR +/*! @brief Legacy name for compatibility. + * + * This is an alias for compatibility with earlier versions. + */ +#define GLFW_HAND_CURSOR GLFW_POINTING_HAND_CURSOR /*! @} */ #define GLFW_CONNECTED 0x00040001 @@ -2608,7 +2685,7 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value); * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) * in the Mac Developer Library. The GLFW test and example programs use * a custom `Info.plist` template for this, which can be found as - * `CMake/MacOSXBundleInfo.plist.in` in the source tree. + * `CMake/Info.plist.in` in the source tree. * * @remark @macos When activating frame autosaving with * [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified @@ -4417,19 +4494,44 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) /*! @brief Creates a cursor with a standard shape. * - * Returns a cursor with a [standard shape](@ref shapes), that can be set for - * a window with @ref glfwSetCursor. + * Returns a cursor with a standard shape, that can be set for a window with + * @ref glfwSetCursor. The images for these cursors come from the system + * cursor theme and their exact appearance will vary between platforms. + * + * Most of these shapes are guaranteed to exist on every supported platform but + * a few may not be present. See the table below for details. + * + * Cursor shape | Windows | macOS | X11 | Wayland + * ------------------------------ | ------- | ----- | ------ | ------- + * @ref GLFW_ARROW_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_IBEAM_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_CROSSHAIR_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_POINTING_HAND_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_RESIZE_EW_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_RESIZE_NS_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_RESIZE_NWSE_CURSOR | Yes | Yes1 | Maybe2 | Maybe2 + * @ref GLFW_RESIZE_NESW_CURSOR | Yes | Yes1 | Maybe2 | Maybe2 + * @ref GLFW_RESIZE_ALL_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_NOT_ALLOWED_CURSOR | Yes | Yes | Maybe2 | Maybe2 + * + * 1) This uses a private system API and may fail in the future. + * + * 2) This uses a newer standard that not all cursor themes support. + * + * If the requested shape is not available, this function emits a @ref + * GLFW_CURSOR_UNAVAILABLE error and returns `NULL`. * * @param[in] shape One of the [standard shapes](@ref shapes). * @return A new cursor ready to use or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * GLFW_INVALID_ENUM, @ref GLFW_CURSOR_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * - * @sa @ref cursor_object + * @sa @ref cursor_standard * @sa @ref glfwCreateCursor * * @since Added in version 3.1. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6cbeed6d6..3fb2a54ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,118 +1,96 @@ -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) +add_library(glfw "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h" + internal.h mappings.h 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) + target_sources(glfw PRIVATE cocoa_platform.h cocoa_joystick.h posix_thread.h + nsgl_context.h egl_context.h osmesa_context.h + 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) + target_sources(glfw PRIVATE win32_platform.h win32_joystick.h wgl_context.h + egl_context.h osmesa_context.h 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) + target_sources(glfw PRIVATE x11_platform.h xkb_unicode.h posix_time.h + posix_thread.h glx_context.h egl_context.h + osmesa_context.h 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) + target_sources(glfw PRIVATE wl_platform.h posix_time.h posix_thread.h + xkb_unicode.h egl_context.h osmesa_context.h + wl_init.c wl_monitor.c wl_window.c posix_time.c + posix_thread.c xkb_unicode.c egl_context.c + osmesa_context.c) elseif (_GLFW_OSMESA) - set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h - posix_time.h posix_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) + target_sources(glfw PRIVATE null_platform.h null_joystick.h posix_time.h + posix_thread.h osmesa_context.h 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) + target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c) else() - set(glfw_HEADERS ${glfw_HEADERS} null_joystick.h) - set(glfw_SOURCES ${glfw_SOURCES} null_joystick.c) + target_sources(glfw PRIVATE null_joystick.h 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) +if (_GLFW_WAYLAND) + ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml" + BASENAME xdg-shell) + ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" + BASENAME xdg-decoration) + ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml" + BASENAME viewporter) + ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" + BASENAME relative-pointer-unstable-v1) + ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" + BASENAME pointer-constraints-unstable-v1) + ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" + BASENAME idle-inhibit-unstable-v1) + target_sources(glfw PRIVATE ${GLFW_WAYLAND_PROTOCOL_SOURCES}) 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) +if (WIN32 AND BUILD_SHARED_LIBS) + configure_file(glfw.rc.in glfw.rc @ONLY) + target_sources(glfw PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/glfw.rc") endif() -add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) +configure_file(glfw_config.h.in glfw_config.h @ONLY) +target_compile_definitions(glfw PRIVATE _GLFW_USE_CONFIG_H) +target_sources(glfw PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/glfw_config.h") + 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 + C_STANDARD 99 + C_EXTENSIONS OFF + DEFINE_SYMBOL _GLFW_BUILD_DLL 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 "$" "$") @@ -120,26 +98,50 @@ target_include_directories(glfw PRIVATE "${GLFW_SOURCE_DIR}/src" "${GLFW_BINARY_DIR}/src" ${glfw_INCLUDE_DIRS}) +target_link_libraries(glfw PRIVATE Threads::Threads ${glfw_LIBRARIES}) + +if (APPLE) + # For some reason CMake didn't know about .m until version 3.16 + set_source_files_properties(cocoa_init.m cocoa_joystick.m cocoa_monitor.m + cocoa_window.m nsgl_context.m PROPERTIES + LANGUAGE C) +endif() + +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + + # Make GCC and Clang warn about declarations that VS 2010 and 2012 won't + # accept for all source files that VS will build + set_source_files_properties(context.c init.c input.c monitor.c vulkan.c + window.c 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 PROPERTIES + COMPILE_FLAGS -Wdeclaration-after-statement) + + # Enable a reasonable set of warnings (no, -Wextra is not reasonable) + target_compile_options(glfw PRIVATE "-Wall") +endif() + +if (WIN32) + target_compile_definitions(glfw PRIVATE _UNICODE) +endif() # 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 (MINGW) + target_compile_definitions(glfw PRIVATE UNICODE WINVER=0x0501) +endif() 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") + target_link_libraries(glfw PRIVATE "-static-libgcc") # Remove the lib prefix on the DLL (but not the import library) set_target_properties(glfw PROPERTIES PREFIX "") @@ -151,11 +153,8 @@ if (BUILD_SHARED_LIBS) set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") endif() - target_compile_definitions(glfw INTERFACE GLFW_DLL) + 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() @@ -164,10 +163,6 @@ if (BUILD_SHARED_LIBS) # 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) diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 01c1b319e..7e75299ac 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -431,9 +431,8 @@ static GLFWbool initializeTIS(void) // 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 @@ static GLFWbool initializeTIS(void) - (void)applicationDidFinishLaunching:(NSNotification *)notification { - [NSApp stop:nil]; - + _glfw.ns.finishedLaunching = GLFW_TRUE; _glfwPlatformPostEmptyEvent(); + [NSApp stop:nil]; } - (void)applicationDidHide:(NSNotification *)notification diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index b98f9f67d..88636a87b 100644 --- a/src/cocoa_joystick.m +++ b/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/src/cocoa_monitor.m b/src/cocoa_monitor.m index 9ef2cdc97..42f2dce28 100644 --- a/src/cocoa_monitor.m +++ b/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 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) *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 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) 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 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) } 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/src/cocoa_platform.h b/src/cocoa_platform.h index 21d83bcc7..434f46ddd 100644 --- a/src/cocoa_platform.h +++ b/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 @@ -170,6 +168,7 @@ typedef struct _GLFWmonitorNS CGDisplayModeRef previousMode; uint32_t unitNumber; id screen; + double fallbackRefreshRate; } _GLFWmonitorNS; diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 8e0b28aa6..546f9a828 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -322,12 +322,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; _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 @@ -1603,23 +1607,49 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { @autoreleasepool { - if (shape == GLFW_ARROW_CURSOR) - cursor->ns.object = [NSCursor arrowCursor]; - else if (shape == GLFW_IBEAM_CURSOR) - cursor->ns.object = [NSCursor IBeamCursor]; - else if (shape == GLFW_CROSSHAIR_CURSOR) - cursor->ns.object = [NSCursor crosshairCursor]; - else if (shape == GLFW_HAND_CURSOR) - cursor->ns.object = [NSCursor pointingHandCursor]; - else if (shape == GLFW_HRESIZE_CURSOR) - cursor->ns.object = [NSCursor resizeLeftRightCursor]; - else if (shape == GLFW_VRESIZE_CURSOR) - cursor->ns.object = [NSCursor resizeUpDownCursor]; + SEL cursorSelector = NULL; + + // HACK: Try to use a private message + if (shape == GLFW_RESIZE_EW_CURSOR) + cursorSelector = NSSelectorFromString(@"_windowResizeEastWestCursor"); + else if (shape == GLFW_RESIZE_NS_CURSOR) + cursorSelector = NSSelectorFromString(@"_windowResizeNorthSouthCursor"); + else if (shape == GLFW_RESIZE_NWSE_CURSOR) + cursorSelector = NSSelectorFromString(@"_windowResizeNorthWestSouthEastCursor"); + else if (shape == GLFW_RESIZE_NESW_CURSOR) + cursorSelector = NSSelectorFromString(@"_windowResizeNorthEastSouthWestCursor"); + + if (cursorSelector && [NSCursor respondsToSelector:cursorSelector]) + { + id object = [NSCursor performSelector:cursorSelector]; + if ([object isKindOfClass:[NSCursor class]]) + cursor->ns.object = object; + } if (!cursor->ns.object) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to retrieve standard cursor"); + if (shape == GLFW_ARROW_CURSOR) + cursor->ns.object = [NSCursor arrowCursor]; + else if (shape == GLFW_IBEAM_CURSOR) + cursor->ns.object = [NSCursor IBeamCursor]; + else if (shape == GLFW_CROSSHAIR_CURSOR) + cursor->ns.object = [NSCursor crosshairCursor]; + else if (shape == GLFW_POINTING_HAND_CURSOR) + cursor->ns.object = [NSCursor pointingHandCursor]; + else if (shape == GLFW_RESIZE_EW_CURSOR) + cursor->ns.object = [NSCursor resizeLeftRightCursor]; + else if (shape == GLFW_RESIZE_NS_CURSOR) + cursor->ns.object = [NSCursor resizeUpDownCursor]; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + cursor->ns.object = [NSCursor closedHandCursor]; + else if (shape == GLFW_NOT_ALLOWED_CURSOR) + cursor->ns.object = [NSCursor operationNotAllowedCursor]; + } + + if (!cursor->ns.object) + { + _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + "Cocoa: Standard cursor shape unavailable"); return GLFW_FALSE; } diff --git a/src/egl_context.c b/src/egl_context.c index 6a33396f8..706a79224 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -123,23 +123,24 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, continue; #if defined(_GLFW_X11) - XVisualInfo vi = {0}; - - // 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) + XVisualInfo vi = {0}; + + // Only consider EGLConfigs with associated Visuals + vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!vi.visualid) + continue; + + 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/src/glfw.rc.in b/src/glfw.rc.in new file mode 100644 index 000000000..ac3460a7c --- /dev/null +++ b/src/glfw.rc.in @@ -0,0 +1,30 @@ + +#include + +VS_VERSION_INFO VERSIONINFO +FILEVERSION @GLFW_VERSION_MAJOR@,@GLFW_VERSION_MINOR@,@GLFW_VERSION_PATCH@,0 +PRODUCTVERSION @GLFW_VERSION_MAJOR@,@GLFW_VERSION_MINOR@,@GLFW_VERSION_PATCH@,0 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS 0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DLL +FILESUBTYPE 0 +{ + BLOCK "StringFileInfo" + { + BLOCK "040904B0" + { + VALUE "CompanyName", "GLFW" + VALUE "FileDescription", "GLFW @GLFW_VERSION@ DLL" + VALUE "FileVersion", "@GLFW_VERSION@" + VALUE "OriginalFilename", "glfw3.dll" + VALUE "ProductName", "GLFW" + VALUE "ProductVersion", "@GLFW_VERSION@" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x409, 1200 + } +} + diff --git a/src/glfw3Config.cmake.in b/src/glfw3Config.cmake.in index 1fa200e27..4a13a88b9 100644 --- a/src/glfw3Config.cmake.in +++ b/src/glfw3Config.cmake.in @@ -1 +1,3 @@ +include(CMakeFindDependencyMacro) +find_dependency(Threads) include("${CMAKE_CURRENT_LIST_DIR}/glfw3Targets.cmake") diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index 018952d2f..f4876da28 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in @@ -45,8 +45,6 @@ // 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 diff --git a/src/init.c b/src/init.c index 96feab0cb..13baff707 100644 --- a/src/init.c +++ b/src/init.c @@ -189,6 +189,8 @@ void _glfwInputError(int code, const char* format, ...) strcpy(description, "The requested format is unavailable"); else if (code == GLFW_NO_WINDOW_CONTEXT) strcpy(description, "The specified window has no context"); + else if (code == GLFW_CURSOR_UNAVAILABLE) + strcpy(description, "The specified cursor shape is unavailable"); else strcpy(description, "ERROR: UNKNOWN GLFW ERROR"); } diff --git a/src/input.c b/src/input.c index 282917504..f6163093c 100644 --- a/src/input.c +++ b/src/input.c @@ -757,9 +757,13 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) if (shape != GLFW_ARROW_CURSOR && shape != GLFW_IBEAM_CURSOR && shape != GLFW_CROSSHAIR_CURSOR && - shape != GLFW_HAND_CURSOR && - shape != GLFW_HRESIZE_CURSOR && - shape != GLFW_VRESIZE_CURSOR) + shape != GLFW_POINTING_HAND_CURSOR && + shape != GLFW_RESIZE_EW_CURSOR && + shape != GLFW_RESIZE_NS_CURSOR && + shape != GLFW_RESIZE_NWSE_CURSOR && + shape != GLFW_RESIZE_NESW_CURSOR && + shape != GLFW_RESIZE_ALL_CURSOR && + shape != GLFW_NOT_ALLOWED_CURSOR) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); return NULL; diff --git a/src/nsgl_context.h b/src/nsgl_context.h index edd958e16..9c31436cf 100644 --- a/src/nsgl_context.h +++ b/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/src/nsgl_context.m b/src/nsgl_context.m index e455d412a..e011fa5e0 100644 --- a/src/nsgl_context.m +++ b/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; @@ -354,17 +334,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; @@ -372,26 +345,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/src/posix_time.c b/src/posix_time.c index 301cb958c..ae3d5c789 100644 --- a/src/posix_time.c +++ b/src/posix_time.c @@ -27,8 +27,11 @@ // It is fine to use C99 in this file because it will not be built with VS //======================================================================== +#define _POSIX_C_SOURCE 199309L + #include "internal.h" +#include #include #include @@ -41,7 +44,7 @@ // void _glfwInitTimerPOSIX(void) { -#if defined(CLOCK_MONOTONIC) +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) @@ -64,7 +67,7 @@ void _glfwInitTimerPOSIX(void) uint64_t _glfwPlatformGetTimerValue(void) { -#if defined(CLOCK_MONOTONIC) +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) if (_glfw.timer.posix.monotonic) { struct timespec ts; diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 3067b65ec..5f91c579b 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -33,6 +33,7 @@ #include #include #include +#include // Callback for EnumDisplayMonitors in createMonitor diff --git a/src/win32_window.c b/src/win32_window.c index 81cdf62a4..3a50c542b 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -2068,14 +2068,25 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) id = OCR_IBEAM; else if (shape == GLFW_CROSSHAIR_CURSOR) id = OCR_CROSS; - else if (shape == GLFW_HAND_CURSOR) + else if (shape == GLFW_POINTING_HAND_CURSOR) id = OCR_HAND; - else if (shape == GLFW_HRESIZE_CURSOR) + else if (shape == GLFW_RESIZE_EW_CURSOR) id = OCR_SIZEWE; - else if (shape == GLFW_VRESIZE_CURSOR) + else if (shape == GLFW_RESIZE_NS_CURSOR) id = OCR_SIZENS; + else if (shape == GLFW_RESIZE_NWSE_CURSOR) + id = OCR_SIZENWSE; + else if (shape == GLFW_RESIZE_NESW_CURSOR) + id = OCR_SIZENESW; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + id = OCR_SIZEALL; + else if (shape == GLFW_NOT_ALLOWED_CURSOR) + id = OCR_NO; else + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Unknown standard cursor"); return GLFW_FALSE; + } cursor->win32.handle = LoadImageW(NULL, MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, diff --git a/src/wl_init.c b/src/wl_init.c index 9e692f0e6..558ff8a80 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -26,6 +26,8 @@ // It is fine to use C99 in this file because it will not be built with VS //======================================================================== +#define _POSIX_C_SOURCE 199309L + #include "internal.h" #include @@ -38,6 +40,7 @@ #include #include #include +#include #include @@ -125,6 +128,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) @@ -196,6 +200,7 @@ static void pointerHandleMotion(void* data, window->wl.cursorPosX = x; window->wl.cursorPosY = y; _glfwInputCursorPos(window, x, y); + _glfw.wl.cursorPreviousName = NULL; return; case topDecoration: if (y < _GLFW_DECORATION_WIDTH) diff --git a/src/wl_window.c b/src/wl_window.c index 200b004ca..c8dde30ad 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -770,28 +770,6 @@ static void handleEvents(int timeout) } } -// Translates a GLFW standard cursor to a theme cursor name -// -static char *translateCursorShape(int shape) -{ - switch (shape) - { - case GLFW_ARROW_CURSOR: - return "left_ptr"; - case GLFW_IBEAM_CURSOR: - return "xterm"; - case GLFW_CROSSHAIR_CURSOR: - return "crosshair"; - case GLFW_HAND_CURSOR: - return "grabbing"; - case GLFW_HRESIZE_CURSOR: - return "sb_h_double_arrow"; - case GLFW_VRESIZE_CURSOR: - return "sb_v_double_arrow"; - } - return NULL; -} - ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// @@ -1233,26 +1211,79 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { - struct wl_cursor* standardCursor; + const char* name = NULL; - standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, - translateCursorShape(shape)); - if (!standardCursor) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Standard cursor \"%s\" not found", - translateCursorShape(shape)); - return GLFW_FALSE; - } + // Try the XDG names first + if (shape == GLFW_ARROW_CURSOR) + name = "default"; + else if (shape == GLFW_IBEAM_CURSOR) + name = "text"; + else if (shape == GLFW_CROSSHAIR_CURSOR) + name = "crosshair"; + else if (shape == GLFW_POINTING_HAND_CURSOR) + name = "pointer"; + else if (shape == GLFW_RESIZE_EW_CURSOR) + name = "ew-resize"; + else if (shape == GLFW_RESIZE_NS_CURSOR) + name = "ns-resize"; + else if (shape == GLFW_RESIZE_NWSE_CURSOR) + name = "nwse-resize"; + else if (shape == GLFW_RESIZE_NESW_CURSOR) + name = "nesw-resize"; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + name = "all-scroll"; + else if (shape == GLFW_NOT_ALLOWED_CURSOR) + name = "not-allowed"; - cursor->wl.cursor = standardCursor; - cursor->wl.currentImage = 0; + cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name); if (_glfw.wl.cursorThemeHiDPI) { - standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, - translateCursorShape(shape)); - cursor->wl.cursorHiDPI = standardCursor; + cursor->wl.cursorHiDPI = + wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name); + } + + if (!cursor->wl.cursor) + { + // Fall back to the core X11 names + if (shape == GLFW_ARROW_CURSOR) + name = "left_ptr"; + else if (shape == GLFW_IBEAM_CURSOR) + name = "xterm"; + else if (shape == GLFW_CROSSHAIR_CURSOR) + name = "crosshair"; + else if (shape == GLFW_POINTING_HAND_CURSOR) + name = "hand2"; + else if (shape == GLFW_RESIZE_EW_CURSOR) + name = "sb_h_double_arrow"; + else if (shape == GLFW_RESIZE_NS_CURSOR) + name = "sb_v_double_arrow"; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + name = "fleur"; + else + { + _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + "Wayland: Standard cursor shape unavailable"); + return GLFW_FALSE; + } + + cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name); + if (!cursor->wl.cursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create standard cursor \"%s\"", + name); + return GLFW_FALSE; + } + + if (_glfw.wl.cursorThemeHiDPI) + { + if (!cursor->wl.cursorHiDPI) + { + cursor->wl.cursorHiDPI = + wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name); + } + } } return GLFW_TRUE; diff --git a/src/x11_init.c b/src/x11_init.c index 76bb2a1b5..7a41dbedf 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -36,6 +36,7 @@ #include #include #include +#include // Create key code translation tables @@ -491,6 +492,12 @@ static GLFWbool initExtensions(void) _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); + _glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme) + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetTheme"); + _glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize) + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize"); + _glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage) + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage"); } #if defined(__CYGWIN__) diff --git a/src/x11_platform.h b/src/x11_platform.h index 33145e63e..04c46647c 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -85,9 +85,15 @@ typedef int (* PFN_XRRUpdateConfiguration)(XEvent*); typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int); typedef void (* PFN_XcursorImageDestroy)(XcursorImage*); typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*); +typedef char* (* PFN_XcursorGetTheme)(Display*); +typedef int (* PFN_XcursorGetDefaultSize)(Display*); +typedef XcursorImage* (* PFN_XcursorLibraryLoadImage)(const char*,const char*,int); #define XcursorImageCreate _glfw.x11.xcursor.ImageCreate #define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy #define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor +#define XcursorGetTheme _glfw.x11.xcursor.GetTheme +#define XcursorGetDefaultSize _glfw.x11.xcursor.GetDefaultSize +#define XcursorLibraryLoadImage _glfw.x11.xcursor.LibraryLoadImage typedef Bool (* PFN_XineramaIsActive)(Display*); typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*); @@ -180,6 +186,7 @@ typedef struct _GLFWwindowX11 { Colormap colormap; Window handle; + Window parent; XIC ic; GLFWbool overrideRedirect; @@ -352,6 +359,9 @@ typedef struct _GLFWlibraryX11 PFN_XcursorImageCreate ImageCreate; PFN_XcursorImageDestroy ImageDestroy; PFN_XcursorImageLoadCursor ImageLoadCursor; + PFN_XcursorGetTheme GetTheme; + PFN_XcursorGetDefaultSize GetDefaultSize; + PFN_XcursorLibraryLoadImage LibraryLoadImage; } xcursor; struct { diff --git a/src/x11_window.c b/src/x11_window.c index 56379a3ca..8a00b34fe 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -613,46 +613,40 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, window->x11.transparent = _glfwIsVisualTransparentX11(visual); - // Create the actual 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.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) { - 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); + _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 +676,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 +781,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 +1258,18 @@ static void processEvent(XEvent *event) switch (event->type) { + case CreateNotify: + { + window->x11.parent = event->xcreatewindow.parent; + return; + } + + case ReparentNotify: + { + window->x11.parent = event->xreparent.parent; + return; + } + case KeyPress: { const int key = translateKey(keycode); @@ -1541,18 +1554,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) - { - if (window->x11.overrideRedirect || event->xany.send_event) - { - _glfwInputWindowPos(window, - event->xconfigure.x, - event->xconfigure.y); + int xpos = event->xconfigure.x; + int ypos = event->xconfigure.y; - window->x11.xpos = event->xconfigure.x; - window->x11.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) + { + Window dummy; + XTranslateCoordinates(_glfw.x11.display, + window->x11.parent, + _glfw.x11.root, + xpos, ypos, + &xpos, &ypos, + &dummy); + } + + if (xpos != window->x11.xpos || ypos != window->x11.ypos) + { + _glfwInputWindowPos(window, xpos, ypos); + window->x11.xpos = xpos; + window->x11.ypos = ypos; } return; @@ -2340,18 +2363,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 +2443,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, @@ -2567,7 +2642,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 +2651,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 +2670,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); @@ -2823,29 +2903,76 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { - int native = 0; + if (_glfw.x11.xcursor.handle) + { + char* theme = XcursorGetTheme(_glfw.x11.display); + if (theme) + { + const int size = XcursorGetDefaultSize(_glfw.x11.display); + const char* name = NULL; - if (shape == GLFW_ARROW_CURSOR) - native = XC_left_ptr; - else if (shape == GLFW_IBEAM_CURSOR) - native = XC_xterm; - else if (shape == GLFW_CROSSHAIR_CURSOR) - native = XC_crosshair; - else if (shape == GLFW_HAND_CURSOR) - native = XC_hand2; - else if (shape == GLFW_HRESIZE_CURSOR) - native = XC_sb_h_double_arrow; - else if (shape == GLFW_VRESIZE_CURSOR) - native = XC_sb_v_double_arrow; - else - return GLFW_FALSE; + if (shape == GLFW_ARROW_CURSOR) + name = "default"; + else if (shape == GLFW_IBEAM_CURSOR) + name = "text"; + else if (shape == GLFW_CROSSHAIR_CURSOR) + name = "crosshair"; + else if (shape == GLFW_POINTING_HAND_CURSOR) + name = "pointer"; + else if (shape == GLFW_RESIZE_EW_CURSOR) + name = "ew-resize"; + else if (shape == GLFW_RESIZE_NS_CURSOR) + name = "ns-resize"; + else if (shape == GLFW_RESIZE_NWSE_CURSOR) + name = "nwse-resize"; + else if (shape == GLFW_RESIZE_NESW_CURSOR) + name = "nesw-resize"; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + name = "all-scroll"; + else if (shape == GLFW_NOT_ALLOWED_CURSOR) + name = "not-allowed"; + + XcursorImage* image = XcursorLibraryLoadImage(name, theme, size); + if (image) + { + cursor->x11.handle = XcursorImageLoadCursor(_glfw.x11.display, image); + XcursorImageDestroy(image); + } + } + } - cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); if (!cursor->x11.handle) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to create standard cursor"); - return GLFW_FALSE; + unsigned int native = 0; + + if (shape == GLFW_ARROW_CURSOR) + native = XC_left_ptr; + else if (shape == GLFW_IBEAM_CURSOR) + native = XC_xterm; + else if (shape == GLFW_CROSSHAIR_CURSOR) + native = XC_crosshair; + else if (shape == GLFW_POINTING_HAND_CURSOR) + native = XC_hand2; + else if (shape == GLFW_RESIZE_EW_CURSOR) + native = XC_sb_h_double_arrow; + else if (shape == GLFW_RESIZE_NS_CURSOR) + native = XC_sb_v_double_arrow; + else if (shape == GLFW_RESIZE_ALL_CURSOR) + native = XC_fleur; + else + { + _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + "X11: Standard cursor shape unavailable"); + return GLFW_FALSE; + } + + cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); + if (!cursor->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create standard cursor"); + return GLFW_FALSE; + } } return GLFW_TRUE; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c471d8b94..e36ed56c7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,7 @@ link_libraries(glfw) -include_directories(${glfw_INCLUDE_DIRS} "${GLFW_SOURCE_DIR}/deps") +include_directories("${GLFW_SOURCE_DIR}/deps") if (MATH_LIBRARY) link_libraries("${MATH_LIBRARY}") @@ -20,17 +20,6 @@ set(GETOPT "${GLFW_SOURCE_DIR}/deps/getopt.h" set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h" "${GLFW_SOURCE_DIR}/deps/tinycthread.c") -if (${CMAKE_VERSION} VERSION_EQUAL "3.1.0" OR - ${CMAKE_VERSION} VERSION_GREATER "3.1.0") - set(CMAKE_C_STANDARD 99) -else() - # Remove this fallback when removing support for CMake version less than 3.1 - add_compile_options("$<$:-std=c99>" - "$<$:-std=c99>" - "$<$:-std=c99>") - -endif() - add_executable(clipboard clipboard.c ${GETOPT} ${GLAD_GL}) add_executable(events events.c ${GETOPT} ${GLAD_GL}) add_executable(msaa msaa.c ${GETOPT} ${GLAD_GL}) @@ -50,27 +39,28 @@ add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GLAD_GL}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD_GL}) add_executable(timeout WIN32 MACOSX_BUNDLE timeout.c ${GLAD_GL}) add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD_GL}) -add_executable(triangle-vulkan WIN32 triangle-vulkan.c ${ICON} ${GLAD_VULKAN}) -add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${GETOPT} ${GLAD_GL}) +add_executable(triangle-vulkan WIN32 triangle-vulkan.c ${GLAD_VULKAN}) +add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${GLAD_GL}) -target_link_libraries(empty "${CMAKE_THREAD_LIBS_INIT}") -target_link_libraries(threads "${CMAKE_THREAD_LIBS_INIT}") +target_link_libraries(empty Threads::Threads) +target_link_libraries(threads Threads::Threads) if (RT_LIBRARY) target_link_libraries(empty "${RT_LIBRARY}") target_link_libraries(threads "${RT_LIBRARY}") endif() -set(WINDOWS_BINARIES empty gamma icon inputlag joysticks opacity tearing - threads timeout title triangle-vulkan windows) +set(GUI_ONLY_BINARIES empty gamma icon inputlag joysticks opacity tearing + threads timeout title triangle-vulkan windows) set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen cursor) -set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES +set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES + C_STANDARD 99 FOLDER "GLFW3/Tests") if (MSVC) # Tell MSVC to use main instead of WinMain for Windows subsystem executables - set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES + set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES LINK_FLAGS "/ENTRY:mainCRTStartup") endif() @@ -84,12 +74,11 @@ if (APPLE) 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(triangle-vulkan PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Vulkan Triangle") set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows") - set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES + set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION} MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION} - MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/MacOSXBundleInfo.plist.in") + MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/Info.plist.in") endif() diff --git a/tests/cursor.c b/tests/cursor.c index b6288f6ac..f72c0f911 100644 --- a/tests/cursor.c +++ b/tests/cursor.c @@ -69,7 +69,7 @@ static int swap_interval = 1; static int wait_events = GLFW_TRUE; static int animate_cursor = GLFW_FALSE; static int track_cursor = GLFW_FALSE; -static GLFWcursor* standard_cursors[6]; +static GLFWcursor* standard_cursors[10]; static GLFWcursor* tracking_cursor = NULL; static void error_callback(int error, const char* description) @@ -271,28 +271,24 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, break; case GLFW_KEY_1: - glfwSetCursor(window, standard_cursors[0]); - break; - case GLFW_KEY_2: - glfwSetCursor(window, standard_cursors[1]); - break; - case GLFW_KEY_3: - glfwSetCursor(window, standard_cursors[2]); - break; - case GLFW_KEY_4: - glfwSetCursor(window, standard_cursors[3]); - break; - case GLFW_KEY_5: - glfwSetCursor(window, standard_cursors[4]); - break; - case GLFW_KEY_6: - glfwSetCursor(window, standard_cursors[5]); + case GLFW_KEY_7: + case GLFW_KEY_8: + case GLFW_KEY_9: + { + int index = key - GLFW_KEY_1; + if (mods & GLFW_MOD_SHIFT) + index += 9; + + if (index < sizeof(standard_cursors) / sizeof(standard_cursors[0])) + glfwSetCursor(window, standard_cursors[index]); + break; + } case GLFW_KEY_F11: case GLFW_KEY_ENTER: @@ -358,17 +354,16 @@ int main(void) GLFW_ARROW_CURSOR, GLFW_IBEAM_CURSOR, GLFW_CROSSHAIR_CURSOR, - GLFW_HAND_CURSOR, - GLFW_HRESIZE_CURSOR, - GLFW_VRESIZE_CURSOR + GLFW_POINTING_HAND_CURSOR, + GLFW_RESIZE_EW_CURSOR, + GLFW_RESIZE_NS_CURSOR, + GLFW_RESIZE_NWSE_CURSOR, + GLFW_RESIZE_NESW_CURSOR, + GLFW_RESIZE_ALL_CURSOR, + GLFW_NOT_ALLOWED_CURSOR }; standard_cursors[i] = glfwCreateStandardCursor(shapes[i]); - if (!standard_cursors[i]) - { - glfwTerminate(); - exit(EXIT_FAILURE); - } } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); diff --git a/tests/windows.c b/tests/windows.c index 6669856f1..881338fbe 100644 --- a/tests/windows.c +++ b/tests/windows.c @@ -34,8 +34,7 @@ #include #include -#include "getopt.h" - +static GLFWwindow* windows[4]; static const char* titles[] = { "Red", @@ -55,20 +54,26 @@ static const struct { 0.98f, 0.74f, 0.04f } }; -static void usage(void) -{ - printf("Usage: windows [-h] [-b] [-f] \n"); - printf("Options:\n"); - printf(" -b create decorated windows\n"); - printf(" -f set focus on show off for all but first window\n"); - printf(" -h show this help\n"); -} - static void error_callback(int error, const char* description) { fprintf(stderr, "Error: %s\n", description); } +static void arrange_windows(void) +{ + int xbase, ybase; + glfwGetWindowPos(windows[0], &xbase, &ybase); + + for (int i = 0; i < 4; i++) + { + int left, top, right, bottom; + glfwGetWindowFrameSize(windows[i], &left, &top, &right, &bottom); + glfwSetWindowPos(windows[i], + xbase + (i & 1) * (200 + left + right), + ybase + (i >> 1) * (200 + top + bottom)); + } +} + static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action != GLFW_PRESS) @@ -87,49 +92,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_D: + { + for (int i = 0; i < 4; i++) + { + const int decorated = glfwGetWindowAttrib(windows[i], GLFW_DECORATED); + glfwSetWindowAttrib(windows[i], GLFW_DECORATED, !decorated); + } + + arrange_windows(); + break; + } } } int main(int argc, char** argv) { - int i, ch; - int decorated = GLFW_FALSE; - int focusOnShow = GLFW_TRUE; - int running = GLFW_TRUE; - GLFWwindow* windows[4]; - - while ((ch = getopt(argc, argv, "bfh")) != -1) - { - switch (ch) - { - case 'b': - decorated = GLFW_TRUE; - break; - case 'f': - focusOnShow = GLFW_FALSE; - break; - case 'h': - usage(); - exit(EXIT_SUCCESS); - default: - usage(); - exit(EXIT_FAILURE); - } - } - glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(EXIT_FAILURE); - glfwWindowHint(GLFW_DECORATED, decorated); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); - for (i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { - int left, top, right, bottom; - if (i) - glfwWindowHint(GLFW_FOCUS_ON_SHOW, focusOnShow); + if (i > 0) + glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE); windows[i] = glfwCreateWindow(200, 200, titles[i], NULL, NULL); if (!windows[i]) @@ -143,32 +133,29 @@ int main(int argc, char** argv) glfwMakeContextCurrent(windows[i]); gladLoadGL(glfwGetProcAddress); glClearColor(colors[i].r, colors[i].g, colors[i].b, 1.f); - - glfwGetWindowFrameSize(windows[i], &left, &top, &right, &bottom); - glfwSetWindowPos(windows[i], - 100 + (i & 1) * (200 + left + right), - 100 + (i >> 1) * (200 + top + bottom)); } - for (i = 0; i < 4; i++) + arrange_windows(); + + for (int i = 0; i < 4; i++) glfwShowWindow(windows[i]); - while (running) + for (;;) { - for (i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { glfwMakeContextCurrent(windows[i]); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(windows[i]); if (glfwWindowShouldClose(windows[i])) - running = GLFW_FALSE; + { + glfwTerminate(); + exit(EXIT_SUCCESS); + } } glfwWaitEvents(); } - - glfwTerminate(); - exit(EXIT_SUCCESS); }