Resolved .gitignore conflict
This commit is contained in:
TheCherno 2020-05-01 13:31:40 +10:00
commit 4fba735d5e
44 changed files with 1844 additions and 921 deletions

View File

@ -7,11 +7,6 @@ branches:
- master - master
- 3.3-stable - 3.3-stable
skip_tags: true skip_tags: true
skip_commits:
files:
- README.md
- LICENSE.md
- docs/*
environment: environment:
matrix: matrix:
- GENERATOR: MinGW Makefiles - GENERATOR: MinGW Makefiles

19
.gitignore vendored
View File

@ -7,18 +7,24 @@ _ReSharper*
*.dir *.dir
*.vcxproj* *.vcxproj*
*.sln *.sln
.vs/ .vs
CMakeSettings.json
Win32 Win32
x64 x64
Debug Debug
Release Release
MinSizeRel MinSizeRel
RelWithDebInfo RelWithDebInfo
*.xcodeproj *.opensdf
bin
bin-int
# CMake files # Xcode clutter
GLFW.build
GLFW.xcodeproj
# macOS clutter
.DS_Store
# Makefile generator clutter
Makefile Makefile
CMakeCache.txt CMakeCache.txt
CMakeFiles CMakeFiles
@ -85,3 +91,6 @@ tests/title
tests/triangle-vulkan tests/triangle-vulkan
tests/windows tests/windows
# Hazel-specific
bin
bin-int

View File

@ -75,12 +75,14 @@ matrix:
env: env:
- BUILD_SHARED_LIBS=ON - BUILD_SHARED_LIBS=ON
- CFLAGS=-Werror - CFLAGS=-Werror
- MACOSX_DEPLOYMENT_TARGET=10.8
- os: osx - os: osx
sudo: false sudo: false
name: "Cocoa static library" name: "Cocoa static library"
env: env:
- BUILD_SHARED_LIBS=OFF - BUILD_SHARED_LIBS=OFF
- CFLAGS=-Werror - CFLAGS=-Werror
- MACOSX_DEPLOYMENT_TARGET=10.8
script: script:
- if grep -Inr '\s$' src include docs tests examples CMake *.md .gitattributes .gitignore; then - if grep -Inr '\s$' src include docs tests examples CMake *.md .gitattributes .gitignore; then
echo Trailing whitespace found, aborting; echo Trailing whitespace found, aborting;

View File

@ -0,0 +1,3 @@
include(CMakeFindDependencyMacro)
find_dependency(Threads)
include("${CMAKE_CURRENT_LIST_DIR}/glfw3Targets.cmake")

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.1)
project(GLFW VERSION 3.4.0 LANGUAGES C) project(GLFW VERSION 3.4.0 LANGUAGES C)
@ -37,10 +37,6 @@ cmake_dependent_option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF
cmake_dependent_option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON cmake_dependent_option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON
"MSVC" OFF) "MSVC" OFF)
if (BUILD_SHARED_LIBS)
set(_GLFW_BUILD_DLL 1)
endif()
if (BUILD_SHARED_LIBS AND UNIX) if (BUILD_SHARED_LIBS AND UNIX)
# On Unix-like systems, shared libraries can use the soname system. # On Unix-like systems, shared libraries can use the soname system.
set(GLFW_LIB_NAME glfw) set(GLFW_LIB_NAME glfw)
@ -75,7 +71,7 @@ if (MSVC)
include(CheckIncludeFile) include(CheckIncludeFile)
check_include_file(dinput.h DINPUT_H_FOUND) check_include_file(dinput.h DINPUT_H_FOUND)
if (NOT DINPUT_H_FOUND) if (NOT DINPUT_H_FOUND)
message(FATAL_ERROR "DirectX 9 SDK not found") message(FATAL_ERROR "DirectX 9 headers not found; install DirectX 9 SDK")
endif() endif()
# Workaround for VS 2008 not shipping with stdint.h # Workaround for VS 2008 not shipping with stdint.h
list(APPEND glfw_INCLUDE_DIRS "${GLFW_SOURCE_DIR}/deps/vs2008") list(APPEND glfw_INCLUDE_DIRS "${GLFW_SOURCE_DIR}/deps/vs2008")
@ -199,42 +195,33 @@ if (_GLFW_X11)
find_package(X11 REQUIRED) find_package(X11 REQUIRED)
list(APPEND glfw_PKG_DEPS "x11")
# Set up library and include paths # Set up library and include paths
list(APPEND glfw_INCLUDE_DIRS "${X11_X11_INCLUDE_PATH}") list(APPEND glfw_INCLUDE_DIRS "${X11_X11_INCLUDE_PATH}")
list(APPEND glfw_LIBRARIES "${X11_X11_LIB}" "${CMAKE_THREAD_LIBS_INIT}")
# Check for XRandR (modern resolution switching and gamma control) # Check for XRandR (modern resolution switching and gamma control)
if (NOT X11_Xrandr_INCLUDE_PATH) if (NOT X11_Xrandr_INCLUDE_PATH)
message(FATAL_ERROR "The RandR headers were not found") message(FATAL_ERROR "RandR headers not found; install libxrandr development package")
endif() endif()
# Check for Xinerama (legacy multi-monitor support) # Check for Xinerama (legacy multi-monitor support)
if (NOT X11_Xinerama_INCLUDE_PATH) if (NOT X11_Xinerama_INCLUDE_PATH)
message(FATAL_ERROR "The Xinerama headers were not found") message(FATAL_ERROR "Xinerama headers not found; install libxinerama development package")
endif() endif()
# Check for Xkb (X keyboard extension) # Check for Xkb (X keyboard extension)
if (NOT X11_Xkb_INCLUDE_PATH) if (NOT X11_Xkb_INCLUDE_PATH)
message(FATAL_ERROR "The X keyboard extension headers were not found") message(FATAL_ERROR "XKB headers not found; install X11 development package")
endif() endif()
# Check for Xcursor (cursor creation from RGBA images) # Check for Xcursor (cursor creation from RGBA images)
if (NOT X11_Xcursor_INCLUDE_PATH) if (NOT X11_Xcursor_INCLUDE_PATH)
message(FATAL_ERROR "The Xcursor headers were not found") message(FATAL_ERROR "Xcursor headers not found; install libxcursor development package")
endif() endif()
# Check for XInput (modern HID input) # Check for XInput (modern HID input)
if (NOT X11_Xi_INCLUDE_PATH) if (NOT X11_Xi_INCLUDE_PATH)
message(FATAL_ERROR "The XInput headers were not found") message(FATAL_ERROR "XInput headers not found; install libxi development package")
endif() endif()
list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}"
"${X11_Xinerama_INCLUDE_PATH}"
"${X11_Xkb_INCLUDE_PATH}"
"${X11_Xcursor_INCLUDE_PATH}"
"${X11_Xi_INCLUDE_PATH}")
endif() endif()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
@ -248,10 +235,10 @@ if (_GLFW_WAYLAND)
find_package(WaylandScanner REQUIRED) find_package(WaylandScanner REQUIRED)
find_package(WaylandProtocols 1.15 REQUIRED) find_package(WaylandProtocols 1.15 REQUIRED)
list(APPEND glfw_PKG_DEPS "wayland-egl") list(APPEND glfw_PKG_DEPS "wayland-client")
list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIRS}") list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIRS}")
list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}")
find_package(XKBCommon REQUIRED) find_package(XKBCommon REQUIRED)
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}")
@ -275,7 +262,6 @@ endif()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
if (_GLFW_OSMESA) if (_GLFW_OSMESA)
find_package(OSMesa REQUIRED) find_package(OSMesa REQUIRED)
list(APPEND glfw_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
endif() endif()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
@ -286,11 +272,10 @@ if (_GLFW_COCOA)
list(APPEND glfw_LIBRARIES list(APPEND glfw_LIBRARIES
"-framework Cocoa" "-framework Cocoa"
"-framework IOKit" "-framework IOKit"
"-framework CoreFoundation" "-framework CoreFoundation")
"-framework CoreVideo")
set(glfw_PKG_DEPS "") set(glfw_PKG_DEPS "")
set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo") set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation")
endif() endif()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
@ -317,7 +302,7 @@ include(CMakePackageConfigHelpers)
set(GLFW_CONFIG_PATH "${CMAKE_INSTALL_LIBDIR}/cmake/glfw3") set(GLFW_CONFIG_PATH "${CMAKE_INSTALL_LIBDIR}/cmake/glfw3")
configure_package_config_file(src/glfw3Config.cmake.in configure_package_config_file(CMake/glfw3Config.cmake.in
src/glfw3Config.cmake src/glfw3Config.cmake
INSTALL_DESTINATION "${GLFW_CONFIG_PATH}" INSTALL_DESTINATION "${GLFW_CONFIG_PATH}"
NO_CHECK_REQUIRED_COMPONENTS_MACRO) NO_CHECK_REQUIRED_COMPONENTS_MACRO)
@ -326,9 +311,7 @@ write_basic_package_version_file(src/glfw3ConfigVersion.cmake
VERSION ${GLFW_VERSION} VERSION ${GLFW_VERSION}
COMPATIBILITY SameMajorVersion) COMPATIBILITY SameMajorVersion)
configure_file(src/glfw_config.h.in src/glfw_config.h @ONLY) configure_file(CMake/glfw3.pc.in src/glfw3.pc @ONLY)
configure_file(src/glfw3.pc.in src/glfw3.pc @ONLY)
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# Add subdirectories # Add subdirectories
@ -365,6 +348,11 @@ if (GLFW_INSTALL)
install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc" install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
if (DOXYGEN_FOUND AND GLFW_BUILD_DOCS)
install(DIRECTORY "${GLFW_BINARY_DIR}/docs/html"
DESTINATION "${CMAKE_INSTALL_DOCDIR}")
endif()
# Only generate this target if no higher-level project already has # Only generate this target if no higher-level project already has
if (NOT TARGET uninstall) if (NOT TARGET uninstall)
configure_file(CMake/cmake_uninstall.cmake.in configure_file(CMake/cmake_uninstall.cmake.in

View File

@ -11,7 +11,7 @@ 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. On GLFW natively supports Windows, macOS and Linux and other Unix-like systems. On
Linux both X11 and Wayland is supported. Linux both X11 and Wayland are supported.
GLFW is licensed under the [zlib/libpng GLFW is licensed under the [zlib/libpng
license](http://www.glfw.org/license.html). license](http://www.glfw.org/license.html).
@ -85,10 +85,11 @@ in the documentation for more information.
## Dependencies ## Dependencies
GLFW itself depends only on the headers and libraries for your window system. GLFW itself needs only CMake 3.1 or later and the headers and libraries for your
OS and window system.
The (experimental) Wayland backend also depends on the `extra-cmake-modules` The (experimental) Wayland backend also depends on the `extra-cmake-modules`
package, which is used to generated Wayland protocol headers. package, which is used to generate Wayland protocol headers.
The examples and test programs depend on a number of tiny libraries. These are The examples and test programs depend on a number of tiny libraries. These are
located in the `deps/` directory. located in the `deps/` directory.
@ -123,29 +124,70 @@ information on what to include when reporting a bug.
- Added `GLFW_RESIZE_EW_CURSOR` alias for `GLFW_HRESIZE_CURSOR` (#427) - Added `GLFW_RESIZE_EW_CURSOR` alias for `GLFW_HRESIZE_CURSOR` (#427)
- Added `GLFW_RESIZE_NS_CURSOR` alias for `GLFW_VRESIZE_CURSOR` (#427) - Added `GLFW_RESIZE_NS_CURSOR` alias for `GLFW_VRESIZE_CURSOR` (#427)
- Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427) - Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427)
- Updated the minimum required CMake version to 3.1
- Disabled tests and examples by default when built as a CMake subdirectory - Disabled tests and examples by default when built as a CMake subdirectory
- Bugfix: The CMake config-file package used an absolute path and was not - Bugfix: The CMake config-file package used an absolute path and was not
relocatable (#1470) relocatable (#1470)
- Bugfix: Video modes with a duplicate screen area were discarded (#1555,#1556) - Bugfix: Video modes with a duplicate screen area were discarded (#1555,#1556)
- Bugfix: Compiling with -Wextra-semi caused warnings (#1440) - Bugfix: Compiling with -Wextra-semi caused warnings (#1440)
- Bugfix: Built-in mappings failed because some OEMs re-used VID/PID (#1583)
- [Win32] Added the `GLFW_WIN32_KEYBOARD_MENU` window hint for enabling access - [Win32] Added the `GLFW_WIN32_KEYBOARD_MENU` window hint for enabling access
to the window menu to the window menu
- [Win32] Added a version info resource to the GLFW DLL
- [Win32] Bugfix: `GLFW_INCLUDE_VULKAN` plus `VK_USE_PLATFORM_WIN32_KHR` caused - [Win32] Bugfix: `GLFW_INCLUDE_VULKAN` plus `VK_USE_PLATFORM_WIN32_KHR` caused
symbol redefinition (#1524) symbol redefinition (#1524)
- [Win32] Bugfix: The cursor position event was emitted before its cursor enter - [Win32] Bugfix: The cursor position event was emitted before its cursor enter
event (#1490) event (#1490)
- [Win32] Bugfix: The window hint `GLFW_MAXIMIZED` did not move or resize the - [Win32] Bugfix: The window hint `GLFW_MAXIMIZED` did not move or resize the
window (#1499) window (#1499)
- [Win32] Bugfix: Disabled cursor mode interfered with some non-client actions
- [Win32] Bugfix: Super key was not released after Win+V hotkey (#1622)
- [Win32] Bugfix: `glfwGetKeyName` could access out of bounds and return an
invalid pointer
- [Win32] Bugfix: Some synthetic key events were reported as `GLFW_KEY_UNKNOWN`
(#1623)
- [Cocoa] Added support for `VK_EXT_metal_surface` (#1619)
- [Cocoa] Added locating the Vulkan loader at runtime in an application bundle
- [Cocoa] Moved main menu creation to GLFW initialization time (#1649)
- [Cocoa] Removed dependency on the CoreVideo framework
- [Cocoa] Bugfix: `glfwSetWindowSize` used a bottom-left anchor point (#1553) - [Cocoa] Bugfix: `glfwSetWindowSize` used a bottom-left anchor point (#1553)
- [Cocoa] Bugfix: Window remained on screen after destruction until event poll - [Cocoa] Bugfix: Window remained on screen after destruction until event poll
(#1412) (#1412)
- [Cocoa] Bugfix: Event processing before window creation would assert (#1543)
- [Cocoa] Bugfix: Undecorated windows could not be iconified on recent macOS
- [Cocoa] Bugfix: Touching event queue from secondary thread before main thread
would abort (#1649)
- [X11] Bugfix: The CMake files did not check for the XInput headers (#1480) - [X11] Bugfix: The CMake files did not check for the XInput headers (#1480)
- [X11] Bugfix: Key names were not updated when the keyboard layout changed - [X11] Bugfix: Key names were not updated when the keyboard layout changed
(#1462,#1528) (#1462,#1528)
- [X11] Bugfix: Decorations could not be enabled after window creation (#1566) - [X11] Bugfix: Decorations could not be enabled after window creation (#1566)
- [X11] Bugfix: Content scale fallback value could be inconsistent (#1578) - [X11] Bugfix: Content scale fallback value could be inconsistent (#1578)
- [X11] Bugfix: `glfwMaximizeWindow` had no effect on hidden windows
- [X11] Bugfix: Clearing `GLFW_FLOATING` on a hidden window caused invalid read
- [X11] Bugfix: Changing `GLFW_FLOATING` on a hidden window could silently fail
- [X11] Bugfix: Disabled cursor mode was interrupted by indicator windows
- [X11] Bugfix: Monitor physical dimensions could be reported as zero mm
- [X11] Bugfix: Window position events were not emitted during resizing (#1613)
- [X11] Bugfix: `glfwFocusWindow` could terminate on older WMs or without a WM
- [X11] Bugfix: Querying a disconnected monitor could segfault (#1602)
- [X11] Bugfix: IME input of CJK was broken for "C" locale (#1587,#1636)
- [X11] Bugfix: Termination would segfault if the IM had been destroyed
- [X11] Bugfix: Any IM started after initialization would not be detected
- [X11] Bugfix: Xlib errors caused by other parts of the application could be
reported as GLFW errors
- [X11] Bugfix: A handle race condition could cause a `BadWindow` error (#1633)
- [X11] Bugfix: XKB path used keysyms instead of physical locations for
non-printable keys (#1598)
- [X11] Bugfix: Function keys were mapped to `GLFW_KEY_UNKNOWN` for some layout
combinaitons (#1598)
- [Wayland] Removed support for `wl_shell` (#1443)
- [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432) - [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432)
- [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
- [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled
- [NSGL] Removed enforcement of forward-compatible flag for core contexts - [NSGL] Removed enforcement of forward-compatible flag for core contexts
- [NSGL] Bugfix: `GLFW_COCOA_RETINA_FRAMEBUFFER` had no effect on newer
macOS versions (#1442)
- [NSGL] Bugfix: Workaround for swap interval on 10.14 broke on 10.12 (#1483)
## Contact ## Contact
@ -218,6 +260,7 @@ skills.
- GeO4d - GeO4d
- Marcus Geelnard - Marcus Geelnard
- Charles Giessen - Charles Giessen
- Ryan C. Gordon
- Stephen Gowen - Stephen Gowen
- Kovid Goyal - Kovid Goyal
- Eloi Marín Gratacós - Eloi Marín Gratacós
@ -238,6 +281,7 @@ skills.
- Cem Karan - Cem Karan
- Osman Keskin - Osman Keskin
- Josh Kilmer - Josh Kilmer
- Byunghoon Kim
- Cameron King - Cameron King
- Peter Knut - Peter Knut
- Christoph Kubisch - Christoph Kubisch
@ -245,6 +289,7 @@ skills.
- Rokas Kupstys - Rokas Kupstys
- Konstantin Käfer - Konstantin Käfer
- Eric Larson - Eric Larson
- Francis Lecavalier
- Robin Leffmann - Robin Leffmann
- Glenn Lewis - Glenn Lewis
- Shane Liesegang - Shane Liesegang
@ -253,6 +298,7 @@ skills.
- Eyal Lotem - Eyal Lotem
- Aaron Loucks - Aaron Loucks
- Luflosi - Luflosi
- lukect
- Tristam MacDonald - Tristam MacDonald
- Hans Mackowiak - Hans Mackowiak
- Дмитри Малышев - Дмитри Малышев
@ -298,6 +344,7 @@ skills.
- Alexandre Pretyman - Alexandre Pretyman
- Pablo Prietz - Pablo Prietz
- przemekmirek - przemekmirek
- pthom
- Guillaume Racicot - Guillaume Racicot
- Philip Rideout - Philip Rideout
- Eddie Ringle - Eddie Ringle
@ -312,6 +359,7 @@ skills.
- Matt Sealey - Matt Sealey
- Steve Sexton - Steve Sexton
- Arkady Shapkin - Arkady Shapkin
- Ali Sherief
- Yoshiki Shibukawa - Yoshiki Shibukawa
- Dmitri Shuralyov - Dmitri Shuralyov
- Daniel Skorupski - Daniel Skorupski
@ -328,6 +376,7 @@ skills.
- Paul Sultana - Paul Sultana
- Nathan Sweet - Nathan Sweet
- TTK-Bandit - TTK-Bandit
- Jared Tiala
- Sergey Tikhomirov - Sergey Tikhomirov
- Arthur Tombs - Arthur Tombs
- Ioannis Tsakpinis - Ioannis Tsakpinis

197
deps/linmath.h vendored
View File

@ -3,31 +3,40 @@
#include <math.h> #include <math.h>
#ifdef _MSC_VER /* 2020-03-02 Camilla Löwy <elmindreda@elmindreda.org>
#define inline __inline * - Added inclusion of string.h for memcpy
* - Replaced tan and acos with tanf and acosf
* - Replaced double constants with float equivalents
*/
#include <string.h>
#ifdef LINMATH_NO_INLINE
#define LINMATH_H_FUNC static
#else
#define LINMATH_H_FUNC static inline
#endif #endif
#define LINMATH_H_DEFINE_VEC(n) \ #define LINMATH_H_DEFINE_VEC(n) \
typedef float vec##n[n]; \ typedef float vec##n[n]; \
static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ LINMATH_H_FUNC void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \
{ \ { \
int i; \ int i; \
for(i=0; i<n; ++i) \ for(i=0; i<n; ++i) \
r[i] = a[i] + b[i]; \ r[i] = a[i] + b[i]; \
} \ } \
static inline void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \ LINMATH_H_FUNC void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \
{ \ { \
int i; \ int i; \
for(i=0; i<n; ++i) \ for(i=0; i<n; ++i) \
r[i] = a[i] - b[i]; \ r[i] = a[i] - b[i]; \
} \ } \
static inline void vec##n##_scale(vec##n r, vec##n const v, float const s) \ LINMATH_H_FUNC void vec##n##_scale(vec##n r, vec##n const v, float const s) \
{ \ { \
int i; \ int i; \
for(i=0; i<n; ++i) \ for(i=0; i<n; ++i) \
r[i] = v[i] * s; \ r[i] = v[i] * s; \
} \ } \
static inline float vec##n##_mul_inner(vec##n const a, vec##n const b) \ LINMATH_H_FUNC float vec##n##_mul_inner(vec##n const a, vec##n const b) \
{ \ { \
float p = 0.; \ float p = 0.; \
int i; \ int i; \
@ -35,28 +44,40 @@ static inline float vec##n##_mul_inner(vec##n const a, vec##n const b) \
p += b[i]*a[i]; \ p += b[i]*a[i]; \
return p; \ return p; \
} \ } \
static inline float vec##n##_len(vec##n const v) \ LINMATH_H_FUNC float vec##n##_len(vec##n const v) \
{ \ { \
return (float) sqrt(vec##n##_mul_inner(v,v)); \ return sqrtf(vec##n##_mul_inner(v,v)); \
} \ } \
static inline void vec##n##_norm(vec##n r, vec##n const v) \ LINMATH_H_FUNC void vec##n##_norm(vec##n r, vec##n const v) \
{ \ { \
float k = 1.f / vec##n##_len(v); \ float k = 1.f / vec##n##_len(v); \
vec##n##_scale(r, v, k); \ vec##n##_scale(r, v, k); \
} \
LINMATH_H_FUNC void vec##n##_min(vec##n r, vec##n const a, vec##n const b) \
{ \
int i; \
for(i=0; i<n; ++i) \
r[i] = a[i]<b[i] ? a[i] : b[i]; \
} \
LINMATH_H_FUNC void vec##n##_max(vec##n r, vec##n const a, vec##n const b) \
{ \
int i; \
for(i=0; i<n; ++i) \
r[i] = a[i]>b[i] ? a[i] : b[i]; \
} }
LINMATH_H_DEFINE_VEC(2) LINMATH_H_DEFINE_VEC(2)
LINMATH_H_DEFINE_VEC(3) LINMATH_H_DEFINE_VEC(3)
LINMATH_H_DEFINE_VEC(4) LINMATH_H_DEFINE_VEC(4)
static inline void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b) LINMATH_H_FUNC void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b)
{ {
r[0] = a[1]*b[2] - a[2]*b[1]; r[0] = a[1]*b[2] - a[2]*b[1];
r[1] = a[2]*b[0] - a[0]*b[2]; r[1] = a[2]*b[0] - a[0]*b[2];
r[2] = a[0]*b[1] - a[1]*b[0]; r[2] = a[0]*b[1] - a[1]*b[0];
} }
static inline void vec3_reflect(vec3 r, vec3 const v, vec3 const n) LINMATH_H_FUNC void vec3_reflect(vec3 r, vec3 const v, vec3 const n)
{ {
float p = 2.f*vec3_mul_inner(v, n); float p = 2.f*vec3_mul_inner(v, n);
int i; int i;
@ -64,7 +85,7 @@ static inline void vec3_reflect(vec3 r, vec3 const v, vec3 const n)
r[i] = v[i] - p*n[i]; r[i] = v[i] - p*n[i];
} }
static inline void vec4_mul_cross(vec4 r, vec4 a, vec4 b) LINMATH_H_FUNC void vec4_mul_cross(vec4 r, vec4 a, vec4 b)
{ {
r[0] = a[1]*b[2] - a[2]*b[1]; r[0] = a[1]*b[2] - a[2]*b[1];
r[1] = a[2]*b[0] - a[0]*b[2]; r[1] = a[2]*b[0] - a[0]*b[2];
@ -72,7 +93,7 @@ static inline void vec4_mul_cross(vec4 r, vec4 a, vec4 b)
r[3] = 1.f; r[3] = 1.f;
} }
static inline void vec4_reflect(vec4 r, vec4 v, vec4 n) LINMATH_H_FUNC void vec4_reflect(vec4 r, vec4 v, vec4 n)
{ {
float p = 2.f*vec4_mul_inner(v, n); float p = 2.f*vec4_mul_inner(v, n);
int i; int i;
@ -81,58 +102,58 @@ static inline void vec4_reflect(vec4 r, vec4 v, vec4 n)
} }
typedef vec4 mat4x4[4]; typedef vec4 mat4x4[4];
static inline void mat4x4_identity(mat4x4 M) LINMATH_H_FUNC void mat4x4_identity(mat4x4 M)
{ {
int i, j; int i, j;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
for(j=0; j<4; ++j) for(j=0; j<4; ++j)
M[i][j] = i==j ? 1.f : 0.f; M[i][j] = i==j ? 1.f : 0.f;
} }
static inline void mat4x4_dup(mat4x4 M, mat4x4 N) LINMATH_H_FUNC void mat4x4_dup(mat4x4 M, mat4x4 N)
{ {
int i, j; int i, j;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
for(j=0; j<4; ++j) for(j=0; j<4; ++j)
M[i][j] = N[i][j]; M[i][j] = N[i][j];
} }
static inline void mat4x4_row(vec4 r, mat4x4 M, int i) LINMATH_H_FUNC void mat4x4_row(vec4 r, mat4x4 M, int i)
{ {
int k; int k;
for(k=0; k<4; ++k) for(k=0; k<4; ++k)
r[k] = M[k][i]; r[k] = M[k][i];
} }
static inline void mat4x4_col(vec4 r, mat4x4 M, int i) LINMATH_H_FUNC void mat4x4_col(vec4 r, mat4x4 M, int i)
{ {
int k; int k;
for(k=0; k<4; ++k) for(k=0; k<4; ++k)
r[k] = M[i][k]; r[k] = M[i][k];
} }
static inline void mat4x4_transpose(mat4x4 M, mat4x4 N) LINMATH_H_FUNC void mat4x4_transpose(mat4x4 M, mat4x4 N)
{ {
int i, j; int i, j;
for(j=0; j<4; ++j) for(j=0; j<4; ++j)
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
M[i][j] = N[j][i]; M[i][j] = N[j][i];
} }
static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b) LINMATH_H_FUNC void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b)
{ {
int i; int i;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
vec4_add(M[i], a[i], b[i]); vec4_add(M[i], a[i], b[i]);
} }
static inline void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b) LINMATH_H_FUNC void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b)
{ {
int i; int i;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
vec4_sub(M[i], a[i], b[i]); vec4_sub(M[i], a[i], b[i]);
} }
static inline void mat4x4_scale(mat4x4 M, mat4x4 a, float k) LINMATH_H_FUNC void mat4x4_scale(mat4x4 M, mat4x4 a, float k)
{ {
int i; int i;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
vec4_scale(M[i], a[i], k); vec4_scale(M[i], a[i], k);
} }
static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z) LINMATH_H_FUNC void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z)
{ {
int i; int i;
vec4_scale(M[0], a[0], x); vec4_scale(M[0], a[0], x);
@ -142,7 +163,7 @@ static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, floa
M[3][i] = a[3][i]; M[3][i] = a[3][i];
} }
} }
static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b) LINMATH_H_FUNC void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b)
{ {
mat4x4 temp; mat4x4 temp;
int k, r, c; int k, r, c;
@ -153,7 +174,7 @@ static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b)
} }
mat4x4_dup(M, temp); mat4x4_dup(M, temp);
} }
static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v) LINMATH_H_FUNC void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v)
{ {
int i, j; int i, j;
for(j=0; j<4; ++j) { for(j=0; j<4; ++j) {
@ -162,14 +183,14 @@ static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v)
r[j] += M[i][j] * v[i]; r[j] += M[i][j] * v[i];
} }
} }
static inline void mat4x4_translate(mat4x4 T, float x, float y, float z) LINMATH_H_FUNC void mat4x4_translate(mat4x4 T, float x, float y, float z)
{ {
mat4x4_identity(T); mat4x4_identity(T);
T[3][0] = x; T[3][0] = x;
T[3][1] = y; T[3][1] = y;
T[3][2] = z; T[3][2] = z;
} }
static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z) LINMATH_H_FUNC void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z)
{ {
vec4 t = {x, y, z, 0}; vec4 t = {x, y, z, 0};
vec4 r; vec4 r;
@ -179,33 +200,32 @@ static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z
M[3][i] += vec4_mul_inner(r, t); M[3][i] += vec4_mul_inner(r, t);
} }
} }
static inline void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b) LINMATH_H_FUNC void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b)
{ {
int i, j; int i, j;
for(i=0; i<4; ++i) for(j=0; j<4; ++j) for(i=0; i<4; ++i) for(j=0; j<4; ++j)
M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f; M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f;
} }
static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle) LINMATH_H_FUNC void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle)
{ {
float s = sinf(angle); float s = sinf(angle);
float c = cosf(angle); float c = cosf(angle);
vec3 u = {x, y, z}; vec3 u = {x, y, z};
if(vec3_len(u) > 1e-4) { if(vec3_len(u) > 1e-4) {
mat4x4 T, C, S = {{0}};
vec3_norm(u, u); vec3_norm(u, u);
mat4x4 T;
mat4x4_from_vec3_mul_outer(T, u, u); mat4x4_from_vec3_mul_outer(T, u, u);
S[1][2] = u[0]; mat4x4 S = {
S[2][1] = -u[0]; { 0, u[2], -u[1], 0},
S[2][0] = u[1]; {-u[2], 0, u[0], 0},
S[0][2] = -u[1]; { u[1], -u[0], 0, 0},
S[0][1] = u[2]; { 0, 0, 0, 0}
S[1][0] = -u[2]; };
mat4x4_scale(S, S, s); mat4x4_scale(S, S, s);
mat4x4 C;
mat4x4_identity(C); mat4x4_identity(C);
mat4x4_sub(C, C, T); mat4x4_sub(C, C, T);
@ -220,7 +240,7 @@ static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z,
mat4x4_dup(R, M); mat4x4_dup(R, M);
} }
} }
static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle) LINMATH_H_FUNC void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle)
{ {
float s = sinf(angle); float s = sinf(angle);
float c = cosf(angle); float c = cosf(angle);
@ -232,7 +252,7 @@ static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle)
}; };
mat4x4_mul(Q, M, R); mat4x4_mul(Q, M, R);
} }
static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) LINMATH_H_FUNC void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle)
{ {
float s = sinf(angle); float s = sinf(angle);
float c = cosf(angle); float c = cosf(angle);
@ -244,7 +264,7 @@ static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle)
}; };
mat4x4_mul(Q, M, R); mat4x4_mul(Q, M, R);
} }
static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle) LINMATH_H_FUNC void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle)
{ {
float s = sinf(angle); float s = sinf(angle);
float c = cosf(angle); float c = cosf(angle);
@ -256,9 +276,8 @@ static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle)
}; };
mat4x4_mul(Q, M, R); mat4x4_mul(Q, M, R);
} }
static inline void mat4x4_invert(mat4x4 T, mat4x4 M) LINMATH_H_FUNC void mat4x4_invert(mat4x4 T, mat4x4 M)
{ {
float idet;
float s[6]; float s[6];
float c[6]; float c[6];
s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1];
@ -276,7 +295,7 @@ static inline void mat4x4_invert(mat4x4 T, mat4x4 M)
c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3];
/* Assumes it is invertible */ /* Assumes it is invertible */
idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); float idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] );
T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet;
T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet;
@ -298,17 +317,12 @@ static inline void mat4x4_invert(mat4x4 T, mat4x4 M)
T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet;
T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet;
} }
static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) LINMATH_H_FUNC void mat4x4_orthonormalize(mat4x4 R, mat4x4 M)
{ {
mat4x4_dup(R, M);
float s = 1.; float s = 1.;
vec3 h; vec3 h;
mat4x4_dup(R, M);
vec3_norm(R[2], R[2]);
s = vec3_mul_inner(R[1], R[2]);
vec3_scale(h, R[2], s);
vec3_sub(R[1], R[1], h);
vec3_norm(R[2], R[2]); vec3_norm(R[2], R[2]);
s = vec3_mul_inner(R[1], R[2]); s = vec3_mul_inner(R[1], R[2]);
@ -316,13 +330,17 @@ static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M)
vec3_sub(R[1], R[1], h); vec3_sub(R[1], R[1], h);
vec3_norm(R[1], R[1]); vec3_norm(R[1], R[1]);
s = vec3_mul_inner(R[0], R[2]);
vec3_scale(h, R[2], s);
vec3_sub(R[0], R[0], h);
s = vec3_mul_inner(R[0], R[1]); s = vec3_mul_inner(R[0], R[1]);
vec3_scale(h, R[1], s); vec3_scale(h, R[1], s);
vec3_sub(R[0], R[0], h); vec3_sub(R[0], R[0], h);
vec3_norm(R[0], R[0]); vec3_norm(R[0], R[0]);
} }
static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) LINMATH_H_FUNC void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f)
{ {
M[0][0] = 2.f*n/(r-l); M[0][0] = 2.f*n/(r-l);
M[0][1] = M[0][2] = M[0][3] = 0.f; M[0][1] = M[0][2] = M[0][3] = 0.f;
@ -338,7 +356,7 @@ static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t,
M[3][2] = -2.f*(f*n)/(f-n); M[3][2] = -2.f*(f*n)/(f-n);
M[3][0] = M[3][1] = M[3][3] = 0.f; M[3][0] = M[3][1] = M[3][3] = 0.f;
} }
static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) LINMATH_H_FUNC void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f)
{ {
M[0][0] = 2.f/(r-l); M[0][0] = 2.f/(r-l);
M[0][1] = M[0][2] = M[0][3] = 0.f; M[0][1] = M[0][2] = M[0][3] = 0.f;
@ -354,11 +372,11 @@ static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, fl
M[3][2] = -(f+n)/(f-n); M[3][2] = -(f+n)/(f-n);
M[3][3] = 1.f; M[3][3] = 1.f;
} }
static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) LINMATH_H_FUNC void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f)
{ {
/* NOTE: Degrees are an unhandy unit to work with. /* NOTE: Degrees are an unhandy unit to work with.
* linmath.h uses radians for everything! */ * linmath.h uses radians for everything! */
float const a = 1.f / (float) tan(y_fov / 2.f); float const a = 1.f / tanf(y_fov / 2.f);
m[0][0] = a / aspect; m[0][0] = a / aspect;
m[0][1] = 0.f; m[0][1] = 0.f;
@ -380,7 +398,7 @@ static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float
m[3][2] = -((2.f * f * n) / (f - n)); m[3][2] = -((2.f * f * n) / (f - n));
m[3][3] = 0.f; m[3][3] = 0.f;
} }
static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) LINMATH_H_FUNC void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up)
{ {
/* Adapted from Android's OpenGL Matrix.java. */ /* Adapted from Android's OpenGL Matrix.java. */
/* See the OpenGL GLUT documentation for gluLookAt for a description */ /* See the OpenGL GLUT documentation for gluLookAt for a description */
@ -389,15 +407,14 @@ static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up)
/* TODO: The negation of of can be spared by swapping the order of /* TODO: The negation of of can be spared by swapping the order of
* operands in the following cross products in the right way. */ * operands in the following cross products in the right way. */
vec3 f; vec3 f;
vec3 s;
vec3 t;
vec3_sub(f, center, eye); vec3_sub(f, center, eye);
vec3_norm(f, f); vec3_norm(f, f);
vec3 s;
vec3_mul_cross(s, f, up); vec3_mul_cross(s, f, up);
vec3_norm(s, s); vec3_norm(s, s);
vec3 t;
vec3_mul_cross(t, s, f); vec3_mul_cross(t, s, f);
m[0][0] = s[0]; m[0][0] = s[0];
@ -424,24 +441,24 @@ static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up)
} }
typedef float quat[4]; typedef float quat[4];
static inline void quat_identity(quat q) LINMATH_H_FUNC void quat_identity(quat q)
{ {
q[0] = q[1] = q[2] = 0.f; q[0] = q[1] = q[2] = 0.f;
q[3] = 1.f; q[3] = 1.f;
} }
static inline void quat_add(quat r, quat a, quat b) LINMATH_H_FUNC void quat_add(quat r, quat a, quat b)
{ {
int i; int i;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
r[i] = a[i] + b[i]; r[i] = a[i] + b[i];
} }
static inline void quat_sub(quat r, quat a, quat b) LINMATH_H_FUNC void quat_sub(quat r, quat a, quat b)
{ {
int i; int i;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
r[i] = a[i] - b[i]; r[i] = a[i] - b[i];
} }
static inline void quat_mul(quat r, quat p, quat q) LINMATH_H_FUNC void quat_mul(quat r, quat p, quat q)
{ {
vec3 w; vec3 w;
vec3_mul_cross(r, p, q); vec3_mul_cross(r, p, q);
@ -451,13 +468,13 @@ static inline void quat_mul(quat r, quat p, quat q)
vec3_add(r, r, w); vec3_add(r, r, w);
r[3] = p[3]*q[3] - vec3_mul_inner(p, q); r[3] = p[3]*q[3] - vec3_mul_inner(p, q);
} }
static inline void quat_scale(quat r, quat v, float s) LINMATH_H_FUNC void quat_scale(quat r, quat v, float s)
{ {
int i; int i;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
r[i] = v[i] * s; r[i] = v[i] * s;
} }
static inline float quat_inner_product(quat a, quat b) LINMATH_H_FUNC float quat_inner_product(quat a, quat b)
{ {
float p = 0.f; float p = 0.f;
int i; int i;
@ -465,42 +482,43 @@ static inline float quat_inner_product(quat a, quat b)
p += b[i]*a[i]; p += b[i]*a[i];
return p; return p;
} }
static inline void quat_conj(quat r, quat q) LINMATH_H_FUNC void quat_conj(quat r, quat q)
{ {
int i; int i;
for(i=0; i<3; ++i) for(i=0; i<3; ++i)
r[i] = -q[i]; r[i] = -q[i];
r[3] = q[3]; r[3] = q[3];
} }
static inline void quat_rotate(quat r, float angle, vec3 axis) { LINMATH_H_FUNC void quat_rotate(quat r, float angle, vec3 axis) {
int i;
vec3 v; vec3 v;
vec3_scale(v, axis, sinf(angle / 2)); vec3_scale(v, axis, sinf(angle / 2));
int i;
for(i=0; i<3; ++i) for(i=0; i<3; ++i)
r[i] = v[i]; r[i] = v[i];
r[3] = cosf(angle / 2); r[3] = cosf(angle / 2);
} }
#define quat_norm vec4_norm #define quat_norm vec4_norm
static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) LINMATH_H_FUNC void quat_mul_vec3(vec3 r, quat q, vec3 v)
{ {
/* /*
* Method by Fabian 'ryg' Giessen (of Farbrausch) * Method by Fabian 'ryg' Giessen (of Farbrausch)
t = 2 * cross(q.xyz, v) t = 2 * cross(q.xyz, v)
v' = v + q.w * t + cross(q.xyz, t) v' = v + q.w * t + cross(q.xyz, t)
*/ */
vec3 t = {q[0], q[1], q[2]}; vec3 t;
vec3 q_xyz = {q[0], q[1], q[2]};
vec3 u = {q[0], q[1], q[2]}; vec3 u = {q[0], q[1], q[2]};
vec3_mul_cross(t, t, v); vec3_mul_cross(t, q_xyz, v);
vec3_scale(t, t, 2); vec3_scale(t, t, 2);
vec3_mul_cross(u, u, t); vec3_mul_cross(u, q_xyz, t);
vec3_scale(t, t, q[3]); vec3_scale(t, t, q[3]);
vec3_add(r, v, t); vec3_add(r, v, t);
vec3_add(r, r, u); vec3_add(r, r, u);
} }
static inline void mat4x4_from_quat(mat4x4 M, quat q) LINMATH_H_FUNC void mat4x4_from_quat(mat4x4 M, quat q)
{ {
float a = q[3]; float a = q[3];
float b = q[0]; float b = q[0];
@ -530,7 +548,7 @@ static inline void mat4x4_from_quat(mat4x4 M, quat q)
M[3][3] = 1.f; M[3][3] = 1.f;
} }
static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) LINMATH_H_FUNC void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q)
{ {
/* XXX: The way this is written only works for othogonal matrices. */ /* XXX: The way this is written only works for othogonal matrices. */
/* TODO: Take care of non-orthogonal case. */ /* TODO: Take care of non-orthogonal case. */
@ -541,7 +559,7 @@ static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q)
R[3][0] = R[3][1] = R[3][2] = 0.f; R[3][0] = R[3][1] = R[3][2] = 0.f;
R[3][3] = 1.f; R[3][3] = 1.f;
} }
static inline void quat_from_mat4x4(quat q, mat4x4 M) LINMATH_H_FUNC void quat_from_mat4x4(quat q, mat4x4 M)
{ {
float r=0.f; float r=0.f;
int i; int i;
@ -557,7 +575,7 @@ static inline void quat_from_mat4x4(quat q, mat4x4 M)
p = &perm[i]; p = &perm[i];
} }
r = (float) sqrt(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] );
if(r < 1e-6) { if(r < 1e-6) {
q[0] = 1.f; q[0] = 1.f;
@ -571,4 +589,33 @@ static inline void quat_from_mat4x4(quat q, mat4x4 M)
q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r);
} }
LINMATH_H_FUNC void mat4x4_arcball(mat4x4 R, mat4x4 M, vec2 _a, vec2 _b, float s)
{
vec2 a; memcpy(a, _a, sizeof(a));
vec2 b; memcpy(b, _b, sizeof(b));
float z_a = 0.;
float z_b = 0.;
if(vec2_len(a) < 1.f) {
z_a = sqrtf(1.f - vec2_mul_inner(a, a));
} else {
vec2_norm(a, a);
}
if(vec2_len(b) < 1.f) {
z_b = sqrtf(1.f - vec2_mul_inner(b, b));
} else {
vec2_norm(b, b);
}
vec3 a_ = {a[0], a[1], z_a};
vec3 b_ = {b[0], b[1], z_b};
vec3 c_;
vec3_mul_cross(c_, a_, b_);
float const angle = acosf(vec3_mul_inner(a_, b_)) * s;
mat4x4_rotate(R, M, c_[0], c_[1], c_[2], angle);
}
#endif #endif

View File

@ -30,3 +30,5 @@ add_custom_target(docs ALL "${DOXYGEN_EXECUTABLE}"
WORKING_DIRECTORY "${GLFW_BINARY_DIR}/docs" WORKING_DIRECTORY "${GLFW_BINARY_DIR}/docs"
COMMENT "Generating HTML documentation" VERBATIM) COMMENT "Generating HTML documentation" VERBATIM)
set_target_properties(docs PROPERTIES FOLDER "GLFW3")

View File

@ -78,6 +78,11 @@ compiler that the GLFW functions are defined in a DLL.
The following macros control which OpenGL or OpenGL ES API header is included. The following macros control which OpenGL or OpenGL ES API header is included.
Only one of these may be defined at a time. Only one of these may be defined at a time.
@note GLFW does not provide any of the API headers mentioned below. They are
provided by your development environment or your OpenGL, OpenGL ES or Vulkan
SDK, and most of them can be downloaded from the
[Khronos Registry](https://www.khronos.org/registry/).
@anchor GLFW_INCLUDE_GLCOREARB @anchor GLFW_INCLUDE_GLCOREARB
__GLFW_INCLUDE_GLCOREARB__ makes the GLFW header include the modern __GLFW_INCLUDE_GLCOREARB__ makes the GLFW header include the modern
`GL/glcorearb.h` header (`OpenGL/gl3.h` on macOS) instead of the regular OpenGL `GL/glcorearb.h` header (`OpenGL/gl3.h` on macOS) instead of the regular OpenGL
@ -129,10 +134,6 @@ header selected above. This should only be used with the standard OpenGL header
and only for compatibility with legacy code. GLU has been deprecated and should and only for compatibility with legacy code. GLU has been deprecated and should
not be used in new code. not be used in new code.
@note GLFW does not provide any of the API headers mentioned above. They must
be provided by your development environment or your OpenGL, OpenGL ES or Vulkan
SDK.
@note None of these macros may be defined during the compilation of GLFW itself. @note None of these macros may be defined during the compilation of GLFW itself.
If your build includes GLFW and you define any these in your build files, make If your build includes GLFW and you define any these in your build files, make
sure they are not applied to the GLFW sources. sure they are not applied to the GLFW sources.
@ -166,16 +167,11 @@ must also explicitly link with `gdi32`. Other toolchains including MinGW-w64
include it in the set of default libraries along with other dependencies like include it in the set of default libraries along with other dependencies like
`user32` and `kernel32`. `user32` and `kernel32`.
If you are using GLU, you must also link with `glu32`.
The link library for the GLFW DLL is named `glfw3dll`. When compiling an The link library for the GLFW DLL is named `glfw3dll`. When compiling an
application that uses the DLL version of GLFW, you need to define the @ref application that uses the DLL version of GLFW, you need to define the @ref
GLFW_DLL macro _before_ any inclusion of the GLFW header. This can be done GLFW_DLL macro _before_ any inclusion of the GLFW header. This can be done
either with a compiler switch or by defining it in your source code. either with a compiler switch or by defining it in your source code.
An application using the GLFW DLL does not need to link against any of its
dependencies, but you still have to link against `glu32` if it uses GLU.
@subsection build_link_cmake_source With CMake and GLFW source @subsection build_link_cmake_source With CMake and GLFW source
@ -187,51 +183,38 @@ With a few changes to your `CMakeLists.txt` you can have the GLFW source tree
built along with your application. built along with your application.
Add the root directory of the GLFW source tree to your project. This will add Add the root directory of the GLFW source tree to your project. This will add
the `glfw` target and the necessary cache variables to your project. the `glfw` target to your project.
@code{.cmake} @code{.cmake}
add_subdirectory(path/to/glfw) add_subdirectory(path/to/glfw)
@endcode @endcode
Once GLFW has been added to the project, link against it with the `glfw` target. Once GLFW has been added, link your application against the `glfw` target.
This adds all link-time dependencies of GLFW as it is currently configured, This adds the GLFW library and its link-time dependencies as it is currently
the include directory for the GLFW header and, when applicable, the @ref configured, the include directory for the GLFW header and, when applicable, the
GLFW_DLL macro. @ref GLFW_DLL macro.
@code{.cmake} @code{.cmake}
target_link_libraries(myapp glfw) target_link_libraries(myapp glfw)
@endcode @endcode
Note that the dependencies do not include OpenGL or GLU, as GLFW loads any Note that the `glfw` target does not depend on OpenGL, as GLFW loads any OpenGL,
OpenGL, OpenGL ES or Vulkan libraries it needs at runtime and does not use GLU. OpenGL ES or Vulkan libraries it needs at runtime. If your application calls
If your application calls OpenGL directly, instead of using a modern OpenGL directly, instead of using a modern
[extension loader library](@ref context_glext_auto) you can find it by requiring [extension loader library](@ref context_glext_auto), use the OpenGL CMake
the OpenGL package. package.
@code{.cmake} @code{.cmake}
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
@endcode @endcode
If OpenGL is found, the `OPENGL_FOUND` variable is true and the If OpenGL is found, the `OpenGL::GL` target is added to your project, containing
`OPENGL_INCLUDE_DIR` and `OPENGL_gl_LIBRARY` cache variables can be used. library and include directory paths. Link against this like any other library.
@code{.cmake} @code{.cmake}
target_include_directories(myapp PUBLIC ${OPENGL_INCLUDE_DIR}) target_link_libraries(myapp OpenGL::GL)
target_link_libraries(myapp ${OPENGL_gl_LIBRARY})
@endcode @endcode
The OpenGL CMake package also looks for GLU. If GLU is found, the
`OPENGL_GLU_FOUND` variable is true and the `OPENGL_INCLUDE_DIR` and
`OPENGL_glu_LIBRARY` cache variables can be used.
@code{.cmake}
target_link_libraries(myapp ${OPENGL_glu_LIBRARY})
@endcode
@note GLU has been deprecated and should not be used in new code, but some
legacy code requires it. See the [section on GLU](@ref moving_glu) in the
transition guide for suggested replacements.
@subsection build_link_cmake_package With CMake and installed GLFW binaries @subsection build_link_cmake_package With CMake and installed GLFW binaries
@ -247,44 +230,30 @@ find_package(glfw3 3.4 REQUIRED)
@endcode @endcode
Once GLFW has been added to the project, link against it with the `glfw` target. Once GLFW has been added to the project, link against it with the `glfw` target.
This adds all link-time dependencies of GLFW as it is currently configured, This adds the GLFW library and its link-time dependencies, the include directory
the include directory for the GLFW header and, when applicable, the @ref for the GLFW header and, when applicable, the @ref GLFW_DLL macro.
GLFW_DLL macro.
@code{.cmake} @code{.cmake}
target_link_libraries(myapp glfw) target_link_libraries(myapp glfw)
@endcode @endcode
Note that the dependencies do not include OpenGL or GLU, as GLFW loads any Note that the `glfw` target does not depend on OpenGL, as GLFW loads any OpenGL,
OpenGL, OpenGL ES or Vulkan libraries it needs at runtime and does not use GLU. OpenGL ES or Vulkan libraries it needs at runtime. If your application calls
If your application calls OpenGL directly, instead of using a modern OpenGL directly, instead of using a modern
[extension loader library](@ref context_glext_auto) you can find it by requiring [extension loader library](@ref context_glext_auto), use the OpenGL CMake
the OpenGL package. package.
@code{.cmake} @code{.cmake}
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
@endcode @endcode
If OpenGL is found, the `OPENGL_FOUND` variable is true and the If OpenGL is found, the `OpenGL::GL` target is added to your project, containing
`OPENGL_INCLUDE_DIR` and `OPENGL_gl_LIBRARY` cache variables can be used. library and include directory paths. Link against this like any other library.
@code{.cmake} @code{.cmake}
target_include_directories(myapp PUBLIC ${OPENGL_INCLUDE_DIR}) target_link_libraries(myapp OpenGL::GL)
target_link_libraries(myapp ${OPENGL_gl_LIBRARY})
@endcode @endcode
The OpenGL CMake package also looks for GLU. If GLU is found, the
`OPENGL_GLU_FOUND` variable is true and the `OPENGL_INCLUDE_DIR` and
`OPENGL_glu_LIBRARY` cache variables can be used.
@code{.cmake}
target_link_libraries(myapp ${OPENGL_glu_LIBRARY})
@endcode
@note GLU has been deprecated and should not be used in new code, but some
legacy code requires it. See the [section on GLU](@ref moving_glu) in the
transition guide for suggested replacements.
@subsection build_link_pkgconfig With makefiles and pkg-config on Unix @subsection build_link_pkgconfig With makefiles and pkg-config on Unix
@ -299,42 +268,31 @@ A typical compile and link command-line when using the static version of the
GLFW library may look like this: GLFW library may look like this:
@code{.sh} @code{.sh}
cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --static --libs glfw3` cc $(pkg-config --cflags glfw3) -o myprog myprog.c $(pkg-config --static --libs glfw3)
@endcode @endcode
If you are using the shared version of the GLFW library, omit the `--static` If you are using the shared version of the GLFW library, omit the `--static`
flag. flag.
@code{.sh} @code{.sh}
cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --libs glfw3` cc $(pkg-config --cflags glfw3) -o myprog myprog.c $(pkg-config --libs glfw3)
@endcode @endcode
You can also use the `glfw3.pc` file without installing it first, by using the You can also use the `glfw3.pc` file without installing it first, by using the
`PKG_CONFIG_PATH` environment variable. `PKG_CONFIG_PATH` environment variable.
@code{.sh} @code{.sh}
env PKG_CONFIG_PATH=path/to/glfw/src cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --libs glfw3` env PKG_CONFIG_PATH=path/to/glfw/src cc $(pkg-config --cflags glfw3) -o myprog myprog.c $(pkg-config --libs glfw3)
@endcode @endcode
The dependencies do not include OpenGL or GLU, as GLFW loads any OpenGL, OpenGL The dependencies do not include OpenGL, as GLFW loads any OpenGL, OpenGL ES or
ES or Vulkan libraries it needs at runtime and does not use GLU. On macOS, GLU Vulkan libraries it needs at runtime. If your application calls OpenGL
is built into the OpenGL framework, so if you need GLU you don't need to do directly, instead of using a modern
anything extra. If you need GLU and are using Linux or BSD, you should add the [extension loader library](@ref context_glext_auto), you should add the `gl`
`glu` pkg-config package. pkg-config package.
@code{.sh} @code{.sh}
cc `pkg-config --cflags glfw3 glu` -o myprog myprog.c `pkg-config --libs glfw3 glu` cc $(pkg-config --cflags glfw3 gl) -o myprog myprog.c $(pkg-config --libs glfw3 gl)
@endcode
@note GLU has been deprecated and should not be used in new code, but some
legacy code requires it. See the [section on GLU](@ref moving_glu) in the
transition guide for suggested replacements.
If you are using the static version of the GLFW library, make sure you don't
link statically against GLU.
@code{.sh}
cc `pkg-config --cflags glfw3 glu` -o myprog myprog.c `pkg-config --static --libs glfw3` `pkg-config --libs glu`
@endcode @endcode
@ -344,8 +302,8 @@ If you are using the dynamic library version of GLFW, add it to the project
dependencies. dependencies.
If you are using the static library version of GLFW, add it and the Cocoa, If you are using the static library version of GLFW, add it and the Cocoa,
OpenGL, IOKit and CoreVideo frameworks to the project as dependencies. They can OpenGL and IOKit frameworks to the project as dependencies. They can all be
all be found in `/System/Library/Frameworks`. found in `/System/Library/Frameworks`.
@subsection build_link_osx With command-line on macOS @subsection build_link_osx With command-line on macOS
@ -359,7 +317,7 @@ the `-l` and `-framework` switches.
If you are using the dynamic GLFW library, which is named `libglfw.3.dylib`, do: If you are using the dynamic GLFW library, which is named `libglfw.3.dylib`, do:
@code{.sh} @code{.sh}
cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit
@endcode @endcode
If you are using the static library, named `libglfw3.a`, substitute `-lglfw3` If you are using the static library, named `libglfw3.a`, substitute `-lglfw3`
@ -368,9 +326,7 @@ for `-lglfw`.
Note that you do not add the `.framework` extension to a framework when linking Note that you do not add the `.framework` extension to a framework when linking
against it from the command-line. against it from the command-line.
The OpenGL framework contains both the OpenGL and GLU APIs, so there is nothing @note Your machine may have `libGL.*.dylib` style OpenGL library, but that is
special to do when using GLU. Also note that even though your machine may have for the X Window System and will not work with the macOS native version of GLFW.
`libGL`-style OpenGL libraries, they are for use with the X Window System and
will _not_ work with the macOS native version of GLFW.
*/ */

View File

@ -111,7 +111,7 @@ has been configured in the compositor.
GLFW uses the [xdg-shell GLFW uses the [xdg-shell
protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/xdg-shell/xdg-shell.xml) protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/xdg-shell/xdg-shell.xml)
to provide better window management. This protocol is part of to provide better window management. This protocol is part of
wayland-protocols 1.12, and mandatory at build time. wayland-protocols 1.12, and is mandatory for GLFW to display a window.
GLFW uses the [relative pointer GLFW uses the [relative pointer
protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/unstable/relative-pointer/relative-pointer-unstable-v1.xml) protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/unstable/relative-pointer/relative-pointer-unstable-v1.xml)
@ -268,10 +268,10 @@ surfaces on Microsoft Windows. If any of these extensions are not available,
@ref glfwGetRequiredInstanceExtensions will return an empty list and window @ref glfwGetRequiredInstanceExtensions will return an empty list and window
surface creation will fail. surface creation will fail.
GLFW uses the `VK_KHR_surface` and `VK_MVK_macos_surface` extensions to create GLFW uses the `VK_KHR_surface` and either the `VK_MVK_macos_surface` or
surfaces on macOS. If any of these extensions are not available, @ref `VK_EXT_metal_surface` extensions to create surfaces on macOS. If any of these
glfwGetRequiredInstanceExtensions will return an empty list and window surface extensions are not available, @ref glfwGetRequiredInstanceExtensions will
creation will fail. return an empty list and window surface creation will fail.
GLFW uses the `VK_KHR_surface` and either the `VK_KHR_xlib_surface` or GLFW uses the `VK_KHR_surface` and either the `VK_KHR_xlib_surface` or
`VK_KHR_xcb_surface` extensions to create surfaces on X11. If `VK_KHR_surface` `VK_KHR_xcb_surface` extensions to create surfaces on X11. If `VK_KHR_surface`

View File

@ -84,10 +84,6 @@ objects are recommended for rendering with such contexts.
You should still [process events](@ref events) as long as you have at least one You should still [process events](@ref events) as long as you have at least one
window, even if none of them are visible. window, even if none of them are visible.
@macos The first time a window is created the menu bar is created. This is not
desirable for example when writing a command-line only application. Menu bar
creation can be disabled with the @ref GLFW_COCOA_MENUBAR init hint.
@subsection context_less Windows without contexts @subsection context_less Windows without contexts

View File

@ -62,6 +62,11 @@ before the application exits. Modern systems are very good at freeing resources
allocated by programs that exit, but GLFW sometimes has to change global system allocated by programs that exit, but GLFW sometimes has to change global system
settings and these might not be restored without termination. settings and these might not be restored without termination.
@macos When the library is initialized the main menu and dock icon are created.
These are not desirable for a command-line only program. The creation of the
main menu and dock icon can be disabled with the @ref GLFW_COCOA_MENUBAR init
hint.
@subsection init_hints Initialization hints @subsection init_hints Initialization hints
@ -97,9 +102,9 @@ the application to the `Contents/Resources` subdirectory of the application's
bundle, if present. Set this with @ref glfwInitHint. bundle, if present. Set this with @ref glfwInitHint.
@anchor GLFW_COCOA_MENUBAR_hint @anchor GLFW_COCOA_MENUBAR_hint
__GLFW_COCOA_MENUBAR__ specifies whether to create a basic menu bar, either from __GLFW_COCOA_MENUBAR__ specifies whether to create the menu bar and dock icon
a nib or manually, when the first window is created, which is when AppKit is when GLFW is initialized. This applies whether the menu bar is created from
initialized. Set this with @ref glfwInitHint. a nib or manually by GLFW. Set this with @ref glfwInitHint.
@subsubsection init_hints_values Supported and default values @subsubsection init_hints_values Supported and default values

View File

@ -52,6 +52,19 @@ add_subdirectory(path/to/glfw)
@endcode @endcode
@subsubsection initmenu_34 macOS main menu now created at initialization
GLFW now creates the main menu and completes the initialization of NSApplication
during initialization. Programs that do not want a main menu can disable it
with the [GLFW_COCOA_MENUBAR](@ref GLFW_COCOA_MENUBAR_hint) init hint.
@subsubsection corevideo_34 CoreVideo dependency has been removed
GLFW no longer depends on the CoreVideo framework on macOS and it no longer
needs to be specified during compilation or linking.
@subsection deprecations_34 Deprecations in version 3.4 @subsection deprecations_34 Deprecations in version 3.4
@subsection removals_34 Removals in 3.4 @subsection removals_34 Removals in 3.4

View File

@ -1,7 +1,7 @@
link_libraries(glfw) link_libraries(glfw)
include_directories(${glfw_INCLUDE_DIRS} "${GLFW_SOURCE_DIR}/deps") include_directories("${GLFW_SOURCE_DIR}/deps")
if (MATH_LIBRARY) if (MATH_LIBRARY)
link_libraries("${MATH_LIBRARY}") link_libraries("${MATH_LIBRARY}")
@ -11,27 +11,10 @@ if (MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif() endif()
if (GLFW_USE_OSMESA)
add_definitions(-DUSE_NATIVE_OSMESA)
endif()
if (WIN32) if (WIN32)
set(ICON glfw.rc) set(ICON glfw.rc)
elseif (APPLE) elseif (APPLE)
set(ICON glfw.icns) set(ICON glfw.icns)
set_source_files_properties(glfw.icns PROPERTIES
MACOSX_PACKAGE_LOCATION "Resources")
endif()
if (${CMAKE_VERSION} VERSION_EQUAL "3.1.0" OR
${CMAKE_VERSION} VERSION_GREATER "3.1.0")
set(CMAKE_C_STANDARD 99)
else()
# Remove this fallback when removing support for CMake version less than 3.1
add_compile_options("$<$<C_COMPILER_ID:AppleClang>:-std=c99>"
"$<$<C_COMPILER_ID:Clang>:-std=c99>"
"$<$<C_COMPILER_ID:GNU>:-std=c99>")
endif() endif()
set(GLAD_GL "${GLFW_SOURCE_DIR}/deps/glad/gl.h" set(GLAD_GL "${GLFW_SOURCE_DIR}/deps/glad/gl.h"
@ -51,20 +34,26 @@ add_executable(splitview WIN32 MACOSX_BUNDLE splitview.c ${ICON} ${GLAD_GL})
add_executable(triangle-opengl WIN32 MACOSX_BUNDLE triangle-opengl.c ${ICON} ${GLAD_GL}) add_executable(triangle-opengl WIN32 MACOSX_BUNDLE triangle-opengl.c ${ICON} ${GLAD_GL})
add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD_GL}) add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD_GL})
target_link_libraries(particles "${CMAKE_THREAD_LIBS_INIT}") target_link_libraries(particles Threads::Threads)
if (RT_LIBRARY) if (RT_LIBRARY)
target_link_libraries(particles "${RT_LIBRARY}") target_link_libraries(particles "${RT_LIBRARY}")
endif() endif()
set(WINDOWS_BINARIES boing gears heightmap particles sharing splitview triangle-opengl wave) set(GUI_ONLY_BINARIES boing gears heightmap particles sharing splitview
triangle-opengl wave)
set(CONSOLE_BINARIES offscreen) set(CONSOLE_BINARIES offscreen)
set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
C_STANDARD 99
FOLDER "GLFW3/Examples") FOLDER "GLFW3/Examples")
if (GLFW_USE_OSMESA)
target_compile_definitions(offscreen PRIVATE USE_NATIVE_OSMESA)
endif()
if (MSVC) if (MSVC)
# Tell MSVC to use main instead of WinMain for Windows subsystem executables # Tell MSVC to use main instead of WinMain for Windows subsystem executables
set_target_properties(${WINDOWS_BINARIES} PROPERTIES set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES
LINK_FLAGS "/ENTRY:mainCRTStartup") LINK_FLAGS "/ENTRY:mainCRTStartup")
endif() endif()
@ -78,11 +67,12 @@ if (APPLE)
set_target_properties(splitview PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "SplitView") set_target_properties(splitview PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "SplitView")
set_target_properties(wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave") set_target_properties(wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave")
set_target_properties(${WINDOWS_BINARIES} PROPERTIES set_source_files_properties(glfw.icns PROPERTIES
RESOURCE glfw.icns MACOSX_PACKAGE_LOCATION "Resources")
set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES
MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION}
MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION} MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION}
MACOSX_BUNDLE_ICON_FILE glfw.icns MACOSX_BUNDLE_ICON_FILE glfw.icns
MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/MacOSXBundleInfo.plist.in") MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/Info.plist.in")
endif() endif()

View File

@ -148,6 +148,7 @@ int main(void)
glUseProgram(program); glUseProgram(program);
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp); glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
glFinish();
#if USE_NATIVE_OSMESA #if USE_NATIVE_OSMESA
glfwGetOSMesaColorBuffer(window, &width, &height, NULL, (void**) &buffer); glfwGetOSMesaColorBuffer(window, &width, &height, NULL, (void**) &buffer);

View File

@ -1831,6 +1831,18 @@ typedef struct GLFWgamepadstate
* bundle, if present. This can be disabled with the @ref * bundle, if present. This can be disabled with the @ref
* GLFW_COCOA_CHDIR_RESOURCES init hint. * GLFW_COCOA_CHDIR_RESOURCES init hint.
* *
* @remark @macos This function will create the main menu and dock icon for the
* application. If GLFW finds a `MainMenu.nib` it is loaded and assumed to
* contain a menu bar. Otherwise a minimal menu bar is created manually with
* common commands like Hide, Quit and About. The About entry opens a minimal
* about dialog with information from the application's bundle. The menu bar
* and dock icon can be disabled entirely with the @ref GLFW_COCOA_MENUBAR init
* hint.
*
* @remark @x11 This function will set the `LC_CTYPE` category of the
* application locale according to the current environment if that category is
* still "C". This is because the "C" locale breaks Unicode text input.
*
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref intro_init * @sa @ref intro_init
@ -2670,13 +2682,6 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
* in the Mac Developer Library. * in the Mac Developer Library.
* *
* @remark @macos The first time a window is created the menu bar is created.
* If GLFW finds a `MainMenu.nib` it is loaded and assumed to contain a menu
* bar. Otherwise a minimal menu bar is created manually with common commands
* like Hide, Quit and About. The About entry opens a minimal about dialog
* with information from the application's bundle. Menu bar creation can be
* disabled entirely with the @ref GLFW_COCOA_MENUBAR init hint.
*
* @remark @macos On OS X 10.10 and later the window frame will not be rendered * @remark @macos On OS X 10.10 and later the window frame will not be rendered
* at full resolution on Retina displays unless the * at full resolution on Retina displays unless the
* [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint) * [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint)
@ -2685,7 +2690,7 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
* [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html)
* in the Mac Developer Library. The GLFW test and example programs use * in the Mac Developer Library. The GLFW test and example programs use
* a custom `Info.plist` template for this, which can be found as * a custom `Info.plist` template for this, which can be found as
* `CMake/MacOSXBundleInfo.plist.in` in the source tree. * `CMake/Info.plist.in` in the source tree.
* *
* @remark @macos When activating frame autosaving with * @remark @macos When activating frame autosaving with
* [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified * [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified
@ -5776,8 +5781,9 @@ GLFWAPI int glfwVulkanSupported(void);
* returned array, as it is an error to specify an extension more than once in * returned array, as it is an error to specify an extension more than once in
* the `VkInstanceCreateInfo` struct. * the `VkInstanceCreateInfo` struct.
* *
* @remark @macos This function currently only supports the * @remark @macos This function currently supports either the
* `VK_MVK_macos_surface` extension from MoltenVK. * `VK_MVK_macos_surface` extension from MoltenVK or `VK_EXT_metal_surface`
* extension.
* *
* @pointer_lifetime The returned array is allocated and freed by GLFW. You * @pointer_lifetime The returned array is allocated and freed by GLFW. You
* should not free it yourself. It is guaranteed to be valid only until the * should not free it yourself. It is guaranteed to be valid only until the

View File

@ -1,118 +1,96 @@
set(common_HEADERS internal.h mappings.h add_library(glfw "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h"
"${GLFW_BINARY_DIR}/src/glfw_config.h" "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h"
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" internal.h mappings.h context.c init.c input.c monitor.c
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") vulkan.c window.c)
set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c)
if (_GLFW_COCOA) if (_GLFW_COCOA)
set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h target_sources(glfw PRIVATE cocoa_platform.h cocoa_joystick.h posix_thread.h
posix_thread.h nsgl_context.h egl_context.h osmesa_context.h) nsgl_context.h egl_context.h osmesa_context.h
set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m cocoa_init.m cocoa_joystick.m cocoa_monitor.m
cocoa_monitor.m cocoa_window.m cocoa_time.c posix_thread.c cocoa_window.m cocoa_time.c posix_thread.c
nsgl_context.m egl_context.c osmesa_context.c) nsgl_context.m egl_context.c osmesa_context.c)
elseif (_GLFW_WIN32) elseif (_GLFW_WIN32)
set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h target_sources(glfw PRIVATE win32_platform.h win32_joystick.h wgl_context.h
wgl_context.h egl_context.h osmesa_context.h) egl_context.h osmesa_context.h win32_init.c
set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c win32_joystick.c win32_monitor.c win32_time.c
win32_monitor.c win32_time.c win32_thread.c win32_window.c win32_thread.c win32_window.c wgl_context.c
wgl_context.c egl_context.c osmesa_context.c) egl_context.c osmesa_context.c)
elseif (_GLFW_X11) elseif (_GLFW_X11)
set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h posix_time.h target_sources(glfw PRIVATE x11_platform.h xkb_unicode.h posix_time.h
posix_thread.h glx_context.h egl_context.h osmesa_context.h) posix_thread.h glx_context.h egl_context.h
set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c osmesa_context.h x11_init.c x11_monitor.c
xkb_unicode.c posix_time.c posix_thread.c glx_context.c x11_window.c xkb_unicode.c posix_time.c
egl_context.c osmesa_context.c) posix_thread.c glx_context.c egl_context.c
osmesa_context.c)
elseif (_GLFW_WAYLAND) elseif (_GLFW_WAYLAND)
set(glfw_HEADERS ${common_HEADERS} wl_platform.h target_sources(glfw PRIVATE wl_platform.h posix_time.h posix_thread.h
posix_time.h posix_thread.h xkb_unicode.h egl_context.h xkb_unicode.h egl_context.h osmesa_context.h
osmesa_context.h) wl_init.c wl_monitor.c wl_window.c posix_time.c
set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c posix_thread.c xkb_unicode.c egl_context.c
posix_time.c posix_thread.c xkb_unicode.c osmesa_context.c)
egl_context.c osmesa_context.c)
ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml"
BASENAME xdg-shell)
ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
BASENAME xdg-decoration)
ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml"
BASENAME viewporter)
ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
BASENAME relative-pointer-unstable-v1)
ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
BASENAME pointer-constraints-unstable-v1)
ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
BASENAME idle-inhibit-unstable-v1)
elseif (_GLFW_OSMESA) elseif (_GLFW_OSMESA)
set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h target_sources(glfw PRIVATE null_platform.h null_joystick.h posix_time.h
posix_time.h posix_thread.h osmesa_context.h) posix_thread.h osmesa_context.h null_init.c
set(glfw_SOURCES ${common_SOURCES} null_init.c null_monitor.c null_window.c null_monitor.c null_window.c null_joystick.c
null_joystick.c posix_time.c posix_thread.c osmesa_context.c) posix_time.c posix_thread.c osmesa_context.c)
endif() endif()
if (_GLFW_X11 OR _GLFW_WAYLAND) if (_GLFW_X11 OR _GLFW_WAYLAND)
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
set(glfw_HEADERS ${glfw_HEADERS} linux_joystick.h) target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c)
set(glfw_SOURCES ${glfw_SOURCES} linux_joystick.c)
else() else()
set(glfw_HEADERS ${glfw_HEADERS} null_joystick.h) target_sources(glfw PRIVATE null_joystick.h null_joystick.c)
set(glfw_SOURCES ${glfw_SOURCES} null_joystick.c)
endif() endif()
endif() endif()
if (APPLE) if (_GLFW_WAYLAND)
# For some reason, CMake doesn't know about .m ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES
set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml"
BASENAME xdg-shell)
ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
BASENAME xdg-decoration)
ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml"
BASENAME viewporter)
ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
BASENAME relative-pointer-unstable-v1)
ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
BASENAME pointer-constraints-unstable-v1)
ecm_add_wayland_client_protocol(GLFW_WAYLAND_PROTOCOL_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
BASENAME idle-inhibit-unstable-v1)
target_sources(glfw PRIVATE ${GLFW_WAYLAND_PROTOCOL_SOURCES})
endif() endif()
# Make GCC and Clang warn about declarations that VS 2010 and 2012 won't accept if (WIN32 AND BUILD_SHARED_LIBS)
# for all source files that VS will build configure_file(glfw.rc.in glfw.rc @ONLY)
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR target_sources(glfw PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/glfw.rc")
"${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
if (WIN32)
set(windows_SOURCES ${glfw_SOURCES})
else()
set(windows_SOURCES ${common_SOURCES})
endif()
set_source_files_properties(${windows_SOURCES} PROPERTIES
COMPILE_FLAGS -Wdeclaration-after-statement)
endif() endif()
add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) configure_file(glfw_config.h.in glfw_config.h @ONLY)
target_compile_definitions(glfw PRIVATE _GLFW_USE_CONFIG_H)
target_sources(glfw PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/glfw_config.h")
set_target_properties(glfw PROPERTIES set_target_properties(glfw PROPERTIES
OUTPUT_NAME ${GLFW_LIB_NAME} OUTPUT_NAME ${GLFW_LIB_NAME}
VERSION ${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR} VERSION ${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}
SOVERSION ${GLFW_VERSION_MAJOR} SOVERSION ${GLFW_VERSION_MAJOR}
POSITION_INDEPENDENT_CODE ON POSITION_INDEPENDENT_CODE ON
C_STANDARD 99
C_EXTENSIONS OFF
DEFINE_SYMBOL _GLFW_BUILD_DLL
FOLDER "GLFW3") FOLDER "GLFW3")
if (${CMAKE_VERSION} VERSION_EQUAL "3.1.0" OR
${CMAKE_VERSION} VERSION_GREATER "3.1.0")
set_target_properties(glfw PROPERTIES C_STANDARD 99)
else()
# Remove this fallback when removing support for CMake version less than 3.1
target_compile_options(glfw PRIVATE
"$<$<C_COMPILER_ID:AppleClang>:-std=c99>"
"$<$<C_COMPILER_ID:Clang>:-std=c99>"
"$<$<C_COMPILER_ID:GNU>:-std=c99>")
endif()
target_compile_definitions(glfw PRIVATE _GLFW_USE_CONFIG_H)
target_include_directories(glfw PUBLIC target_include_directories(glfw PUBLIC
"$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>" "$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>") "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
@ -120,26 +98,50 @@ target_include_directories(glfw PRIVATE
"${GLFW_SOURCE_DIR}/src" "${GLFW_SOURCE_DIR}/src"
"${GLFW_BINARY_DIR}/src" "${GLFW_BINARY_DIR}/src"
${glfw_INCLUDE_DIRS}) ${glfw_INCLUDE_DIRS})
target_link_libraries(glfw PRIVATE Threads::Threads ${glfw_LIBRARIES})
if (APPLE)
# For some reason CMake didn't know about .m until version 3.16
set_source_files_properties(cocoa_init.m cocoa_joystick.m cocoa_monitor.m
cocoa_window.m nsgl_context.m PROPERTIES
LANGUAGE C)
endif()
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
"${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
# Make GCC and Clang warn about declarations that VS 2010 and 2012 won't
# accept for all source files that VS will build
set_source_files_properties(context.c init.c input.c monitor.c vulkan.c
window.c win32_init.c win32_joystick.c
win32_monitor.c win32_time.c win32_thread.c
win32_window.c wgl_context.c egl_context.c
osmesa_context.c PROPERTIES
COMPILE_FLAGS -Wdeclaration-after-statement)
# Enable a reasonable set of warnings (no, -Wextra is not reasonable)
target_compile_options(glfw PRIVATE "-Wall")
endif()
if (WIN32)
target_compile_definitions(glfw PRIVATE _UNICODE)
endif()
# HACK: When building on MinGW, WINVER and UNICODE need to be defined before # HACK: When building on MinGW, WINVER and UNICODE need to be defined before
# the inclusion of stddef.h (by glfw3.h), which is itself included before # the inclusion of stddef.h (by glfw3.h), which is itself included before
# win32_platform.h. We define them here until a saner solution can be found # win32_platform.h. We define them here until a saner solution can be found
# NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. # NOTE: MinGW-w64 and Visual C++ do /not/ need this hack.
target_compile_definitions(glfw PRIVATE if (MINGW)
"$<$<BOOL:${MINGW}>:UNICODE;WINVER=0x0501>") target_compile_definitions(glfw PRIVATE UNICODE WINVER=0x0501)
endif()
# Enable a reasonable set of warnings (no, -Wextra is not reasonable)
target_compile_options(glfw PRIVATE
"$<$<C_COMPILER_ID:AppleClang>:-Wall>"
"$<$<C_COMPILER_ID:Clang>:-Wall>"
"$<$<C_COMPILER_ID:GNU>:-Wall>")
if (BUILD_SHARED_LIBS) if (BUILD_SHARED_LIBS)
if (WIN32) if (WIN32)
if (MINGW) if (MINGW)
# Remove the dependency on the shared version of libgcc # Remove the dependency on the shared version of libgcc
# NOTE: MinGW-w64 has the correct default but MinGW needs this # NOTE: MinGW-w64 has the correct default but MinGW needs this
target_link_options(glfw PRIVATE "-static-libgcc") target_link_libraries(glfw PRIVATE "-static-libgcc")
# Remove the lib prefix on the DLL (but not the import library) # Remove the lib prefix on the DLL (but not the import library)
set_target_properties(glfw PROPERTIES PREFIX "") set_target_properties(glfw PROPERTIES PREFIX "")
@ -151,11 +153,8 @@ if (BUILD_SHARED_LIBS)
set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib")
endif() endif()
target_compile_definitions(glfw INTERFACE GLFW_DLL) target_compile_definitions(glfw INTERFACE GLFW_DLL)
elseif (APPLE) elseif (APPLE)
# Add -fno-common to work around a bug in Apple's GCC
target_compile_options(glfw PRIVATE "-fno-common")
set_target_properties(glfw PROPERTIES set_target_properties(glfw PROPERTIES
INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}") INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}")
endif() endif()
@ -164,10 +163,6 @@ if (BUILD_SHARED_LIBS)
# 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 PRIVATE "-fvisibility=hidden") target_compile_options(glfw PRIVATE "-fvisibility=hidden")
endif() endif()
target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES})
else()
target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES})
endif() endif()
if (MSVC) if (MSVC)

View File

@ -431,9 +431,8 @@ static GLFWbool initializeTIS(void)
// In case we are unbundled, make us a proper UI application // In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
// Menu bar setup must go between sharedApplication above and // Menu bar setup must go between sharedApplication and finishLaunching
// finishLaunching below, in order to properly emulate the behavior // in order to properly emulate the behavior of NSApplicationMain
// of NSApplicationMain
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
{ {
@ -448,9 +447,8 @@ static GLFWbool initializeTIS(void)
- (void)applicationDidFinishLaunching:(NSNotification *)notification - (void)applicationDidFinishLaunching:(NSNotification *)notification
{ {
[NSApp stop:nil];
_glfwPlatformPostEmptyEvent(); _glfwPlatformPostEmptyEvent();
[NSApp stop:nil];
} }
- (void)applicationDidHide:(NSNotification *)notification - (void)applicationDidHide:(NSNotification *)notification
@ -464,6 +462,32 @@ static GLFWbool initializeTIS(void)
@end // GLFWApplicationDelegate @end // GLFWApplicationDelegate
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void* _glfwLoadLocalVulkanLoaderNS(void)
{
CFBundleRef bundle = CFBundleGetMainBundle();
if (!bundle)
return NULL;
CFURLRef url =
CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
if (!url)
return NULL;
char path[PATH_MAX];
void* handle = NULL;
if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
handle = _glfw_dlopen(path);
CFRelease(url);
return handle;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -478,9 +502,6 @@ int _glfwPlatformInit(void)
toTarget:_glfw.ns.helper toTarget:_glfw.ns.helper
withObject:nil]; withObject:nil];
if (NSApp)
_glfw.ns.finishedLaunching = GLFW_TRUE;
[NSApplication sharedApplication]; [NSApplication sharedApplication];
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
@ -533,6 +554,10 @@ int _glfwPlatformInit(void)
_glfwInitJoysticksNS(); _glfwInitJoysticksNS();
_glfwPollMonitorsNS(); _glfwPollMonitorsNS();
if (![[NSRunningApplication currentApplication] isFinishedLaunching])
[NSApp run];
return GLFW_TRUE; return GLFW_TRUE;
} // autoreleasepool } // autoreleasepool

View File

@ -331,7 +331,7 @@ void _glfwInitJoysticksNS(void)
return; return;
} }
for (int i = 0; i < sizeof(usages) / sizeof(long); i++) for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++)
{ {
const long page = kHIDPage_GenericDesktop; const long page = kHIDPage_GenericDesktop;

View File

@ -144,7 +144,7 @@ static GLFWbool modeIsGood(CGDisplayModeRef mode)
// Convert Core Graphics display mode to GLFW video mode // Convert Core Graphics display mode to GLFW video mode
// //
static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode, static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
CVDisplayLinkRef link) double fallbackRefreshRate)
{ {
GLFWvidmode result; GLFWvidmode result;
result.width = (int) CGDisplayModeGetWidth(mode); result.width = (int) CGDisplayModeGetWidth(mode);
@ -152,11 +152,7 @@ static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
result.refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode)); result.refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode));
if (result.refreshRate == 0) if (result.refreshRate == 0)
{ result.refreshRate = (int) round(fallbackRefreshRate);
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
if (!(time.flags & kCVTimeIsIndefinite))
result.refreshRate = (int) (time.timeScale / (double) time.timeValue);
}
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 #if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
@ -238,6 +234,68 @@ static GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor)
return GLFW_FALSE; return GLFW_FALSE;
} }
// Returns the display refresh rate queried from the I/O registry
//
static double getFallbackRefreshRate(CGDirectDisplayID displayID)
{
double refreshRate = 60.0;
io_iterator_t it;
io_service_t service;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IOFramebuffer"),
&it) != 0)
{
return refreshRate;
}
while ((service = IOIteratorNext(it)) != 0)
{
const CFNumberRef indexRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFramebufferOpenGLIndex"),
kCFAllocatorDefault,
kNilOptions);
if (!indexRef)
continue;
uint32_t index = 0;
CFNumberGetValue(indexRef, kCFNumberIntType, &index);
CFRelease(indexRef);
if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID)
continue;
const CFNumberRef clockRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFBCurrentPixelClock"),
kCFAllocatorDefault,
kNilOptions);
const CFNumberRef countRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFBCurrentPixelCount"),
kCFAllocatorDefault,
kNilOptions);
if (!clockRef || !countRef)
break;
uint32_t clock = 0, count = 0;
CFNumberGetValue(clockRef, kCFNumberIntType, &clock);
CFNumberGetValue(countRef, kCFNumberIntType, &count);
CFRelease(clockRef);
CFRelease(countRef);
if (clock > 0 && count > 0)
refreshRate = clock / (double) count;
break;
}
IOObjectRelease(it);
return refreshRate;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW internal API ////// ////// GLFW internal API //////
@ -294,6 +352,11 @@ void _glfwPollMonitorsNS(void)
free(name); free(name);
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
if (CGDisplayModeGetRefreshRate(mode) == 0.0)
monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]);
CGDisplayModeRelease(mode);
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
} }
@ -318,9 +381,6 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
if (_glfwCompareVideoModes(&current, best) == 0) if (_glfwCompareVideoModes(&current, best) == 0)
return; return;
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
const CFIndex count = CFArrayGetCount(modes); const CFIndex count = CFArrayGetCount(modes);
CGDisplayModeRef native = NULL; CGDisplayModeRef native = NULL;
@ -331,7 +391,8 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
if (!modeIsGood(dm)) if (!modeIsGood(dm))
continue; continue;
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); const GLFWvidmode mode =
vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
if (_glfwCompareVideoModes(best, &mode) == 0) if (_glfwCompareVideoModes(best, &mode) == 0)
{ {
native = dm; native = dm;
@ -350,7 +411,6 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
} }
CFRelease(modes); CFRelease(modes);
CVDisplayLinkRelease(link);
} }
// Restore the previously saved (original) video mode // Restore the previously saved (original) video mode
@ -440,9 +500,6 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
*count = 0; *count = 0;
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
const CFIndex found = CFArrayGetCount(modes); const CFIndex found = CFArrayGetCount(modes);
GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode)); GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode));
@ -453,7 +510,8 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
if (!modeIsGood(dm)) if (!modeIsGood(dm))
continue; continue;
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); const GLFWvidmode mode =
vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
CFIndex j; CFIndex j;
for (j = 0; j < *count; j++) for (j = 0; j < *count; j++)
@ -471,7 +529,6 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
} }
CFRelease(modes); CFRelease(modes);
CVDisplayLinkRelease(link);
return result; return result;
} // autoreleasepool } // autoreleasepool
@ -481,15 +538,10 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
{ {
@autoreleasepool { @autoreleasepool {
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID); CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
*mode = vidmodeFromCGDisplayMode(native, link); *mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate);
CGDisplayModeRelease(native); CGDisplayModeRelease(native);
CVDisplayLinkRelease(link);
} // autoreleasepool } // autoreleasepool
} }

View File

@ -28,8 +28,6 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
#include <CoreVideo/CVBase.h>
#include <CoreVideo/CVDisplayLink.h>
// NOTE: All of NSGL was deprecated in the 10.14 SDK // NOTE: All of NSGL was deprecated in the 10.14 SDK
// This disables the pointless warnings for every symbol we use // This disables the pointless warnings for every symbol we use
@ -63,6 +61,7 @@ typedef void* id;
#endif #endif
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef VkFlags VkMetalSurfaceCreateFlagsEXT;
typedef struct VkMacOSSurfaceCreateInfoMVK typedef struct VkMacOSSurfaceCreateInfoMVK
{ {
@ -72,7 +71,16 @@ typedef struct VkMacOSSurfaceCreateInfoMVK
const void* pView; const void* pView;
} VkMacOSSurfaceCreateInfoMVK; } VkMacOSSurfaceCreateInfoMVK;
typedef struct VkMetalSurfaceCreateInfoEXT
{
VkStructureType sType;
const void* pNext;
VkMetalSurfaceCreateFlagsEXT flags;
const void* pLayer;
} VkMetalSurfaceCreateInfoEXT;
typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMetalSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*);
#include "posix_thread.h" #include "posix_thread.h"
#include "cocoa_joystick.h" #include "cocoa_joystick.h"
@ -133,7 +141,6 @@ typedef struct _GLFWlibraryNS
{ {
CGEventSourceRef eventSource; CGEventSourceRef eventSource;
id delegate; id delegate;
GLFWbool finishedLaunching;
GLFWbool cursorHidden; GLFWbool cursorHidden;
TISInputSourceRef inputSource; TISInputSourceRef inputSource;
IOHIDManagerRef hidManager; IOHIDManagerRef hidManager;
@ -170,6 +177,7 @@ typedef struct _GLFWmonitorNS
CGDisplayModeRef previousMode; CGDisplayModeRef previousMode;
uint32_t unitNumber; uint32_t unitNumber;
id screen; id screen;
double fallbackRefreshRate;
} _GLFWmonitorNS; } _GLFWmonitorNS;
@ -198,3 +206,5 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
float _glfwTransformYNS(float y); float _glfwTransformYNS(float y);
void* _glfwLoadLocalVulkanLoaderNS(void);

View File

@ -322,12 +322,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
_glfwInputWindowFocus(window, GLFW_FALSE); _glfwInputWindowFocus(window, GLFW_FALSE);
} }
- (void)windowDidChangeScreen:(NSNotification *)notification
{
if (window->context.source == GLFW_NATIVE_CONTEXT_API)
_glfwUpdateDisplayLinkDisplayNSGL(window);
}
@end @end
@ -890,12 +884,6 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{ {
@autoreleasepool { @autoreleasepool {
if (!_glfw.ns.finishedLaunching)
{
[NSApp run];
_glfw.ns.finishedLaunching = GLFW_TRUE;
}
if (!createNativeWindow(window, wndconfig, fbconfig)) if (!createNativeWindow(window, wndconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
@ -967,13 +955,14 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
} // autoreleasepool } // autoreleasepool
} }
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
{ {
@autoreleasepool { @autoreleasepool {
[window->ns.object setTitle:@(title)]; NSString* string = @(title);
[window->ns.object setTitle:string];
// HACK: Set the miniwindow title explicitly as setTitle: doesn't update it // HACK: Set the miniwindow title explicitly as setTitle: doesn't update it
// if the window lacks NSWindowStyleMaskTitled // if the window lacks NSWindowStyleMaskTitled
[window->ns.object setMiniwindowTitle:@(title)]; [window->ns.object setMiniwindowTitle:string];
} // autoreleasepool } // autoreleasepool
} }
@ -1512,6 +1501,13 @@ const char* _glfwPlatformGetScancodeName(int scancode)
{ {
@autoreleasepool { @autoreleasepool {
if (scancode < 0 || scancode > 0xff ||
_glfw.ns.keycodes[scancode] == GLFW_KEY_UNKNOWN)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");
return NULL;
}
const int key = _glfw.ns.keycodes[scancode]; const int key = _glfw.ns.keycodes[scancode];
UInt32 deadKeyState = 0; UInt32 deadKeyState = 0;
@ -1607,13 +1603,13 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
// HACK: Try to use a private message // HACK: Try to use a private message
if (shape == GLFW_RESIZE_EW_CURSOR) if (shape == GLFW_RESIZE_EW_CURSOR)
cursorSelector = @selector(_windowResizeEastWestCursor); cursorSelector = NSSelectorFromString(@"_windowResizeEastWestCursor");
else if (shape == GLFW_RESIZE_NS_CURSOR) else if (shape == GLFW_RESIZE_NS_CURSOR)
cursorSelector = @selector(_windowResizeNorthSouthCursor); cursorSelector = NSSelectorFromString(@"_windowResizeNorthSouthCursor");
else if (shape == GLFW_RESIZE_NWSE_CURSOR) else if (shape == GLFW_RESIZE_NWSE_CURSOR)
cursorSelector = @selector(_windowResizeNorthWestSouthEastCursor); cursorSelector = NSSelectorFromString(@"_windowResizeNorthWestSouthEastCursor");
else if (shape == GLFW_RESIZE_NESW_CURSOR) else if (shape == GLFW_RESIZE_NESW_CURSOR)
cursorSelector = @selector(_windowResizeNorthEastSouthWestCursor); cursorSelector = NSSelectorFromString(@"_windowResizeNorthEastSouthWestCursor");
if (cursorSelector && [NSCursor respondsToSelector:cursorSelector]) if (cursorSelector && [NSCursor respondsToSelector:cursorSelector])
{ {
@ -1711,11 +1707,16 @@ const char* _glfwPlatformGetClipboardString(void)
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
{ {
if (!_glfw.vk.KHR_surface || !_glfw.vk.MVK_macos_surface) if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface)
return; {
extensions[0] = "VK_KHR_surface";
extensions[0] = "VK_KHR_surface"; extensions[1] = "VK_EXT_metal_surface";
extensions[1] = "VK_MVK_macos_surface"; }
else if (_glfw.vk.KHR_surface && _glfw.vk.MVK_macos_surface)
{
extensions[0] = "VK_KHR_surface";
extensions[1] = "VK_MVK_macos_surface";
}
} }
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
@ -1733,19 +1734,6 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
@autoreleasepool { @autoreleasepool {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
VkResult err;
VkMacOSSurfaceCreateInfoMVK sci;
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK;
vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)
vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK");
if (!vkCreateMacOSSurfaceMVK)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Cocoa: Vulkan instance missing VK_MVK_macos_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
// HACK: Dynamically load Core Animation to avoid adding an extra // HACK: Dynamically load Core Animation to avoid adding an extra
// dependency for the majority who don't use MoltenVK // dependency for the majority who don't use MoltenVK
NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"]; NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"];
@ -1771,11 +1759,49 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
[window->ns.view setLayer:window->ns.layer]; [window->ns.view setLayer:window->ns.layer];
[window->ns.view setWantsLayer:YES]; [window->ns.view setWantsLayer:YES];
memset(&sci, 0, sizeof(sci)); VkResult err;
sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
sci.pView = window->ns.view; if (_glfw.vk.EXT_metal_surface)
{
VkMetalSurfaceCreateInfoEXT sci;
PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT;
vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT)
vkGetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT");
if (!vkCreateMetalSurfaceEXT)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Cocoa: Vulkan instance missing VK_EXT_metal_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
sci.pLayer = window->ns.layer;
err = vkCreateMetalSurfaceEXT(instance, &sci, allocator, surface);
}
else
{
VkMacOSSurfaceCreateInfoMVK sci;
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK;
vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)
vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK");
if (!vkCreateMacOSSurfaceMVK)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Cocoa: Vulkan instance missing VK_MVK_macos_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
sci.pView = window->ns.view;
err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface);
}
err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface);
if (err) if (err)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,

View File

@ -123,23 +123,24 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
continue; continue;
#if defined(_GLFW_X11) #if defined(_GLFW_X11)
XVisualInfo vi = {0};
// Only consider EGLConfigs with associated Visuals
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
if (!vi.visualid)
continue;
if (desired->transparent)
{ {
int count; XVisualInfo vi = {0};
XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display,
VisualIDMask, &vi, // Only consider EGLConfigs with associated Visuals
&count); vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
if (vis) if (!vi.visualid)
continue;
if (desired->transparent)
{ {
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); int count;
XFree(vis); XVisualInfo* vis =
XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
if (vis)
{
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
XFree(vis);
}
} }
} }
#endif // _GLFW_X11 #endif // _GLFW_X11

30
src/glfw.rc.in Normal file
View File

@ -0,0 +1,30 @@
#include <winver.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION @GLFW_VERSION_MAJOR@,@GLFW_VERSION_MINOR@,@GLFW_VERSION_PATCH@,0
PRODUCTVERSION @GLFW_VERSION_MAJOR@,@GLFW_VERSION_MINOR@,@GLFW_VERSION_PATCH@,0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0
{
BLOCK "StringFileInfo"
{
BLOCK "040904B0"
{
VALUE "CompanyName", "GLFW"
VALUE "FileDescription", "GLFW @GLFW_VERSION@ DLL"
VALUE "FileVersion", "@GLFW_VERSION@"
VALUE "OriginalFilename", "glfw3.dll"
VALUE "ProductName", "GLFW"
VALUE "ProductVersion", "@GLFW_VERSION@"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x409, 1200
}
}

View File

@ -1 +0,0 @@
include("${CMAKE_CURRENT_LIST_DIR}/glfw3Targets.cmake")

View File

@ -45,8 +45,6 @@
// Define this to 1 if building GLFW for OSMesa // Define this to 1 if building GLFW for OSMesa
#cmakedefine _GLFW_OSMESA #cmakedefine _GLFW_OSMESA
// Define this to 1 if building as a shared library / dynamic library / DLL
#cmakedefine _GLFW_BUILD_DLL
// Define this to 1 to use Vulkan loader linked statically into application // Define this to 1 to use Vulkan loader linked statically into application
#cmakedefine _GLFW_VULKAN_STATIC #cmakedefine _GLFW_VULKAN_STATIC

View File

@ -128,6 +128,7 @@ typedef enum VkStructureType
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
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_METAL_SURFACE_CREATE_INFO_EXT = 1000217000,
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
} VkStructureType; } VkStructureType;
@ -559,6 +560,7 @@ struct _GLFWlibrary
GLFWbool KHR_win32_surface; GLFWbool KHR_win32_surface;
#elif defined(_GLFW_COCOA) #elif defined(_GLFW_COCOA)
GLFWbool MVK_macos_surface; GLFWbool MVK_macos_surface;
GLFWbool EXT_metal_surface;
#elif defined(_GLFW_X11) #elif defined(_GLFW_X11)
GLFWbool KHR_xlib_surface; GLFWbool KHR_xlib_surface;
GLFWbool KHR_xcb_surface; GLFWbool KHR_xcb_surface;

View File

@ -44,10 +44,6 @@ typedef struct _GLFWcontextNSGL
{ {
id pixelFormat; id pixelFormat;
id object; id object;
CVDisplayLinkRef displayLink;
atomic_int swapInterval;
int swapIntervalsPassed;
id swapIntervalCond;
} _GLFWcontextNSGL; } _GLFWcontextNSGL;
@ -67,5 +63,4 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
void _glfwDestroyContextNSGL(_GLFWwindow* window); void _glfwDestroyContextNSGL(_GLFWwindow* window);
void _glfwUpdateDisplayLinkDisplayNSGL(_GLFWwindow* window);

View File

@ -28,29 +28,8 @@
#include "internal.h" #include "internal.h"
// Display link callback for manual swap interval implementation #include <unistd.h>
// This is based on a similar workaround added to SDL2 #include <math.h>
//
static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink,
const CVTimeStamp* now,
const CVTimeStamp* outputTime,
CVOptionFlags flagsIn,
CVOptionFlags* flagsOut,
void* userInfo)
{
_GLFWwindow* window = (_GLFWwindow *) userInfo;
const int interval = atomic_load(&window->context.nsgl.swapInterval);
if (interval > 0)
{
[window->context.nsgl.swapIntervalCond lock];
window->context.nsgl.swapIntervalsPassed++;
[window->context.nsgl.swapIntervalCond signal];
[window->context.nsgl.swapIntervalCond unlock];
}
return kCVReturnSuccess;
}
static void makeContextCurrentNSGL(_GLFWwindow* window) static void makeContextCurrentNSGL(_GLFWwindow* window)
{ {
@ -70,19 +49,28 @@ static void swapBuffersNSGL(_GLFWwindow* window)
{ {
@autoreleasepool { @autoreleasepool {
const int interval = atomic_load(&window->context.nsgl.swapInterval); // HACK: Simulate vsync with usleep as NSGL swap interval does not apply to
if (interval > 0) // windows with a non-visible occlusion state
if (!([window->ns.object occlusionState] & NSWindowOcclusionStateVisible))
{ {
[window->context.nsgl.swapIntervalCond lock]; int interval = 0;
do [window->context.nsgl.object getValues:&interval
forParameter:NSOpenGLContextParameterSwapInterval];
if (interval > 0)
{ {
[window->context.nsgl.swapIntervalCond wait]; const double framerate = 60.0;
} while (window->context.nsgl.swapIntervalsPassed % interval != 0); const uint64_t frequency = _glfwPlatformGetTimerFrequency();
window->context.nsgl.swapIntervalsPassed = 0; const uint64_t value = _glfwPlatformGetTimerValue();
[window->context.nsgl.swapIntervalCond unlock];
const double elapsed = value / (double) frequency;
const double period = 1.0 / framerate;
const double delay = period - fmod(elapsed, period);
usleep(floorl(delay * 1e6));
}
} }
// ARP appears to be unnecessary, but this is future-proof
[window->context.nsgl.object flushBuffer]; [window->context.nsgl.object flushBuffer];
} // autoreleasepool } // autoreleasepool
@ -91,11 +79,14 @@ static void swapBuffersNSGL(_GLFWwindow* window)
static void swapIntervalNSGL(int interval) static void swapIntervalNSGL(int interval)
{ {
@autoreleasepool { @autoreleasepool {
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
atomic_store(&window->context.nsgl.swapInterval, interval); if (window)
[window->context.nsgl.swapIntervalCond lock]; {
window->context.nsgl.swapIntervalsPassed = 0; [window->context.nsgl.object setValues:&interval
[window->context.nsgl.swapIntervalCond unlock]; forParameter:NSOpenGLContextParameterSwapInterval];
}
} // autoreleasepool } // autoreleasepool
} }
@ -123,17 +114,6 @@ static void destroyContextNSGL(_GLFWwindow* window)
{ {
@autoreleasepool { @autoreleasepool {
if (window->context.nsgl.displayLink)
{
if (CVDisplayLinkIsRunning(window->context.nsgl.displayLink))
CVDisplayLinkStop(window->context.nsgl.displayLink);
CVDisplayLinkRelease(window->context.nsgl.displayLink);
}
[window->context.nsgl.swapIntervalCond release];
window->context.nsgl.swapIntervalCond = nil;
[window->context.nsgl.pixelFormat release]; [window->context.nsgl.pixelFormat release];
window->context.nsgl.pixelFormat = nil; window->context.nsgl.pixelFormat = nil;
@ -354,17 +334,10 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
forParameter:NSOpenGLContextParameterSurfaceOpacity]; forParameter:NSOpenGLContextParameterSurfaceOpacity];
} }
if (window->ns.retina) [window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina];
[window->ns.view setWantsBestResolutionOpenGLSurface:YES];
GLint interval = 0;
[window->context.nsgl.object setValues:&interval
forParameter:NSOpenGLContextParameterSwapInterval];
[window->context.nsgl.object setView:window->ns.view]; [window->context.nsgl.object setView:window->ns.view];
window->context.nsgl.swapIntervalCond = [NSCondition new];
window->context.makeCurrent = makeContextCurrentNSGL; window->context.makeCurrent = makeContextCurrentNSGL;
window->context.swapBuffers = swapBuffersNSGL; window->context.swapBuffers = swapBuffersNSGL;
window->context.swapInterval = swapIntervalNSGL; window->context.swapInterval = swapIntervalNSGL;
@ -372,26 +345,9 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
window->context.getProcAddress = getProcAddressNSGL; window->context.getProcAddress = getProcAddressNSGL;
window->context.destroy = destroyContextNSGL; window->context.destroy = destroyContextNSGL;
CVDisplayLinkCreateWithActiveCGDisplays(&window->context.nsgl.displayLink);
CVDisplayLinkSetOutputCallback(window->context.nsgl.displayLink,
&displayLinkCallback,
window);
CVDisplayLinkStart(window->context.nsgl.displayLink);
_glfwUpdateDisplayLinkDisplayNSGL(window);
return GLFW_TRUE; return GLFW_TRUE;
} }
void _glfwUpdateDisplayLinkDisplayNSGL(_GLFWwindow* window)
{
CGDirectDisplayID displayID =
[[[window->ns.object screen] deviceDescription][@"NSScreenNumber"] unsignedIntValue];
if (!displayID)
return;
CVDisplayLinkSetCurrentCGDisplay(window->context.nsgl.displayLink, displayID);
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////

View File

@ -27,8 +27,11 @@
// It is fine to use C99 in this file because it will not be built with VS // It is fine to use C99 in this file because it will not be built with VS
//======================================================================== //========================================================================
#define _POSIX_C_SOURCE 199309L
#include "internal.h" #include "internal.h"
#include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
@ -41,7 +44,7 @@
// //
void _glfwInitTimerPOSIX(void) void _glfwInitTimerPOSIX(void)
{ {
#if defined(CLOCK_MONOTONIC) #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
struct timespec ts; struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
@ -64,7 +67,7 @@ void _glfwInitTimerPOSIX(void)
uint64_t _glfwPlatformGetTimerValue(void) uint64_t _glfwPlatformGetTimerValue(void)
{ {
#if defined(CLOCK_MONOTONIC) #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
if (_glfw.timer.posix.monotonic) if (_glfw.timer.posix.monotonic)
{ {
struct timespec ts; struct timespec ts;

View File

@ -57,6 +57,8 @@ GLFWbool _glfwInitVulkan(int mode)
_glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
#elif defined(_GLFW_COCOA) #elif defined(_GLFW_COCOA)
_glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib"); _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
if (!_glfw.vk.handle)
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS();
#else #else
_glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
#endif #endif
@ -130,6 +132,8 @@ GLFWbool _glfwInitVulkan(int mode)
#elif defined(_GLFW_COCOA) #elif defined(_GLFW_COCOA)
else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0) else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
_glfw.vk.MVK_macos_surface = GLFW_TRUE; _glfw.vk.MVK_macos_surface = GLFW_TRUE;
else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0)
_glfw.vk.EXT_metal_surface = GLFW_TRUE;
#elif defined(_GLFW_X11) #elif defined(_GLFW_X11)
else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0) else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
_glfw.vk.KHR_xlib_surface = GLFW_TRUE; _glfw.vk.KHR_xlib_surface = GLFW_TRUE;

View File

@ -104,10 +104,6 @@ typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC);
#define wglMakeCurrent _glfw.wgl.MakeCurrent #define wglMakeCurrent _glfw.wgl.MakeCurrent
#define wglShareLists _glfw.wgl.ShareLists #define wglShareLists _glfw.wgl.ShareLists
#define _GLFW_RECREATION_NOT_NEEDED 0
#define _GLFW_RECREATION_REQUIRED 1
#define _GLFW_RECREATION_IMPOSSIBLE 2
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl

View File

@ -33,6 +33,7 @@
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <malloc.h> #include <malloc.h>
#include <wchar.h>
// Callback for EnumDisplayMonitors in createMonitor // Callback for EnumDisplayMonitors in createMonitor

View File

@ -36,8 +36,6 @@
#include <windowsx.h> #include <windowsx.h>
#include <shellapi.h> #include <shellapi.h>
#define _GLFW_KEY_INVALID -2
// Returns the window style for the specified window // Returns the window style for the specified window
// //
static DWORD getWindowStyle(const _GLFWwindow* window) static DWORD getWindowStyle(const _GLFWwindow* window)
@ -448,77 +446,6 @@ static int getKeyMods(void)
return mods; return mods;
} }
// Retrieves and translates modifier keys
//
static int getAsyncKeyMods(void)
{
int mods = 0;
if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
mods |= GLFW_MOD_SHIFT;
if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
mods |= GLFW_MOD_CONTROL;
if (GetAsyncKeyState(VK_MENU) & 0x8000)
mods |= GLFW_MOD_ALT;
if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000)
mods |= GLFW_MOD_SUPER;
if (GetAsyncKeyState(VK_CAPITAL) & 1)
mods |= GLFW_MOD_CAPS_LOCK;
if (GetAsyncKeyState(VK_NUMLOCK) & 1)
mods |= GLFW_MOD_NUM_LOCK;
return mods;
}
// Translates a Windows key to the corresponding GLFW key
//
static int translateKey(WPARAM wParam, LPARAM lParam)
{
// The Ctrl keys require special handling
if (wParam == VK_CONTROL)
{
MSG next;
DWORD time;
// Right side keys have the extended key bit set
if (HIWORD(lParam) & KF_EXTENDED)
return GLFW_KEY_RIGHT_CONTROL;
// HACK: Alt Gr sends Left Ctrl and then Right Alt in close sequence
// We only want the Right Alt message, so if the next message is
// Right Alt we ignore this (synthetic) Left Ctrl message
time = GetMessageTime();
if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
{
if (next.message == WM_KEYDOWN ||
next.message == WM_SYSKEYDOWN ||
next.message == WM_KEYUP ||
next.message == WM_SYSKEYUP)
{
if (next.wParam == VK_MENU &&
(HIWORD(next.lParam) & KF_EXTENDED) &&
next.time == time)
{
// Next message is Right Alt down so discard this
return _GLFW_KEY_INVALID;
}
}
}
return GLFW_KEY_LEFT_CONTROL;
}
if (wParam == VK_PROCESSKEY)
{
// IME notifies that keys have been filtered by setting the virtual
// key-code to VK_PROCESSKEY
return _GLFW_KEY_INVALID;
}
return _glfw.win32.keycodes[HIWORD(lParam) & 0x1FF];
}
static void fitToMonitor(_GLFWwindow* window) static void fitToMonitor(_GLFWwindow* window)
{ {
MONITORINFO mi = { sizeof(mi) }; MONITORINFO mi = { sizeof(mi) };
@ -748,13 +675,64 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_KEYUP: case WM_KEYUP:
case WM_SYSKEYUP: case WM_SYSKEYUP:
{ {
const int key = translateKey(wParam, lParam); int key, scancode;
const int scancode = (HIWORD(lParam) & 0x1ff);
const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS; const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS;
const int mods = getKeyMods(); const int mods = getKeyMods();
if (key == _GLFW_KEY_INVALID) scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
if (!scancode)
{
// NOTE: Some synthetic key messages have a scancode of zero
// HACK: Map the virtual key back to a usable scancode
scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC);
}
key = _glfw.win32.keycodes[scancode];
// The Ctrl keys require special handling
if (wParam == VK_CONTROL)
{
if (HIWORD(lParam) & KF_EXTENDED)
{
// Right side keys have the extended key bit set
key = GLFW_KEY_RIGHT_CONTROL;
}
else
{
// NOTE: Alt Gr sends Left Ctrl followed by Right Alt
// HACK: We only want one event for Alt Gr, so if we detect
// this sequence we discard this Left Ctrl message now
// and later report Right Alt normally
MSG next;
const DWORD time = GetMessageTime();
if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
{
if (next.message == WM_KEYDOWN ||
next.message == WM_SYSKEYDOWN ||
next.message == WM_KEYUP ||
next.message == WM_SYSKEYUP)
{
if (next.wParam == VK_MENU &&
(HIWORD(next.lParam) & KF_EXTENDED) &&
next.time == time)
{
// Next message is Right Alt down so discard this
break;
}
}
}
// This is a regular Left Ctrl message
key = GLFW_KEY_LEFT_CONTROL;
}
}
else if (wParam == VK_PROCESSKEY)
{
// IME notifies that keys have been filtered by setting the
// virtual key-code to VK_PROCESSKEY
break; break;
}
if (action == GLFW_RELEASE && wParam == VK_SHIFT) if (action == GLFW_RELEASE && wParam == VK_SHIFT)
{ {
@ -1934,30 +1912,40 @@ void _glfwPlatformPollEvents(void)
} }
} }
// HACK: Release modifier keys that the system did not emit KEYUP for
// NOTE: Shift keys on Windows tend to "stick" when both are pressed as
// no key up message is generated by the first key release
// NOTE: Windows key is not reported as released by the Win+V hotkey
// Other Win hotkeys are handled implicitly by _glfwInputWindowFocus
// because they change the input focus
// NOTE: The other half of this is in the WM_*KEY* handler in windowProc
handle = GetActiveWindow(); handle = GetActiveWindow();
if (handle) if (handle)
{ {
// NOTE: Shift keys on Windows tend to "stick" when both are pressed as
// no key up message is generated by the first key release
// The other half of this is in the handling of WM_KEYUP
// HACK: Query actual key state and synthesize release events as needed
window = GetPropW(handle, L"GLFW"); window = GetPropW(handle, L"GLFW");
if (window) if (window)
{ {
const GLFWbool lshift = (GetAsyncKeyState(VK_LSHIFT) & 0x8000) != 0; int i;
const GLFWbool rshift = (GetAsyncKeyState(VK_RSHIFT) & 0x8000) != 0; const int keys[4][2] =
{
{ VK_LSHIFT, GLFW_KEY_LEFT_SHIFT },
{ VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT },
{ VK_LWIN, GLFW_KEY_LEFT_SUPER },
{ VK_RWIN, GLFW_KEY_RIGHT_SUPER }
};
if (!lshift && window->keys[GLFW_KEY_LEFT_SHIFT] == GLFW_PRESS) for (i = 0; i < 4; i++)
{ {
const int mods = getAsyncKeyMods(); const int vk = keys[i][0];
const int scancode = _glfw.win32.scancodes[GLFW_KEY_LEFT_SHIFT]; const int key = keys[i][1];
_glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods); const int scancode = _glfw.win32.scancodes[key];
}
else if (!rshift && window->keys[GLFW_KEY_RIGHT_SHIFT] == GLFW_PRESS) if ((GetKeyState(vk) & 0x8000))
{ continue;
const int mods = getAsyncKeyMods(); if (window->keys[key] != GLFW_PRESS)
const int scancode = _glfw.win32.scancodes[GLFW_KEY_RIGHT_SHIFT]; continue;
_glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods);
_glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods());
} }
} }
} }
@ -2039,6 +2027,13 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
const char* _glfwPlatformGetScancodeName(int scancode) const char* _glfwPlatformGetScancodeName(int scancode)
{ {
if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) ||
_glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");
return NULL;
}
return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]]; return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]];
} }

View File

@ -26,6 +26,8 @@
// It is fine to use C99 in this file because it will not be built with VS // It is fine to use C99 in this file because it will not be built with VS
//======================================================================== //========================================================================
#define _POSIX_C_SOURCE 199309L
#include "internal.h" #include "internal.h"
#include <assert.h> #include <assert.h>
@ -38,6 +40,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/timerfd.h> #include <sys/timerfd.h>
#include <unistd.h> #include <unistd.h>
#include <time.h>
#include <wayland-client.h> #include <wayland-client.h>
@ -125,6 +128,7 @@ static void pointerHandleLeave(void* data,
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
_glfw.wl.pointerFocus = NULL; _glfw.wl.pointerFocus = NULL;
_glfwInputCursorEnter(window, GLFW_FALSE); _glfwInputCursorEnter(window, GLFW_FALSE);
_glfw.wl.cursorPreviousName = NULL;
} }
static void setCursor(_GLFWwindow* window, const char* name) static void setCursor(_GLFWwindow* window, const char* name)
@ -196,6 +200,7 @@ static void pointerHandleMotion(void* data,
window->wl.cursorPosX = x; window->wl.cursorPosX = x;
window->wl.cursorPosY = y; window->wl.cursorPosY = y;
_glfwInputCursorPos(window, x, y); _glfwInputCursorPos(window, x, y);
_glfw.wl.cursorPreviousName = NULL;
return; return;
case topDecoration: case topDecoration:
if (y < _GLFW_DECORATION_WIDTH) if (y < _GLFW_DECORATION_WIDTH)

View File

@ -29,33 +29,23 @@
#include "internal.h" #include "internal.h"
#include <X11/Xresource.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <locale.h> #include <locale.h>
#include <unistd.h>
// Translate an X11 key code to a GLFW key code. // Translate the X11 KeySyms for a key to a GLFW key code
// NOTE: This is only used as a fallback, in case the XKB method fails
// It is layout-dependent and will fail partially on most non-US layouts
// //
static int translateKeyCode(int scancode) static int translateKeySyms(const KeySym* keysyms, int width)
{ {
int keySym; if (width > 1)
// Valid key code range is [8,255], according to the Xlib manual
if (scancode < 8 || scancode > 255)
return GLFW_KEY_UNKNOWN;
if (_glfw.x11.xkb.available)
{ {
// Try secondary keysym, for numeric keypad keys switch (keysyms[1])
// Note: This way we always force "NumLock = ON", which is intentional
// since the returned key code should correspond to a physical
// location.
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 1);
switch (keySym)
{ {
case XK_KP_0: return GLFW_KEY_KP_0; case XK_KP_0: return GLFW_KEY_KP_0;
case XK_KP_1: return GLFW_KEY_KP_1; case XK_KP_1: return GLFW_KEY_KP_1;
@ -73,22 +63,9 @@ static int translateKeyCode(int scancode)
case XK_KP_Enter: return GLFW_KEY_KP_ENTER; case XK_KP_Enter: return GLFW_KEY_KP_ENTER;
default: break; default: break;
} }
// Now try primary keysym for function keys (non-printable keys)
// These should not depend on the current keyboard layout
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0);
}
else
{
int dummy;
KeySym* keySyms;
keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy);
keySym = keySyms[0];
XFree(keySyms);
} }
switch (keySym) switch (keysyms[0])
{ {
case XK_Escape: return GLFW_KEY_ESCAPE; case XK_Escape: return GLFW_KEY_ESCAPE;
case XK_Tab: return GLFW_KEY_TAB; case XK_Tab: return GLFW_KEY_TAB;
@ -232,7 +209,7 @@ static int translateKeyCode(int scancode)
// //
static void createKeyTables(void) static void createKeyTables(void)
{ {
int scancode, key; int scancode, scancodeMin, scancodeMax;
memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes));
memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes)); memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes));
@ -242,89 +219,217 @@ static void createKeyTables(void)
// Use XKB to determine physical key locations independently of the // Use XKB to determine physical key locations independently of the
// current keyboard layout // current keyboard layout
char name[XkbKeyNameLength + 1];
XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd);
XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); XkbGetNames(_glfw.x11.display, XkbKeyNamesMask | XkbKeyAliasesMask, desc);
scancodeMin = desc->min_key_code;
scancodeMax = desc->max_key_code;
const struct
{
int key;
char* name;
} keymap[] =
{
{ GLFW_KEY_GRAVE_ACCENT, "TLDE" },
{ GLFW_KEY_1, "AE01" },
{ GLFW_KEY_2, "AE02" },
{ GLFW_KEY_3, "AE03" },
{ GLFW_KEY_4, "AE04" },
{ GLFW_KEY_5, "AE05" },
{ GLFW_KEY_6, "AE06" },
{ GLFW_KEY_7, "AE07" },
{ GLFW_KEY_8, "AE08" },
{ GLFW_KEY_9, "AE09" },
{ GLFW_KEY_0, "AE10" },
{ GLFW_KEY_MINUS, "AE11" },
{ GLFW_KEY_EQUAL, "AE12" },
{ GLFW_KEY_Q, "AD01" },
{ GLFW_KEY_W, "AD02" },
{ GLFW_KEY_E, "AD03" },
{ GLFW_KEY_R, "AD04" },
{ GLFW_KEY_T, "AD05" },
{ GLFW_KEY_Y, "AD06" },
{ GLFW_KEY_U, "AD07" },
{ GLFW_KEY_I, "AD08" },
{ GLFW_KEY_O, "AD09" },
{ GLFW_KEY_P, "AD10" },
{ GLFW_KEY_LEFT_BRACKET, "AD11" },
{ GLFW_KEY_RIGHT_BRACKET, "AD12" },
{ GLFW_KEY_A, "AC01" },
{ GLFW_KEY_S, "AC02" },
{ GLFW_KEY_D, "AC03" },
{ GLFW_KEY_F, "AC04" },
{ GLFW_KEY_G, "AC05" },
{ GLFW_KEY_H, "AC06" },
{ GLFW_KEY_J, "AC07" },
{ GLFW_KEY_K, "AC08" },
{ GLFW_KEY_L, "AC09" },
{ GLFW_KEY_SEMICOLON, "AC10" },
{ GLFW_KEY_APOSTROPHE, "AC11" },
{ GLFW_KEY_Z, "AB01" },
{ GLFW_KEY_X, "AB02" },
{ GLFW_KEY_C, "AB03" },
{ GLFW_KEY_V, "AB04" },
{ GLFW_KEY_B, "AB05" },
{ GLFW_KEY_N, "AB06" },
{ GLFW_KEY_M, "AB07" },
{ GLFW_KEY_COMMA, "AB08" },
{ GLFW_KEY_PERIOD, "AB09" },
{ GLFW_KEY_SLASH, "AB10" },
{ GLFW_KEY_BACKSLASH, "BKSL" },
{ GLFW_KEY_WORLD_1, "LSGT" },
{ GLFW_KEY_SPACE, "SPCE" },
{ GLFW_KEY_ESCAPE, "ESC" },
{ GLFW_KEY_ENTER, "RTRN" },
{ GLFW_KEY_TAB, "TAB" },
{ GLFW_KEY_BACKSPACE, "BKSP" },
{ GLFW_KEY_INSERT, "INS" },
{ GLFW_KEY_DELETE, "DELE" },
{ GLFW_KEY_RIGHT, "RGHT" },
{ GLFW_KEY_LEFT, "LEFT" },
{ GLFW_KEY_DOWN, "DOWN" },
{ GLFW_KEY_UP, "UP" },
{ GLFW_KEY_PAGE_UP, "PGUP" },
{ GLFW_KEY_PAGE_DOWN, "PGDN" },
{ GLFW_KEY_HOME, "HOME" },
{ GLFW_KEY_END, "END" },
{ GLFW_KEY_CAPS_LOCK, "CAPS" },
{ GLFW_KEY_SCROLL_LOCK, "SCLK" },
{ GLFW_KEY_NUM_LOCK, "NMLK" },
{ GLFW_KEY_PRINT_SCREEN, "PRSC" },
{ GLFW_KEY_PAUSE, "PAUS" },
{ GLFW_KEY_F1, "FK01" },
{ GLFW_KEY_F2, "FK02" },
{ GLFW_KEY_F3, "FK03" },
{ GLFW_KEY_F4, "FK04" },
{ GLFW_KEY_F5, "FK05" },
{ GLFW_KEY_F6, "FK06" },
{ GLFW_KEY_F7, "FK07" },
{ GLFW_KEY_F8, "FK08" },
{ GLFW_KEY_F9, "FK09" },
{ GLFW_KEY_F10, "FK10" },
{ GLFW_KEY_F11, "FK11" },
{ GLFW_KEY_F12, "FK12" },
{ GLFW_KEY_F13, "FK13" },
{ GLFW_KEY_F14, "FK14" },
{ GLFW_KEY_F15, "FK15" },
{ GLFW_KEY_F16, "FK16" },
{ GLFW_KEY_F17, "FK17" },
{ GLFW_KEY_F18, "FK18" },
{ GLFW_KEY_F19, "FK19" },
{ GLFW_KEY_F20, "FK20" },
{ GLFW_KEY_F21, "FK21" },
{ GLFW_KEY_F22, "FK22" },
{ GLFW_KEY_F23, "FK23" },
{ GLFW_KEY_F24, "FK24" },
{ GLFW_KEY_F25, "FK25" },
{ GLFW_KEY_KP_0, "KP0" },
{ GLFW_KEY_KP_1, "KP1" },
{ GLFW_KEY_KP_2, "KP2" },
{ GLFW_KEY_KP_3, "KP3" },
{ GLFW_KEY_KP_4, "KP4" },
{ GLFW_KEY_KP_5, "KP5" },
{ GLFW_KEY_KP_6, "KP6" },
{ GLFW_KEY_KP_7, "KP7" },
{ GLFW_KEY_KP_8, "KP8" },
{ GLFW_KEY_KP_9, "KP9" },
{ GLFW_KEY_KP_DECIMAL, "KPDL" },
{ GLFW_KEY_KP_DIVIDE, "KPDV" },
{ GLFW_KEY_KP_MULTIPLY, "KPMU" },
{ GLFW_KEY_KP_SUBTRACT, "KPSU" },
{ GLFW_KEY_KP_ADD, "KPAD" },
{ GLFW_KEY_KP_ENTER, "KPEN" },
{ GLFW_KEY_KP_EQUAL, "KPEQ" },
{ GLFW_KEY_LEFT_SHIFT, "LFSH" },
{ GLFW_KEY_LEFT_CONTROL, "LCTL" },
{ GLFW_KEY_LEFT_ALT, "LALT" },
{ GLFW_KEY_LEFT_SUPER, "LWIN" },
{ GLFW_KEY_RIGHT_SHIFT, "RTSH" },
{ GLFW_KEY_RIGHT_CONTROL, "RCTL" },
{ GLFW_KEY_RIGHT_ALT, "RALT" },
{ GLFW_KEY_RIGHT_ALT, "LVL3" },
{ GLFW_KEY_RIGHT_ALT, "MDSW" },
{ GLFW_KEY_RIGHT_SUPER, "RWIN" },
{ GLFW_KEY_MENU, "MENU" }
};
// Find the X11 key code -> GLFW key code mapping // Find the X11 key code -> GLFW key code mapping
for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++) for (scancode = scancodeMin; scancode <= scancodeMax; scancode++)
{ {
memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength); int key = GLFW_KEY_UNKNOWN;
name[XkbKeyNameLength] = '\0';
// Map the key name to a GLFW key code. Note: We only map printable // Map the key name to a GLFW key code. Note: We use the US
// keys here, and we use the US keyboard layout. The rest of the // keyboard layout. Because function keys aren't mapped correctly
// keys (function keys) are mapped using traditional KeySym // when using traditional KeySym translations, they are mapped
// translations. // here instead.
if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; for (int i = 0; i < sizeof(keymap) / sizeof(keymap[0]); i++)
else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; {
else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; if (strncmp(desc->names->keys[scancode].name,
else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; keymap[i].name,
else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; XkbKeyNameLength) == 0)
else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; {
else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; key = keymap[i].key;
else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; break;
else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; }
else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; }
else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0;
else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS;
else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL;
else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q;
else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W;
else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E;
else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R;
else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T;
else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y;
else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U;
else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I;
else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O;
else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P;
else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET;
else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET;
else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A;
else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S;
else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D;
else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F;
else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G;
else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H;
else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J;
else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K;
else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L;
else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON;
else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE;
else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z;
else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X;
else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C;
else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V;
else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B;
else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N;
else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M;
else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA;
else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD;
else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH;
else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH;
else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1;
else key = GLFW_KEY_UNKNOWN;
if ((scancode >= 0) && (scancode < 256)) // Fall back to key aliases in case the key name did not match
_glfw.x11.keycodes[scancode] = key; for (int i = 0; i < desc->names->num_key_aliases; i++)
{
if (key != GLFW_KEY_UNKNOWN)
break;
if (strncmp(desc->names->key_aliases[i].real,
desc->names->keys[scancode].name,
XkbKeyNameLength) != 0)
{
continue;
}
for (int j = 0; j < sizeof(keymap) / sizeof(keymap[0]); j++)
{
if (strncmp(desc->names->key_aliases[i].alias,
keymap[j].name,
XkbKeyNameLength) == 0)
{
key = keymap[j].key;
break;
}
}
}
_glfw.x11.keycodes[scancode] = key;
} }
XkbFreeNames(desc, XkbKeyNamesMask, True); XkbFreeNames(desc, XkbKeyNamesMask, True);
XkbFreeKeyboard(desc, 0, True); XkbFreeKeyboard(desc, 0, True);
} }
else
XDisplayKeycodes(_glfw.x11.display, &scancodeMin, &scancodeMax);
for (scancode = 0; scancode < 256; scancode++) int width;
KeySym* keysyms = XGetKeyboardMapping(_glfw.x11.display,
scancodeMin,
scancodeMax - scancodeMin + 1,
&width);
for (scancode = scancodeMin; scancode <= scancodeMax; scancode++)
{ {
// Translate the un-translated key codes using traditional X11 KeySym // Translate the un-translated key codes using traditional X11 KeySym
// lookups // lookups
if (_glfw.x11.keycodes[scancode] < 0) if (_glfw.x11.keycodes[scancode] < 0)
_glfw.x11.keycodes[scancode] = translateKeyCode(scancode); {
const size_t base = (scancode - scancodeMin) * width;
_glfw.x11.keycodes[scancode] = translateKeySyms(&keysyms[base], width);
}
// Store the reverse translation for faster key name lookup // Store the reverse translation for faster key name lookup
if (_glfw.x11.keycodes[scancode] > 0) if (_glfw.x11.keycodes[scancode] > 0)
_glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode;
} }
XFree(keysyms);
} }
// Check whether the IM has a usable style // Check whether the IM has a usable style
@ -350,6 +455,40 @@ static GLFWbool hasUsableInputMethodStyle(void)
return found; return found;
} }
static void inputMethodDestroyCallback(XIM im, XPointer clientData, XPointer callData)
{
_glfw.x11.im = NULL;
}
static void inputMethodInstantiateCallback(Display* display,
XPointer clientData,
XPointer callData)
{
if (_glfw.x11.im)
return;
_glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL);
if (_glfw.x11.im)
{
if (!hasUsableInputMethodStyle())
{
XCloseIM(_glfw.x11.im);
_glfw.x11.im = NULL;
}
}
if (_glfw.x11.im)
{
XIMCallback callback;
callback.callback = (XIMProc) inputMethodDestroyCallback;
callback.client_data = NULL;
XSetIMValues(_glfw.x11.im, XNDestroyCallback, &callback, NULL);
for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next)
_glfwCreateInputContextX11(window);
}
}
// Check whether the specified atom is supported // Check whether the specified atom is supported
// //
static Atom getSupportedAtom(Atom* supportedAtoms, static Atom getSupportedAtom(Atom* supportedAtoms,
@ -857,6 +996,9 @@ static Window createHelperWindow(void)
// //
static int errorHandler(Display *display, XErrorEvent* event) static int errorHandler(Display *display, XErrorEvent* event)
{ {
if (_glfw.x11.display != display)
return 0;
_glfw.x11.errorCode = event->error_code; _glfw.x11.errorCode = event->error_code;
return 0; return 0;
} }
@ -937,15 +1079,224 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot)
int _glfwPlatformInit(void) int _glfwPlatformInit(void)
{ {
#if !defined(X_HAVE_UTF8_STRING) // HACK: If the application has left the locale as "C" then both wide
// HACK: If the current locale is "C" and the Xlib UTF-8 functions are // character text input and explicit UTF-8 input via XIM will break
// unavailable, apply the environment's locale in the hope that it's // This sets the CTYPE part of the current locale from the environment
// both available and not "C" // in the hope that it is set to something more sane than "C"
// This is done because the "C" locale breaks wide character input,
// which is what we fall back on when UTF-8 support is missing
if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0)
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
#if defined(__CYGWIN__)
_glfw.x11.xlib.handle = _glfw_dlopen("libX11-6.so");
#else
_glfw.x11.xlib.handle = _glfw_dlopen("libX11.so.6");
#endif #endif
if (!_glfw.x11.xlib.handle)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib");
return GLFW_FALSE;
}
_glfw.x11.xlib.AllocClassHint = (PFN_XAllocClassHint)
_glfw_dlsym(_glfw.x11.xlib.handle, "XAllocClassHint");
_glfw.x11.xlib.AllocSizeHints = (PFN_XAllocSizeHints)
_glfw_dlsym(_glfw.x11.xlib.handle, "XAllocSizeHints");
_glfw.x11.xlib.AllocWMHints = (PFN_XAllocWMHints)
_glfw_dlsym(_glfw.x11.xlib.handle, "XAllocWMHints");
_glfw.x11.xlib.ChangeProperty = (PFN_XChangeProperty)
_glfw_dlsym(_glfw.x11.xlib.handle, "XChangeProperty");
_glfw.x11.xlib.ChangeWindowAttributes = (PFN_XChangeWindowAttributes)
_glfw_dlsym(_glfw.x11.xlib.handle, "XChangeWindowAttributes");
_glfw.x11.xlib.CheckIfEvent = (PFN_XCheckIfEvent)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCheckIfEvent");
_glfw.x11.xlib.CheckTypedWindowEvent = (PFN_XCheckTypedWindowEvent)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCheckTypedWindowEvent");
_glfw.x11.xlib.CloseDisplay = (PFN_XCloseDisplay)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCloseDisplay");
_glfw.x11.xlib.CloseIM = (PFN_XCloseIM)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCloseIM");
_glfw.x11.xlib.ConvertSelection = (PFN_XConvertSelection)
_glfw_dlsym(_glfw.x11.xlib.handle, "XConvertSelection");
_glfw.x11.xlib.CreateColormap = (PFN_XCreateColormap)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCreateColormap");
_glfw.x11.xlib.CreateFontCursor = (PFN_XCreateFontCursor)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCreateFontCursor");
_glfw.x11.xlib.CreateIC = (PFN_XCreateIC)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCreateIC");
_glfw.x11.xlib.CreateWindow = (PFN_XCreateWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCreateWindow");
_glfw.x11.xlib.DefineCursor = (PFN_XDefineCursor)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDefineCursor");
_glfw.x11.xlib.DeleteContext = (PFN_XDeleteContext)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteContext");
_glfw.x11.xlib.DeleteProperty = (PFN_XDeleteProperty)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteProperty");
_glfw.x11.xlib.DestroyIC = (PFN_XDestroyIC)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyIC");
_glfw.x11.xlib.DestroyWindow = (PFN_XDestroyWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyWindow");
_glfw.x11.xlib.DisplayKeycodes = (PFN_XDisplayKeycodes)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDisplayKeycodes");
_glfw.x11.xlib.EventsQueued = (PFN_XEventsQueued)
_glfw_dlsym(_glfw.x11.xlib.handle, "XEventsQueued");
_glfw.x11.xlib.FilterEvent = (PFN_XFilterEvent)
_glfw_dlsym(_glfw.x11.xlib.handle, "XFilterEvent");
_glfw.x11.xlib.FindContext = (PFN_XFindContext)
_glfw_dlsym(_glfw.x11.xlib.handle, "XFindContext");
_glfw.x11.xlib.Flush = (PFN_XFlush)
_glfw_dlsym(_glfw.x11.xlib.handle, "XFlush");
_glfw.x11.xlib.Free = (PFN_XFree)
_glfw_dlsym(_glfw.x11.xlib.handle, "XFree");
_glfw.x11.xlib.FreeColormap = (PFN_XFreeColormap)
_glfw_dlsym(_glfw.x11.xlib.handle, "XFreeColormap");
_glfw.x11.xlib.FreeCursor = (PFN_XFreeCursor)
_glfw_dlsym(_glfw.x11.xlib.handle, "XFreeCursor");
_glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData)
_glfw_dlsym(_glfw.x11.xlib.handle, "XFreeEventData");
_glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetErrorText");
_glfw.x11.xlib.GetEventData = (PFN_XGetEventData)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetEventData");
_glfw.x11.xlib.GetICValues = (PFN_XGetICValues)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetICValues");
_glfw.x11.xlib.GetIMValues = (PFN_XGetIMValues)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetIMValues");
_glfw.x11.xlib.GetInputFocus = (PFN_XGetInputFocus)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetInputFocus");
_glfw.x11.xlib.GetKeyboardMapping = (PFN_XGetKeyboardMapping)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetKeyboardMapping");
_glfw.x11.xlib.GetScreenSaver = (PFN_XGetScreenSaver)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetScreenSaver");
_glfw.x11.xlib.GetSelectionOwner = (PFN_XGetSelectionOwner)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetSelectionOwner");
_glfw.x11.xlib.GetVisualInfo = (PFN_XGetVisualInfo)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetVisualInfo");
_glfw.x11.xlib.GetWMNormalHints = (PFN_XGetWMNormalHints)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetWMNormalHints");
_glfw.x11.xlib.GetWindowAttributes = (PFN_XGetWindowAttributes)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetWindowAttributes");
_glfw.x11.xlib.GetWindowProperty = (PFN_XGetWindowProperty)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetWindowProperty");
_glfw.x11.xlib.GrabPointer = (PFN_XGrabPointer)
_glfw_dlsym(_glfw.x11.xlib.handle, "XGrabPointer");
_glfw.x11.xlib.IconifyWindow = (PFN_XIconifyWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XIconifyWindow");
_glfw.x11.xlib.InitThreads = (PFN_XInitThreads)
_glfw_dlsym(_glfw.x11.xlib.handle, "XInitThreads");
_glfw.x11.xlib.InternAtom = (PFN_XInternAtom)
_glfw_dlsym(_glfw.x11.xlib.handle, "XInternAtom");
_glfw.x11.xlib.LookupString = (PFN_XLookupString)
_glfw_dlsym(_glfw.x11.xlib.handle, "XLookupString");
_glfw.x11.xlib.MapRaised = (PFN_XMapRaised)
_glfw_dlsym(_glfw.x11.xlib.handle, "XMapRaised");
_glfw.x11.xlib.MapWindow = (PFN_XMapWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XMapWindow");
_glfw.x11.xlib.MoveResizeWindow = (PFN_XMoveResizeWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XMoveResizeWindow");
_glfw.x11.xlib.MoveWindow = (PFN_XMoveWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XMoveWindow");
_glfw.x11.xlib.NextEvent = (PFN_XNextEvent)
_glfw_dlsym(_glfw.x11.xlib.handle, "XNextEvent");
_glfw.x11.xlib.OpenDisplay = (PFN_XOpenDisplay)
_glfw_dlsym(_glfw.x11.xlib.handle, "XOpenDisplay");
_glfw.x11.xlib.OpenIM = (PFN_XOpenIM)
_glfw_dlsym(_glfw.x11.xlib.handle, "XOpenIM");
_glfw.x11.xlib.PeekEvent = (PFN_XPeekEvent)
_glfw_dlsym(_glfw.x11.xlib.handle, "XPeekEvent");
_glfw.x11.xlib.Pending = (PFN_XPending)
_glfw_dlsym(_glfw.x11.xlib.handle, "XPending");
_glfw.x11.xlib.QueryExtension = (PFN_XQueryExtension)
_glfw_dlsym(_glfw.x11.xlib.handle, "XQueryExtension");
_glfw.x11.xlib.QueryPointer = (PFN_XQueryPointer)
_glfw_dlsym(_glfw.x11.xlib.handle, "XQueryPointer");
_glfw.x11.xlib.RaiseWindow = (PFN_XRaiseWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XRaiseWindow");
_glfw.x11.xlib.RegisterIMInstantiateCallback = (PFN_XRegisterIMInstantiateCallback)
_glfw_dlsym(_glfw.x11.xlib.handle, "XRegisterIMInstantiateCallback");
_glfw.x11.xlib.ResizeWindow = (PFN_XResizeWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XResizeWindow");
_glfw.x11.xlib.ResourceManagerString = (PFN_XResourceManagerString)
_glfw_dlsym(_glfw.x11.xlib.handle, "XResourceManagerString");
_glfw.x11.xlib.SaveContext = (PFN_XSaveContext)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSaveContext");
_glfw.x11.xlib.SelectInput = (PFN_XSelectInput)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSelectInput");
_glfw.x11.xlib.SendEvent = (PFN_XSendEvent)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSendEvent");
_glfw.x11.xlib.SetClassHint = (PFN_XSetClassHint)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetClassHint");
_glfw.x11.xlib.SetErrorHandler = (PFN_XSetErrorHandler)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetErrorHandler");
_glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetICFocus");
_glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetIMValues");
_glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetInputFocus");
_glfw.x11.xlib.SetLocaleModifiers = (PFN_XSetLocaleModifiers)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetLocaleModifiers");
_glfw.x11.xlib.SetScreenSaver = (PFN_XSetScreenSaver)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetScreenSaver");
_glfw.x11.xlib.SetSelectionOwner = (PFN_XSetSelectionOwner)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetSelectionOwner");
_glfw.x11.xlib.SetWMHints = (PFN_XSetWMHints)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMHints");
_glfw.x11.xlib.SetWMNormalHints = (PFN_XSetWMNormalHints)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMNormalHints");
_glfw.x11.xlib.SetWMProtocols = (PFN_XSetWMProtocols)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMProtocols");
_glfw.x11.xlib.SupportsLocale = (PFN_XSupportsLocale)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSupportsLocale");
_glfw.x11.xlib.Sync = (PFN_XSync)
_glfw_dlsym(_glfw.x11.xlib.handle, "XSync");
_glfw.x11.xlib.TranslateCoordinates = (PFN_XTranslateCoordinates)
_glfw_dlsym(_glfw.x11.xlib.handle, "XTranslateCoordinates");
_glfw.x11.xlib.UndefineCursor = (PFN_XUndefineCursor)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUndefineCursor");
_glfw.x11.xlib.UngrabPointer = (PFN_XUngrabPointer)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUngrabPointer");
_glfw.x11.xlib.UnmapWindow = (PFN_XUnmapWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUnmapWindow");
_glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUnsetICFocus");
_glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual)
_glfw_dlsym(_glfw.x11.xlib.handle, "XVisualIDFromVisual");
_glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer)
_glfw_dlsym(_glfw.x11.xlib.handle, "XWarpPointer");
_glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeKeyboard");
_glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeNames");
_glfw.x11.xkb.GetMap = (PFN_XkbGetMap)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetMap");
_glfw.x11.xkb.GetNames = (PFN_XkbGetNames)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetNames");
_glfw.x11.xkb.GetState = (PFN_XkbGetState)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetState");
_glfw.x11.xkb.KeycodeToKeysym = (PFN_XkbKeycodeToKeysym)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbKeycodeToKeysym");
_glfw.x11.xkb.QueryExtension = (PFN_XkbQueryExtension)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbQueryExtension");
_glfw.x11.xkb.SelectEventDetails = (PFN_XkbSelectEventDetails)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbSelectEventDetails");
_glfw.x11.xkb.SetDetectableAutoRepeat = (PFN_XkbSetDetectableAutoRepeat)
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbSetDetectableAutoRepeat");
_glfw.x11.xrm.DestroyDatabase = (PFN_XrmDestroyDatabase)
_glfw_dlsym(_glfw.x11.xlib.handle, "XrmDestroyDatabase");
_glfw.x11.xrm.GetResource = (PFN_XrmGetResource)
_glfw_dlsym(_glfw.x11.xlib.handle, "XrmGetResource");
_glfw.x11.xrm.GetStringDatabase = (PFN_XrmGetStringDatabase)
_glfw_dlsym(_glfw.x11.xlib.handle, "XrmGetStringDatabase");
_glfw.x11.xrm.Initialize = (PFN_XrmInitialize)
_glfw_dlsym(_glfw.x11.xlib.handle, "XrmInitialize");
_glfw.x11.xrm.UniqueQuark = (PFN_XrmUniqueQuark)
_glfw_dlsym(_glfw.x11.xlib.handle, "XrmUniqueQuark");
_glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback");
_glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString)
_glfw_dlsym(_glfw.x11.xlib.handle, "Xutf8LookupString");
_glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties)
_glfw_dlsym(_glfw.x11.xlib.handle, "Xutf8SetWMProperties");
XInitThreads(); XInitThreads();
XrmInitialize(); XrmInitialize();
@ -984,15 +1335,11 @@ int _glfwPlatformInit(void)
{ {
XSetLocaleModifiers(""); XSetLocaleModifiers("");
_glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL); // If an IM is already present our callback will be called right away
if (_glfw.x11.im) XRegisterIMInstantiateCallback(_glfw.x11.display,
{ NULL, NULL, NULL,
if (!hasUsableInputMethodStyle()) inputMethodInstantiateCallback,
{ NULL);
XCloseIM(_glfw.x11.im);
_glfw.x11.im = NULL;
}
}
} }
#if defined(__linux__) #if defined(__linux__)
@ -1029,6 +1376,11 @@ void _glfwPlatformTerminate(void)
free(_glfw.x11.primarySelectionString); free(_glfw.x11.primarySelectionString);
free(_glfw.x11.clipboardString); free(_glfw.x11.clipboardString);
XUnregisterIMInstantiateCallback(_glfw.x11.display,
NULL, NULL, NULL,
inputMethodInstantiateCallback,
NULL);
if (_glfw.x11.im) if (_glfw.x11.im)
{ {
XCloseIM(_glfw.x11.im); XCloseIM(_glfw.x11.im);
@ -1091,6 +1443,12 @@ void _glfwPlatformTerminate(void)
#if defined(__linux__) #if defined(__linux__)
_glfwTerminateJoysticksLinux(); _glfwTerminateJoysticksLinux();
#endif #endif
if (_glfw.x11.xlib.handle)
{
_glfw_dlclose(_glfw.x11.xlib.handle);
_glfw.x11.xlib.handle = NULL;
}
} }
const char* _glfwPlatformGetVersionString(void) const char* _glfwPlatformGetVersionString(void)

View File

@ -322,12 +322,16 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
if (xpos) if (ci)
*xpos = ci->x; {
if (ypos) if (xpos)
*ypos = ci->y; *xpos = ci->x;
if (ypos)
*ypos = ci->y;
XRRFreeCrtcInfo(ci);
}
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr); XRRFreeScreenResources(sr);
} }
} }
@ -493,9 +497,15 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
*mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci); if (ci)
{
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
if (mi) // mi can be NULL if the monitor has been disconnected
*mode = vidmodeFromModeInfo(mi, ci);
XRRFreeCrtcInfo(ci);
}
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr); XRRFreeScreenResources(sr);
} }
else else

View File

@ -33,6 +33,7 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xresource.h>
#include <X11/Xcursor/Xcursor.h> #include <X11/Xcursor/Xcursor.h>
// The XRandR extension provides mode setting and gamma control // The XRandR extension provides mode setting and gamma control
@ -47,6 +48,207 @@
// The XInput extension provides raw mouse motion input // The XInput extension provides raw mouse motion input
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
typedef XClassHint* (* PFN_XAllocClassHint)(void);
typedef XSizeHints* (* PFN_XAllocSizeHints)(void);
typedef XWMHints* (* PFN_XAllocWMHints)(void);
typedef int (* PFN_XChangeProperty)(Display*,Window,Atom,Atom,int,int,const unsigned char*,int);
typedef int (* PFN_XChangeWindowAttributes)(Display*,Window,unsigned long,XSetWindowAttributes*);
typedef Bool (* PFN_XCheckIfEvent)(Display*,XEvent*,Bool(*)(Display*,XEvent*,XPointer),XPointer);
typedef Bool (* PFN_XCheckTypedWindowEvent)(Display*,Window,int,XEvent*);
typedef int (* PFN_XCloseDisplay)(Display*);
typedef Status (* PFN_XCloseIM)(XIM);
typedef int (* PFN_XConvertSelection)(Display*,Atom,Atom,Atom,Window,Time);
typedef Colormap (* PFN_XCreateColormap)(Display*,Window,Visual*,int);
typedef Cursor (* PFN_XCreateFontCursor)(Display*,unsigned int);
typedef XIC (* PFN_XCreateIC)(XIM,...);
typedef Window (* PFN_XCreateWindow)(Display*,Window,int,int,unsigned int,unsigned int,unsigned int,int,unsigned int,Visual*,unsigned long,XSetWindowAttributes*);
typedef int (* PFN_XDefineCursor)(Display*,Window,Cursor);
typedef int (* PFN_XDeleteContext)(Display*,XID,XContext);
typedef int (* PFN_XDeleteProperty)(Display*,Window,Atom);
typedef void (* PFN_XDestroyIC)(XIC);
typedef int (* PFN_XDestroyWindow)(Display*,Window);
typedef int (* PFN_XDisplayKeycodes)(Display*,int*,int*);
typedef int (* PFN_XEventsQueued)(Display*,int);
typedef Bool (* PFN_XFilterEvent)(XEvent*,Window);
typedef int (* PFN_XFindContext)(Display*,XID,XContext,XPointer*);
typedef int (* PFN_XFlush)(Display*);
typedef int (* PFN_XFree)(void*);
typedef int (* PFN_XFreeColormap)(Display*,Colormap);
typedef int (* PFN_XFreeCursor)(Display*,Cursor);
typedef void (* PFN_XFreeEventData)(Display*,XGenericEventCookie*);
typedef int (* PFN_XGetErrorText)(Display*,int,char*,int);
typedef Bool (* PFN_XGetEventData)(Display*,XGenericEventCookie*);
typedef char* (* PFN_XGetICValues)(XIC,...);
typedef char* (* PFN_XGetIMValues)(XIM,...);
typedef int (* PFN_XGetInputFocus)(Display*,Window*,int*);
typedef KeySym* (* PFN_XGetKeyboardMapping)(Display*,KeyCode,int,int*);
typedef int (* PFN_XGetScreenSaver)(Display*,int*,int*,int*,int*);
typedef Window (* PFN_XGetSelectionOwner)(Display*,Atom);
typedef XVisualInfo* (* PFN_XGetVisualInfo)(Display*,long,XVisualInfo*,int*);
typedef Status (* PFN_XGetWMNormalHints)(Display*,Window,XSizeHints*,long*);
typedef Status (* PFN_XGetWindowAttributes)(Display*,Window,XWindowAttributes*);
typedef int (* PFN_XGetWindowProperty)(Display*,Window,Atom,long,long,Bool,Atom,Atom*,int*,unsigned long*,unsigned long*,unsigned char**);
typedef int (* PFN_XGrabPointer)(Display*,Window,Bool,unsigned int,int,int,Window,Cursor,Time);
typedef Status (* PFN_XIconifyWindow)(Display*,Window,int);
typedef Status (* PFN_XInitThreads)(void);
typedef Atom (* PFN_XInternAtom)(Display*,const char*,Bool);
typedef int (* PFN_XLookupString)(XKeyEvent*,char*,int,KeySym*,XComposeStatus*);
typedef int (* PFN_XMapRaised)(Display*,Window);
typedef int (* PFN_XMapWindow)(Display*,Window);
typedef int (* PFN_XMoveResizeWindow)(Display*,Window,int,int,unsigned int,unsigned int);
typedef int (* PFN_XMoveWindow)(Display*,Window,int,int);
typedef int (* PFN_XNextEvent)(Display*,XEvent*);
typedef Display* (* PFN_XOpenDisplay)(const char*);
typedef XIM (* PFN_XOpenIM)(Display*,XrmDatabase*,char*,char*);
typedef int (* PFN_XPeekEvent)(Display*,XEvent*);
typedef int (* PFN_XPending)(Display*);
typedef Bool (* PFN_XQueryExtension)(Display*,const char*,int*,int*,int*);
typedef Bool (* PFN_XQueryPointer)(Display*,Window,Window*,Window*,int*,int*,int*,int*,unsigned int*);
typedef int (* PFN_XRaiseWindow)(Display*,Window);
typedef Bool (* PFN_XRegisterIMInstantiateCallback)(Display*,void*,char*,char*,XIDProc,XPointer);
typedef int (* PFN_XResizeWindow)(Display*,Window,unsigned int,unsigned int);
typedef char* (* PFN_XResourceManagerString)(Display*);
typedef int (* PFN_XSaveContext)(Display*,XID,XContext,const char*);
typedef int (* PFN_XSelectInput)(Display*,Window,long);
typedef Status (* PFN_XSendEvent)(Display*,Window,Bool,long,XEvent*);
typedef int (* PFN_XSetClassHint)(Display*,Window,XClassHint*);
typedef XErrorHandler (* PFN_XSetErrorHandler)(XErrorHandler);
typedef void (* PFN_XSetICFocus)(XIC);
typedef char* (* PFN_XSetIMValues)(XIM,...);
typedef int (* PFN_XSetInputFocus)(Display*,Window,int,Time);
typedef char* (* PFN_XSetLocaleModifiers)(const char*);
typedef int (* PFN_XSetScreenSaver)(Display*,int,int,int,int);
typedef int (* PFN_XSetSelectionOwner)(Display*,Atom,Window,Time);
typedef int (* PFN_XSetWMHints)(Display*,Window,XWMHints*);
typedef void (* PFN_XSetWMNormalHints)(Display*,Window,XSizeHints*);
typedef Status (* PFN_XSetWMProtocols)(Display*,Window,Atom*,int);
typedef Bool (* PFN_XSupportsLocale)(void);
typedef int (* PFN_XSync)(Display*,Bool);
typedef Bool (* PFN_XTranslateCoordinates)(Display*,Window,Window,int,int,int*,int*,Window*);
typedef int (* PFN_XUndefineCursor)(Display*,Window);
typedef int (* PFN_XUngrabPointer)(Display*,Time);
typedef int (* PFN_XUnmapWindow)(Display*,Window);
typedef void (* PFN_XUnsetICFocus)(XIC);
typedef VisualID (* PFN_XVisualIDFromVisual)(Visual*);
typedef int (* PFN_XWarpPointer)(Display*,Window,Window,int,int,unsigned int,unsigned int,int,int);
typedef void (* PFN_XkbFreeKeyboard)(XkbDescPtr,unsigned int,Bool);
typedef void (* PFN_XkbFreeNames)(XkbDescPtr,unsigned int,Bool);
typedef XkbDescPtr (* PFN_XkbGetMap)(Display*,unsigned int,unsigned int);
typedef Status (* PFN_XkbGetNames)(Display*,unsigned int,XkbDescPtr);
typedef Status (* PFN_XkbGetState)(Display*,unsigned int,XkbStatePtr);
typedef KeySym (* PFN_XkbKeycodeToKeysym)(Display*,KeyCode,int,int);
typedef Bool (* PFN_XkbQueryExtension)(Display*,int*,int*,int*,int*,int*);
typedef Bool (* PFN_XkbSelectEventDetails)(Display*,unsigned int,unsigned int,unsigned long,unsigned long);
typedef Bool (* PFN_XkbSetDetectableAutoRepeat)(Display*,Bool,Bool*);
typedef void (* PFN_XrmDestroyDatabase)(XrmDatabase);
typedef Bool (* PFN_XrmGetResource)(XrmDatabase,const char*,const char*,char**,XrmValue*);
typedef XrmDatabase (* PFN_XrmGetStringDatabase)(const char*);
typedef void (* PFN_XrmInitialize)(void);
typedef XrmQuark (* PFN_XrmUniqueQuark)(void);
typedef Bool (* PFN_XUnregisterIMInstantiateCallback)(Display*,void*,char*,char*,XIDProc,XPointer);
typedef int (* PFN_Xutf8LookupString)(XIC,XKeyPressedEvent*,char*,int,KeySym*,Status*);
typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char*,char**,int,XSizeHints*,XWMHints*,XClassHint*);
#define XAllocClassHint _glfw.x11.xlib.AllocClassHint
#define XAllocSizeHints _glfw.x11.xlib.AllocSizeHints
#define XAllocWMHints _glfw.x11.xlib.AllocWMHints
#define XChangeProperty _glfw.x11.xlib.ChangeProperty
#define XChangeWindowAttributes _glfw.x11.xlib.ChangeWindowAttributes
#define XCheckIfEvent _glfw.x11.xlib.CheckIfEvent
#define XCheckTypedWindowEvent _glfw.x11.xlib.CheckTypedWindowEvent
#define XCloseDisplay _glfw.x11.xlib.CloseDisplay
#define XCloseIM _glfw.x11.xlib.CloseIM
#define XConvertSelection _glfw.x11.xlib.ConvertSelection
#define XCreateColormap _glfw.x11.xlib.CreateColormap
#define XCreateFontCursor _glfw.x11.xlib.CreateFontCursor
#define XCreateIC _glfw.x11.xlib.CreateIC
#define XCreateWindow _glfw.x11.xlib.CreateWindow
#define XDefineCursor _glfw.x11.xlib.DefineCursor
#define XDeleteContext _glfw.x11.xlib.DeleteContext
#define XDeleteProperty _glfw.x11.xlib.DeleteProperty
#define XDestroyIC _glfw.x11.xlib.DestroyIC
#define XDestroyWindow _glfw.x11.xlib.DestroyWindow
#define XDisplayKeycodes _glfw.x11.xlib.DisplayKeycodes
#define XEventsQueued _glfw.x11.xlib.EventsQueued
#define XFilterEvent _glfw.x11.xlib.FilterEvent
#define XFindContext _glfw.x11.xlib.FindContext
#define XFlush _glfw.x11.xlib.Flush
#define XFree _glfw.x11.xlib.Free
#define XFreeColormap _glfw.x11.xlib.FreeColormap
#define XFreeCursor _glfw.x11.xlib.FreeCursor
#define XFreeEventData _glfw.x11.xlib.FreeEventData
#define XGetErrorText _glfw.x11.xlib.GetErrorText
#define XGetEventData _glfw.x11.xlib.GetEventData
#define XGetICValues _glfw.x11.xlib.GetICValues
#define XGetIMValues _glfw.x11.xlib.GetIMValues
#define XGetInputFocus _glfw.x11.xlib.GetInputFocus
#define XGetKeyboardMapping _glfw.x11.xlib.GetKeyboardMapping
#define XGetScreenSaver _glfw.x11.xlib.GetScreenSaver
#define XGetSelectionOwner _glfw.x11.xlib.GetSelectionOwner
#define XGetVisualInfo _glfw.x11.xlib.GetVisualInfo
#define XGetWMNormalHints _glfw.x11.xlib.GetWMNormalHints
#define XGetWindowAttributes _glfw.x11.xlib.GetWindowAttributes
#define XGetWindowProperty _glfw.x11.xlib.GetWindowProperty
#define XGrabPointer _glfw.x11.xlib.GrabPointer
#define XIconifyWindow _glfw.x11.xlib.IconifyWindow
#define XInitThreads _glfw.x11.xlib.InitThreads
#define XInternAtom _glfw.x11.xlib.InternAtom
#define XLookupString _glfw.x11.xlib.LookupString
#define XMapRaised _glfw.x11.xlib.MapRaised
#define XMapWindow _glfw.x11.xlib.MapWindow
#define XMoveResizeWindow _glfw.x11.xlib.MoveResizeWindow
#define XMoveWindow _glfw.x11.xlib.MoveWindow
#define XNextEvent _glfw.x11.xlib.NextEvent
#define XOpenDisplay _glfw.x11.xlib.OpenDisplay
#define XOpenIM _glfw.x11.xlib.OpenIM
#define XPeekEvent _glfw.x11.xlib.PeekEvent
#define XPending _glfw.x11.xlib.Pending
#define XQueryExtension _glfw.x11.xlib.QueryExtension
#define XQueryPointer _glfw.x11.xlib.QueryPointer
#define XRaiseWindow _glfw.x11.xlib.RaiseWindow
#define XRegisterIMInstantiateCallback _glfw.x11.xlib.RegisterIMInstantiateCallback
#define XResizeWindow _glfw.x11.xlib.ResizeWindow
#define XResourceManagerString _glfw.x11.xlib.ResourceManagerString
#define XSaveContext _glfw.x11.xlib.SaveContext
#define XSelectInput _glfw.x11.xlib.SelectInput
#define XSendEvent _glfw.x11.xlib.SendEvent
#define XSetClassHint _glfw.x11.xlib.SetClassHint
#define XSetErrorHandler _glfw.x11.xlib.SetErrorHandler
#define XSetICFocus _glfw.x11.xlib.SetICFocus
#define XSetIMValues _glfw.x11.xlib.SetIMValues
#define XSetInputFocus _glfw.x11.xlib.SetInputFocus
#define XSetLocaleModifiers _glfw.x11.xlib.SetLocaleModifiers
#define XSetScreenSaver _glfw.x11.xlib.SetScreenSaver
#define XSetSelectionOwner _glfw.x11.xlib.SetSelectionOwner
#define XSetWMHints _glfw.x11.xlib.SetWMHints
#define XSetWMNormalHints _glfw.x11.xlib.SetWMNormalHints
#define XSetWMProtocols _glfw.x11.xlib.SetWMProtocols
#define XSupportsLocale _glfw.x11.xlib.SupportsLocale
#define XSync _glfw.x11.xlib.Sync
#define XTranslateCoordinates _glfw.x11.xlib.TranslateCoordinates
#define XUndefineCursor _glfw.x11.xlib.UndefineCursor
#define XUngrabPointer _glfw.x11.xlib.UngrabPointer
#define XUnmapWindow _glfw.x11.xlib.UnmapWindow
#define XUnsetICFocus _glfw.x11.xlib.UnsetICFocus
#define XVisualIDFromVisual _glfw.x11.xlib.VisualIDFromVisual
#define XWarpPointer _glfw.x11.xlib.WarpPointer
#define XkbFreeKeyboard _glfw.x11.xkb.FreeKeyboard
#define XkbFreeNames _glfw.x11.xkb.FreeNames
#define XkbGetMap _glfw.x11.xkb.GetMap
#define XkbGetNames _glfw.x11.xkb.GetNames
#define XkbGetState _glfw.x11.xkb.GetState
#define XkbKeycodeToKeysym _glfw.x11.xkb.KeycodeToKeysym
#define XkbQueryExtension _glfw.x11.xkb.QueryExtension
#define XkbSelectEventDetails _glfw.x11.xkb.SelectEventDetails
#define XkbSetDetectableAutoRepeat _glfw.x11.xkb.SetDetectableAutoRepeat
#define XrmDestroyDatabase _glfw.x11.xrm.DestroyDatabase
#define XrmGetResource _glfw.x11.xrm.GetResource
#define XrmGetStringDatabase _glfw.x11.xrm.GetStringDatabase
#define XrmInitialize _glfw.x11.xrm.Initialize
#define XrmUniqueQuark _glfw.x11.xrm.UniqueQuark
#define XUnregisterIMInstantiateCallback _glfw.x11.xlib.UnregisterIMInstantiateCallback
#define Xutf8LookupString _glfw.x11.xlib.utf8LookupString
#define Xutf8SetWMProperties _glfw.x11.xlib.utf8SetWMProperties
typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int); typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int);
typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*); typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*);
typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*); typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*);
@ -186,6 +388,7 @@ typedef struct _GLFWwindowX11
{ {
Colormap colormap; Colormap colormap;
Window handle; Window handle;
Window parent;
XIC ic; XIC ic;
GLFWbool overrideRedirect; GLFWbool overrideRedirect;
@ -300,6 +503,104 @@ typedef struct _GLFWlibraryX11
Atom ATOM_PAIR; Atom ATOM_PAIR;
Atom GLFW_SELECTION; Atom GLFW_SELECTION;
struct {
void* handle;
PFN_XAllocClassHint AllocClassHint;
PFN_XAllocSizeHints AllocSizeHints;
PFN_XAllocWMHints AllocWMHints;
PFN_XChangeProperty ChangeProperty;
PFN_XChangeWindowAttributes ChangeWindowAttributes;
PFN_XCheckIfEvent CheckIfEvent;
PFN_XCheckTypedWindowEvent CheckTypedWindowEvent;
PFN_XCloseDisplay CloseDisplay;
PFN_XCloseIM CloseIM;
PFN_XConvertSelection ConvertSelection;
PFN_XCreateColormap CreateColormap;
PFN_XCreateFontCursor CreateFontCursor;
PFN_XCreateIC CreateIC;
PFN_XCreateWindow CreateWindow;
PFN_XDefineCursor DefineCursor;
PFN_XDeleteContext DeleteContext;
PFN_XDeleteProperty DeleteProperty;
PFN_XDestroyIC DestroyIC;
PFN_XDestroyWindow DestroyWindow;
PFN_XDisplayKeycodes DisplayKeycodes;
PFN_XEventsQueued EventsQueued;
PFN_XFilterEvent FilterEvent;
PFN_XFindContext FindContext;
PFN_XFlush Flush;
PFN_XFree Free;
PFN_XFreeColormap FreeColormap;
PFN_XFreeCursor FreeCursor;
PFN_XFreeEventData FreeEventData;
PFN_XGetErrorText GetErrorText;
PFN_XGetEventData GetEventData;
PFN_XGetICValues GetICValues;
PFN_XGetIMValues GetIMValues;
PFN_XGetInputFocus GetInputFocus;
PFN_XGetKeyboardMapping GetKeyboardMapping;
PFN_XGetScreenSaver GetScreenSaver;
PFN_XGetSelectionOwner GetSelectionOwner;
PFN_XGetVisualInfo GetVisualInfo;
PFN_XGetWMNormalHints GetWMNormalHints;
PFN_XGetWindowAttributes GetWindowAttributes;
PFN_XGetWindowProperty GetWindowProperty;
PFN_XGrabPointer GrabPointer;
PFN_XIconifyWindow IconifyWindow;
PFN_XInitThreads InitThreads;
PFN_XInternAtom InternAtom;
PFN_XLookupString LookupString;
PFN_XMapRaised MapRaised;
PFN_XMapWindow MapWindow;
PFN_XMoveResizeWindow MoveResizeWindow;
PFN_XMoveWindow MoveWindow;
PFN_XNextEvent NextEvent;
PFN_XOpenDisplay OpenDisplay;
PFN_XOpenIM OpenIM;
PFN_XPeekEvent PeekEvent;
PFN_XPending Pending;
PFN_XQueryExtension QueryExtension;
PFN_XQueryPointer QueryPointer;
PFN_XRaiseWindow RaiseWindow;
PFN_XRegisterIMInstantiateCallback RegisterIMInstantiateCallback;
PFN_XResizeWindow ResizeWindow;
PFN_XResourceManagerString ResourceManagerString;
PFN_XSaveContext SaveContext;
PFN_XSelectInput SelectInput;
PFN_XSendEvent SendEvent;
PFN_XSetClassHint SetClassHint;
PFN_XSetErrorHandler SetErrorHandler;
PFN_XSetICFocus SetICFocus;
PFN_XSetIMValues SetIMValues;
PFN_XSetInputFocus SetInputFocus;
PFN_XSetLocaleModifiers SetLocaleModifiers;
PFN_XSetScreenSaver SetScreenSaver;
PFN_XSetSelectionOwner SetSelectionOwner;
PFN_XSetWMHints SetWMHints;
PFN_XSetWMNormalHints SetWMNormalHints;
PFN_XSetWMProtocols SetWMProtocols;
PFN_XSupportsLocale SupportsLocale;
PFN_XSync Sync;
PFN_XTranslateCoordinates TranslateCoordinates;
PFN_XUndefineCursor UndefineCursor;
PFN_XUngrabPointer UngrabPointer;
PFN_XUnmapWindow UnmapWindow;
PFN_XUnsetICFocus UnsetICFocus;
PFN_XVisualIDFromVisual VisualIDFromVisual;
PFN_XWarpPointer WarpPointer;
PFN_XUnregisterIMInstantiateCallback UnregisterIMInstantiateCallback;
PFN_Xutf8LookupString utf8LookupString;
PFN_Xutf8SetWMProperties utf8SetWMProperties;
} xlib;
struct {
PFN_XrmDestroyDatabase DestroyDatabase;
PFN_XrmGetResource GetResource;
PFN_XrmGetStringDatabase GetStringDatabase;
PFN_XrmInitialize Initialize;
PFN_XrmUniqueQuark UniqueQuark;
} xrm;
struct { struct {
GLFWbool available; GLFWbool available;
void* handle; void* handle;
@ -337,6 +638,15 @@ typedef struct _GLFWlibraryX11
int major; int major;
int minor; int minor;
unsigned int group; unsigned int group;
PFN_XkbFreeKeyboard FreeKeyboard;
PFN_XkbFreeNames FreeNames;
PFN_XkbGetMap GetMap;
PFN_XkbGetNames GetNames;
PFN_XkbGetState GetState;
PFN_XkbKeycodeToKeysym KeycodeToKeysym;
PFN_XkbQueryExtension QueryExtension;
PFN_XkbSelectEventDetails SelectEventDetails;
PFN_XkbSetDetectableAutoRepeat SetDetectableAutoRepeat;
} xkb; } xkb;
struct { struct {
@ -455,4 +765,5 @@ void _glfwReleaseErrorHandlerX11(void);
void _glfwInputErrorX11(int error, const char* message); void _glfwInputErrorX11(int error, const char* message);
void _glfwPushSelectionToManagerX11(void); void _glfwPushSelectionToManagerX11(void);
void _glfwCreateInputContextX11(_GLFWwindow* window);

View File

@ -590,6 +590,14 @@ static void enableCursor(_GLFWwindow* window)
updateCursorImage(window); updateCursorImage(window);
} }
// Clear its handle when the input context has been destroyed
//
static void inputContextDestroyCallback(XIC ic, XPointer clientData, XPointer callData)
{
_GLFWwindow* window = (_GLFWwindow*) clientData;
window->x11.ic = NULL;
}
// Create the X11 window (and its colormap) // Create the X11 window (and its colormap)
// //
static GLFWbool createNativeWindow(_GLFWwindow* window, static GLFWbool createNativeWindow(_GLFWwindow* window,
@ -613,46 +621,41 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
window->x11.transparent = _glfwIsVisualTransparentX11(visual); window->x11.transparent = _glfwIsVisualTransparentX11(visual);
// Create the actual window XSetWindowAttributes wa = { 0 };
wa.colormap = window->x11.colormap;
wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
ExposureMask | FocusChangeMask | VisibilityChangeMask |
EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
_glfwGrabErrorHandlerX11();
window->x11.parent = _glfw.x11.root;
window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root,
0, 0, // Position
width, height,
0, // Border width
depth, // Color depth
InputOutput,
visual,
CWBorderPixel | CWColormap | CWEventMask,
&wa);
_glfwReleaseErrorHandlerX11();
if (!window->x11.handle)
{ {
XSetWindowAttributes wa; _glfwInputErrorX11(GLFW_PLATFORM_ERROR,
const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask; "X11: Failed to create window");
return GLFW_FALSE;
wa.colormap = window->x11.colormap;
wa.border_pixel = 0;
wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
ExposureMask | FocusChangeMask | VisibilityChangeMask |
EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
_glfwGrabErrorHandlerX11();
window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root,
0, 0,
width, height,
0, // Border width
depth, // Color depth
InputOutput,
visual,
wamask,
&wa);
_glfwReleaseErrorHandlerX11();
if (!window->x11.handle)
{
_glfwInputErrorX11(GLFW_PLATFORM_ERROR,
"X11: Failed to create window");
return GLFW_FALSE;
}
XSaveContext(_glfw.x11.display,
window->x11.handle,
_glfw.x11.context,
(XPointer) window);
} }
XSaveContext(_glfw.x11.display,
window->x11.handle,
_glfw.x11.context,
(XPointer) window);
if (!wndconfig->decorated) if (!wndconfig->decorated)
_glfwPlatformSetWindowDecorated(window, GLFW_FALSE); _glfwPlatformSetWindowDecorated(window, GLFW_FALSE);
@ -682,7 +685,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
{ {
XChangeProperty(_glfw.x11.display, window->x11.handle, XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32, _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char*) &states, count); PropModeReplace, (unsigned char*) states, count);
} }
} }
@ -773,20 +776,10 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
PropModeReplace, (unsigned char*) &version, 1); PropModeReplace, (unsigned char*) &version, 1);
} }
_glfwPlatformSetWindowTitle(window, wndconfig->title);
if (_glfw.x11.im) if (_glfw.x11.im)
{ _glfwCreateInputContextX11(window);
window->x11.ic = XCreateIC(_glfw.x11.im,
XNInputStyle,
XIMPreeditNothing | XIMStatusNothing,
XNClientWindow,
window->x11.handle,
XNFocusWindow,
window->x11.handle,
NULL);
}
_glfwPlatformSetWindowTitle(window, wndconfig->title);
_glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos);
_glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
@ -1171,8 +1164,7 @@ static void processEvent(XEvent *event)
if (event->type == KeyPress || event->type == KeyRelease) if (event->type == KeyPress || event->type == KeyRelease)
keycode = event->xkey.keycode; keycode = event->xkey.keycode;
if (_glfw.x11.im) filtered = XFilterEvent(event, None);
filtered = XFilterEvent(event, None);
if (_glfw.x11.randr.available) if (_glfw.x11.randr.available)
{ {
@ -1257,6 +1249,12 @@ static void processEvent(XEvent *event)
switch (event->type) switch (event->type)
{ {
case ReparentNotify:
{
window->x11.parent = event->xreparent.parent;
return;
}
case KeyPress: case KeyPress:
{ {
const int key = translateKey(keycode); const int key = translateKey(keycode);
@ -1541,18 +1539,34 @@ static void processEvent(XEvent *event)
window->x11.height = event->xconfigure.height; window->x11.height = event->xconfigure.height;
} }
if (event->xconfigure.x != window->x11.xpos || int xpos = event->xconfigure.x;
event->xconfigure.y != window->x11.ypos) int ypos = event->xconfigure.y;
{
if (window->x11.overrideRedirect || event->xany.send_event)
{
_glfwInputWindowPos(window,
event->xconfigure.x,
event->xconfigure.y);
window->x11.xpos = event->xconfigure.x; // NOTE: ConfigureNotify events from the server are in local
window->x11.ypos = event->xconfigure.y; // coordinates, so if we are reparented we need to translate
} // the position into root (screen) coordinates
if (!event->xany.send_event && window->x11.parent != _glfw.x11.root)
{
_glfwGrabErrorHandlerX11();
Window dummy;
XTranslateCoordinates(_glfw.x11.display,
window->x11.parent,
_glfw.x11.root,
xpos, ypos,
&xpos, &ypos,
&dummy);
_glfwReleaseErrorHandlerX11();
if (_glfw.x11.errorCode == BadWindow)
return;
}
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
{
_glfwInputWindowPos(window, xpos, ypos);
window->x11.xpos = xpos;
window->x11.ypos = ypos;
} }
return; return;
@ -1943,6 +1957,38 @@ void _glfwPushSelectionToManagerX11(void)
} }
} }
void _glfwCreateInputContextX11(_GLFWwindow* window)
{
XIMCallback callback;
callback.callback = (XIMProc) inputContextDestroyCallback;
callback.client_data = (XPointer) window;
window->x11.ic = XCreateIC(_glfw.x11.im,
XNInputStyle,
XIMPreeditNothing | XIMStatusNothing,
XNClientWindow,
window->x11.handle,
XNFocusWindow,
window->x11.handle,
XNDestroyCallback,
&callback,
NULL);
if (window->x11.ic)
{
XWindowAttributes attribs;
XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs);
unsigned long filter = 0;
if (XGetICValues(window->x11.ic, XNFilterEvents, &filter, NULL) == NULL)
{
XSelectInput(_glfw.x11.display,
window->x11.handle,
attribs.your_event_mask | filter);
}
}
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW platform API ////// ////// GLFW platform API //////
@ -2340,18 +2386,67 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
void _glfwPlatformMaximizeWindow(_GLFWwindow* window) void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{ {
if (_glfw.x11.NET_WM_STATE && if (!_glfw.x11.NET_WM_STATE ||
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
{
return;
}
if (_glfwPlatformWindowVisible(window))
{ {
sendEventToWM(window, sendEventToWM(window,
_glfw.x11.NET_WM_STATE, _glfw.x11.NET_WM_STATE,
_NET_WM_STATE_ADD, _NET_WM_STATE_ADD,
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
1, 0); 1, 0);
XFlush(_glfw.x11.display);
} }
else
{
Atom* states = NULL;
unsigned long count =
_glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE,
XA_ATOM,
(unsigned char**) &states);
// NOTE: We don't check for failure as this property may not exist yet
// and that's fine (and we'll create it implicitly with append)
Atom missing[2] =
{
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ
};
unsigned long missingCount = 2;
for (unsigned long i = 0; i < count; i++)
{
for (unsigned long j = 0; j < missingCount; j++)
{
if (states[i] == missing[j])
{
missing[j] = missing[missingCount - 1];
missingCount--;
}
}
}
if (states)
XFree(states);
if (!missingCount)
return;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) missing,
missingCount);
}
XFlush(_glfw.x11.display);
} }
void _glfwPlatformShowWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window)
@ -2371,6 +2466,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
{ {
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION)
return;
sendEventToWM(window, sendEventToWM(window,
_glfw.x11.NET_WM_STATE, _glfw.x11.NET_WM_STATE,
_NET_WM_STATE_ADD, _NET_WM_STATE_ADD,
@ -2382,7 +2480,7 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
{ {
if (_glfw.x11.NET_ACTIVE_WINDOW) if (_glfw.x11.NET_ACTIVE_WINDOW)
sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0);
else else if (_glfwPlatformWindowVisible(window))
{ {
XRaiseWindow(_glfw.x11.display, window->x11.handle); XRaiseWindow(_glfw.x11.display, window->x11.handle);
XSetInputFocus(_glfw.x11.display, window->x11.handle, XSetInputFocus(_glfw.x11.display, window->x11.handle,
@ -2567,7 +2665,7 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
if (_glfwPlatformWindowVisible(window)) if (_glfwPlatformWindowVisible(window))
{ {
const Atom action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; const long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
sendEventToWM(window, sendEventToWM(window,
_glfw.x11.NET_WM_STATE, _glfw.x11.NET_WM_STATE,
action, action,
@ -2576,15 +2674,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
} }
else else
{ {
Atom* states; Atom* states = NULL;
unsigned long i, count; unsigned long i, count;
count = _glfwGetWindowPropertyX11(window->x11.handle, count = _glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE, _glfw.x11.NET_WM_STATE,
XA_ATOM, XA_ATOM,
(unsigned char**) &states); (unsigned char**) &states);
if (!states)
return; // NOTE: We don't check for failure as this property may not exist yet
// and that's fine (and we'll create it implicitly with append)
if (enabled) if (enabled)
{ {
@ -2594,32 +2693,36 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
break; break;
} }
if (i == count) if (i < count)
{ return;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32, XChangeProperty(_glfw.x11.display, window->x11.handle,
PropModeAppend, _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, PropModeAppend,
1); (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
} 1);
} }
else else if (states)
{ {
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
{ break;
states[i] = states[count - 1];
count--;
}
} }
if (i == count)
return;
states[i] = states[count - 1];
count--;
XChangeProperty(_glfw.x11.display, window->x11.handle, XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32, _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char*) &states, count); PropModeReplace, (unsigned char*) states, count);
} }
XFree(states); if (states)
XFree(states);
} }
XFlush(_glfw.x11.display); XFlush(_glfw.x11.display);
@ -2684,7 +2787,7 @@ void _glfwPlatformPollEvents(void)
#endif #endif
XPending(_glfw.x11.display); XPending(_glfw.x11.display);
while (XQLength(_glfw.x11.display)) while (QLength(_glfw.x11.display))
{ {
XEvent event; XEvent event;
XNextEvent(_glfw.x11.display, &event); XNextEvent(_glfw.x11.display, &event);
@ -2787,6 +2890,13 @@ const char* _glfwPlatformGetScancodeName(int scancode)
if (!_glfw.x11.xkb.available) if (!_glfw.x11.xkb.available)
return NULL; return NULL;
if (scancode < 0 || scancode > 0xff ||
_glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");
return NULL;
}
const int key = _glfw.x11.keycodes[scancode]; const int key = _glfw.x11.keycodes[scancode];
const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display,
scancode, _glfw.x11.xkb.group, 0); scancode, _glfw.x11.xkb.group, 0);
@ -2915,8 +3025,9 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
void _glfwPlatformSetClipboardString(const char* string) void _glfwPlatformSetClipboardString(const char* string)
{ {
char* copy = _glfw_strdup(string);
free(_glfw.x11.clipboardString); free(_glfw.x11.clipboardString);
_glfw.x11.clipboardString = _glfw_strdup(string); _glfw.x11.clipboardString = copy;
XSetSelectionOwner(_glfw.x11.display, XSetSelectionOwner(_glfw.x11.display,
_glfw.x11.CLIPBOARD, _glfw.x11.CLIPBOARD,

View File

@ -1,7 +1,7 @@
link_libraries(glfw) link_libraries(glfw)
include_directories(${glfw_INCLUDE_DIRS} "${GLFW_SOURCE_DIR}/deps") include_directories("${GLFW_SOURCE_DIR}/deps")
if (MATH_LIBRARY) if (MATH_LIBRARY)
link_libraries("${MATH_LIBRARY}") link_libraries("${MATH_LIBRARY}")
@ -20,17 +20,6 @@ set(GETOPT "${GLFW_SOURCE_DIR}/deps/getopt.h"
set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h" set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h"
"${GLFW_SOURCE_DIR}/deps/tinycthread.c") "${GLFW_SOURCE_DIR}/deps/tinycthread.c")
if (${CMAKE_VERSION} VERSION_EQUAL "3.1.0" OR
${CMAKE_VERSION} VERSION_GREATER "3.1.0")
set(CMAKE_C_STANDARD 99)
else()
# Remove this fallback when removing support for CMake version less than 3.1
add_compile_options("$<$<C_COMPILER_ID:AppleClang>:-std=c99>"
"$<$<C_COMPILER_ID:Clang>:-std=c99>"
"$<$<C_COMPILER_ID:GNU>:-std=c99>")
endif()
add_executable(clipboard clipboard.c ${GETOPT} ${GLAD_GL}) add_executable(clipboard clipboard.c ${GETOPT} ${GLAD_GL})
add_executable(events events.c ${GETOPT} ${GLAD_GL}) add_executable(events events.c ${GETOPT} ${GLAD_GL})
add_executable(msaa msaa.c ${GETOPT} ${GLAD_GL}) add_executable(msaa msaa.c ${GETOPT} ${GLAD_GL})
@ -50,27 +39,28 @@ add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GLAD_GL})
add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD_GL}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD_GL})
add_executable(timeout WIN32 MACOSX_BUNDLE timeout.c ${GLAD_GL}) add_executable(timeout WIN32 MACOSX_BUNDLE timeout.c ${GLAD_GL})
add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD_GL}) add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD_GL})
add_executable(triangle-vulkan WIN32 triangle-vulkan.c ${ICON} ${GLAD_VULKAN}) add_executable(triangle-vulkan WIN32 triangle-vulkan.c ${GLAD_VULKAN})
add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${GETOPT} ${GLAD_GL}) add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${GLAD_GL})
target_link_libraries(empty "${CMAKE_THREAD_LIBS_INIT}") target_link_libraries(empty Threads::Threads)
target_link_libraries(threads "${CMAKE_THREAD_LIBS_INIT}") target_link_libraries(threads Threads::Threads)
if (RT_LIBRARY) if (RT_LIBRARY)
target_link_libraries(empty "${RT_LIBRARY}") target_link_libraries(empty "${RT_LIBRARY}")
target_link_libraries(threads "${RT_LIBRARY}") target_link_libraries(threads "${RT_LIBRARY}")
endif() endif()
set(WINDOWS_BINARIES empty gamma icon inputlag joysticks opacity tearing set(GUI_ONLY_BINARIES empty gamma icon inputlag joysticks opacity tearing
threads timeout title triangle-vulkan windows) threads timeout title triangle-vulkan windows)
set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen
cursor) cursor)
set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
C_STANDARD 99
FOLDER "GLFW3/Tests") FOLDER "GLFW3/Tests")
if (MSVC) if (MSVC)
# Tell MSVC to use main instead of WinMain for Windows subsystem executables # Tell MSVC to use main instead of WinMain for Windows subsystem executables
set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES
LINK_FLAGS "/ENTRY:mainCRTStartup") LINK_FLAGS "/ENTRY:mainCRTStartup")
endif() endif()
@ -84,12 +74,11 @@ if (APPLE)
set_target_properties(threads PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Threads") set_target_properties(threads PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Threads")
set_target_properties(timeout PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Timeout") set_target_properties(timeout PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Timeout")
set_target_properties(title PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Title") set_target_properties(title PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Title")
set_target_properties(triangle-vulkan PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Vulkan Triangle")
set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows") set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows")
set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES
MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION}
MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION} MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION}
MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/MacOSXBundleInfo.plist.in") MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/Info.plist.in")
endif() endif()

View File

@ -241,6 +241,8 @@ int main(int argc, char** argv)
glfwSetErrorCallback(error_callback); glfwSetErrorCallback(error_callback);
glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_FALSE);
if (!glfwInit()) if (!glfwInit())
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@ -34,8 +34,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "getopt.h" static GLFWwindow* windows[4];
static const char* titles[] = static const char* titles[] =
{ {
"Red", "Red",
@ -55,20 +54,26 @@ static const struct
{ 0.98f, 0.74f, 0.04f } { 0.98f, 0.74f, 0.04f }
}; };
static void usage(void)
{
printf("Usage: windows [-h] [-b] [-f] \n");
printf("Options:\n");
printf(" -b create decorated windows\n");
printf(" -f set focus on show off for all but first window\n");
printf(" -h show this help\n");
}
static void error_callback(int error, const char* description) static void error_callback(int error, const char* description)
{ {
fprintf(stderr, "Error: %s\n", description); fprintf(stderr, "Error: %s\n", description);
} }
static void arrange_windows(void)
{
int xbase, ybase;
glfwGetWindowPos(windows[0], &xbase, &ybase);
for (int i = 0; i < 4; i++)
{
int left, top, right, bottom;
glfwGetWindowFrameSize(windows[i], &left, &top, &right, &bottom);
glfwSetWindowPos(windows[i],
xbase + (i & 1) * (200 + left + right),
ybase + (i >> 1) * (200 + top + bottom));
}
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{ {
if (action != GLFW_PRESS) if (action != GLFW_PRESS)
@ -87,49 +92,34 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
case GLFW_KEY_ESCAPE: case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, GLFW_TRUE); glfwSetWindowShouldClose(window, GLFW_TRUE);
break; break;
case GLFW_KEY_D:
{
for (int i = 0; i < 4; i++)
{
const int decorated = glfwGetWindowAttrib(windows[i], GLFW_DECORATED);
glfwSetWindowAttrib(windows[i], GLFW_DECORATED, !decorated);
}
arrange_windows();
break;
}
} }
} }
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int i, ch;
int decorated = GLFW_FALSE;
int focusOnShow = GLFW_TRUE;
int running = GLFW_TRUE;
GLFWwindow* windows[4];
while ((ch = getopt(argc, argv, "bfh")) != -1)
{
switch (ch)
{
case 'b':
decorated = GLFW_TRUE;
break;
case 'f':
focusOnShow = GLFW_FALSE;
break;
case 'h':
usage();
exit(EXIT_SUCCESS);
default:
usage();
exit(EXIT_FAILURE);
}
}
glfwSetErrorCallback(error_callback); glfwSetErrorCallback(error_callback);
if (!glfwInit()) if (!glfwInit())
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
glfwWindowHint(GLFW_DECORATED, decorated);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
for (i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
int left, top, right, bottom; if (i > 0)
if (i) glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE);
glfwWindowHint(GLFW_FOCUS_ON_SHOW, focusOnShow);
windows[i] = glfwCreateWindow(200, 200, titles[i], NULL, NULL); windows[i] = glfwCreateWindow(200, 200, titles[i], NULL, NULL);
if (!windows[i]) if (!windows[i])
@ -143,32 +133,29 @@ int main(int argc, char** argv)
glfwMakeContextCurrent(windows[i]); glfwMakeContextCurrent(windows[i]);
gladLoadGL(glfwGetProcAddress); gladLoadGL(glfwGetProcAddress);
glClearColor(colors[i].r, colors[i].g, colors[i].b, 1.f); glClearColor(colors[i].r, colors[i].g, colors[i].b, 1.f);
glfwGetWindowFrameSize(windows[i], &left, &top, &right, &bottom);
glfwSetWindowPos(windows[i],
100 + (i & 1) * (200 + left + right),
100 + (i >> 1) * (200 + top + bottom));
} }
for (i = 0; i < 4; i++) arrange_windows();
for (int i = 0; i < 4; i++)
glfwShowWindow(windows[i]); glfwShowWindow(windows[i]);
while (running) for (;;)
{ {
for (i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
glfwMakeContextCurrent(windows[i]); glfwMakeContextCurrent(windows[i]);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(windows[i]); glfwSwapBuffers(windows[i]);
if (glfwWindowShouldClose(windows[i])) if (glfwWindowShouldClose(windows[i]))
running = GLFW_FALSE; {
glfwTerminate();
exit(EXIT_SUCCESS);
}
} }
glfwWaitEvents(); glfwWaitEvents();
} }
glfwTerminate();
exit(EXIT_SUCCESS);
} }