glfw: Update GLFW to current master

glfw/glfw@5595fa3ae6 implements a proper fix for the macOS Mojave
problem of OpenGL windows not being rendered until moved or manually
updated.

Pull in the current master and rebase the three patches we have on top:
- two commits we have for reuse of the GLFW CMake build system for Wayland
It hasn't yet to be acknowledged upstream.
- one commit removing #include <windows.h> in glfw3native.h to avoid
duplicate declarations.

Fixes #655 and #665.
This commit is contained in:
Ahmad Fatoum 2018-10-27 11:02:30 +02:00
parent f719de4bf8
commit c3d2b1b184
43 changed files with 10989 additions and 10029 deletions

View file

@ -65,7 +65,7 @@ script:
sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb;
git clone git://anongit.freedesktop.org/wayland/wayland-protocols; git clone git://anongit.freedesktop.org/wayland/wayland-protocols;
pushd wayland-protocols; pushd wayland-protocols;
git checkout 1.12 && ./autogen.sh --prefix=/usr && make && sudo make install; git checkout 1.15 && ./autogen.sh --prefix=/usr && make && sudo make install;
popd; popd;
fi fi
- cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} .. - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} ..

View file

@ -1,34 +0,0 @@
# FindMir
# -------
# Finds the Mir library
#
# This will will define the following variables::
#
# MIR_FOUND - the system has Mir
# MIR_INCLUDE_DIRS - the Mir include directory
# MIR_LIBRARIES - the Mir libraries
# MIR_DEFINITIONS - the Mir definitions
find_package (PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules (PC_MIR mirclient>=0.26.2 QUIET)
find_path(MIR_INCLUDE_DIR NAMES mir_toolkit/mir_client_library.h
PATHS ${PC_MIR_INCLUDE_DIRS})
find_library(MIR_LIBRARY NAMES mirclient
PATHS ${PC_MIR_LIBRARIES} ${PC_MIR_LIBRARY_DIRS})
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (MIR
REQUIRED_VARS MIR_LIBRARY MIR_INCLUDE_DIR)
if (MIR_FOUND)
set(MIR_LIBRARIES ${MIR_LIBRARY})
set(MIR_INCLUDE_DIRS ${PC_MIR_INCLUDE_DIRS})
set(MIR_DEFINITIONS -DHAVE_MIR=1)
endif()
mark_as_advanced (MIR_LIBRARY MIR_INCLUDE_DIR)
endif()

View file

@ -4,7 +4,7 @@ project(GLFW C)
set(CMAKE_LEGACY_CYGWIN_WIN32 OFF) set(CMAKE_LEGACY_CYGWIN_WIN32 OFF)
if (NOT CMAKE_VERSION VERSION_LESS "3.1") if (POLICY CMP0054)
cmake_policy(SET CMP0054 NEW) cmake_policy(SET CMP0054 NEW)
endif() endif()
@ -14,7 +14,6 @@ set(GLFW_VERSION_PATCH "0")
set(GLFW_VERSION_EXTRA "") set(GLFW_VERSION_EXTRA "")
set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}") set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}")
set(GLFW_VERSION_FULL "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}") set(GLFW_VERSION_FULL "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}")
set(LIB_SUFFIX "" CACHE STRING "Takes an empty string or 64. Directory where lib will be installed: lib or lib64")
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@ -25,6 +24,8 @@ option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON)
option(GLFW_INSTALL "Generate installation target" ON) option(GLFW_INSTALL "Generate installation target" ON)
option(GLFW_VULKAN_STATIC "Use the Vulkan loader statically linked into application" OFF) option(GLFW_VULKAN_STATIC "Use the Vulkan loader statically linked into application" OFF)
include(GNUInstallDirs)
if (UNIX) if (UNIX)
option(GLFW_USE_OSMESA "Use OSMesa for offscreen context creation" OFF) option(GLFW_USE_OSMESA "Use OSMesa for offscreen context creation" OFF)
endif() endif()
@ -35,7 +36,6 @@ endif()
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF) option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF)
option(GLFW_USE_MIR "Use Mir for window creation" OFF)
endif() endif()
if (MSVC) if (MSVC)
@ -141,9 +141,6 @@ endif()
if (GLFW_USE_WAYLAND) if (GLFW_USE_WAYLAND)
set(_GLFW_WAYLAND 1) set(_GLFW_WAYLAND 1)
message(STATUS "Using Wayland for window creation") message(STATUS "Using Wayland for window creation")
elseif (GLFW_USE_MIR)
set(_GLFW_MIR 1)
message(STATUS "Using Mir for window creation")
elseif (GLFW_USE_OSMESA) elseif (GLFW_USE_OSMESA)
set(_GLFW_OSMESA 1) set(_GLFW_OSMESA 1)
message(STATUS "Using OSMesa for headless context creation") message(STATUS "Using OSMesa for headless context creation")
@ -262,7 +259,7 @@ if (_GLFW_WAYLAND)
find_package(Wayland REQUIRED Client Cursor Egl) find_package(Wayland REQUIRED Client Cursor Egl)
find_package(WaylandScanner REQUIRED) find_package(WaylandScanner REQUIRED)
find_package(WaylandProtocols 1.12 REQUIRED) find_package(WaylandProtocols 1.15 REQUIRED)
list(APPEND glfw_PKG_DEPS "wayland-egl") list(APPEND glfw_PKG_DEPS "wayland-egl")
@ -273,7 +270,9 @@ if (_GLFW_WAYLAND)
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}")
include(CheckIncludeFiles) include(CheckIncludeFiles)
include(CheckFunctionExists)
check_include_files(xkbcommon/xkbcommon-compose.h HAVE_XKBCOMMON_COMPOSE_H) check_include_files(xkbcommon/xkbcommon-compose.h HAVE_XKBCOMMON_COMPOSE_H)
check_function_exists(memfd_create HAVE_MEMFD_CREATE)
if (NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")) if (NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux"))
find_package(EpollShim) find_package(EpollShim)
@ -284,22 +283,6 @@ if (_GLFW_WAYLAND)
endif() endif()
endif() endif()
#--------------------------------------------------------------------
# Use Mir for window creation
#--------------------------------------------------------------------
if (_GLFW_MIR)
find_package(Mir REQUIRED)
list(APPEND glfw_PKG_DEPS "mirclient")
list(APPEND glfw_INCLUDE_DIRS "${MIR_INCLUDE_DIRS}")
list(APPEND glfw_LIBRARIES "${MIR_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}")
find_package(XKBCommon REQUIRED)
list(APPEND glfw_PKG_DEPS "xkbcommon")
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}")
list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}")
endif()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# Use OSMesa for offscreen context creation # Use OSMesa for offscreen context creation
#-------------------------------------------------------------------- #--------------------------------------------------------------------
@ -340,7 +323,7 @@ endforeach()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
set(GLFW_CONFIG_PATH "lib${LIB_SUFFIX}/cmake/glfw3") set(GLFW_CONFIG_PATH "${CMAKE_INSTALL_LIBDIR}/cmake/glfw3")
configure_package_config_file(src/glfw3Config.cmake.in configure_package_config_file(src/glfw3Config.cmake.in
src/glfw3Config.cmake src/glfw3Config.cmake
@ -377,7 +360,7 @@ endif()
# The library is installed by src/CMakeLists.txt # The library is installed by src/CMakeLists.txt
#-------------------------------------------------------------------- #--------------------------------------------------------------------
if (GLFW_INSTALL) if (GLFW_INSTALL)
install(DIRECTORY include/GLFW DESTINATION include install(DIRECTORY include/GLFW DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h) FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h)
install(FILES "${GLFW_BINARY_DIR}/src/glfw3Config.cmake" install(FILES "${GLFW_BINARY_DIR}/src/glfw3Config.cmake"
@ -388,7 +371,7 @@ if (GLFW_INSTALL)
EXPORT_LINK_INTERFACE_LIBRARIES EXPORT_LINK_INTERFACE_LIBRARIES
DESTINATION "${GLFW_CONFIG_PATH}") DESTINATION "${GLFW_CONFIG_PATH}")
install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc" install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc"
DESTINATION "lib${LIB_SUFFIX}/pkgconfig") DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# Only generate this target if no higher-level project already has # Only generate this target if no higher-level project already has
if (NOT TARGET uninstall) if (NOT TARGET uninstall)

View file

@ -11,8 +11,8 @@ application development. It provides a simple, platform-independent API for
creating windows, contexts and surfaces, reading input, handling events, etc. creating windows, contexts and surfaces, reading input, handling events, etc.
GLFW natively supports Windows, macOS and Linux and other Unix-like systems. GLFW natively supports Windows, macOS and Linux and other Unix-like systems.
Experimental implementations for the Wayland protocol and the Mir display server An experimental implementation for the Wayland protocol is available but not
are available but not yet officially supported. yet officially supported.
GLFW is licensed under the [zlib/libpng GLFW is licensed under the [zlib/libpng
license](http://www.glfw.org/license.html). license](http://www.glfw.org/license.html).
@ -167,6 +167,8 @@ information on what to include when reporting a bug.
(#749,#842) (#749,#842)
- Added `GLFW_FOCUS_ON_SHOW` window hint and attribute to control input focus - Added `GLFW_FOCUS_ON_SHOW` window hint and attribute to control input focus
on calling show window (#1189) on calling show window (#1189)
- Added `GLFW_SCALE_TO_MONITOR` window hint for automatic window resizing
(#676,#1115)
- Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889)
- Added `GLFW_LOCK_KEY_MODS` input mode and `GLFW_MOD_*_LOCK` mod bits (#946) - Added `GLFW_LOCK_KEY_MODS` input mode and `GLFW_MOD_*_LOCK` mod bits (#946)
- Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint - Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint
@ -180,6 +182,10 @@ information on what to include when reporting a bug.
- Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with - Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with
[OSMesa](https://www.mesa3d.org/osmesa.html) (#281) [OSMesa](https://www.mesa3d.org/osmesa.html) (#281)
- Added `GenerateMappings.cmake` script for updating gamepad mappings - Added `GenerateMappings.cmake` script for updating gamepad mappings
- Export CMake `GLFW_PKG_DEPS` and `GLFW_PKG_LIBS` to parent scope for use
in client pkg-configs (#1307)
- Added a `glfw_objlib` CMake OBJECT library target for embedding into static
libraries (#1307)
- Made `glfwCreateWindowSurface` emit an error when the window has a context - Made `glfwCreateWindowSurface` emit an error when the window has a context
(#1194,#1205) (#1194,#1205)
- Deprecated window parameter of clipboard string functions - Deprecated window parameter of clipboard string functions
@ -195,6 +201,8 @@ information on what to include when reporting a bug.
- Bugfix: Invalid library paths were used in test and example CMake files (#930) - Bugfix: Invalid library paths were used in test and example CMake files (#930)
- Bugfix: The scancode for synthetic key release events was always zero - Bugfix: The scancode for synthetic key release events was always zero
- Bugfix: The generated Doxyfile did not handle paths with spaces (#1081) - Bugfix: The generated Doxyfile did not handle paths with spaces (#1081)
- Bugfix: The gamma ramp generated by `glfwSetGamma` did not use the monitor
ramp size (#1387,#1388)
- [Win32] Added system error strings to relevant GLFW error descriptions (#733) - [Win32] Added system error strings to relevant GLFW error descriptions (#733)
- [Win32] Moved to `WM_INPUT` for disabled cursor mode motion input (#125) - [Win32] Moved to `WM_INPUT` for disabled cursor mode motion input (#125)
- [Win32] Removed XInput circular deadzone from joystick axis data (#1045) - [Win32] Removed XInput circular deadzone from joystick axis data (#1045)
@ -221,6 +229,10 @@ information on what to include when reporting a bug.
- [Win32] Bugfix: The HID device notification was not unregistered (#1170) - [Win32] Bugfix: The HID device notification was not unregistered (#1170)
- [Win32] Bugfix: `glfwCreateWindow` activated window even with `GLFW_FOCUSED` - [Win32] Bugfix: `glfwCreateWindow` activated window even with `GLFW_FOCUSED`
hint set to false (#1179,#1180) hint set to false (#1179,#1180)
- [Win32] Bugfix: The keypad equals key was reported as `GLFW_KEY_UNKNOWN`
(#1315,#1316)
- [Win32] Bugfix: A title bar would be drawn over undecorated windows in some
circumstances (#1383)
- [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125)
- [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading
- [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X
@ -235,6 +247,8 @@ information on what to include when reporting a bug.
- [X11] Bugfix: Selection I/O reported but did not support `COMPOUND_TEXT` - [X11] Bugfix: Selection I/O reported but did not support `COMPOUND_TEXT`
- [X11] Bugfix: Latin-1 text read from selections was not converted to UTF-8 - [X11] Bugfix: Latin-1 text read from selections was not converted to UTF-8
- [X11] Bugfix: NVidia EGL would segfault if unloaded before closing the display - [X11] Bugfix: NVidia EGL would segfault if unloaded before closing the display
- [X11] Bugfix: Checking window maximized attrib could crash some WMs (#1356)
- [X11] Bugfix: Update cursor position on enter event (#1366)
- [Linux] Added workaround for missing `SYN_DROPPED` in pre-2.6.39 kernel - [Linux] Added workaround for missing `SYN_DROPPED` in pre-2.6.39 kernel
headers (#1196) headers (#1196)
- [Linux] Moved to evdev for joystick input (#906,#1005) - [Linux] Moved to evdev for joystick input (#906,#1005)
@ -267,6 +281,9 @@ information on what to include when reporting a bug.
- [Cocoa] Bugfix: Window was resized twice when entering full screen (#1085) - [Cocoa] Bugfix: Window was resized twice when entering full screen (#1085)
- [Cocoa] Bugfix: Duplicate size events were not filtered (#1085) - [Cocoa] Bugfix: Duplicate size events were not filtered (#1085)
- [Cocoa] Bugfix: Event polling did not initialize AppKit if necessary (#1218) - [Cocoa] Bugfix: Event polling did not initialize AppKit if necessary (#1218)
- [Cocoa] Bugfix: OpenGL rendering was not initially visible on 10.14
(#1334,#1346)
- [Cocoa] Bugfix: Caps Lock did not generate any key events (#1368,#1373)
- [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts
- [WGL] Added support for `WGL_ARB_create_context_no_error` - [WGL] Added support for `WGL_ARB_create_context_no_error`
- [GLX] Added support for `GLX_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error`
@ -304,7 +321,9 @@ skills.
- David Avedissian - David Avedissian
- Keith Bauer - Keith Bauer
- John Bartholomew - John Bartholomew
- Coşku Baş
- Niklas Behrens - Niklas Behrens
- Andrew Belt
- Niklas Bergström - Niklas Bergström
- Denis Bernard - Denis Bernard
- Doug Binks - Doug Binks
@ -371,6 +390,7 @@ skills.
- Glenn Lewis - Glenn Lewis
- Shane Liesegang - Shane Liesegang
- Eyal Lotem - Eyal Lotem
- Aaron Loucks
- Tristam MacDonald - Tristam MacDonald
- Hans Mackowiak - Hans Mackowiak
- Дмитри Малышев - Дмитри Малышев
@ -387,6 +407,7 @@ skills.
- Bruce Mitchener - Bruce Mitchener
- Jack Moffitt - Jack Moffitt
- Jeff Molofee - Jeff Molofee
- Alexander Monakov
- Pierre Morel - Pierre Morel
- Jon Morton - Jon Morton
- Pierre Moulon - Pierre Moulon

File diff suppressed because it is too large Load diff

View file

@ -35,12 +35,6 @@
#endif #endif
#ifdef VK_USE_PLATFORM_MIR_KHR
#include <mir_toolkit/client_types.h>
#include "vulkan_mir.h"
#endif
#ifdef VK_USE_PLATFORM_VI_NN #ifdef VK_USE_PLATFORM_VI_NN
#include "vulkan_vi.h" #include "vulkan_vi.h"
#endif #endif

View file

@ -269,23 +269,22 @@ extern "C" {
#define GLFW_VERSION_REVISION 0 #define GLFW_VERSION_REVISION 0
/*! @} */ /*! @} */
/*! @name Boolean values
* @{ */
/*! @brief One. /*! @brief One.
* *
* One. Seriously. You don't _need_ to use this symbol in your code. It's * This is only semantic sugar for the number 1. You can instead use `1` or
* semantic sugar for the number 1. You can also use `1` or `true` or `_True` * `true` or `_True` or `GL_TRUE` or anything else that is equal to one.
* or `GL_TRUE` or whatever you want. *
* @ingroup init
*/ */
#define GLFW_TRUE 1 #define GLFW_TRUE 1
/*! @brief Zero. /*! @brief Zero.
* *
* Zero. Seriously. You don't _need_ to use this symbol in your code. It's * This is only semantic sugar for the number 0. You can instead use `0` or
* semantic sugar for the number 0. You can also use `0` or `false` or * `false` or `_False` or `GL_FALSE` or anything else that is equal to zero.
* `_False` or `GL_FALSE` or whatever you want. *
* @ingroup init
*/ */
#define GLFW_FALSE 0 #define GLFW_FALSE 0
/*! @} */
/*! @name Key and button actions /*! @name Key and button actions
* @{ */ * @{ */
@ -313,6 +312,7 @@ extern "C" {
/*! @} */ /*! @} */
/*! @defgroup hat_state Joystick hat states /*! @defgroup hat_state Joystick hat states
* @brief Joystick hat states.
* *
* See [joystick hat input](@ref joystick_hat) for how these are used. * See [joystick hat input](@ref joystick_hat) for how these are used.
* *
@ -973,6 +973,10 @@ extern "C" {
* [attribute](@ref GLFW_CLIENT_API_attrib). * [attribute](@ref GLFW_CLIENT_API_attrib).
*/ */
#define GLFW_CONTEXT_CREATION_API 0x0002200B #define GLFW_CONTEXT_CREATION_API 0x0002200B
/*! @brief Window content area scaling window
* [window hint](@ref GLFW_SCALE_TO_MONITOR).
*/
#define GLFW_SCALE_TO_MONITOR 0x0002200C
#define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001
#define GLFW_COCOA_FRAME_NAME 0x00023002 #define GLFW_COCOA_FRAME_NAME 0x00023002
@ -1056,9 +1060,20 @@ extern "C" {
/*! @addtogroup init /*! @addtogroup init
* @{ */ * @{ */
/*! @brief Joystick hat buttons init hint.
*
* Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS)
*/
#define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001 #define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001
/*! @brief macOS specific init hint.
*
* macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES)
*/
#define GLFW_COCOA_CHDIR_RESOURCES 0x00051001 #define GLFW_COCOA_CHDIR_RESOURCES 0x00051001
/*! @brief macOS specific init hint.
*
* macOS specific [init hint](@ref GLFW_COCOA_MENUBAR)
*/
#define GLFW_COCOA_MENUBAR 0x00051002 #define GLFW_COCOA_MENUBAR 0x00051002
/*! @} */ /*! @} */
@ -1129,7 +1144,7 @@ typedef struct GLFWwindow GLFWwindow;
* *
* @since Added in version 3.1. * @since Added in version 3.1.
* *
* @ingroup cursor * @ingroup input
*/ */
typedef struct GLFWcursor GLFWcursor; typedef struct GLFWcursor GLFWcursor;
@ -1567,6 +1582,8 @@ typedef struct GLFWgammaramp
* *
* @since Added in version 2.1. * @since Added in version 2.1.
* @glfw3 Removed format and bytes-per-pixel members. * @glfw3 Removed format and bytes-per-pixel members.
*
* @ingroup window
*/ */
typedef struct GLFWimage typedef struct GLFWimage
{ {
@ -1589,6 +1606,8 @@ typedef struct GLFWimage
* @sa @ref glfwGetGamepadState * @sa @ref glfwGetGamepadState
* *
* @since Added in version 3.3. * @since Added in version 3.3.
*
* @ingroup input
*/ */
typedef struct GLFWgamepadstate typedef struct GLFWgamepadstate
{ {
@ -2137,9 +2156,9 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
/*! @brief Generates a gamma ramp and sets it for the specified monitor. /*! @brief Generates a gamma ramp and sets it for the specified monitor.
* *
* This function generates a 256-element gamma ramp from the specified exponent * This function generates an appropriately sized gamma ramp from the specified
* and then calls @ref glfwSetGammaRamp with it. The value must be a finite * exponent and then calls @ref glfwSetGammaRamp with it. The value must be
* number greater than zero. * a finite number greater than zero.
* *
* The software controlled gamma ramp is applied _in addition_ to the hardware * The software controlled gamma ramp is applied _in addition_ to the hardware
* gamma correction, which today is usually an approximation of sRGB gamma. * gamma correction, which today is usually an approximation of sRGB gamma.
@ -2218,8 +2237,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
* *
* @remark Gamma ramp sizes other than 256 are not supported by all platforms * @remark The size of the specified gamma ramp should match the size of the
* or graphics hardware. * current ramp for that monitor.
* *
* @remark @win32 The gamma ramp size must be 256. * @remark @win32 The gamma ramp size must be 256.
* *
@ -3758,6 +3777,9 @@ GLFWAPI void glfwWaitEvents(void);
* *
* @param[in] timeout The maximum amount of time, in seconds, to wait. * @param[in] timeout The maximum amount of time, in seconds, to wait.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
*
* @reentrancy This function must not be called from a callback. * @reentrancy This function must not be called from a callback.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
@ -4011,8 +4033,8 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key);
* `GLFW_RELEASE`. * `GLFW_RELEASE`.
* *
* If the @ref GLFW_STICKY_MOUSE_BUTTONS input mode is enabled, this function * If the @ref GLFW_STICKY_MOUSE_BUTTONS input mode is enabled, this function
* `GLFW_PRESS` the first time you call it for a mouse button that was pressed, * returns `GLFW_PRESS` the first time you call it for a mouse button that was
* even if that mouse button has already been released. * pressed, even if that mouse button has already been released.
* *
* @param[in] window The desired window. * @param[in] window The desired window.
* @param[in] button The desired [mouse button](@ref buttons). * @param[in] button The desired [mouse button](@ref buttons).
@ -4283,9 +4305,7 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
* The character callback behaves as system text input normally does and will * The character callback behaves as system text input normally does and will
* not be called if modifier keys are held down that would prevent normal text * not be called if modifier keys are held down that would prevent normal text
* input on that platform, for example a Super (Command) key on macOS or Alt key * input on that platform, for example a Super (Command) key on macOS or Alt key
* on Windows. There is a * on Windows.
* [character with modifiers callback](@ref glfwSetCharModsCallback) that
* receives these events.
* *
* @param[in] window The window whose callback to set. * @param[in] window The window whose callback to set.
* @param[in] cbfun The new callback, or `NULL` to remove the currently set * @param[in] cbfun The new callback, or `NULL` to remove the currently set
@ -4581,7 +4601,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count);
* Each element in the array is one of the following values: * Each element in the array is one of the following values:
* *
* Name | Value * Name | Value
* --------------------- | -------------------------------- * ---- | -----
* `GLFW_HAT_CENTERED` | 0 * `GLFW_HAT_CENTERED` | 0
* `GLFW_HAT_UP` | 1 * `GLFW_HAT_UP` | 1
* `GLFW_HAT_RIGHT` | 2 * `GLFW_HAT_RIGHT` | 2
@ -4901,6 +4921,8 @@ GLFWAPI const char* glfwGetGamepadName(int jid);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_INVALID_ENUM. * GLFW_INVALID_ENUM.
* *
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref gamepad * @sa @ref gamepad
* @sa @ref glfwUpdateGamepadMappings * @sa @ref glfwUpdateGamepadMappings
* @sa @ref glfwJoystickIsGamepad * @sa @ref glfwJoystickIsGamepad
@ -4922,8 +4944,6 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
* *
* @remark @wayland Clipboard is currently unimplemented.
*
* @pointer_lifetime The specified string is copied before this function * @pointer_lifetime The specified string is copied before this function
* returns. * returns.
* *
@ -4952,8 +4972,6 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
* *
* @remark @wayland Clipboard is currently unimplemented.
*
* @pointer_lifetime The returned string is allocated and freed by GLFW. You * @pointer_lifetime The returned string is allocated and freed by GLFW. You
* should not free it yourself. It is valid until the next call to @ref * should not free it yourself. It is valid until the next call to @ref
* glfwGetClipboardString or @ref glfwSetClipboardString, or until the library * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library

View file

@ -62,7 +62,6 @@ extern "C" {
* * `GLFW_EXPOSE_NATIVE_COCOA` * * `GLFW_EXPOSE_NATIVE_COCOA`
* * `GLFW_EXPOSE_NATIVE_X11` * * `GLFW_EXPOSE_NATIVE_X11`
* * `GLFW_EXPOSE_NATIVE_WAYLAND` * * `GLFW_EXPOSE_NATIVE_WAYLAND`
* * `GLFW_EXPOSE_NATIVE_MIR`
* *
* The available context API macros are: * The available context API macros are:
* * `GLFW_EXPOSE_NATIVE_WGL` * * `GLFW_EXPOSE_NATIVE_WGL`
@ -82,7 +81,7 @@ extern "C" {
* System headers and types * System headers and types
*************************************************************************/ *************************************************************************/
#if defined(GLFW_EXPOSE_NATIVE_WIN32) #if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL)
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
// example to allow applications to correctly declare a GL_ARB_debug_output // example to allow applications to correctly declare a GL_ARB_debug_output
// callback) but windows.h assumes no one will define APIENTRY before it does // callback) but windows.h assumes no one will define APIENTRY before it does
@ -96,23 +95,19 @@ extern "C" {
typedef void *PVOID; typedef void *PVOID;
typedef PVOID HANDLE; typedef PVOID HANDLE;
typedef HANDLE HWND; typedef HANDLE HWND;
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) #elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
#include <ApplicationServices/ApplicationServices.h> #include <ApplicationServices/ApplicationServices.h>
#if defined(__OBJC__) #if defined(__OBJC__)
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#else #else
// RAY: Added protection in case OBJC types defined #include <ApplicationServices/ApplicationServices.h>
#if !OBJC_TYPES_DEFINED typedef void* id;
typedef void* id;
#endif
#endif #endif
#elif defined(GLFW_EXPOSE_NATIVE_X11) #elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h> #include <X11/extensions/Xrandr.h>
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) #elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
#include <wayland-client.h> #include <wayland-client.h>
#elif defined(GLFW_EXPOSE_NATIVE_MIR)
#include <mir_toolkit/mir_client_library.h>
#endif #endif
#if defined(GLFW_EXPOSE_NATIVE_WGL) #if defined(GLFW_EXPOSE_NATIVE_WGL)
@ -426,50 +421,6 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
#endif #endif
#if defined(GLFW_EXPOSE_NATIVE_MIR)
/*! @brief Returns the `MirConnection*` used by GLFW.
*
* @return The `MirConnection*` used by GLFW, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI MirConnection* glfwGetMirDisplay(void);
/*! @brief Returns the Mir output ID of the specified monitor.
*
* @return The Mir output ID of the specified monitor, or zero if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
/*! @brief Returns the `MirWindow*` of the specified window.
*
* @return The `MirWindow*` of the specified window, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_EGL) #if defined(GLFW_EXPOSE_NATIVE_EGL)
/*! @brief Returns the `EGLDisplay` used by GLFW. /*! @brief Returns the `EGLDisplay` used by GLFW.
* *

View file

@ -35,6 +35,10 @@ elseif (_GLFW_WAYLAND)
PROTOCOL PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml" "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml"
BASENAME xdg-shell) 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 ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml" "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml"
@ -51,13 +55,6 @@ elseif (_GLFW_WAYLAND)
PROTOCOL PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
BASENAME idle-inhibit-unstable-v1) BASENAME idle-inhibit-unstable-v1)
elseif (_GLFW_MIR)
set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h
posix_time.h posix_thread.h xkb_unicode.h egl_context.h
osmesa_context.h)
set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c
linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c
egl_context.c osmesa_context.c)
elseif (_GLFW_OSMESA) elseif (_GLFW_OSMESA)
set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h
posix_time.h posix_thread.h osmesa_context.h) posix_time.h posix_thread.h osmesa_context.h)
@ -104,10 +101,10 @@ set_target_properties(glfw PROPERTIES
target_compile_definitions(glfw_objlib PRIVATE _GLFW_USE_CONFIG_H) target_compile_definitions(glfw_objlib PRIVATE _GLFW_USE_CONFIG_H)
target_include_directories(glfw_objlib PUBLIC target_include_directories(glfw_objlib PUBLIC
"$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>" "$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>") "$<INSTALL_INTERFACE:${CMAKE_INSTALL_FULL_INCLUDEDIR}>")
target_include_directories(glfw PUBLIC target_include_directories(glfw PUBLIC
"$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>" "$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>") "$<INSTALL_INTERFACE:${CMAKE_INSTALL_FULL_INCLUDEDIR}>")
target_include_directories(glfw_objlib PRIVATE target_include_directories(glfw_objlib PRIVATE
"${GLFW_SOURCE_DIR}/src" "${GLFW_SOURCE_DIR}/src"
"${GLFW_BINARY_DIR}/src" "${GLFW_BINARY_DIR}/src"
@ -128,7 +125,7 @@ target_compile_options(glfw_objlib PRIVATE
if (BUILD_SHARED_LIBS) if (BUILD_SHARED_LIBS)
if (WIN32) if (WIN32)
if (MINGW) if (MINGW)
# Remove the lib prefix on the DLL (but not the import library # Remove the lib prefix on the DLL (but not the import library)
set_target_properties(glfw PROPERTIES PREFIX "") set_target_properties(glfw PROPERTIES PREFIX "")
# Add a suffix to the import library to avoid naming conflicts # Add a suffix to the import library to avoid naming conflicts
@ -142,7 +139,7 @@ if (BUILD_SHARED_LIBS)
target_compile_options(glfw_objlib PRIVATE "-fno-common") target_compile_options(glfw_objlib PRIVATE "-fno-common")
set_target_properties(glfw PROPERTIES set_target_properties(glfw PROPERTIES
INSTALL_NAME_DIR "lib${LIB_SUFFIX}") INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}")
elseif (UNIX) elseif (UNIX)
# Hide symbols not explicitly tagged for export from the shared library # Hide symbols not explicitly tagged for export from the shared library
target_compile_options(glfw_objlib PRIVATE "-fvisibility=hidden") target_compile_options(glfw_objlib PRIVATE "-fvisibility=hidden")
@ -162,7 +159,7 @@ if (GLFW_INSTALL)
install(TARGETS glfw install(TARGETS glfw
EXPORT glfwTargets EXPORT glfwTargets
RUNTIME DESTINATION "bin" RUNTIME DESTINATION "bin"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "lib${LIB_SUFFIX}") LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
endif() endif()

View file

@ -27,6 +27,10 @@
#include "internal.h" #include "internal.h"
#include <sys/param.h> // For MAXPATHLEN #include <sys/param.h> // For MAXPATHLEN
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
#define NSEventMaskKeyUp NSKeyUpMask
#define NSEventModifierFlagCommand NSCommandKeyMask
#endif
// Change to our application bundle's resources directory, if present // Change to our application bundle's resources directory, if present
// //
@ -271,17 +275,21 @@ static GLFWbool initializeTIS(void)
return updateUnicodeDataNS(); return updateUnicodeDataNS();
} }
@interface GLFWLayoutListener : NSObject @interface GLFWHelper : NSObject
@end @end
@implementation GLFWLayoutListener @implementation GLFWHelper
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object - (void)selectedKeyboardInputSourceChanged:(NSObject* )object
{ {
updateUnicodeDataNS(); updateUnicodeDataNS();
} }
@end - (void)doNothing:(id)object
{
}
@end // GLFWHelper
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -291,13 +299,31 @@ static GLFWbool initializeTIS(void)
int _glfwPlatformInit(void) int _glfwPlatformInit(void)
{ {
_glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
_glfw.ns.helper = [[GLFWHelper alloc] init];
[NSThread detachNewThreadSelector:@selector(doNothing:)
toTarget:_glfw.ns.helper
withObject:nil];
[NSApplication sharedApplication];
NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
{
if ([event modifierFlags] & NSEventModifierFlagCommand)
[[NSApp keyWindow] sendEvent:event];
return event;
};
_glfw.ns.keyUpMonitor =
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
handler:block];
if (_glfw.hints.init.ns.chdir) if (_glfw.hints.init.ns.chdir)
changeToResourcesDirectory(); changeToResourcesDirectory();
_glfw.ns.listener = [[GLFWLayoutListener alloc] init];
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
addObserver:_glfw.ns.listener addObserver:_glfw.ns.helper
selector:@selector(selectedKeyboardInputSourceChanged:) selector:@selector(selectedKeyboardInputSourceChanged:)
name:NSTextInputContextKeyboardSelectionDidChangeNotification name:NSTextInputContextKeyboardSelectionDidChangeNotification
object:nil]; object:nil];
@ -342,18 +368,21 @@ void _glfwPlatformTerminate(void)
_glfw.ns.delegate = nil; _glfw.ns.delegate = nil;
} }
if (_glfw.ns.listener) if (_glfw.ns.helper)
{ {
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
removeObserver:_glfw.ns.listener removeObserver:_glfw.ns.helper
name:NSTextInputContextKeyboardSelectionDidChangeNotification name:NSTextInputContextKeyboardSelectionDidChangeNotification
object:nil]; object:nil];
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
removeObserver:_glfw.ns.listener]; removeObserver:_glfw.ns.helper];
[_glfw.ns.listener release]; [_glfw.ns.helper release];
_glfw.ns.listener = nil; _glfw.ns.helper = nil;
} }
if (_glfw.ns.keyUpMonitor)
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
free(_glfw.ns.clipboardString); free(_glfw.ns.clipboardString);
_glfwTerminateNSGL(); _glfwTerminateNSGL();

View file

@ -467,7 +467,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
CVDisplayLinkRelease(link); CVDisplayLinkRelease(link);
} }
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{ {
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID); uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
@ -489,6 +489,7 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
} }
free(values); free(values);
return GLFW_TRUE;
} }
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)

View file

@ -27,12 +27,10 @@
#include <stdint.h> #include <stdint.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <Carbon/Carbon.h>
#if defined(__OBJC__) #if defined(__OBJC__)
#import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#else #else
#include <Carbon/Carbon.h>
#include <ApplicationServices/ApplicationServices.h>
typedef void* id; typedef void* id;
#endif #endif
@ -111,7 +109,9 @@ typedef struct _GLFWlibraryNS
TISInputSourceRef inputSource; TISInputSourceRef inputSource;
IOHIDManagerRef hidManager; IOHIDManagerRef hidManager;
id unicodeData; id unicodeData;
id listener; id helper;
id keyUpMonitor;
id nibObjects;
char keyName[64]; char keyName[64];
short int keycodes[256]; short int keycodes[256];

View file

@ -32,7 +32,6 @@
// Needed for _NSGetProgname // Needed for _NSGetProgname
#include <crt_externs.h> #include <crt_externs.h>
// HACK: The 10.12 SDK adds new symbols and immediately deprecates the old ones
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
#define NSWindowStyleMaskBorderless NSBorderlessWindowMask #define NSWindowStyleMaskBorderless NSBorderlessWindowMask
#define NSWindowStyleMaskClosable NSClosableWindowMask #define NSWindowStyleMaskClosable NSClosableWindowMask
@ -47,10 +46,9 @@
#define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
#define NSEventMaskAny NSAnyEventMask #define NSEventMaskAny NSAnyEventMask
#define NSEventTypeApplicationDefined NSApplicationDefined #define NSEventTypeApplicationDefined NSApplicationDefined
#define NSEventTypeKeyUp NSKeyUp #define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
#endif #endif
// Returns the style mask corresponding to the window settings // Returns the style mask corresponding to the window settings
// //
static NSUInteger getStyleMask(_GLFWwindow* window) static NSUInteger getStyleMask(_GLFWwindow* window)
@ -237,6 +235,8 @@ static NSUInteger translateKeyToModifierFlag(int key)
case GLFW_KEY_LEFT_SUPER: case GLFW_KEY_LEFT_SUPER:
case GLFW_KEY_RIGHT_SUPER: case GLFW_KEY_RIGHT_SUPER:
return NSEventModifierFlagCommand; return NSEventModifierFlagCommand;
case GLFW_KEY_CAPS_LOCK:
return NSEventModifierFlagCapsLock;
} }
return 0; return 0;
@ -365,7 +365,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
// Delegate for application related notifications // Delegate for application related notifications
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@interface GLFWApplicationDelegate : NSObject @interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
@end @end
@implementation GLFWApplicationDelegate @implementation GLFWApplicationDelegate
@ -438,8 +438,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
markedText = [[NSMutableAttributedString alloc] init]; markedText = [[NSMutableAttributedString alloc] init];
[self updateTrackingAreas]; [self updateTrackingAreas];
[self registerForDraggedTypes:[NSArray arrayWithObjects: // NOTE: kUTTypeURL corresponds to NSPasteboardTypeURL but is available
NSFilenamesPboardType, nil]]; // on 10.7 without having been deprecated yet
[self registerForDraggedTypes:@[(__bridge NSString*) kUTTypeURL]];
} }
return self; return self;
@ -472,6 +473,14 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
return YES; return YES;
} }
- (void)updateLayer
{
if (window->context.client != GLFW_NO_API)
[window->context.nsgl.object update];
_glfwInputWindowDamage(window);
}
- (id)makeBackingLayer - (id)makeBackingLayer
{ {
if (window->ns.layer) if (window->ns.layer)
@ -485,6 +494,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
updateCursorImage(window); updateCursorImage(window);
} }
- (BOOL)acceptsFirstMouse:(NSEvent *)event
{
return YES;
}
- (void)mouseDown:(NSEvent *)event - (void)mouseDown:(NSEvent *)event
{ {
_glfwInputMouseClick(window, _glfwInputMouseClick(window,
@ -650,7 +664,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
_glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
[self interpretKeyEvents:[NSArray arrayWithObject:event]]; [self interpretKeyEvents:@[event]];
} }
- (void)flagsChanged:(NSEvent *)event - (void)flagsChanged:(NSEvent *)event
@ -701,45 +715,33 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{ {
if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) // HACK: We don't know what to say here because we don't know what the
== NSDragOperationGeneric) // application wants to do with the paths
{ return NSDragOperationGeneric;
[self setNeedsDisplay:YES];
return NSDragOperationGeneric;
}
return NSDragOperationNone;
}
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
[self setNeedsDisplay:YES];
return YES;
} }
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{ {
NSPasteboard* pasteboard = [sender draggingPasteboard];
NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType];
const NSRect contentRect = [window->ns.view frame]; const NSRect contentRect = [window->ns.view frame];
_glfwInputCursorPos(window, _glfwInputCursorPos(window,
[sender draggingLocation].x, [sender draggingLocation].x,
contentRect.size.height - [sender draggingLocation].y); contentRect.size.height - [sender draggingLocation].y);
const NSUInteger count = [files count]; NSPasteboard* pasteboard = [sender draggingPasteboard];
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
options:options];
const NSUInteger count = [urls count];
if (count) if (count)
{ {
NSEnumerator* e = [files objectEnumerator];
char** paths = calloc(count, sizeof(char*)); char** paths = calloc(count, sizeof(char*));
NSUInteger i;
for (i = 0; i < count; i++) for (NSUInteger i = 0; i < count; i++)
paths[i] = _glfw_strdup([[e nextObject] UTF8String]); paths[i] = _glfw_strdup([[urls objectAtIndex:i] fileSystemRepresentation]);
_glfwInputDrop(window, (int) count, (const char**) paths); _glfwInputDrop(window, (int) count, (const char**) paths);
for (i = 0; i < count; i++) for (NSUInteger i = 0; i < count; i++)
free(paths[i]); free(paths[i]);
free(paths); free(paths);
} }
@ -747,11 +749,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
return YES; return YES;
} }
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
[self setNeedsDisplay:YES];
}
- (BOOL)hasMarkedText - (BOOL)hasMarkedText
{ {
return [markedText length] > 0; return [markedText length] > 0;
@ -865,52 +862,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
@end @end
//------------------------------------------------------------------------
// GLFW application class
//------------------------------------------------------------------------
@interface GLFWApplication : NSApplication
{
NSArray* nibObjects;
}
@end
@implementation GLFWApplication
// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
// This works around an AppKit bug, where key up events while holding
// down the command key don't get sent to the key window.
- (void)sendEvent:(NSEvent *)event
{
if ([event type] == NSEventTypeKeyUp &&
([event modifierFlags] & NSEventModifierFlagCommand))
{
[[self keyWindow] sendEvent:event];
}
else
[super sendEvent:event];
}
// No-op thread entry point
//
- (void)doNothing:(id)object
{
}
- (void)loadMainMenu
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
owner:NSApp
topLevelObjects:&nibObjects];
#else
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp];
#endif
}
@end
// Set up the menu bar (manually) // Set up the menu bar (manually)
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that // This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
// could go away at any moment, lots of stuff that really should be // could go away at any moment, lots of stuff that really should be
@ -1020,32 +971,9 @@ static void createMenuBar(void)
// //
static GLFWbool initializeAppKit(void) static GLFWbool initializeAppKit(void)
{ {
if (NSApp) if (_glfw.ns.delegate)
return GLFW_TRUE; return GLFW_TRUE;
// Implicitly create shared NSApplication instance
[GLFWApplication sharedApplication];
// Make Cocoa enter multi-threaded mode
[NSThread detachNewThreadSelector:@selector(doNothing:)
toTarget:NSApp
withObject:nil];
if (_glfw.hints.init.ns.menubar)
{
// 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
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
[NSApp loadMainMenu];
else
createMenuBar();
}
// There can only be one application delegate, but we allocate it the // There can only be one application delegate, but we allocate it the
// first time a window is created to keep all window code in this file // first time a window is created to keep all window code in this file
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
@ -1057,13 +985,34 @@ static GLFWbool initializeAppKit(void)
} }
[NSApp setDelegate:_glfw.ns.delegate]; [NSApp setDelegate:_glfw.ns.delegate];
if (_glfw.hints.init.ns.menubar)
{
// 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
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
owner:NSApp
topLevelObjects:&_glfw.ns.nibObjects];
#else
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp];
#endif
}
else
createMenuBar();
}
[NSApp run]; [NSApp run];
// Press and Hold prevents some keys from emitting repeated characters // Press and Hold prevents some keys from emitting repeated characters
NSDictionary* defaults = NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],
@"ApplePressAndHoldEnabled",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
return GLFW_TRUE; return GLFW_TRUE;
@ -1563,9 +1512,6 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
void _glfwPlatformPollEvents(void) void _glfwPlatformPollEvents(void)
{ {
if (!initializeAppKit())
return;
for (;;) for (;;)
{ {
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
@ -1716,9 +1662,6 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
NSImage* native; NSImage* native;
NSBitmapImageRep* rep; NSBitmapImageRep* rep;
if (!initializeAppKit())
return GLFW_FALSE;
rep = [[NSBitmapImageRep alloc] rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL initWithBitmapDataPlanes:NULL
pixelsWide:image->width pixelsWide:image->width
@ -1728,7 +1671,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
hasAlpha:YES hasAlpha:YES
isPlanar:NO isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:NSAlphaNonpremultipliedBitmapFormat bitmapFormat:NSBitmapFormatAlphaNonpremultiplied
bytesPerRow:image->width * 4 bytesPerRow:image->width * 4
bitsPerPixel:32]; bitsPerPixel:32];
@ -1754,9 +1697,6 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{ {
if (!initializeAppKit())
return GLFW_FALSE;
if (shape == GLFW_ARROW_CURSOR) if (shape == GLFW_ARROW_CURSOR)
cursor->ns.object = [NSCursor arrowCursor]; cursor->ns.object = [NSCursor arrowCursor];
else if (shape == GLFW_IBEAM_CURSOR) else if (shape == GLFW_IBEAM_CURSOR)
@ -1795,26 +1735,24 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
void _glfwPlatformSetClipboardString(const char* string) void _glfwPlatformSetClipboardString(const char* string)
{ {
NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil];
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
[pasteboard declareTypes:types owner:nil]; [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil];
[pasteboard setString:[NSString stringWithUTF8String:string] [pasteboard setString:[NSString stringWithUTF8String:string]
forType:NSStringPboardType]; forType:NSPasteboardTypeString];
} }
const char* _glfwPlatformGetClipboardString(void) const char* _glfwPlatformGetClipboardString(void)
{ {
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
if (![[pasteboard types] containsObject:NSStringPboardType]) if (![[pasteboard types] containsObject:NSPasteboardTypeString])
{ {
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"Cocoa: Failed to retrieve string from pasteboard"); "Cocoa: Failed to retrieve string from pasteboard");
return NULL; return NULL;
} }
NSString* object = [pasteboard stringForType:NSStringPboardType]; NSString* object = [pasteboard stringForType:NSPasteboardTypeString];
if (!object) if (!object)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,

View file

@ -43,10 +43,6 @@ typedef Window EGLNativeWindowType;
#define EGLAPIENTRY #define EGLAPIENTRY
typedef struct wl_display* EGLNativeDisplayType; typedef struct wl_display* EGLNativeDisplayType;
typedef struct wl_egl_window* EGLNativeWindowType; typedef struct wl_egl_window* EGLNativeWindowType;
#elif defined(_GLFW_MIR)
#define EGLAPIENTRY
typedef MirEGLNativeDisplayType EGLNativeDisplayType;
typedef MirEGLNativeWindowType EGLNativeWindowType;
#else #else
#error "No supported EGL platform selected" #error "No supported EGL platform selected"
#endif #endif

View file

@ -1,12 +1,12 @@
prefix=@CMAKE_INSTALL_PREFIX@ prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix} exec_prefix=${prefix}
includedir=${prefix}/include includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
libdir=${exec_prefix}/lib@LIB_SUFFIX@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@
Name: GLFW Name: GLFW
Description: A multi-platform library for OpenGL, window and input Description: A multi-platform library for OpenGL, window and input
Version: @GLFW_VERSION_FULL@ Version: @GLFW_VERSION_FULL@
URL: http://www.glfw.org/ URL: https://www.glfw.org/
Requires.private: @GLFW_PKG_DEPS@ Requires.private: @GLFW_PKG_DEPS@
Libs: -L${libdir} -l@GLFW_LIB_NAME@ Libs: -L${libdir} -l@GLFW_LIB_NAME@
Libs.private: @GLFW_PKG_LIBS@ Libs.private: @GLFW_PKG_LIBS@

View file

@ -42,8 +42,6 @@
#cmakedefine _GLFW_COCOA #cmakedefine _GLFW_COCOA
// Define this to 1 if building GLFW for Wayland // Define this to 1 if building GLFW for Wayland
#cmakedefine _GLFW_WAYLAND #cmakedefine _GLFW_WAYLAND
// Define this to 1 if building GLFW for Mir
#cmakedefine _GLFW_MIR
// Define this to 1 if building GLFW for OSMesa // Define this to 1 if building GLFW for OSMesa
#cmakedefine _GLFW_OSMESA #cmakedefine _GLFW_OSMESA
@ -57,4 +55,6 @@
// Define this to 1 if xkbcommon supports the compose key // Define this to 1 if xkbcommon supports the compose key
#cmakedefine HAVE_XKBCOMMON_COMPOSE_H #cmakedefine HAVE_XKBCOMMON_COMPOSE_H
// Define this to 1 if the libc supports memfd_create()
#cmakedefine HAVE_MEMFD_CREATE

View file

@ -119,6 +119,30 @@ char* _glfw_strdup(const char* source)
return result; return result;
} }
float _glfw_fminf(float a, float b)
{
if (a != a)
return b;
else if (b != b)
return a;
else if (a < b)
return a;
else
return b;
}
float _glfw_fmaxf(float a, float b)
{
if (a != a)
return b;
else if (b != b)
return a;
else if (a > b)
return a;
else
return b;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW event API ////// ////// GLFW event API //////

View file

@ -1242,7 +1242,7 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
if (e->type == _GLFW_JOYSTICK_AXIS) if (e->type == _GLFW_JOYSTICK_AXIS)
{ {
const float value = js->axes[e->index] * e->axisScale + e->axisOffset; const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
state->axes[i] = fminf(fmaxf(value, -1.f), 1.f); state->axes[i] = _glfw_fminf(_glfw_fmaxf(value, -1.f), 1.f);
} }
else if (e->type == _GLFW_JOYSTICK_HATBIT) else if (e->type == _GLFW_JOYSTICK_HATBIT)
{ {

View file

@ -126,7 +126,6 @@ typedef enum VkStructureType
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
@ -188,8 +187,6 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
#include "x11_platform.h" #include "x11_platform.h"
#elif defined(_GLFW_WAYLAND) #elif defined(_GLFW_WAYLAND)
#include "wl_platform.h" #include "wl_platform.h"
#elif defined(_GLFW_MIR)
#include "mir_platform.h"
#elif defined(_GLFW_OSMESA) #elif defined(_GLFW_OSMESA)
#include "null_platform.h" #include "null_platform.h"
#else #else
@ -268,6 +265,7 @@ struct _GLFWwndconfig
GLFWbool maximized; GLFWbool maximized;
GLFWbool centerCursor; GLFWbool centerCursor;
GLFWbool focusOnShow; GLFWbool focusOnShow;
GLFWbool scaleToMonitor;
struct { struct {
GLFWbool retina; GLFWbool retina;
char frameName[256]; char frameName[256];
@ -562,8 +560,6 @@ struct _GLFWlibrary
GLFWbool KHR_xcb_surface; GLFWbool KHR_xcb_surface;
#elif defined(_GLFW_WAYLAND) #elif defined(_GLFW_WAYLAND)
GLFWbool KHR_wayland_surface; GLFWbool KHR_wayland_surface;
#elif defined(_GLFW_MIR)
GLFWbool KHR_mir_surface;
#endif #endif
} vk; } vk;
@ -615,7 +611,7 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale); float* xscale, float* yscale);
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwPlatformSetClipboardString(const char* string); void _glfwPlatformSetClipboardString(const char* string);
@ -770,4 +766,6 @@ void _glfwTerminateVulkan(void);
const char* _glfwGetVulkanResultString(VkResult result); const char* _glfwGetVulkanResultString(VkResult result);
char* _glfw_strdup(const char* source); char* _glfw_strdup(const char* source);
float _glfw_fminf(float a, float b);
float _glfw_fmaxf(float a, float b);

View file

@ -228,7 +228,7 @@ static GLFWbool openJoystickDevice(const char* path)
return GLFW_FALSE; return GLFW_FALSE;
} }
strncpy(linjs.path, path, sizeof(linjs.path)); strncpy(linjs.path, path, sizeof(linjs.path) - 1);
memcpy(&js->linjs, &linjs, sizeof(linjs)); memcpy(&js->linjs, &linjs, sizeof(linjs));
pollAbsState(js); pollAbsState(js);

View file

@ -1,240 +0,0 @@
//========================================================================
// GLFW 3.3 Mir - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014-2017 Brandon Schaefer <brandon.schaefer@canonical.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <linux/input.h>
#include <stdlib.h>
#include <string.h>
// Create key code translation tables
//
static void createKeyTables(void)
{
int scancode;
memset(_glfw.mir.keycodes, -1, sizeof(_glfw.mir.keycodes));
memset(_glfw.mir.scancodes, -1, sizeof(_glfw.mir.scancodes));
_glfw.mir.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT;
_glfw.mir.keycodes[KEY_1] = GLFW_KEY_1;
_glfw.mir.keycodes[KEY_2] = GLFW_KEY_2;
_glfw.mir.keycodes[KEY_3] = GLFW_KEY_3;
_glfw.mir.keycodes[KEY_4] = GLFW_KEY_4;
_glfw.mir.keycodes[KEY_5] = GLFW_KEY_5;
_glfw.mir.keycodes[KEY_6] = GLFW_KEY_6;
_glfw.mir.keycodes[KEY_7] = GLFW_KEY_7;
_glfw.mir.keycodes[KEY_8] = GLFW_KEY_8;
_glfw.mir.keycodes[KEY_9] = GLFW_KEY_9;
_glfw.mir.keycodes[KEY_0] = GLFW_KEY_0;
_glfw.mir.keycodes[KEY_SPACE] = GLFW_KEY_SPACE;
_glfw.mir.keycodes[KEY_MINUS] = GLFW_KEY_MINUS;
_glfw.mir.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL;
_glfw.mir.keycodes[KEY_Q] = GLFW_KEY_Q;
_glfw.mir.keycodes[KEY_W] = GLFW_KEY_W;
_glfw.mir.keycodes[KEY_E] = GLFW_KEY_E;
_glfw.mir.keycodes[KEY_R] = GLFW_KEY_R;
_glfw.mir.keycodes[KEY_T] = GLFW_KEY_T;
_glfw.mir.keycodes[KEY_Y] = GLFW_KEY_Y;
_glfw.mir.keycodes[KEY_U] = GLFW_KEY_U;
_glfw.mir.keycodes[KEY_I] = GLFW_KEY_I;
_glfw.mir.keycodes[KEY_O] = GLFW_KEY_O;
_glfw.mir.keycodes[KEY_P] = GLFW_KEY_P;
_glfw.mir.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET;
_glfw.mir.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;
_glfw.mir.keycodes[KEY_A] = GLFW_KEY_A;
_glfw.mir.keycodes[KEY_S] = GLFW_KEY_S;
_glfw.mir.keycodes[KEY_D] = GLFW_KEY_D;
_glfw.mir.keycodes[KEY_F] = GLFW_KEY_F;
_glfw.mir.keycodes[KEY_G] = GLFW_KEY_G;
_glfw.mir.keycodes[KEY_H] = GLFW_KEY_H;
_glfw.mir.keycodes[KEY_J] = GLFW_KEY_J;
_glfw.mir.keycodes[KEY_K] = GLFW_KEY_K;
_glfw.mir.keycodes[KEY_L] = GLFW_KEY_L;
_glfw.mir.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON;
_glfw.mir.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
_glfw.mir.keycodes[KEY_Z] = GLFW_KEY_Z;
_glfw.mir.keycodes[KEY_X] = GLFW_KEY_X;
_glfw.mir.keycodes[KEY_C] = GLFW_KEY_C;
_glfw.mir.keycodes[KEY_V] = GLFW_KEY_V;
_glfw.mir.keycodes[KEY_B] = GLFW_KEY_B;
_glfw.mir.keycodes[KEY_N] = GLFW_KEY_N;
_glfw.mir.keycodes[KEY_M] = GLFW_KEY_M;
_glfw.mir.keycodes[KEY_COMMA] = GLFW_KEY_COMMA;
_glfw.mir.keycodes[KEY_DOT] = GLFW_KEY_PERIOD;
_glfw.mir.keycodes[KEY_SLASH] = GLFW_KEY_SLASH;
_glfw.mir.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH;
_glfw.mir.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE;
_glfw.mir.keycodes[KEY_TAB] = GLFW_KEY_TAB;
_glfw.mir.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT;
_glfw.mir.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;
_glfw.mir.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL;
_glfw.mir.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL;
_glfw.mir.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT;
_glfw.mir.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT;
_glfw.mir.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER;
_glfw.mir.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER;
_glfw.mir.keycodes[KEY_MENU] = GLFW_KEY_MENU;
_glfw.mir.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK;
_glfw.mir.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK;
_glfw.mir.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN;
_glfw.mir.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;
_glfw.mir.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE;
_glfw.mir.keycodes[KEY_DELETE] = GLFW_KEY_DELETE;
_glfw.mir.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE;
_glfw.mir.keycodes[KEY_ENTER] = GLFW_KEY_ENTER;
_glfw.mir.keycodes[KEY_HOME] = GLFW_KEY_HOME;
_glfw.mir.keycodes[KEY_END] = GLFW_KEY_END;
_glfw.mir.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP;
_glfw.mir.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN;
_glfw.mir.keycodes[KEY_INSERT] = GLFW_KEY_INSERT;
_glfw.mir.keycodes[KEY_LEFT] = GLFW_KEY_LEFT;
_glfw.mir.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT;
_glfw.mir.keycodes[KEY_DOWN] = GLFW_KEY_DOWN;
_glfw.mir.keycodes[KEY_UP] = GLFW_KEY_UP;
_glfw.mir.keycodes[KEY_F1] = GLFW_KEY_F1;
_glfw.mir.keycodes[KEY_F2] = GLFW_KEY_F2;
_glfw.mir.keycodes[KEY_F3] = GLFW_KEY_F3;
_glfw.mir.keycodes[KEY_F4] = GLFW_KEY_F4;
_glfw.mir.keycodes[KEY_F5] = GLFW_KEY_F5;
_glfw.mir.keycodes[KEY_F6] = GLFW_KEY_F6;
_glfw.mir.keycodes[KEY_F7] = GLFW_KEY_F7;
_glfw.mir.keycodes[KEY_F8] = GLFW_KEY_F8;
_glfw.mir.keycodes[KEY_F9] = GLFW_KEY_F9;
_glfw.mir.keycodes[KEY_F10] = GLFW_KEY_F10;
_glfw.mir.keycodes[KEY_F11] = GLFW_KEY_F11;
_glfw.mir.keycodes[KEY_F12] = GLFW_KEY_F12;
_glfw.mir.keycodes[KEY_F13] = GLFW_KEY_F13;
_glfw.mir.keycodes[KEY_F14] = GLFW_KEY_F14;
_glfw.mir.keycodes[KEY_F15] = GLFW_KEY_F15;
_glfw.mir.keycodes[KEY_F16] = GLFW_KEY_F16;
_glfw.mir.keycodes[KEY_F17] = GLFW_KEY_F17;
_glfw.mir.keycodes[KEY_F18] = GLFW_KEY_F18;
_glfw.mir.keycodes[KEY_F19] = GLFW_KEY_F19;
_glfw.mir.keycodes[KEY_F20] = GLFW_KEY_F20;
_glfw.mir.keycodes[KEY_F21] = GLFW_KEY_F21;
_glfw.mir.keycodes[KEY_F22] = GLFW_KEY_F22;
_glfw.mir.keycodes[KEY_F23] = GLFW_KEY_F23;
_glfw.mir.keycodes[KEY_F24] = GLFW_KEY_F24;
_glfw.mir.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE;
_glfw.mir.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY;
_glfw.mir.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT;
_glfw.mir.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD;
_glfw.mir.keycodes[KEY_KP0] = GLFW_KEY_KP_0;
_glfw.mir.keycodes[KEY_KP1] = GLFW_KEY_KP_1;
_glfw.mir.keycodes[KEY_KP2] = GLFW_KEY_KP_2;
_glfw.mir.keycodes[KEY_KP3] = GLFW_KEY_KP_3;
_glfw.mir.keycodes[KEY_KP4] = GLFW_KEY_KP_4;
_glfw.mir.keycodes[KEY_KP5] = GLFW_KEY_KP_5;
_glfw.mir.keycodes[KEY_KP6] = GLFW_KEY_KP_6;
_glfw.mir.keycodes[KEY_KP7] = GLFW_KEY_KP_7;
_glfw.mir.keycodes[KEY_KP8] = GLFW_KEY_KP_8;
_glfw.mir.keycodes[KEY_KP9] = GLFW_KEY_KP_9;
_glfw.mir.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL;
_glfw.mir.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL;
_glfw.mir.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER;
for (scancode = 0; scancode < 256; scancode++)
{
if (_glfw.mir.keycodes[scancode] > 0)
_glfw.mir.scancodes[_glfw.mir.keycodes[scancode]] = scancode;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformInit(void)
{
int error;
_glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__);
if (!mir_connection_is_valid(_glfw.mir.connection))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unable to connect to server: %s",
mir_connection_get_error_message(_glfw.mir.connection));
return GLFW_FALSE;
}
_glfw.mir.display =
mir_connection_get_egl_native_display(_glfw.mir.connection);
createKeyTables();
if (!_glfwInitJoysticksLinux())
return GLFW_FALSE;
_glfwInitTimerPOSIX();
_glfw.mir.eventQueue = calloc(1, sizeof(EventQueue));
_glfwInitEventQueueMir(_glfw.mir.eventQueue);
error = pthread_mutex_init(&_glfw.mir.eventMutex, NULL);
if (error)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Failed to create event mutex: %s",
strerror(error));
return GLFW_FALSE;
}
_glfwPollMonitorsMir();
return GLFW_TRUE;
}
void _glfwPlatformTerminate(void)
{
_glfwTerminateEGL();
_glfwTerminateJoysticksLinux();
_glfwDeleteEventQueueMir(_glfw.mir.eventQueue);
pthread_mutex_destroy(&_glfw.mir.eventMutex);
mir_connection_release(_glfw.mir.connection);
}
const char* _glfwPlatformGetVersionString(void)
{
return _GLFW_VERSION_NUMBER " Mir EGL"
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
" clock_gettime"
#else
" gettimeofday"
#endif
" evdev"
#if defined(_GLFW_BUILD_DLL)
" shared"
#endif
;
}

View file

@ -1,218 +0,0 @@
//========================================================================
// GLFW 3.3 Mir - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014-2017 Brandon Schaefer <brandon.schaefer@canonical.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdlib.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Poll for changes in the set of connected monitors
//
void _glfwPollMonitorsMir(void)
{
int i;
MirDisplayConfig* displayConfig =
mir_connection_create_display_configuration(_glfw.mir.connection);
int numOutputs = mir_display_config_get_num_outputs(displayConfig);
for (i = 0; i < numOutputs; i++)
{
const MirOutput* output = mir_display_config_get_output(displayConfig, i);
MirOutputConnectionState state = mir_output_get_connection_state(output);
bool enabled = mir_output_is_enabled(output);
if (enabled && state == mir_output_connection_state_connected)
{
int widthMM = mir_output_get_physical_width_mm(output);
int heightMM = mir_output_get_physical_height_mm(output);
int x = mir_output_get_position_x(output);
int y = mir_output_get_position_y(output);
int id = mir_output_get_id(output);
size_t currentMode = mir_output_get_current_mode_index(output);
const char* name = mir_output_type_name(mir_output_get_type(output));
_GLFWmonitor* monitor = _glfwAllocMonitor(name,
widthMM,
heightMM);
monitor->mir.x = x;
monitor->mir.y = y;
monitor->mir.outputId = id;
monitor->mir.curMode = currentMode;
monitor->modes = _glfwPlatformGetVideoModes(monitor, &monitor->modeCount);
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
}
}
mir_display_config_release(displayConfig);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
if (xpos)
*xpos = monitor->mir.x;
if (ypos)
*ypos = monitor->mir.y;
}
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
if (xscale)
*xscale = 1.f;
if (yscale)
*yscale = 1.f;
}
static void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf)
{
switch (pf)
{
case mir_pixel_format_rgb_565:
mode->redBits = 5;
mode->greenBits = 6;
mode->blueBits = 5;
break;
case mir_pixel_format_rgba_5551:
mode->redBits = 5;
mode->greenBits = 5;
mode->blueBits = 5;
break;
case mir_pixel_format_rgba_4444:
mode->redBits = 4;
mode->greenBits = 4;
mode->blueBits = 4;
break;
case mir_pixel_format_abgr_8888:
case mir_pixel_format_xbgr_8888:
case mir_pixel_format_argb_8888:
case mir_pixel_format_xrgb_8888:
case mir_pixel_format_bgr_888:
case mir_pixel_format_rgb_888:
default:
mode->redBits = 8;
mode->greenBits = 8;
mode->blueBits = 8;
break;
}
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
{
int i;
GLFWvidmode* modes = NULL;
MirDisplayConfig* displayConfig =
mir_connection_create_display_configuration(_glfw.mir.connection);
int numOutputs = mir_display_config_get_num_outputs(displayConfig);
for (i = 0; i < numOutputs; i++)
{
const MirOutput* output = mir_display_config_get_output(displayConfig, i);
int id = mir_output_get_id(output);
if (id != monitor->mir.outputId)
continue;
MirOutputConnectionState state = mir_output_get_connection_state(output);
bool enabled = mir_output_is_enabled(output);
// We must have been disconnected
if (!enabled || state != mir_output_connection_state_connected)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Monitor no longer connected");
return NULL;
}
int numModes = mir_output_get_num_modes(output);
modes = calloc(numModes, sizeof(GLFWvidmode));
for (*found = 0; *found < numModes; (*found)++)
{
const MirOutputMode* mode = mir_output_get_mode(output, *found);
int width = mir_output_mode_get_width(mode);
int height = mir_output_mode_get_height(mode);
double refreshRate = mir_output_mode_get_refresh_rate(mode);
MirPixelFormat currentFormat = mir_output_get_current_pixel_format(output);
modes[*found].width = width;
modes[*found].height = height;
modes[*found].refreshRate = refreshRate;
FillInRGBBitsFromPixelFormat(&modes[*found], currentFormat);
}
break;
}
mir_display_config_release(displayConfig);
return modes;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
*mode = monitor->modes[monitor->mir.curMode];
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(0);
return monitor->mir.outputId;
}

View file

@ -1,133 +0,0 @@
//========================================================================
// GLFW 3.3 Mir - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014-2017 Brandon Schaefer <brandon.schaefer@canonical.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <sys/queue.h>
#include <pthread.h>
#include <dlfcn.h>
#include <mir_toolkit/mir_client_library.h>
typedef VkFlags VkMirWindowCreateFlagsKHR;
typedef struct VkMirWindowCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkMirWindowCreateFlagsKHR flags;
MirConnection* connection;
MirWindow* mirWindow;
} VkMirWindowCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateMirWindowKHR)(VkInstance,const VkMirWindowCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*);
#include "posix_thread.h"
#include "posix_time.h"
#include "linux_joystick.h"
#include "xkb_unicode.h"
#include "egl_context.h"
#include "osmesa_context.h"
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.nativeWindow)
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display)
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorMir mir
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir
#define _GLFW_PLATFORM_CONTEXT_STATE
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
// Mir-specific Event Queue
//
typedef struct EventQueue
{
TAILQ_HEAD(, EventNode) head;
} EventQueue;
// Mir-specific per-window data
//
typedef struct _GLFWwindowMir
{
MirWindow* window;
int width;
int height;
MirEGLNativeWindowType nativeWindow;
_GLFWcursor* currentCursor;
} _GLFWwindowMir;
// Mir-specific per-monitor data
//
typedef struct _GLFWmonitorMir
{
int curMode;
int outputId;
int x;
int y;
} _GLFWmonitorMir;
// Mir-specific global data
//
typedef struct _GLFWlibraryMir
{
MirConnection* connection;
MirEGLNativeDisplayType display;
EventQueue* eventQueue;
short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1];
pthread_mutex_t eventMutex;
pthread_cond_t eventCond;
// The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow;
} _GLFWlibraryMir;
// Mir-specific per-cursor data
// TODO: Only system cursors are implemented in Mir atm. Need to wait for support.
//
typedef struct _GLFWcursorMir
{
MirCursorConfiguration* conf;
MirBufferStream* customCursor;
char const* cursorName; // only needed for system cursors
} _GLFWcursorMir;
extern void _glfwPollMonitorsMir(void);
extern void _glfwInitEventQueueMir(EventQueue* queue);
extern void _glfwDeleteEventQueueMir(EventQueue* queue);

View file

@ -1,975 +0,0 @@
//========================================================================
// GLFW 3.3 Mir - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014-2017 Brandon Schaefer <brandon.schaefer@canonical.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <linux/input.h>
#include <stdlib.h>
#include <string.h>
typedef struct EventNode
{
TAILQ_ENTRY(EventNode) entries;
const MirEvent* event;
_GLFWwindow* window;
} EventNode;
static void deleteNode(EventQueue* queue, EventNode* node)
{
mir_event_unref(node->event);
free(node);
}
static GLFWbool emptyEventQueue(EventQueue* queue)
{
return queue->head.tqh_first == NULL;
}
// TODO The mir_event_ref is not supposed to be used but ... its needed
// in this case. Need to wait until we can read from an FD set up by mir
// for single threaded event handling.
static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context)
{
EventNode* newNode = calloc(1, sizeof(EventNode));
newNode->event = mir_event_ref(event);
newNode->window = context;
return newNode;
}
static void enqueueEvent(const MirEvent* event, _GLFWwindow* context)
{
pthread_mutex_lock(&_glfw.mir.eventMutex);
EventNode* newNode = newEventNode(event, context);
TAILQ_INSERT_TAIL(&_glfw.mir.eventQueue->head, newNode, entries);
pthread_cond_signal(&_glfw.mir.eventCond);
pthread_mutex_unlock(&_glfw.mir.eventMutex);
}
static EventNode* dequeueEvent(EventQueue* queue)
{
EventNode* node = NULL;
pthread_mutex_lock(&_glfw.mir.eventMutex);
node = queue->head.tqh_first;
if (node)
TAILQ_REMOVE(&queue->head, node, entries);
pthread_mutex_unlock(&_glfw.mir.eventMutex);
return node;
}
static MirPixelFormat findValidPixelFormat(void)
{
unsigned int i, validFormats, mirPixelFormats = 32;
MirPixelFormat formats[mir_pixel_formats];
mir_connection_get_available_surface_formats(_glfw.mir.connection, formats,
mirPixelFormats, &validFormats);
for (i = 0; i < validFormats; i++)
{
if (formats[i] == mir_pixel_format_abgr_8888 ||
formats[i] == mir_pixel_format_xbgr_8888 ||
formats[i] == mir_pixel_format_argb_8888 ||
formats[i] == mir_pixel_format_xrgb_8888)
{
return formats[i];
}
}
return mir_pixel_format_invalid;
}
static int mirModToGLFWMod(uint32_t mods)
{
int publicMods = 0x0;
if (mods & mir_input_event_modifier_alt)
publicMods |= GLFW_MOD_ALT;
if (mods & mir_input_event_modifier_shift)
publicMods |= GLFW_MOD_SHIFT;
if (mods & mir_input_event_modifier_ctrl)
publicMods |= GLFW_MOD_CONTROL;
if (mods & mir_input_event_modifier_meta)
publicMods |= GLFW_MOD_SUPER;
if (mods & mir_input_event_modifier_caps_lock)
publicMods |= GLFW_MOD_CAPS_LOCK;
if (mods & mir_input_event_modifier_num_lock)
publicMods |= GLFW_MOD_NUM_LOCK;
return publicMods;
}
static int toGLFWKeyCode(uint32_t key)
{
if (key < sizeof(_glfw.mir.keycodes) / sizeof(_glfw.mir.keycodes[0]))
return _glfw.mir.keycodes[key];
return GLFW_KEY_UNKNOWN;
}
static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window)
{
const int action = mir_keyboard_event_action (key_event);
const int scan_code = mir_keyboard_event_scan_code(key_event);
const int key_code = mir_keyboard_event_key_code (key_event);
const int modifiers = mir_keyboard_event_modifiers(key_event);
const int pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS;
const int mods = mirModToGLFWMod(modifiers);
const long text = _glfwKeySym2Unicode(key_code);
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
_glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods);
if (text != -1)
_glfwInputChar(window, text, mods, plain);
}
static void handlePointerButton(_GLFWwindow* window,
int pressed,
const MirPointerEvent* pointer_event)
{
int mods = mir_pointer_event_modifiers(pointer_event);
const int publicMods = mirModToGLFWMod(mods);
MirPointerButton button = mir_pointer_button_primary;
static uint32_t oldButtonStates = 0;
uint32_t newButtonStates = mir_pointer_event_buttons(pointer_event);
int publicButton = GLFW_MOUSE_BUTTON_LEFT;
// XOR our old button states our new states to figure out what was added or removed
button = newButtonStates ^ oldButtonStates;
switch (button)
{
case mir_pointer_button_primary:
publicButton = GLFW_MOUSE_BUTTON_LEFT;
break;
case mir_pointer_button_secondary:
publicButton = GLFW_MOUSE_BUTTON_RIGHT;
break;
case mir_pointer_button_tertiary:
publicButton = GLFW_MOUSE_BUTTON_MIDDLE;
break;
case mir_pointer_button_forward:
// FIXME What is the forward button?
publicButton = GLFW_MOUSE_BUTTON_4;
break;
case mir_pointer_button_back:
// FIXME What is the back button?
publicButton = GLFW_MOUSE_BUTTON_5;
break;
default:
break;
}
oldButtonStates = newButtonStates;
_glfwInputMouseClick(window, publicButton, pressed, publicMods);
}
static void handlePointerMotion(_GLFWwindow* window,
const MirPointerEvent* pointer_event)
{
const int hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
const int vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
if (_glfw.mir.disabledCursorWindow != window)
return;
const int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x);
const int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y);
const int current_x = window->virtualCursorPosX;
const int current_y = window->virtualCursorPosY;
_glfwInputCursorPos(window, dx + current_x, dy + current_y);
}
else
{
const int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
const int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
_glfwInputCursorPos(window, x, y);
}
if (hscroll != 0 || vscroll != 0)
_glfwInputScroll(window, hscroll, vscroll);
}
static void handlePointerEvent(const MirPointerEvent* pointer_event,
_GLFWwindow* window)
{
int action = mir_pointer_event_action(pointer_event);
switch (action)
{
case mir_pointer_action_button_down:
handlePointerButton(window, GLFW_PRESS, pointer_event);
break;
case mir_pointer_action_button_up:
handlePointerButton(window, GLFW_RELEASE, pointer_event);
break;
case mir_pointer_action_motion:
handlePointerMotion(window, pointer_event);
break;
case mir_pointer_action_enter:
case mir_pointer_action_leave:
break;
default:
break;
}
}
static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window)
{
int type = mir_input_event_get_type(input_event);
switch (type)
{
case mir_input_event_type_key:
handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window);
break;
case mir_input_event_type_pointer:
handlePointerEvent(mir_input_event_get_pointer_event(input_event), window);
break;
default:
break;
}
}
static void handleEvent(const MirEvent* event, _GLFWwindow* window)
{
int type = mir_event_get_type(event);
switch (type)
{
case mir_event_type_input:
handleInput(mir_event_get_input_event(event), window);
break;
default:
break;
}
}
static void addNewEvent(MirWindow* window, const MirEvent* event, void* context)
{
enqueueEvent(event, context);
}
static GLFWbool createWindow(_GLFWwindow* window)
{
MirWindowSpec* spec;
MirBufferUsage buffer_usage = mir_buffer_usage_hardware;
MirPixelFormat pixel_format = findValidPixelFormat();
if (pixel_format == mir_pixel_format_invalid)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unable to find a correct pixel format");
return GLFW_FALSE;
}
spec = mir_create_normal_window_spec(_glfw.mir.connection,
window->mir.width,
window->mir.height);
mir_window_spec_set_pixel_format(spec, pixel_format);
mir_window_spec_set_buffer_usage(spec, buffer_usage);
window->mir.window = mir_create_window_sync(spec);
mir_window_spec_release(spec);
if (!mir_window_is_valid(window->mir.window))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unable to create window: %s",
mir_window_get_error_message(window->mir.window));
return GLFW_FALSE;
}
mir_window_set_event_handler(window->mir.window, addNewEvent, window);
return GLFW_TRUE;
}
static void setWindowConfinement(_GLFWwindow* window, MirPointerConfinementState state)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_pointer_confinement(spec, state);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void _glfwInitEventQueueMir(EventQueue* queue)
{
TAILQ_INIT(&queue->head);
}
void _glfwDeleteEventQueueMir(EventQueue* queue)
{
if (queue)
{
EventNode* node, *node_next;
node = queue->head.tqh_first;
while (node != NULL)
{
node_next = node->entries.tqe_next;
TAILQ_REMOVE(&queue->head, node, entries);
deleteNode(queue, node);
node = node_next;
}
free(queue);
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (window->monitor)
{
GLFWvidmode mode;
_glfwPlatformGetVideoMode(window->monitor, &mode);
mir_window_set_state(window->mir.window, mir_window_state_fullscreen);
if (wndconfig->width > mode.width || wndconfig->height > mode.height)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Requested window size too large: %ix%i",
wndconfig->width, wndconfig->height);
return GLFW_FALSE;
}
}
window->mir.width = wndconfig->width;
window->mir.height = wndconfig->height;
window->mir.currentCursor = NULL;
if (!createWindow(window))
return GLFW_FALSE;
window->mir.nativeWindow = mir_buffer_stream_get_egl_native_window(
mir_window_get_buffer_stream(window->mir.window));
if (ctxconfig->client != GLFW_NO_API)
{
if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||
ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
{
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
{
if (!_glfwInitOSMesa())
return GLFW_FALSE;
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
}
return GLFW_TRUE;
}
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
{
if (_glfw.mir.disabledCursorWindow == window)
_glfw.mir.disabledCursorWindow = NULL;
if (mir_window_is_valid(window->mir.window))
{
mir_window_release_sync(window->mir.window);
window->mir.window= NULL;
}
if (window->context.destroy)
window->context.destroy(window);
}
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_name(spec, title);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
int count, const GLFWimage* images)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_width (spec, width);
mir_window_spec_set_height(spec, height);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_max_width (spec, maxwidth);
mir_window_spec_set_max_height(spec, maxheight);
mir_window_spec_set_min_width (spec, minwidth);
mir_window_spec_set_min_height(spec, minheight);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->mir.width;
if (height)
*height = window->mir.height;
}
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
float* xscale, float* yscale)
{
if (xscale)
*xscale = 1.f;
if (yscale)
*yscale = 1.f;
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_state(spec, mir_window_state_minimized);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_state(spec, mir_window_state_restored);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_state(spec, mir_window_state_maximized);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformHideWindow(_GLFWwindow* window)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_state(spec, mir_window_state_hidden);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformShowWindow(_GLFWwindow* window)
{
MirWindowSpec* spec;
spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_state(spec, mir_window_state_restored);
mir_window_apply_spec(window->mir.window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformFocusWindow(_GLFWwindow* window)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,
int width, int height,
int refreshRate)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
int _glfwPlatformWindowFocused(_GLFWwindow* window)
{
return mir_window_get_focus_state(window->mir.window) == mir_window_focus_state_focused;
}
int _glfwPlatformWindowIconified(_GLFWwindow* window)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
return GLFW_FALSE;
}
int _glfwPlatformWindowVisible(_GLFWwindow* window)
{
return mir_window_get_visibility(window->mir.window) == mir_window_visibility_exposed;
}
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
{
return mir_window_get_state(window->mir.window) == mir_window_state_maximized;
}
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
return GLFW_FALSE;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
return GLFW_FALSE;
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
{
return 1.f;
}
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
{
}
void _glfwPlatformPollEvents(void)
{
EventNode* node = NULL;
while ((node = dequeueEvent(_glfw.mir.eventQueue)))
{
handleEvent(node->event, node->window);
deleteNode(_glfw.mir.eventQueue, node);
}
}
void _glfwPlatformWaitEvents(void)
{
pthread_mutex_lock(&_glfw.mir.eventMutex);
while (emptyEventQueue(_glfw.mir.eventQueue))
pthread_cond_wait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex);
pthread_mutex_unlock(&_glfw.mir.eventMutex);
_glfwPlatformPollEvents();
}
void _glfwPlatformWaitEventsTimeout(double timeout)
{
pthread_mutex_lock(&_glfw.mir.eventMutex);
if (emptyEventQueue(_glfw.mir.eventQueue))
{
struct timespec time;
clock_gettime(CLOCK_REALTIME, &time);
time.tv_sec += (long) timeout;
time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9);
pthread_cond_timedwait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex, &time);
}
pthread_mutex_unlock(&_glfw.mir.eventMutex);
_glfwPlatformPollEvents();
}
void _glfwPlatformPostEmptyEvent(void)
{
}
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->mir.width;
if (height)
*height = window->mir.height;
}
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
MirBufferStream* stream;
int i_w = image->width;
int i_h = image->height;
stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection,
i_w, i_h,
mir_pixel_format_argb_8888,
mir_buffer_usage_software);
cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot);
MirGraphicsRegion region;
mir_buffer_stream_get_graphics_region(stream, &region);
unsigned char* pixels = image->pixels;
char* dest = region.vaddr;
int i;
for (i = 0; i < i_w * i_h; i++, pixels += 4)
{
unsigned int alpha = pixels[3];
*dest++ = (char)(pixels[2] * alpha / 255);
*dest++ = (char)(pixels[1] * alpha / 255);
*dest++ = (char)(pixels[0] * alpha / 255);
*dest++ = (char)alpha;
}
mir_buffer_stream_swap_buffers_sync(stream);
cursor->mir.customCursor = stream;
return GLFW_TRUE;
}
static const char* getSystemCursorName(int shape)
{
switch (shape)
{
case GLFW_ARROW_CURSOR:
return mir_arrow_cursor_name;
case GLFW_IBEAM_CURSOR:
return mir_caret_cursor_name;
case GLFW_CROSSHAIR_CURSOR:
return mir_crosshair_cursor_name;
case GLFW_HAND_CURSOR:
return mir_open_hand_cursor_name;
case GLFW_HRESIZE_CURSOR:
return mir_horizontal_resize_cursor_name;
case GLFW_VRESIZE_CURSOR:
return mir_vertical_resize_cursor_name;
}
return NULL;
}
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{
cursor->mir.conf = NULL;
cursor->mir.customCursor = NULL;
cursor->mir.cursorName = getSystemCursorName(shape);
return cursor->mir.cursorName != NULL;
}
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{
if (cursor->mir.conf)
mir_cursor_configuration_destroy(cursor->mir.conf);
if (cursor->mir.customCursor)
mir_buffer_stream_release_sync(cursor->mir.customCursor);
}
static void setCursorNameForWindow(MirWindow* window, char const* name)
{
MirWindowSpec* spec = mir_create_window_spec(_glfw.mir.connection);
mir_window_spec_set_cursor_name(spec, name);
mir_window_apply_spec(window, spec);
mir_window_spec_release(spec);
}
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{
if (cursor)
{
window->mir.currentCursor = cursor;
if (cursor->mir.cursorName)
{
setCursorNameForWindow(window->mir.window, cursor->mir.cursorName);
}
else if (cursor->mir.conf)
{
mir_window_configure_cursor(window->mir.window, cursor->mir.conf);
}
}
else
{
setCursorNameForWindow(window->mir.window, mir_default_cursor_name);
}
}
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{
if (mode == GLFW_CURSOR_DISABLED)
{
_glfw.mir.disabledCursorWindow = window;
setWindowConfinement(window, mir_pointer_confined_to_window);
setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name);
}
else
{
// If we were disabled before lets undo that!
if (_glfw.mir.disabledCursorWindow == window)
{
_glfw.mir.disabledCursorWindow = NULL;
setWindowConfinement(window, mir_pointer_unconfined);
}
if (window->cursorMode == GLFW_CURSOR_NORMAL)
{
_glfwPlatformSetCursor(window, window->mir.currentCursor);
}
else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
{
setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name);
}
}
}
const char* _glfwPlatformGetScancodeName(int scancode)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
return NULL;
}
int _glfwPlatformGetKeyScancode(int key)
{
return _glfw.mir.scancodes[key];
}
void _glfwPlatformSetClipboardString(const char* string)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
const char* _glfwPlatformGetClipboardString(void)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
return NULL;
}
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
{
if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_mir_surface)
return;
extensions[0] = "VK_KHR_surface";
extensions[1] = "VK_KHR_mir_surface";
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
PFN_vkGetPhysicalDeviceMirPresentationSupportKHR
vkGetPhysicalDeviceMirPresentationSupportKHR =
(PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
if (!vkGetPhysicalDeviceMirPresentationSupportKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Mir: Vulkan instance missing VK_KHR_mir_surface extension");
return GLFW_FALSE;
}
return vkGetPhysicalDeviceMirPresentationSupportKHR(device,
queuefamily,
_glfw.mir.connection);
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
VkResult err;
VkMirWindowCreateInfoKHR sci;
PFN_vkCreateMirWindowKHR vkCreateMirWindowKHR;
vkCreateMirWindowKHR = (PFN_vkCreateMirWindowKHR)
vkGetInstanceProcAddr(instance, "vkCreateMirWindowKHR");
if (!vkCreateMirWindowKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Mir: Vulkan instance missing VK_KHR_mir_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR;
sci.connection = _glfw.mir.connection;
sci.mirWindow = window->mir.window;
err = vkCreateMirWindowKHR(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Failed to create Vulkan surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI MirConnection* glfwGetMirDisplay(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfw.mir.connection;
}
GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return window->mir.window;
}

View file

@ -427,12 +427,12 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
{ {
int i; unsigned int i;
unsigned short values[256]; unsigned short* values;
GLFWgammaramp ramp; GLFWgammaramp ramp;
const GLFWgammaramp* original;
assert(handle != NULL); assert(handle != NULL);
assert(gamma == gamma); assert(gamma > 0.f);
assert(gamma >= 0.f);
assert(gamma <= FLT_MAX); assert(gamma <= FLT_MAX);
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
@ -443,18 +443,22 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
return; return;
} }
for (i = 0; i < 256; i++) original = glfwGetGammaRamp(handle);
if (!original)
return;
values = calloc(original->size, sizeof(unsigned short));
for (i = 0; i < original->size; i++)
{ {
float value; float value;
// Calculate intensity // Calculate intensity
value = i / 255.f; value = i / (float) (original->size - 1);
// Apply gamma curve // Apply gamma curve
value = powf(value, 1.f / gamma) * 65535.f + 0.5f; value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
// Clamp to value range // Clamp to value range
if (value > 65535.f) value = _glfw_fminf(value, 65535.f);
value = 65535.f;
values[i] = (unsigned short) value; values[i] = (unsigned short) value;
} }
@ -462,9 +466,10 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
ramp.red = values; ramp.red = values;
ramp.green = values; ramp.green = values;
ramp.blue = values; ramp.blue = values;
ramp.size = 256; ramp.size = original->size;
glfwSetGammaRamp(handle, &ramp); glfwSetGammaRamp(handle, &ramp);
free(values);
} }
GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
@ -475,7 +480,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_glfwFreeGammaArrays(&monitor->currentRamp); _glfwFreeGammaArrays(&monitor->currentRamp);
_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp); if (!_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp))
return NULL;
return &monitor->currentRamp; return &monitor->currentRamp;
} }
@ -501,7 +507,10 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
if (!monitor->originalRamp.size) if (!monitor->originalRamp.size)
_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp); {
if (!_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp))
return;
}
_glfwPlatformSetGammaRamp(monitor, ramp); _glfwPlatformSetGammaRamp(monitor, ramp);
} }

View file

@ -26,6 +26,10 @@
#include "internal.h" #include "internal.h"
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101400
#define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
#endif
static void makeContextCurrentNSGL(_GLFWwindow* window) static void makeContextCurrentNSGL(_GLFWwindow* window)
{ {
@ -49,7 +53,7 @@ static void swapIntervalNSGL(int interval)
GLint sync = interval; GLint sync = interval;
[window->context.nsgl.object setValues:&sync [window->context.nsgl.object setValues:&sync
forParameter:NSOpenGLCPSwapInterval]; forParameter:NSOpenGLContextParameterSwapInterval];
} }
static int extensionSupportedNSGL(const char* extension) static int extensionSupportedNSGL(const char* extension)
@ -299,7 +303,8 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
if (fbconfig->transparent) if (fbconfig->transparent)
{ {
GLint opaque = 0; GLint opaque = 0;
[window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; [window->context.nsgl.object setValues:&opaque
forParameter:NSOpenGLContextParameterSurfaceOpacity];
} }
[window->context.nsgl.object setView:window->ns.view]; [window->context.nsgl.object setView:window->ns.view];

View file

@ -58,8 +58,9 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{ {
} }
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{ {
return GLFW_FALSE;
} }
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)

View file

@ -240,7 +240,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
if (ctxconfig->forward) if (ctxconfig->forward)
{ {
_glfwInputError(GLFW_VERSION_UNAVAILABLE, _glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: Foward-compatible contexts not supported"); "OSMesa: Forward-compatible contexts not supported");
return GLFW_FALSE; return GLFW_FALSE;
} }

View file

@ -136,9 +136,6 @@ GLFWbool _glfwInitVulkan(int mode)
#elif defined(_GLFW_WAYLAND) #elif defined(_GLFW_WAYLAND)
else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0) else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
_glfw.vk.KHR_wayland_surface = GLFW_TRUE; _glfw.vk.KHR_wayland_surface = GLFW_TRUE;
#elif defined(_GLFW_MIR)
else if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0)
_glfw.vk.KHR_mir_surface = GLFW_TRUE;
#endif #endif
} }

View file

@ -256,12 +256,20 @@ static void makeContextCurrentWGL(_GLFWwindow* window)
static void swapBuffersWGL(_GLFWwindow* window) static void swapBuffersWGL(_GLFWwindow* window)
{ {
// HACK: Use DwmFlush when desktop composition is enabled if (!window->monitor)
if (_glfwIsCompositionEnabledWin32() && !window->monitor)
{ {
int count = abs(window->context.wgl.interval); if (IsWindowsVistaOrGreater())
while (count--) {
DwmFlush(); BOOL enabled;
// HACK: Use DwmFlush when desktop composition is enabled
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
{
int count = abs(window->context.wgl.interval);
while (count--)
DwmFlush();
}
}
} }
SwapBuffers(window->context.wgl.dc); SwapBuffers(window->context.wgl.dc);
@ -273,10 +281,18 @@ static void swapIntervalWGL(int interval)
window->context.wgl.interval = interval; window->context.wgl.interval = interval;
// HACK: Disable WGL swap interval when desktop composition is enabled to if (!window->monitor)
// avoid interfering with DWM vsync {
if (_glfwIsCompositionEnabledWin32() && !window->monitor) if (IsWindowsVistaOrGreater())
interval = 0; {
BOOL enabled;
// HACK: Disable WGL swap interval when desktop composition is enabled to
// avoid interfering with DWM vsync
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
interval = 0;
}
}
if (_glfw.wgl.EXT_swap_control) if (_glfw.wgl.EXT_swap_control)
_glfw.wgl.SwapIntervalEXT(interval); _glfw.wgl.SwapIntervalEXT(interval);
@ -284,29 +300,17 @@ static void swapIntervalWGL(int interval)
static int extensionSupportedWGL(const char* extension) static int extensionSupportedWGL(const char* extension)
{ {
const char* extensions; const char* extensions = NULL;
if (_glfw.wgl.GetExtensionsStringEXT)
{
extensions = _glfw.wgl.GetExtensionsStringEXT();
if (extensions)
{
if (_glfwStringInExtensionString(extension, extensions))
return GLFW_TRUE;
}
}
if (_glfw.wgl.GetExtensionsStringARB) if (_glfw.wgl.GetExtensionsStringARB)
{
extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC()); extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
if (extensions) else if (_glfw.wgl.GetExtensionsStringEXT)
{ extensions = _glfw.wgl.GetExtensionsStringEXT();
if (_glfwStringInExtensionString(extension, extensions))
return GLFW_TRUE;
}
}
return GLFW_FALSE; if (!extensions)
return GLFW_FALSE;
return _glfwStringInExtensionString(extension, extensions);
} }
static GLFWglproc getProcAddressWGL(const char* procname) static GLFWglproc getProcAddressWGL(const char* procname)

View file

@ -62,17 +62,6 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
#endif // _GLFW_BUILD_DLL #endif // _GLFW_BUILD_DLL
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
{
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp };
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
return VerifyVersionInfoW(&osvi, mask, cond);
}
// Load necessary libraries (DLLs) // Load necessary libraries (DLLs)
// //
static GLFWbool loadLibraries(void) static GLFWbool loadLibraries(void)
@ -100,6 +89,14 @@ static GLFWbool loadLibraries(void)
GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware");
_glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx) _glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx)
GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
_glfw.win32.user32.EnableNonClientDpiScaling_ = (PFN_EnableNonClientDpiScaling)
GetProcAddress(_glfw.win32.user32.instance, "EnableNonClientDpiScaling");
_glfw.win32.user32.SetProcessDpiAwarenessContext_ = (PFN_SetProcessDpiAwarenessContext)
GetProcAddress(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext");
_glfw.win32.user32.GetDpiForWindow_ = (PFN_GetDpiForWindow)
GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow");
_glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi)
GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");
_glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
if (_glfw.win32.dinput8.instance) if (_glfw.win32.dinput8.instance)
@ -155,6 +152,13 @@ static GLFWbool loadLibraries(void)
GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor"); GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor");
} }
_glfw.win32.ntdll.instance = LoadLibraryA("ntdll.dll");
if (_glfw.win32.ntdll.instance)
{
_glfw.win32.ntdll.RtlVerifyVersionInfo_ = (PFN_RtlVerifyVersionInfo)
GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
}
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -179,6 +183,9 @@ static void freeLibraries(void)
if (_glfw.win32.shcore.instance) if (_glfw.win32.shcore.instance)
FreeLibrary(_glfw.win32.shcore.instance); FreeLibrary(_glfw.win32.shcore.instance);
if (_glfw.win32.ntdll.instance)
FreeLibrary(_glfw.win32.ntdll.instance);
} }
// Create key code translation tables // Create key code translation tables
@ -309,6 +316,7 @@ static void createKeyTables(void)
_glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL; _glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL;
_glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE; _glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE;
_glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER; _glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER;
_glfw.win32.keycodes[0x059] = GLFW_KEY_KP_EQUAL;
_glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY; _glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY;
_glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT; _glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT;
@ -339,8 +347,8 @@ static HWND createHelperWindow(void)
return NULL; return NULL;
} }
// HACK: The first call to ShowWindow is ignored if the parent process // HACK: The command to the first ShowWindow call is ignored if the parent
// passed along a STARTUPINFO, so clear that flag with a no-op call // process passed along a STARTUPINFO, so clear that with a no-op call
ShowWindow(window, SW_HIDE); ShowWindow(window, SW_HIDE);
// Register for HID device notifications // Register for HID device notifications
@ -502,6 +510,36 @@ void _glfwUpdateKeyNamesWin32(void)
} }
} }
// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h
//
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp)
{
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp };
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embedd a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
}
// Checks whether we are on at least the specified build of Windows 10
//
BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build)
{
OSVERSIONINFOEXW osvi = { sizeof(osvi), 10, 0, build };
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER;
ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL);
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embedd a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW platform API ////// ////// GLFW platform API //////
@ -523,7 +561,9 @@ int _glfwPlatformInit(void)
createKeyTables(); createKeyTables();
_glfwUpdateKeyNamesWin32(); _glfwUpdateKeyNamesWin32();
if (IsWindows8Point1OrGreater()) if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
else if (IsWindows8Point1OrGreater())
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
else if (IsWindowsVistaOrGreater()) else if (IsWindowsVistaOrGreater())
SetProcessDPIAware(); SetProcessDPIAware();

View file

@ -260,6 +260,8 @@ static void closeJoystick(_GLFWjoystick* js)
IDirectInputDevice8_Release(js->win32.device); IDirectInputDevice8_Release(js->win32.device);
} }
free(js->win32.objects);
_glfwFreeJoystick(js); _glfwFreeJoystick(js);
_glfwInputJoystick(js, GLFW_DISCONNECTED); _glfwInputJoystick(js, GLFW_DISCONNECTED);
} }

View file

@ -324,9 +324,9 @@ void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* ysc
} }
if (xscale) if (xscale)
*xscale = xdpi / 96.f; *xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI;
if (yscale) if (yscale)
*yscale = ydpi / 96.f; *yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI;
} }
@ -455,7 +455,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
&mode->blueBits); &mode->blueBits);
} }
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{ {
HDC dc; HDC dc;
WORD values[768]; WORD values[768];
@ -469,6 +469,8 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short)); memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short));
memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short)); memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short)); memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short));
return GLFW_TRUE;
} }
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)

View file

@ -98,6 +98,12 @@
#ifndef _WIN32_WINNT_WINBLUE #ifndef _WIN32_WINNT_WINBLUE
#define _WIN32_WINNT_WINBLUE 0x0602 #define _WIN32_WINNT_WINBLUE 0x0602
#endif #endif
#ifndef WM_GETDPISCALEDSIZE
#define WM_GETDPISCALEDSIZE 0x02e4
#endif
#ifndef USER_DEFAULT_SCREEN_DPI
#define USER_DEFAULT_SCREEN_DPI 96
#endif
#if WINVER < 0x0601 #if WINVER < 0x0601
typedef struct typedef struct
@ -140,20 +146,31 @@ typedef enum
} MONITOR_DPI_TYPE; } MONITOR_DPI_TYPE;
#endif /*DPI_ENUMS_DECLARED*/ #endif /*DPI_ENUMS_DECLARED*/
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4)
#endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header // HACK: Define versionhelpers.h functions manually as MinGW lacks the header
BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp); #define IsWindowsXPOrGreater() \
#define IsWindowsVistaOrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINXP), \
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), \ LOBYTE(_WIN32_WINNT_WINXP), 0)
LOBYTE(_WIN32_WINNT_VISTA), 0) #define IsWindowsVistaOrGreater() \
#define IsWindows7OrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), \ LOBYTE(_WIN32_WINNT_VISTA), 0)
LOBYTE(_WIN32_WINNT_WIN7), 0) #define IsWindows7OrGreater() \
#define IsWindows8OrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN7), \
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), \ LOBYTE(_WIN32_WINNT_WIN7), 0)
LOBYTE(_WIN32_WINNT_WIN8), 0) #define IsWindows8OrGreater() \
#define IsWindows8Point1OrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN8), \
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), \ LOBYTE(_WIN32_WINNT_WIN8), 0)
LOBYTE(_WIN32_WINNT_WINBLUE), 0) #define IsWindows8Point1OrGreater() \
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \
LOBYTE(_WIN32_WINNT_WINBLUE), 0)
#define _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() \
_glfwIsWindows10BuildOrGreaterWin32(14393)
#define _glfwIsWindows10CreatorsUpdateOrGreaterWin32() \
_glfwIsWindows10BuildOrGreaterWin32(15063)
// HACK: Define macros that some xinput.h variants don't // HACK: Define macros that some xinput.h variants don't
#ifndef XINPUT_CAPS_WIRELESS #ifndef XINPUT_CAPS_WIRELESS
@ -206,8 +223,16 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*
// user32.dll function pointer typedefs // user32.dll function pointer typedefs
typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void);
typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*); typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*);
typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND);
typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE);
typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND);
typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
#define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_
#define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_
#define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_
#define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_
// dwmapi.dll function pointer typedefs // dwmapi.dll function pointer typedefs
typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
@ -223,6 +248,10 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,
#define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_ #define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_
#define GetDpiForMonitor _glfw.win32.shcore.GetDpiForMonitor_ #define GetDpiForMonitor _glfw.win32.shcore.GetDpiForMonitor_
// ntdll.dll function pointer typedefs
typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG);
#define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_
typedef VkFlags VkWin32SurfaceCreateFlagsKHR; typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
typedef struct VkWin32SurfaceCreateInfoKHR typedef struct VkWin32SurfaceCreateInfoKHR
@ -276,6 +305,7 @@ typedef struct _GLFWwindowWin32
GLFWbool maximized; GLFWbool maximized;
// Whether to enable framebuffer transparency on DWM // Whether to enable framebuffer transparency on DWM
GLFWbool transparent; GLFWbool transparent;
GLFWbool scaleToMonitor;
// The last received cursor position, regardless of source // The last received cursor position, regardless of source
int lastCursorPosX, lastCursorPosY; int lastCursorPosX, lastCursorPosY;
@ -300,6 +330,7 @@ typedef struct _GLFWlibraryWin32
_GLFWwindow* disabledCursorWindow; _GLFWwindow* disabledCursorWindow;
RAWINPUT* rawInput; RAWINPUT* rawInput;
int rawInputSize; int rawInputSize;
UINT mouseTrailSize;
struct { struct {
HINSTANCE instance; HINSTANCE instance;
@ -322,6 +353,10 @@ typedef struct _GLFWlibraryWin32
HINSTANCE instance; HINSTANCE instance;
PFN_SetProcessDPIAware SetProcessDPIAware_; PFN_SetProcessDPIAware SetProcessDPIAware_;
PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_; PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_;
PFN_EnableNonClientDpiScaling EnableNonClientDpiScaling_;
PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_;
PFN_GetDpiForWindow GetDpiForWindow_;
PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_;
} user32; } user32;
struct { struct {
@ -337,6 +372,11 @@ typedef struct _GLFWlibraryWin32
PFN_GetDpiForMonitor GetDpiForMonitor_; PFN_GetDpiForMonitor GetDpiForMonitor_;
} shcore; } shcore;
struct {
HINSTANCE instance;
PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_;
} ntdll;
} _GLFWlibraryWin32; } _GLFWlibraryWin32;
// Win32-specific per-monitor data // Win32-specific per-monitor data
@ -392,10 +432,11 @@ typedef struct _GLFWmutexWin32
GLFWbool _glfwRegisterWindowClassWin32(void); GLFWbool _glfwRegisterWindowClassWin32(void);
void _glfwUnregisterWindowClassWin32(void); void _glfwUnregisterWindowClassWin32(void);
GLFWbool _glfwIsCompositionEnabledWin32(void);
WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source);
char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp);
BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build);
void _glfwInputErrorWin32(int error, const char* description); void _glfwInputErrorWin32(int error, const char* description);
void _glfwUpdateKeyNamesWin32(void); void _glfwUpdateKeyNamesWin32(void);

View file

@ -186,14 +186,20 @@ static HICON createIcon(const GLFWimage* image,
return handle; return handle;
} }
// Translate client window size to full window size according to styles // Translate client window size to full window size according to styles and DPI
// //
static void getFullWindowSize(DWORD style, DWORD exStyle, static void getFullWindowSize(DWORD style, DWORD exStyle,
int clientWidth, int clientHeight, int clientWidth, int clientHeight,
int* fullWidth, int* fullHeight) int* fullWidth, int* fullHeight,
UINT dpi)
{ {
RECT rect = { 0, 0, clientWidth, clientHeight }; RECT rect = { 0, 0, clientWidth, clientHeight };
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
else
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
*fullWidth = rect.right - rect.left; *fullWidth = rect.right - rect.left;
*fullHeight = rect.bottom - rect.top; *fullHeight = rect.bottom - rect.top;
} }
@ -203,10 +209,14 @@ static void getFullWindowSize(DWORD style, DWORD exStyle,
static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
{ {
int xoff, yoff; int xoff, yoff;
UINT dpi = USER_DEFAULT_SCREEN_DPI;
const float ratio = (float) window->numer / (float) window->denom; const float ratio = (float) window->numer / (float) window->denom;
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
dpi = GetDpiForWindow(window->win32.handle);
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
0, 0, &xoff, &yoff); 0, 0, &xoff, &yoff, dpi);
if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT ||
edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
@ -337,7 +347,16 @@ static void updateWindowStyles(const _GLFWwindow* window)
style |= getWindowStyle(window); style |= getWindowStyle(window);
GetClientRect(window->win32.handle, &rect); GetClientRect(window->win32.handle, &rect);
AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, style, FALSE,
getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
ClientToScreen(window->win32.handle, (POINT*) &rect.left); ClientToScreen(window->win32.handle, (POINT*) &rect.left);
ClientToScreen(window->win32.handle, (POINT*) &rect.right); ClientToScreen(window->win32.handle, (POINT*) &rect.right);
SetWindowLongW(window->win32.handle, GWL_STYLE, style); SetWindowLongW(window->win32.handle, GWL_STYLE, style);
@ -351,10 +370,12 @@ static void updateWindowStyles(const _GLFWwindow* window)
// //
static void updateFramebufferTransparency(const _GLFWwindow* window) static void updateFramebufferTransparency(const _GLFWwindow* window)
{ {
BOOL enabled;
if (!IsWindowsVistaOrGreater()) if (!IsWindowsVistaOrGreater())
return; return;
if (_glfwIsCompositionEnabledWin32()) if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
{ {
HRGN region = CreateRectRgn(0, 0, -1, -1); HRGN region = CreateRectRgn(0, 0, -1, -1);
DWM_BLURBEHIND bb = {0}; DWM_BLURBEHIND bb = {0};
@ -396,29 +417,6 @@ static void updateFramebufferTransparency(const _GLFWwindow* window)
} }
} }
// Translates a GLFW standard cursor to a resource ID
//
static LPWSTR translateCursorShape(int shape)
{
switch (shape)
{
case GLFW_ARROW_CURSOR:
return IDC_ARROW;
case GLFW_IBEAM_CURSOR:
return IDC_IBEAM;
case GLFW_CROSSHAIR_CURSOR:
return IDC_CROSS;
case GLFW_HAND_CURSOR:
return IDC_HAND;
case GLFW_HRESIZE_CURSOR:
return IDC_SIZEWE;
case GLFW_VRESIZE_CURSOR:
return IDC_SIZENS;
}
return NULL;
}
// Retrieves and translates modifier keys // Retrieves and translates modifier keys
// //
static int getKeyMods(void) static int getKeyMods(void)
@ -529,7 +527,18 @@ static void fitToMonitor(_GLFWwindow* window)
static void acquireMonitor(_GLFWwindow* window) static void acquireMonitor(_GLFWwindow* window)
{ {
if (!_glfw.win32.acquiredMonitorCount) if (!_glfw.win32.acquiredMonitorCount)
{
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
// HACK: When mouse trails are enabled the cursor becomes invisible when
// the OpenGL ICD switches to page flipping
if (IsWindowsXPOrGreater())
{
SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0);
}
}
if (!window->monitor->window) if (!window->monitor->window)
_glfw.win32.acquiredMonitorCount++; _glfw.win32.acquiredMonitorCount++;
@ -546,8 +555,14 @@ static void releaseMonitor(_GLFWwindow* window)
_glfw.win32.acquiredMonitorCount--; _glfw.win32.acquiredMonitorCount--;
if (!_glfw.win32.acquiredMonitorCount) if (!_glfw.win32.acquiredMonitorCount)
{
SetThreadExecutionState(ES_CONTINUOUS); SetThreadExecutionState(ES_CONTINUOUS);
// HACK: Restore mouse trail length saved in acquireMonitor
if (IsWindowsXPOrGreater())
SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
}
_glfwInputMonitorWindow(window->monitor, NULL); _glfwInputMonitorWindow(window->monitor, NULL);
_glfwRestoreVideoModeWin32(window->monitor); _glfwRestoreVideoModeWin32(window->monitor);
} }
@ -561,9 +576,18 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
if (!window) if (!window)
{ {
// This is the message handling for the hidden helper window // This is the message handling for the hidden helper window
// and for a regular window during its initial creation
switch (uMsg) switch (uMsg)
{ {
case WM_NCCREATE:
{
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
EnableNonClientDpiScaling(hWnd);
break;
}
case WM_DISPLAYCHANGE: case WM_DISPLAYCHANGE:
_glfwPollMonitorsWin32(); _glfwPollMonitorsWin32();
break; break;
@ -980,13 +1004,17 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_GETMINMAXINFO: case WM_GETMINMAXINFO:
{ {
int xoff, yoff; int xoff, yoff;
UINT dpi = USER_DEFAULT_SCREEN_DPI;
MINMAXINFO* mmi = (MINMAXINFO*) lParam; MINMAXINFO* mmi = (MINMAXINFO*) lParam;
if (window->monitor) if (window->monitor)
break; break;
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
dpi = GetDpiForWindow(window->win32.handle);
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
0, 0, &xoff, &yoff); 0, 0, &xoff, &yoff, dpi);
if (window->minwidth != GLFW_DONT_CARE && if (window->minwidth != GLFW_DONT_CARE &&
window->minheight != GLFW_DONT_CARE) window->minheight != GLFW_DONT_CARE)
@ -1032,6 +1060,17 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
return TRUE; return TRUE;
} }
case WM_NCACTIVATE:
case WM_NCPAINT:
{
// Prevent title bar from being drawn after restoring a minimized
// undecorated window
if (!window->decorated)
return TRUE;
break;
}
case WM_DWMCOMPOSITIONCHANGED: case WM_DWMCOMPOSITIONCHANGED:
{ {
if (window->win32.transparent) if (window->win32.transparent)
@ -1039,10 +1078,52 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
return 0; return 0;
} }
case WM_GETDPISCALEDSIZE:
{
if (window->win32.scaleToMonitor)
break;
// Adjust the window size to keep the client area size constant
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
{
RECT source = {0}, target = {0};
SIZE* size = (SIZE*) lParam;
AdjustWindowRectExForDpi(&source, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
AdjustWindowRectExForDpi(&target, getWindowStyle(window),
FALSE, getWindowExStyle(window),
LOWORD(wParam));
size->cx += (target.right - target.left) -
(source.right - source.left);
size->cy += (target.bottom - target.top) -
(source.bottom - source.top);
return TRUE;
}
break;
}
case WM_DPICHANGED: case WM_DPICHANGED:
{ {
const float xscale = HIWORD(wParam) / 96.f; const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
const float yscale = LOWORD(wParam) / 96.f; const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
// Only apply the suggested size if the OS is new enough to have
// sent a WM_GETDPISCALEDSIZE before this
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
{
RECT* suggested = (RECT*) lParam;
SetWindowPos(window->win32.handle, HWND_TOP,
suggested->left,
suggested->top,
suggested->right - suggested->left,
suggested->bottom - suggested->top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
_glfwInputWindowContentScale(window, xscale, yscale); _glfwInputWindowContentScale(window, xscale, yscale);
break; break;
} }
@ -1129,7 +1210,8 @@ static int createNativeWindow(_GLFWwindow* window,
getFullWindowSize(style, exStyle, getFullWindowSize(style, exStyle,
wndconfig->width, wndconfig->height, wndconfig->width, wndconfig->height,
&fullWidth, &fullHeight); &fullWidth, &fullHeight,
USER_DEFAULT_SCREEN_DPI);
} }
wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
@ -1168,6 +1250,40 @@ static int createNativeWindow(_GLFWwindow* window,
WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
} }
window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
// Adjust window size to account for DPI scaling of the window frame and
// optionally DPI scaling of the client area
// This cannot be done until we know what monitor it was placed on
if (!window->monitor)
{
RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
if (wndconfig->scaleToMonitor)
{
float xscale, yscale;
_glfwPlatformGetWindowContentScale(window, &xscale, &yscale);
rect.right = (int) (rect.right * xscale);
rect.bottom = (int) (rect.bottom * yscale);
}
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
GetDpiForWindow(window->win32.handle));
}
else
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
SetWindowPos(window->win32.handle, NULL,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
DragAcceptFiles(window->win32.handle, TRUE); DragAcceptFiles(window->win32.handle, TRUE);
if (fbconfig->transparent) if (fbconfig->transparent)
@ -1227,20 +1343,6 @@ void _glfwUnregisterWindowClassWin32(void)
UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
} }
// Returns whether desktop compositing is enabled
//
GLFWbool _glfwIsCompositionEnabledWin32(void)
{
if (IsWindowsVistaOrGreater())
{
BOOL enabled;
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)))
return enabled;
}
return FALSE;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW platform API ////// ////// GLFW platform API //////
@ -1378,8 +1480,19 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
{ {
RECT rect = { xpos, ypos, xpos, ypos }; RECT rect = { xpos, ypos, xpos, ypos };
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window)); if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0, SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
} }
@ -1408,8 +1521,19 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
else else
{ {
RECT rect = { 0, 0, width, height }; RECT rect = { 0, 0, width, height };
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window)); if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
SetWindowPos(window->win32.handle, HWND_TOP, SetWindowPos(window->win32.handle, HWND_TOP,
0, 0, rect.right - rect.left, rect.bottom - rect.top, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
@ -1464,8 +1588,18 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
_glfwPlatformGetWindowSize(window, &width, &height); _glfwPlatformGetWindowSize(window, &width, &height);
SetRect(&rect, 0, 0, width, height); SetRect(&rect, 0, 0, width, height);
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window)); if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
if (left) if (left)
*left = -rect.left; *left = -rect.left;
@ -1541,8 +1675,19 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
else else
{ {
RECT rect = { xpos, ypos, xpos + width, ypos + height }; RECT rect = { xpos, ypos, xpos + width, ypos + height };
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window)); if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
SetWindowPos(window->win32.handle, HWND_TOP, SetWindowPos(window->win32.handle, HWND_TOP,
rect.left, rect.top, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top, rect.right - rect.left, rect.bottom - rect.top,
@ -1602,8 +1747,18 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
else else
after = HWND_NOTOPMOST; after = HWND_NOTOPMOST;
AdjustWindowRectEx(&rect, getWindowStyle(window), if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
FALSE, getWindowExStyle(window)); {
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
SetWindowPos(window->win32.handle, after, SetWindowPos(window->win32.handle, after,
rect.left, rect.top, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top, rect.right - rect.left, rect.bottom - rect.top,
@ -1638,7 +1793,15 @@ int _glfwPlatformWindowHovered(_GLFWwindow* window)
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{ {
return window->win32.transparent && _glfwIsCompositionEnabledWin32(); BOOL enabled;
if (!window->win32.transparent)
return GLFW_FALSE;
if (!IsWindowsVistaOrGreater())
return GLFW_FALSE;
return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled;
} }
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
@ -1845,8 +2008,24 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{ {
cursor->win32.handle = LPCWSTR name = NULL;
CopyCursor(LoadCursorW(NULL, translateCursorShape(shape)));
if (shape == GLFW_ARROW_CURSOR)
name = IDC_ARROW;
else if (shape == GLFW_IBEAM_CURSOR)
name = IDC_IBEAM;
else if (shape == GLFW_CROSSHAIR_CURSOR)
name = IDC_CROSS;
else if (shape == GLFW_HAND_CURSOR)
name = IDC_HAND;
else if (shape == GLFW_HRESIZE_CURSOR)
name = IDC_SIZEWE;
else if (shape == GLFW_VRESIZE_CURSOR)
name = IDC_SIZENS;
else
return GLFW_FALSE;
cursor->win32.handle = CopyCursor(LoadCursorW(NULL, name));
if (!cursor->win32.handle) if (!cursor->win32.handle)
{ {
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,

View file

@ -369,6 +369,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_COCOA_GRAPHICS_SWITCHING: case GLFW_COCOA_GRAPHICS_SWITCHING:
_glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
return; return;
case GLFW_SCALE_TO_MONITOR:
_glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_CENTER_CURSOR: case GLFW_CENTER_CURSOR:
_glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE;
return; return;

View file

@ -27,6 +27,8 @@
#include "internal.h" #include "internal.h"
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <limits.h>
#include <linux/input.h> #include <linux/input.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -42,7 +44,8 @@ static inline int min(int n1, int n2)
return n1 < n2 ? n1 : n2; return n1 < n2 ? n1 : n2;
} }
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, int* which) static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
int* which)
{ {
int focus; int focus;
_GLFWwindow* window = _glfw.windowListHead; _GLFWwindow* window = _glfw.windowListHead;
@ -96,7 +99,7 @@ static void pointerHandleEnter(void* data,
} }
window->wl.decorations.focus = focus; window->wl.decorations.focus = focus;
_glfw.wl.pointerSerial = serial; _glfw.wl.serial = serial;
_glfw.wl.pointerFocus = window; _glfw.wl.pointerFocus = window;
window->wl.hovered = GLFW_TRUE; window->wl.hovered = GLFW_TRUE;
@ -117,26 +120,36 @@ static void pointerHandleLeave(void* data,
window->wl.hovered = GLFW_FALSE; window->wl.hovered = GLFW_FALSE;
_glfw.wl.pointerSerial = serial; _glfw.wl.serial = serial;
_glfw.wl.pointerFocus = NULL; _glfw.wl.pointerFocus = NULL;
_glfwInputCursorEnter(window, GLFW_FALSE); _glfwInputCursorEnter(window, GLFW_FALSE);
} }
static void setCursor(const char* name) static void setCursor(_GLFWwindow* window, const char* name)
{ {
struct wl_buffer* buffer; struct wl_buffer* buffer;
struct wl_cursor* cursor; struct wl_cursor* cursor;
struct wl_cursor_image* image; struct wl_cursor_image* image;
struct wl_surface* surface = _glfw.wl.cursorSurface; struct wl_surface* surface = _glfw.wl.cursorSurface;
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
int scale = 1;
cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI)
name); {
// We only support up to scale=2 for now, since libwayland-cursor
// requires us to load a different theme for each size.
scale = 2;
theme = _glfw.wl.cursorThemeHiDPI;
}
cursor = wl_cursor_theme_get_cursor(theme, name);
if (!cursor) if (!cursor)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Standard cursor not found"); "Wayland: Standard cursor not found");
return; return;
} }
// TODO: handle animated cursors too.
image = cursor->images[0]; image = cursor->images[0];
if (!image) if (!image)
@ -145,10 +158,11 @@ static void setCursor(const char* name)
buffer = wl_cursor_image_get_buffer(image); buffer = wl_cursor_image_get_buffer(image);
if (!buffer) if (!buffer)
return; return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
surface, surface,
image->hotspot_x, image->hotspot_x / scale,
image->hotspot_y); image->hotspot_y / scale);
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buffer, 0, 0); wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0, wl_surface_damage(surface, 0, 0,
image->width, image->height); image->width, image->height);
@ -211,7 +225,7 @@ static void pointerHandleMotion(void* data,
default: default:
assert(0); assert(0);
} }
setCursor(cursorName); setCursor(window, cursorName);
} }
static void pointerHandleButton(void* data, static void pointerHandleButton(void* data,
@ -295,7 +309,7 @@ static void pointerHandleButton(void* data,
if (window->wl.decorations.focus != mainWindow) if (window->wl.decorations.focus != mainWindow)
return; return;
_glfw.wl.pointerSerial = serial; _glfw.wl.serial = serial;
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
* codes. */ * codes. */
@ -464,6 +478,7 @@ static void keyboardHandleEnter(void* data,
return; return;
} }
_glfw.wl.serial = serial;
_glfw.wl.keyboardFocus = window; _glfw.wl.keyboardFocus = window;
_glfwInputWindowFocus(window, GLFW_TRUE); _glfwInputWindowFocus(window, GLFW_TRUE);
} }
@ -478,6 +493,7 @@ static void keyboardHandleLeave(void* data,
if (!window) if (!window)
return; return;
_glfw.wl.serial = serial;
_glfw.wl.keyboardFocus = NULL; _glfw.wl.keyboardFocus = NULL;
_glfwInputWindowFocus(window, GLFW_FALSE); _glfwInputWindowFocus(window, GLFW_FALSE);
} }
@ -561,6 +577,7 @@ static void keyboardHandleKey(void* data,
action = state == WL_KEYBOARD_KEY_STATE_PRESSED action = state == WL_KEYBOARD_KEY_STATE_PRESSED
? GLFW_PRESS : GLFW_RELEASE; ? GLFW_PRESS : GLFW_RELEASE;
_glfw.wl.serial = serial;
_glfwInputKey(window, keyCode, key, action, _glfwInputKey(window, keyCode, key, action,
_glfw.wl.xkb.modifiers); _glfw.wl.xkb.modifiers);
@ -592,6 +609,8 @@ static void keyboardHandleModifiers(void* data,
xkb_mod_mask_t mask; xkb_mod_mask_t mask;
unsigned int modifiers = 0; unsigned int modifiers = 0;
_glfw.wl.serial = serial;
if (!_glfw.wl.xkb.keymap) if (!_glfw.wl.xkb.keymap)
return; return;
@ -686,6 +705,70 @@ static const struct wl_seat_listener seatListener = {
seatHandleName, seatHandleName,
}; };
static void dataOfferHandleOffer(void* data,
struct wl_data_offer* dataOffer,
const char* mimeType)
{
}
static const struct wl_data_offer_listener dataOfferListener = {
dataOfferHandleOffer,
};
static void dataDeviceHandleDataOffer(void* data,
struct wl_data_device* dataDevice,
struct wl_data_offer* id)
{
if (_glfw.wl.dataOffer)
wl_data_offer_destroy(_glfw.wl.dataOffer);
_glfw.wl.dataOffer = id;
wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL);
}
static void dataDeviceHandleEnter(void* data,
struct wl_data_device* dataDevice,
uint32_t serial,
struct wl_surface *surface,
wl_fixed_t x,
wl_fixed_t y,
struct wl_data_offer *id)
{
}
static void dataDeviceHandleLeave(void* data,
struct wl_data_device* dataDevice)
{
}
static void dataDeviceHandleMotion(void* data,
struct wl_data_device* dataDevice,
uint32_t time,
wl_fixed_t x,
wl_fixed_t y)
{
}
static void dataDeviceHandleDrop(void* data,
struct wl_data_device* dataDevice)
{
}
static void dataDeviceHandleSelection(void* data,
struct wl_data_device* dataDevice,
struct wl_data_offer* id)
{
}
static const struct wl_data_device_listener dataDeviceListener = {
dataDeviceHandleDataOffer,
dataDeviceHandleEnter,
dataDeviceHandleLeave,
dataDeviceHandleMotion,
dataDeviceHandleDrop,
dataDeviceHandleSelection,
};
static void wmBaseHandlePing(void* data, static void wmBaseHandlePing(void* data,
struct xdg_wm_base* wmBase, struct xdg_wm_base* wmBase,
uint32_t serial) uint32_t serial)
@ -740,12 +823,28 @@ static void registryHandleGlobal(void* data,
wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
} }
} }
else if (strcmp(interface, "wl_data_device_manager") == 0)
{
if (!_glfw.wl.dataDeviceManager)
{
_glfw.wl.dataDeviceManager =
wl_registry_bind(registry, name,
&wl_data_device_manager_interface, 1);
}
}
else if (strcmp(interface, "xdg_wm_base") == 0) else if (strcmp(interface, "xdg_wm_base") == 0)
{ {
_glfw.wl.wmBase = _glfw.wl.wmBase =
wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL); xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
} }
else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0)
{
_glfw.wl.decorationManager =
wl_registry_bind(registry, name,
&zxdg_decoration_manager_v1_interface,
1);
}
else if (strcmp(interface, "wp_viewporter") == 0) else if (strcmp(interface, "wp_viewporter") == 0)
{ {
_glfw.wl.viewporter = _glfw.wl.viewporter =
@ -939,6 +1038,12 @@ static void createKeyTables(void)
int _glfwPlatformInit(void) int _glfwPlatformInit(void)
{ {
const char *cursorTheme;
const char *cursorSizeStr;
char *cursorSizeEnd;
long cursorSizeLong;
int cursorSize;
_glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0"); _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
if (!_glfw.wl.cursor.handle) if (!_glfw.wl.cursor.handle)
{ {
@ -1059,15 +1164,46 @@ int _glfwPlatformInit(void)
if (_glfw.wl.pointer && _glfw.wl.shm) if (_glfw.wl.pointer && _glfw.wl.shm)
{ {
_glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm); cursorTheme = getenv("XCURSOR_THEME");
cursorSizeStr = getenv("XCURSOR_SIZE");
cursorSize = 32;
if (cursorSizeStr)
{
errno = 0;
cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10);
if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX)
cursorSize = (int)cursorSizeLong;
}
_glfw.wl.cursorTheme =
wl_cursor_theme_load(cursorTheme, cursorSize, _glfw.wl.shm);
if (!_glfw.wl.cursorTheme) if (!_glfw.wl.cursorTheme)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unable to load default cursor theme"); "Wayland: Unable to load default cursor theme");
return GLFW_FALSE; return GLFW_FALSE;
} }
// If this happens to be NULL, we just fallback to the scale=1 version.
_glfw.wl.cursorThemeHiDPI =
wl_cursor_theme_load(cursorTheme, 2 * cursorSize, _glfw.wl.shm);
_glfw.wl.cursorSurface = _glfw.wl.cursorSurface =
wl_compositor_create_surface(_glfw.wl.compositor); wl_compositor_create_surface(_glfw.wl.compositor);
_glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
}
if (_glfw.wl.seat && _glfw.wl.dataDeviceManager)
{
_glfw.wl.dataDevice =
wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
_glfw.wl.seat);
wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
_glfw.wl.clipboardString = malloc(4096);
if (!_glfw.wl.clipboardString)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unable to allocate clipboard memory");
return GLFW_FALSE;
}
_glfw.wl.clipboardSize = 4096;
} }
return GLFW_TRUE; return GLFW_TRUE;
@ -1103,6 +1239,8 @@ void _glfwPlatformTerminate(void)
if (_glfw.wl.cursorTheme) if (_glfw.wl.cursorTheme)
wl_cursor_theme_destroy(_glfw.wl.cursorTheme); wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
if (_glfw.wl.cursorThemeHiDPI)
wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);
if (_glfw.wl.cursor.handle) if (_glfw.wl.cursor.handle)
{ {
_glfw_dlclose(_glfw.wl.cursor.handle); _glfw_dlclose(_glfw.wl.cursor.handle);
@ -1121,8 +1259,18 @@ void _glfwPlatformTerminate(void)
wl_shell_destroy(_glfw.wl.shell); wl_shell_destroy(_glfw.wl.shell);
if (_glfw.wl.viewporter) if (_glfw.wl.viewporter)
wp_viewporter_destroy(_glfw.wl.viewporter); wp_viewporter_destroy(_glfw.wl.viewporter);
if (_glfw.wl.decorationManager)
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
if (_glfw.wl.wmBase) if (_glfw.wl.wmBase)
xdg_wm_base_destroy(_glfw.wl.wmBase); xdg_wm_base_destroy(_glfw.wl.wmBase);
if (_glfw.wl.dataSource)
wl_data_source_destroy(_glfw.wl.dataSource);
if (_glfw.wl.dataDevice)
wl_data_device_destroy(_glfw.wl.dataDevice);
if (_glfw.wl.dataOffer)
wl_data_offer_destroy(_glfw.wl.dataOffer);
if (_glfw.wl.dataDeviceManager)
wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
if (_glfw.wl.pointer) if (_glfw.wl.pointer)
wl_pointer_destroy(_glfw.wl.pointer); wl_pointer_destroy(_glfw.wl.pointer);
if (_glfw.wl.keyboard) if (_glfw.wl.keyboard)
@ -1142,6 +1290,16 @@ void _glfwPlatformTerminate(void)
wl_display_flush(_glfw.wl.display); wl_display_flush(_glfw.wl.display);
wl_display_disconnect(_glfw.wl.display); wl_display_disconnect(_glfw.wl.display);
} }
if (_glfw.wl.timerfd >= 0)
close(_glfw.wl.timerfd);
if (_glfw.wl.cursorTimerfd >= 0)
close(_glfw.wl.cursorTimerfd);
if (_glfw.wl.clipboardString)
free(_glfw.wl.clipboardString);
if (_glfw.wl.clipboardSendString)
free(_glfw.wl.clipboardSendString);
} }
const char* _glfwPlatformGetVersionString(void) const char* _glfwPlatformGetVersionString(void)
@ -1158,4 +1316,3 @@ const char* _glfwPlatformGetVersionString(void)
#endif #endif
; ;
} }

View file

@ -32,16 +32,16 @@
#include <errno.h> #include <errno.h>
static void geometry(void* data, static void outputHandleGeometry(void* data,
struct wl_output* output, struct wl_output* output,
int32_t x, int32_t x,
int32_t y, int32_t y,
int32_t physicalWidth, int32_t physicalWidth,
int32_t physicalHeight, int32_t physicalHeight,
int32_t subpixel, int32_t subpixel,
const char* make, const char* make,
const char* model, const char* model,
int32_t transform) int32_t transform)
{ {
struct _GLFWmonitor *monitor = data; struct _GLFWmonitor *monitor = data;
char name[1024]; char name[1024];
@ -55,12 +55,12 @@ static void geometry(void* data,
monitor->name = _glfw_strdup(name); monitor->name = _glfw_strdup(name);
} }
static void mode(void* data, static void outputHandleMode(void* data,
struct wl_output* output, struct wl_output* output,
uint32_t flags, uint32_t flags,
int32_t width, int32_t width,
int32_t height, int32_t height,
int32_t refresh) int32_t refresh)
{ {
struct _GLFWmonitor *monitor = data; struct _GLFWmonitor *monitor = data;
GLFWvidmode mode; GLFWvidmode mode;
@ -81,16 +81,16 @@ static void mode(void* data,
monitor->wl.currentMode = monitor->modeCount - 1; monitor->wl.currentMode = monitor->modeCount - 1;
} }
static void done(void* data, struct wl_output* output) static void outputHandleDone(void* data, struct wl_output* output)
{ {
struct _GLFWmonitor *monitor = data; struct _GLFWmonitor *monitor = data;
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
} }
static void scale(void* data, static void outputHandleScale(void* data,
struct wl_output* output, struct wl_output* output,
int32_t factor) int32_t factor)
{ {
struct _GLFWmonitor *monitor = data; struct _GLFWmonitor *monitor = data;
@ -98,10 +98,10 @@ static void scale(void* data,
} }
static const struct wl_output_listener outputListener = { static const struct wl_output_listener outputListener = {
geometry, outputHandleGeometry,
mode, outputHandleMode,
done, outputHandleDone,
scale, outputHandleScale,
}; };
@ -180,18 +180,18 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
*mode = monitor->modes[monitor->wl.currentMode]; *mode = monitor->modes[monitor->wl.currentMode];
} }
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{ {
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Gamma ramp getting not supported yet"); "Wayland: Gamma ramp access it not available");
return GLFW_FALSE;
} }
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor,
const GLFWgammaramp* ramp)
{ {
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Gamma ramp setting not supported yet"); "Wayland: Gamma ramp access is not available");
} }

View file

@ -57,6 +57,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#include "osmesa_context.h" #include "osmesa_context.h"
#include "wayland-xdg-shell-client-protocol.h" #include "wayland-xdg-shell-client-protocol.h"
#include "wayland-xdg-decoration-client-protocol.h"
#include "wayland-viewporter-client-protocol.h" #include "wayland-viewporter-client-protocol.h"
#include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
@ -185,6 +186,7 @@ typedef struct _GLFWwindowWayland
struct { struct {
struct xdg_surface* surface; struct xdg_surface* surface;
struct xdg_toplevel* toplevel; struct xdg_toplevel* toplevel;
struct zxdg_toplevel_decoration_v1* decoration;
} xdg; } xdg;
_GLFWcursor* currentCursor; _GLFWcursor* currentCursor;
@ -210,6 +212,7 @@ typedef struct _GLFWwindowWayland
GLFWbool justCreated; GLFWbool justCreated;
struct { struct {
GLFWbool serverSide;
struct wl_buffer* buffer; struct wl_buffer* buffer;
_GLFWdecorationWayland top, left, right, bottom; _GLFWdecorationWayland top, left, right, bottom;
int focus; int focus;
@ -230,7 +233,12 @@ typedef struct _GLFWlibraryWayland
struct wl_seat* seat; struct wl_seat* seat;
struct wl_pointer* pointer; struct wl_pointer* pointer;
struct wl_keyboard* keyboard; struct wl_keyboard* keyboard;
struct wl_data_device_manager* dataDeviceManager;
struct wl_data_device* dataDevice;
struct wl_data_offer* dataOffer;
struct wl_data_source* dataSource;
struct xdg_wm_base* wmBase; struct xdg_wm_base* wmBase;
struct zxdg_decoration_manager_v1* decorationManager;
struct wp_viewporter* viewporter; struct wp_viewporter* viewporter;
struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_relative_pointer_manager_v1* relativePointerManager;
struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_pointer_constraints_v1* pointerConstraints;
@ -240,13 +248,19 @@ typedef struct _GLFWlibraryWayland
int seatVersion; int seatVersion;
struct wl_cursor_theme* cursorTheme; struct wl_cursor_theme* cursorTheme;
struct wl_cursor_theme* cursorThemeHiDPI;
struct wl_surface* cursorSurface; struct wl_surface* cursorSurface;
uint32_t pointerSerial; int cursorTimerfd;
uint32_t serial;
int32_t keyboardRepeatRate; int32_t keyboardRepeatRate;
int32_t keyboardRepeatDelay; int32_t keyboardRepeatDelay;
int keyboardLastKey; int keyboardLastKey;
int keyboardLastScancode; int keyboardLastScancode;
char* clipboardString;
size_t clipboardSize;
char* clipboardSendString;
size_t clipboardSendSize;
int timerfd; int timerfd;
short int keycodes[256]; short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1]; short int scancodes[GLFW_KEY_LAST + 1];
@ -332,10 +346,12 @@ typedef struct _GLFWmonitorWayland
// //
typedef struct _GLFWcursorWayland typedef struct _GLFWcursorWayland
{ {
struct wl_cursor_image* image; struct wl_cursor* cursor;
struct wl_cursor* cursorHiDPI;
struct wl_buffer* buffer; struct wl_buffer* buffer;
int width, height; int width, height;
int xhot, yhot; int xhot, yhot;
int currentImage;
} _GLFWcursorWayland; } _GLFWcursorWayland;

View file

@ -39,18 +39,18 @@
#include <poll.h> #include <poll.h>
static void handlePing(void* data, static void shellSurfaceHandlePing(void* data,
struct wl_shell_surface* shellSurface, struct wl_shell_surface* shellSurface,
uint32_t serial) uint32_t serial)
{ {
wl_shell_surface_pong(shellSurface, serial); wl_shell_surface_pong(shellSurface, serial);
} }
static void handleConfigure(void* data, static void shellSurfaceHandleConfigure(void* data,
struct wl_shell_surface* shellSurface, struct wl_shell_surface* shellSurface,
uint32_t edges, uint32_t edges,
int32_t width, int32_t width,
int32_t height) int32_t height)
{ {
_GLFWwindow* window = data; _GLFWwindow* window = data;
float aspectRatio; float aspectRatio;
@ -94,19 +94,18 @@ static void handleConfigure(void* data,
_glfwInputWindowDamage(window); _glfwInputWindowDamage(window);
} }
static void handlePopupDone(void* data, static void shellSurfaceHandlePopupDone(void* data,
struct wl_shell_surface* shellSurface) struct wl_shell_surface* shellSurface)
{ {
} }
static const struct wl_shell_surface_listener shellSurfaceListener = { static const struct wl_shell_surface_listener shellSurfaceListener = {
handlePing, shellSurfaceHandlePing,
handleConfigure, shellSurfaceHandleConfigure,
handlePopupDone shellSurfaceHandlePopupDone
}; };
static int static int createTmpfileCloexec(char* tmpname)
createTmpfileCloexec(char* tmpname)
{ {
int fd; int fd;
@ -137,8 +136,7 @@ createTmpfileCloexec(char* tmpname)
* is set to ENOSPC. If posix_fallocate() is not supported, program may * is set to ENOSPC. If posix_fallocate() is not supported, program may
* receive SIGBUS on accessing mmap()'ed file contents instead. * receive SIGBUS on accessing mmap()'ed file contents instead.
*/ */
static int static int createAnonymousFile(off_t size)
createAnonymousFile(off_t size)
{ {
static const char template[] = "/glfw-shared-XXXXXX"; static const char template[] = "/glfw-shared-XXXXXX";
const char* path; const char* path;
@ -146,23 +144,37 @@ createAnonymousFile(off_t size)
int fd; int fd;
int ret; int ret;
path = getenv("XDG_RUNTIME_DIR"); #ifdef HAVE_MEMFD_CREATE
if (!path) fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd >= 0)
{ {
errno = ENOENT; // We can add this seal before calling posix_fallocate(), as the file
return -1; // is currently zero-sized anyway.
//
// There is also no need to check for the return value, we couldnt do
// anything with it anyway.
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
}
else
#endif
{
path = getenv("XDG_RUNTIME_DIR");
if (!path)
{
errno = ENOENT;
return -1;
}
name = calloc(strlen(path) + sizeof(template), 1);
strcpy(name, path);
strcat(name, template);
fd = createTmpfileCloexec(name);
free(name);
if (fd < 0)
return -1;
} }
name = calloc(strlen(path) + sizeof(template), 1);
strcpy(name, path);
strcat(name, template);
fd = createTmpfileCloexec(name);
free(name);
if (fd < 0)
return -1;
ret = posix_fallocate(fd, 0, size); ret = posix_fallocate(fd, 0, size);
if (ret != 0) if (ret != 0)
{ {
@ -188,7 +200,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Creating a buffer file for %d B failed: %m", "Wayland: Creating a buffer file for %d B failed: %m",
length); length);
return GLFW_FALSE; return NULL;
} }
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
@ -197,7 +209,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: mmap failed: %m"); "Wayland: mmap failed: %m");
close(fd); close(fd);
return GLFW_FALSE; return NULL;
} }
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
@ -262,11 +274,13 @@ static void createDecorations(_GLFWwindow* window)
const GLFWimage image = { 1, 1, data }; const GLFWimage image = { 1, 1, data };
GLFWbool opaque = (data[3] == 255); GLFWbool opaque = (data[3] == 255);
if (!_glfw.wl.viewporter) if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide)
return; return;
if (!window->wl.decorations.buffer) if (!window->wl.decorations.buffer)
window->wl.decorations.buffer = createShmBuffer(&image); window->wl.decorations.buffer = createShmBuffer(&image);
if (!window->wl.decorations.buffer)
return;
createDecoration(&window->wl.decorations.top, window->wl.surface, createDecoration(&window->wl.decorations.top, window->wl.surface,
window->wl.decorations.buffer, opaque, window->wl.decorations.buffer, opaque,
@ -307,6 +321,22 @@ static void destroyDecorations(_GLFWwindow* window)
destroyDecoration(&window->wl.decorations.bottom); destroyDecoration(&window->wl.decorations.bottom);
} }
static void xdgDecorationHandleConfigure(void* data,
struct zxdg_toplevel_decoration_v1* decoration,
uint32_t mode)
{
_GLFWwindow* window = data;
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
if (!window->wl.decorations.serverSide)
createDecorations(window);
}
static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = {
xdgDecorationHandleConfigure,
};
// Makes the surface considered as XRGB instead of ARGB. // Makes the surface considered as XRGB instead of ARGB.
static void setOpaqueRegion(_GLFWwindow* window) static void setOpaqueRegion(_GLFWwindow* window)
{ {
@ -389,9 +419,9 @@ static void checkScaleChange(_GLFWwindow* window)
} }
} }
static void handleEnter(void *data, static void surfaceHandleEnter(void *data,
struct wl_surface *surface, struct wl_surface *surface,
struct wl_output *output) struct wl_output *output)
{ {
_GLFWwindow* window = data; _GLFWwindow* window = data;
_GLFWmonitor* monitor = wl_output_get_user_data(output); _GLFWmonitor* monitor = wl_output_get_user_data(output);
@ -409,9 +439,9 @@ static void handleEnter(void *data,
checkScaleChange(window); checkScaleChange(window);
} }
static void handleLeave(void *data, static void surfaceHandleLeave(void *data,
struct wl_surface *surface, struct wl_surface *surface,
struct wl_output *output) struct wl_output *output)
{ {
_GLFWwindow* window = data; _GLFWwindow* window = data;
_GLFWmonitor* monitor = wl_output_get_user_data(output); _GLFWmonitor* monitor = wl_output_get_user_data(output);
@ -431,8 +461,8 @@ static void handleLeave(void *data,
} }
static const struct wl_surface_listener surfaceListener = { static const struct wl_surface_listener surfaceListener = {
handleEnter, surfaceHandleEnter,
handleLeave surfaceHandleLeave
}; };
static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)
@ -479,13 +509,11 @@ static GLFWbool createSurface(_GLFWwindow* window,
if (!window->wl.transparent) if (!window->wl.transparent)
setOpaqueRegion(window); setOpaqueRegion(window);
if (window->decorated && !window->monitor)
createDecorations(window);
return GLFW_TRUE; return GLFW_TRUE;
} }
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refreshRate) static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor,
int refreshRate)
{ {
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
{ {
@ -502,7 +530,8 @@ static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refres
monitor->wl.output); monitor->wl.output);
} }
setIdleInhibitor(window, GLFW_TRUE); setIdleInhibitor(window, GLFW_TRUE);
destroyDecorations(window); if (!window->wl.decorations.serverSide)
destroyDecorations(window);
} }
static GLFWbool createShellSurface(_GLFWwindow* window) static GLFWbool createShellSurface(_GLFWwindow* window)
@ -538,11 +567,13 @@ static GLFWbool createShellSurface(_GLFWwindow* window)
{ {
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
createDecorations(window);
} }
else else
{ {
wl_shell_surface_set_toplevel(window->wl.shellSurface); wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
createDecorations(window);
} }
wl_surface_commit(window->wl.surface); wl_surface_commit(window->wl.surface);
@ -631,6 +662,27 @@ static const struct xdg_surface_listener xdgSurfaceListener = {
xdgSurfaceHandleConfigure xdgSurfaceHandleConfigure
}; };
static void setXdgDecorations(_GLFWwindow* window)
{
if (_glfw.wl.decorationManager)
{
window->wl.xdg.decoration =
zxdg_decoration_manager_v1_get_toplevel_decoration(
_glfw.wl.decorationManager, window->wl.xdg.toplevel);
zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration,
&xdgDecorationListener,
window);
zxdg_toplevel_decoration_v1_set_mode(
window->wl.xdg.decoration,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
else
{
window->wl.decorations.serverSide = GLFW_FALSE;
createDecorations(window);
}
}
static GLFWbool createXdgSurface(_GLFWwindow* window) static GLFWbool createXdgSurface(_GLFWwindow* window)
{ {
window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
@ -678,10 +730,12 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
{ {
xdg_toplevel_set_maximized(window->wl.xdg.toplevel); xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
setXdgDecorations(window);
} }
else else
{ {
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
setXdgDecorations(window);
} }
wl_surface_commit(window->wl.surface); wl_surface_commit(window->wl.surface);
@ -690,13 +744,75 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
return GLFW_TRUE; return GLFW_TRUE;
} }
static void static void setCursorImage(_GLFWwindow* window,
handleEvents(int timeout) _GLFWcursorWayland* cursorWayland)
{
struct itimerspec timer = {};
struct wl_cursor* wlCursor = cursorWayland->cursor;
struct wl_cursor_image* image;
struct wl_buffer* buffer;
struct wl_surface* surface = _glfw.wl.cursorSurface;
int scale = 1;
if (!wlCursor)
buffer = cursorWayland->buffer;
else
{
if (window->wl.scale > 1 && cursorWayland->cursorHiDPI)
{
wlCursor = cursorWayland->cursorHiDPI;
scale = 2;
}
image = wlCursor->images[cursorWayland->currentImage];
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
timer.it_value.tv_sec = image->delay / 1000;
timer.it_value.tv_nsec = (image->delay % 1000) * 1000000;
timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, NULL);
cursorWayland->width = image->width;
cursorWayland->height = image->height;
cursorWayland->xhot = image->hotspot_x;
cursorWayland->yhot = image->hotspot_y;
}
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
surface,
cursorWayland->xhot / scale,
cursorWayland->yhot / scale);
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
cursorWayland->width, cursorWayland->height);
wl_surface_commit(surface);
}
static void incrementCursorImage(_GLFWwindow* window)
{
_GLFWcursor* cursor;
if (!window || window->wl.decorations.focus != mainWindow)
return;
cursor = window->wl.currentCursor;
if (cursor && cursor->wl.cursor)
{
cursor->wl.currentImage += 1;
cursor->wl.currentImage %= cursor->wl.cursor->image_count;
setCursorImage(window, &cursor->wl);
}
}
static void handleEvents(int timeout)
{ {
struct wl_display* display = _glfw.wl.display; struct wl_display* display = _glfw.wl.display;
struct pollfd fds[] = { struct pollfd fds[] = {
{ wl_display_get_fd(display), POLLIN }, { wl_display_get_fd(display), POLLIN },
{ _glfw.wl.timerfd, POLLIN }, { _glfw.wl.timerfd, POLLIN },
{ _glfw.wl.cursorTimerfd, POLLIN },
}; };
ssize_t read_ret; ssize_t read_ret;
uint64_t repeats, i; uint64_t repeats, i;
@ -719,7 +835,7 @@ handleEvents(int timeout)
return; return;
} }
if (poll(fds, 2, timeout) > 0) if (poll(fds, 3, timeout) > 0)
{ {
if (fds[0].revents & POLLIN) if (fds[0].revents & POLLIN)
{ {
@ -742,6 +858,15 @@ handleEvents(int timeout)
_glfw.wl.keyboardLastScancode, GLFW_REPEAT, _glfw.wl.keyboardLastScancode, GLFW_REPEAT,
_glfw.wl.xkb.modifiers); _glfw.wl.xkb.modifiers);
} }
if (fds[2].revents & POLLIN)
{
read_ret = read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats));
if (read_ret != 8)
return;
incrementCursorImage(_glfw.wl.pointerFocus);
}
} }
else else
{ {
@ -860,6 +985,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
window->context.destroy(window); window->context.destroy(window);
destroyDecorations(window); destroyDecorations(window);
if (window->wl.xdg.decoration)
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
if (window->wl.decorations.buffer) if (window->wl.decorations.buffer)
wl_buffer_destroy(window->wl.decorations.buffer); wl_buffer_destroy(window->wl.decorations.buffer);
@ -956,13 +1084,15 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
} }
} }
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window,
int numer, int denom)
{ {
// TODO: find out how to trigger a resize. // TODO: find out how to trigger a resize.
// The actual limits are checked in the wl_shell_surface::configure handler. // The actual limits are checked in the wl_shell_surface::configure handler.
} }
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformGetFramebufferSize(_GLFWwindow* window,
int* width, int* height)
{ {
_glfwPlatformGetWindowSize(window, width, height); _glfwPlatformGetWindowSize(window, width, height);
*width *= window->wl.scale; *width *= window->wl.scale;
@ -973,7 +1103,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top, int* left, int* top,
int* right, int* bottom) int* right, int* bottom)
{ {
if (window->decorated && !window->monitor) if (window->decorated && !window->monitor && !window->wl.decorations.serverSide)
{ {
if (top) if (top)
*top = _GLFW_DECORATION_TOP; *top = _GLFW_DECORATION_TOP;
@ -1102,7 +1232,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
else if (window->wl.shellSurface) else if (window->wl.shellSurface)
wl_shell_surface_set_toplevel(window->wl.shellSurface); wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
if (window->decorated) if (!_glfw.wl.decorationManager)
createDecorations(window); createDecorations(window);
} }
_glfwInputWindowMonitor(window, monitor); _glfwInputWindowMonitor(window, monitor);
@ -1236,6 +1366,9 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
int xhot, int yhot) int xhot, int yhot)
{ {
cursor->wl.buffer = createShmBuffer(image); cursor->wl.buffer = createShmBuffer(image);
if (!cursor->wl.buffer)
return GLFW_FALSE;
cursor->wl.width = image->width; cursor->wl.width = image->width;
cursor->wl.height = image->height; cursor->wl.height = image->height;
cursor->wl.xhot = xhot; cursor->wl.xhot = xhot;
@ -1257,28 +1390,37 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
return GLFW_FALSE; return GLFW_FALSE;
} }
cursor->wl.image = standardCursor->images[0]; cursor->wl.cursor = standardCursor;
cursor->wl.currentImage = 0;
if (_glfw.wl.cursorThemeHiDPI)
{
standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,
translateCursorShape(shape));
cursor->wl.cursorHiDPI = standardCursor;
}
return GLFW_TRUE; return GLFW_TRUE;
} }
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{ {
// If it's a standard cursor we don't need to do anything here // If it's a standard cursor we don't need to do anything here
if (cursor->wl.image) if (cursor->wl.cursor)
return; return;
if (cursor->wl.buffer) if (cursor->wl.buffer)
wl_buffer_destroy(cursor->wl.buffer); wl_buffer_destroy(cursor->wl.buffer);
} }
static void handleRelativeMotion(void* data, static void relativePointerHandleRelativeMotion(void* data,
struct zwp_relative_pointer_v1* pointer, struct zwp_relative_pointer_v1* pointer,
uint32_t timeHi, uint32_t timeHi,
uint32_t timeLo, uint32_t timeLo,
wl_fixed_t dx, wl_fixed_t dx,
wl_fixed_t dy, wl_fixed_t dy,
wl_fixed_t dxUnaccel, wl_fixed_t dxUnaccel,
wl_fixed_t dyUnaccel) wl_fixed_t dyUnaccel)
{ {
_GLFWwindow* window = data; _GLFWwindow* window = data;
@ -1291,11 +1433,11 @@ static void handleRelativeMotion(void* data,
} }
static const struct zwp_relative_pointer_v1_listener relativePointerListener = { static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
handleRelativeMotion relativePointerHandleRelativeMotion
}; };
static void handleLocked(void* data, static void lockedPointerHandleLocked(void* data,
struct zwp_locked_pointer_v1* lockedPointer) struct zwp_locked_pointer_v1* lockedPointer)
{ {
} }
@ -1315,14 +1457,14 @@ static void unlockPointer(_GLFWwindow* window)
static void lockPointer(_GLFWwindow* window); static void lockPointer(_GLFWwindow* window);
static void handleUnlocked(void* data, static void lockedPointerHandleUnlocked(void* data,
struct zwp_locked_pointer_v1* lockedPointer) struct zwp_locked_pointer_v1* lockedPointer)
{ {
} }
static const struct zwp_locked_pointer_v1_listener lockedPointerListener = { static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {
handleLocked, lockedPointerHandleLocked,
handleUnlocked lockedPointerHandleUnlocked
}; };
static void lockPointer(_GLFWwindow* window) static void lockPointer(_GLFWwindow* window)
@ -1359,7 +1501,7 @@ static void lockPointer(_GLFWwindow* window)
window->wl.pointerLock.relativePointer = relativePointer; window->wl.pointerLock.relativePointer = relativePointer;
window->wl.pointerLock.lockedPointer = lockedPointer; window->wl.pointerLock.lockedPointer = lockedPointer;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
NULL, 0, 0); NULL, 0, 0);
} }
@ -1370,10 +1512,8 @@ static GLFWbool isPointerLocked(_GLFWwindow* window)
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{ {
struct wl_buffer* buffer;
struct wl_cursor* defaultCursor; struct wl_cursor* defaultCursor;
struct wl_cursor_image* image; struct wl_cursor* defaultCursorHiDPI = NULL;
struct wl_surface* surface = _glfw.wl.cursorSurface;
if (!_glfw.wl.pointer) if (!_glfw.wl.pointer)
return; return;
@ -1382,7 +1522,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
// If we're not in the correct window just save the cursor // If we're not in the correct window just save the cursor
// the next time the pointer enters the window the cursor will change // the next time the pointer enters the window the cursor will change
if (window != _glfw.wl.pointerFocus) if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow)
return; return;
// Unlock possible pointer lock if no longer disabled. // Unlock possible pointer lock if no longer disabled.
@ -1392,7 +1532,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
if (window->cursorMode == GLFW_CURSOR_NORMAL) if (window->cursorMode == GLFW_CURSOR_NORMAL)
{ {
if (cursor) if (cursor)
image = cursor->wl.image; setCursorImage(window, &cursor->wl);
else else
{ {
defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
@ -1403,33 +1543,19 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
"Wayland: Standard cursor not found"); "Wayland: Standard cursor not found");
return; return;
} }
image = defaultCursor->images[0]; if (_glfw.wl.cursorThemeHiDPI)
} defaultCursorHiDPI =
wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,
if (image) "left_ptr");
{ _GLFWcursorWayland cursorWayland = {
buffer = wl_cursor_image_get_buffer(image); defaultCursor,
if (!buffer) defaultCursorHiDPI,
return; NULL,
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, 0, 0,
surface, 0, 0,
image->hotspot_x, 0
image->hotspot_y); };
wl_surface_attach(surface, buffer, 0, 0); setCursorImage(window, &cursorWayland);
wl_surface_damage(surface, 0, 0,
image->width, image->height);
wl_surface_commit(surface);
}
else
{
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
surface,
cursor->wl.xhot,
cursor->wl.yhot);
wl_surface_attach(surface, cursor->wl.buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
cursor->wl.width, cursor->wl.height);
wl_surface_commit(surface);
} }
} }
else if (window->cursorMode == GLFW_CURSOR_DISABLED) else if (window->cursorMode == GLFW_CURSOR_DISABLED)
@ -1439,24 +1565,213 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
} }
else if (window->cursorMode == GLFW_CURSOR_HIDDEN) else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
{ {
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0);
NULL, 0, 0);
} }
} }
static void dataSourceHandleTarget(void* data,
struct wl_data_source* dataSource,
const char* mimeType)
{
if (_glfw.wl.dataSource != dataSource)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unknown clipboard data source");
return;
}
}
static void dataSourceHandleSend(void* data,
struct wl_data_source* dataSource,
const char* mimeType,
int fd)
{
const char* string = _glfw.wl.clipboardSendString;
size_t len = _glfw.wl.clipboardSendSize;
int ret;
if (_glfw.wl.dataSource != dataSource)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unknown clipboard data source");
return;
}
if (!string)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Copy requested from an invalid string");
return;
}
if (strcmp(mimeType, "text/plain;charset=utf-8") != 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Wrong MIME type asked from clipboard");
close(fd);
return;
}
while (len > 0)
{
ret = write(fd, string, len);
if (ret == -1 && errno == EINTR)
continue;
if (ret == -1)
{
// TODO: also report errno maybe.
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Error while writing the clipboard");
close(fd);
return;
}
len -= ret;
}
close(fd);
}
static void dataSourceHandleCancelled(void* data,
struct wl_data_source* dataSource)
{
wl_data_source_destroy(dataSource);
if (_glfw.wl.dataSource != dataSource)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unknown clipboard data source");
return;
}
_glfw.wl.dataSource = NULL;
}
static const struct wl_data_source_listener dataSourceListener = {
dataSourceHandleTarget,
dataSourceHandleSend,
dataSourceHandleCancelled,
};
void _glfwPlatformSetClipboardString(const char* string) void _glfwPlatformSetClipboardString(const char* string)
{ {
// TODO if (_glfw.wl.dataSource)
_glfwInputError(GLFW_PLATFORM_ERROR, {
"Wayland: Clipboard setting not implemented yet"); wl_data_source_destroy(_glfw.wl.dataSource);
_glfw.wl.dataSource = NULL;
}
if (_glfw.wl.clipboardSendString)
{
free(_glfw.wl.clipboardSendString);
_glfw.wl.clipboardSendString = NULL;
}
_glfw.wl.clipboardSendString = strdup(string);
if (!_glfw.wl.clipboardSendString)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Impossible to allocate clipboard string");
return;
}
_glfw.wl.clipboardSendSize = strlen(string);
_glfw.wl.dataSource =
wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager);
if (!_glfw.wl.dataSource)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Impossible to create clipboard source");
free(_glfw.wl.clipboardSendString);
return;
}
wl_data_source_add_listener(_glfw.wl.dataSource,
&dataSourceListener,
NULL);
wl_data_source_offer(_glfw.wl.dataSource, "text/plain;charset=utf-8");
wl_data_device_set_selection(_glfw.wl.dataDevice,
_glfw.wl.dataSource,
_glfw.wl.serial);
}
static GLFWbool growClipboardString(void)
{
char* clipboard = _glfw.wl.clipboardString;
clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2);
if (!clipboard)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Impossible to grow clipboard string");
return GLFW_FALSE;
}
_glfw.wl.clipboardString = clipboard;
_glfw.wl.clipboardSize = _glfw.wl.clipboardSize * 2;
return GLFW_TRUE;
} }
const char* _glfwPlatformGetClipboardString(void) const char* _glfwPlatformGetClipboardString(void)
{ {
// TODO int fds[2];
_glfwInputError(GLFW_PLATFORM_ERROR, int ret;
"Wayland: Clipboard getting not implemented yet"); size_t len = 0;
return NULL;
if (!_glfw.wl.dataOffer)
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"No clipboard data has been sent yet");
return NULL;
}
ret = pipe2(fds, O_CLOEXEC);
if (ret < 0)
{
// TODO: also report errno maybe?
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Impossible to create clipboard pipe fds");
return NULL;
}
wl_data_offer_receive(_glfw.wl.dataOffer, "text/plain;charset=utf-8", fds[1]);
close(fds[1]);
// XXX: this is a huge hack, this function shouldnt be synchronous!
handleEvents(-1);
while (1)
{
// Grow the clipboard if we need to paste something bigger, there is no
// shrink operation yet.
if (len + 4096 > _glfw.wl.clipboardSize)
{
if (!growClipboardString())
{
close(fds[0]);
return NULL;
}
}
// Then read from the fd to the clipboard, handling all known errors.
ret = read(fds[0], _glfw.wl.clipboardString + len, 4096);
if (ret == 0)
break;
if (ret == -1 && errno == EINTR)
continue;
if (ret == -1)
{
// TODO: also report errno maybe.
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Impossible to read from clipboard fd");
close(fds[0]);
return NULL;
}
len += ret;
}
close(fds[0]);
if (len + 1 > _glfw.wl.clipboardSize)
{
if (!growClipboardString())
return NULL;
}
_glfw.wl.clipboardString[len] = '\0';
return _glfw.wl.clipboardString;
} }
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)

View file

@ -780,8 +780,9 @@ static GLFWbool initExtensions(void)
// //
static void getSystemContentScale(float* xscale, float* yscale) static void getSystemContentScale(float* xscale, float* yscale)
{ {
// NOTE: Default to the display-wide DPI as we don't currently have a policy // NOTE: Fall back to the display-wide DPI instead of RandR monitor DPI if
// for which monitor a window is considered to be on // Xft.dpi retrieval below fails as we don't currently have an exact
// policy for which monitor a window is considered to "be on"
float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) * float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) *
25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); 25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) * float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) *

View file

@ -422,7 +422,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
} }
} }
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{ {
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
{ {
@ -438,6 +438,7 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short));
XRRFreeGamma(gamma); XRRFreeGamma(gamma);
return GLFW_TRUE;
} }
else if (_glfw.x11.vidmode.available) else if (_glfw.x11.vidmode.available)
{ {
@ -449,6 +450,13 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
XF86VidModeGetGammaRamp(_glfw.x11.display, XF86VidModeGetGammaRamp(_glfw.x11.display,
_glfw.x11.screen, _glfw.x11.screen,
ramp->size, ramp->red, ramp->green, ramp->blue); ramp->size, ramp->red, ramp->green, ramp->blue);
return GLFW_TRUE;
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Gamma ramp access not supported by server");
return GLFW_FALSE;
} }
} }
@ -481,6 +489,11 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
(unsigned short*) ramp->green, (unsigned short*) ramp->green,
(unsigned short*) ramp->blue); (unsigned short*) ramp->blue);
} }
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Gamma ramp access not supported by server");
}
} }

View file

@ -175,29 +175,6 @@ static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer po
event->xproperty.atom == notification->xselection.property; event->xproperty.atom == notification->xselection.property;
} }
// Translates a GLFW standard cursor to a font cursor shape
//
static int translateCursorShape(int shape)
{
switch (shape)
{
case GLFW_ARROW_CURSOR:
return XC_left_ptr;
case GLFW_IBEAM_CURSOR:
return XC_xterm;
case GLFW_CROSSHAIR_CURSOR:
return XC_crosshair;
case GLFW_HAND_CURSOR:
return XC_hand1;
case GLFW_HRESIZE_CURSOR:
return XC_sb_h_double_arrow;
case GLFW_VRESIZE_CURSOR:
return XC_sb_v_double_arrow;
}
return 0;
}
// Translates an X event modifier state mask // Translates an X event modifier state mask
// //
static int translateState(int state) static int translateState(int state)
@ -231,23 +208,6 @@ static int translateKey(int scancode)
return _glfw.x11.keycodes[scancode]; return _glfw.x11.keycodes[scancode];
} }
// Return the GLFW window corresponding to the specified X11 window
//
static _GLFWwindow* findWindowByHandle(Window handle)
{
_GLFWwindow* window;
if (XFindContext(_glfw.x11.display,
handle,
_glfw.x11.context,
(XPointer*) &window) != 0)
{
return NULL;
}
return window;
}
// Sends an EWMH or ICCCM event to the window manager // Sends an EWMH or ICCCM event to the window manager
// //
static void sendEventToWM(_GLFWwindow* window, Atom type, static void sendEventToWM(_GLFWwindow* window, Atom type,
@ -632,6 +592,15 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig, const _GLFWwndconfig* wndconfig,
Visual* visual, int depth) Visual* visual, int depth)
{ {
int width = wndconfig->width;
int height = wndconfig->height;
if (wndconfig->scaleToMonitor)
{
width *= _glfw.x11.contentScaleX;
height *= _glfw.x11.contentScaleY;
}
// Create a colormap based on the visual used by the current context // Create a colormap based on the visual used by the current context
window->x11.colormap = XCreateColormap(_glfw.x11.display, window->x11.colormap = XCreateColormap(_glfw.x11.display,
_glfw.x11.root, _glfw.x11.root,
@ -657,7 +626,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
window->x11.handle = XCreateWindow(_glfw.x11.display, window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root, _glfw.x11.root,
0, 0, 0, 0,
wndconfig->width, wndconfig->height, width, height,
0, // Border width 0, // Border width
depth, // Color depth depth, // Color depth
InputOutput, InputOutput,
@ -760,7 +729,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
XFree(hints); XFree(hints);
} }
updateNormalHints(window, wndconfig->width, wndconfig->height); updateNormalHints(window, width, height);
// Set ICCCM WM_CLASS property // Set ICCCM WM_CLASS property
{ {
@ -1264,8 +1233,10 @@ static void processEvent(XEvent *event)
return; return;
} }
window = findWindowByHandle(event->xany.window); if (XFindContext(_glfw.x11.display,
if (window == NULL) event->xany.window,
_glfw.x11.context,
(XPointer*) &window) != 0)
{ {
// This is an event for a window that has already been destroyed // This is an event for a window that has already been destroyed
return; return;
@ -1484,12 +1455,20 @@ static void processEvent(XEvent *event)
case EnterNotify: case EnterNotify:
{ {
// XEnterWindowEvent is XCrossingEvent
const int x = event->xcrossing.x;
const int y = event->xcrossing.y;
// HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise
// ignore the defined cursor for hidden cursor mode // ignore the defined cursor for hidden cursor mode
if (window->cursorMode == GLFW_CURSOR_HIDDEN) if (window->cursorMode == GLFW_CURSOR_HIDDEN)
updateCursorImage(window); updateCursorImage(window);
_glfwInputCursorEnter(window, GLFW_TRUE); _glfwInputCursorEnter(window, GLFW_TRUE);
_glfwInputCursorPos(window, x, y);
window->x11.lastCursorPosX = x;
window->x11.lastCursorPosY = y;
return; return;
} }
@ -2479,6 +2458,14 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
Atom* states; Atom* states;
unsigned long i; unsigned long i;
GLFWbool maximized = GLFW_FALSE; GLFWbool maximized = GLFW_FALSE;
if (!_glfw.x11.NET_WM_STATE ||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
{
return maximized;
}
const unsigned long count = const unsigned long count =
_glfwGetWindowPropertyX11(window->x11.handle, _glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE, _glfw.x11.NET_WM_STATE,
@ -2814,8 +2801,24 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{ {
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, int native = 0;
translateCursorShape(shape));
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_hand1;
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;
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
if (!cursor->x11.handle) if (!cursor->x11.handle)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,