Merge branch 'glfw:master' into master

This commit is contained in:
Richard Knight 2022-06-01 19:51:27 +01:00 committed by GitHub
commit 3db230c23b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 2809 additions and 1574 deletions

View File

@ -73,8 +73,8 @@ jobs:
- name: Build shared library - name: Build shared library
run: cmake --build build-shared --parallel run: cmake --build build-shared --parallel
build-windows-win32-vs2019: build-windows-win32-vs2022:
name: Win32 (Windows, VS2019) name: Win32 (Windows, VS2022)
runs-on: windows-latest runs-on: windows-latest
env: env:
CFLAGS: /WX CFLAGS: /WX
@ -82,12 +82,12 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Configure static library - name: Configure static library
run: cmake -S . -B build-static -G "Visual Studio 16 2019" run: cmake -S . -B build-static -G "Visual Studio 17 2022"
- name: Build static library - name: Build static library
run: cmake --build build-static --parallel run: cmake --build build-static --parallel
- name: Configure shared library - name: Configure shared library
run: cmake -S . -B build-shared -G "Visual Studio 16 2019" -D BUILD_SHARED_LIBS=ON run: cmake -S . -B build-shared -G "Visual Studio 17 2022" -D BUILD_SHARED_LIBS=ON
- name: Build shared library - name: Build shared library
run: cmake --build build-shared --parallel run: cmake --build build-shared --parallel

View File

@ -10,6 +10,7 @@ video tutorials.
- Matt Arsenault - Matt Arsenault
- ashishgamedev - ashishgamedev
- David Avedissian - David Avedissian
- Luca Bacci
- Keith Bauer - Keith Bauer
- John Bartholomew - John Bartholomew
- Coşku Baş - Coşku Baş
@ -29,6 +30,7 @@ video tutorials.
- David Carlier - David Carlier
- Arturo Castro - Arturo Castro
- Chi-kwan Chan - Chi-kwan Chan
- TheChocolateOre
- Joseph Chua - Joseph Chua
- Ian Clarkson - Ian Clarkson
- Michał Cichoń - Michał Cichoń
@ -42,6 +44,7 @@ video tutorials.
- Noel Cower - Noel Cower
- CuriouserThing - CuriouserThing
- Jason Daly - Jason Daly
- danhambleton
- Jarrod Davis - Jarrod Davis
- Olivier Delannoy - Olivier Delannoy
- Paul R. Deppe - Paul R. Deppe
@ -68,6 +71,7 @@ video tutorials.
- Ryan C. Gordon - Ryan C. Gordon
- Stephen Gowen - Stephen Gowen
- Kovid Goyal - Kovid Goyal
- Kevin Grandemange
- Eloi Marín Gratacós - Eloi Marín Gratacós
- Stefan Gustavson - Stefan Gustavson
- Andrew Gutekanst - Andrew Gutekanst
@ -81,10 +85,14 @@ video tutorials.
- Paul Holden - Paul Holden
- Warren Hu - Warren Hu
- Charles Huber - Charles Huber
- Brent Huisman
- illustris
- InKryption - InKryption
- IntellectualKitty - IntellectualKitty
- Aaron Jacobs - Aaron Jacobs
- JannikGM
- Erik S. V. Jansson - Erik S. V. Jansson
- jjYBdx4IL
- Toni Jovanoski - Toni Jovanoski
- Arseny Kapoulkine - Arseny Kapoulkine
- Cem Karan - Cem Karan
@ -155,6 +163,7 @@ video tutorials.
- Orson Peters - Orson Peters
- Emmanuel Gil Peyrot - Emmanuel Gil Peyrot
- Cyril Pichard - Cyril Pichard
- Pilzschaf
- Keith Pitt - Keith Pitt
- Stanislav Podgorskiy - Stanislav Podgorskiy
- Konstantin Podsvirov - Konstantin Podsvirov
@ -183,13 +192,16 @@ video tutorials.
- Ali Sherief - Ali Sherief
- Yoshiki Shibukawa - Yoshiki Shibukawa
- Dmitri Shuralyov - Dmitri Shuralyov
- Joao da Silva
- Daniel Sieger - Daniel Sieger
- Daniel Skorupski - Daniel Skorupski
- Slemmie
- Anthony Smith - Anthony Smith
- Bradley Smith - Bradley Smith
- Cliff Smolinsky - Cliff Smolinsky
- Patrick Snape - Patrick Snape
- Erlend Sogge Heggen - Erlend Sogge Heggen
- Olivier Sohn
- Julian Squires - Julian Squires
- Johannes Stein - Johannes Stein
- Pontus Stenetorp - Pontus Stenetorp
@ -202,6 +214,7 @@ video tutorials.
- Jared Tiala - Jared Tiala
- Sergey Tikhomirov - Sergey Tikhomirov
- Arthur Tombs - Arthur Tombs
- TronicLabs
- Ioannis Tsakpinis - Ioannis Tsakpinis
- Samuli Tuomola - Samuli Tuomola
- Matthew Turner - Matthew Turner

View File

@ -172,6 +172,8 @@ information on what to include when reporting a bug.
- Bugfix: Gamepad mapping updates could spam `GLFW_INVALID_VALUE` due to - Bugfix: Gamepad mapping updates could spam `GLFW_INVALID_VALUE` due to
incompatible controllers sharing hardware ID (#1763) incompatible controllers sharing hardware ID (#1763)
- Bugfix: Native access functions for context handles did not check that the API matched - Bugfix: Native access functions for context handles did not check that the API matched
- Bugfix: `glfwMakeContextCurrent` would access TLS slot before initialization
- Bugfix: `glfwSetGammaRamp` could emit `GLFW_INVALID_VALUE` before initialization
- [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] Added a version info resource to the GLFW DLL
@ -205,6 +207,17 @@ information on what to include when reporting a bug.
- [Win32] Bugfix: Content scale queries could fail silently (#1615) - [Win32] Bugfix: Content scale queries could fail silently (#1615)
- [Win32] Bugfix: Content scales could have garbage values if monitor was recently - [Win32] Bugfix: Content scales could have garbage values if monitor was recently
disconnected (#1615) disconnected (#1615)
- [Win32] Bugfix: A window created maximized and undecorated would cover the whole
monitor (#1806)
- [Win32] Bugfix: The default restored window position was lost when creating a maximized
window
- [Win32] Bugfix: `glfwMaximizeWindow` would make a hidden window visible
- [Win32] Bugfix: `Alt+PrtSc` would emit `GLFW_KEY_UNKNOWN` and a different
scancode than `PrtSc` (#1993)
- [Win32] Bugfix: `GLFW_KEY_PAUSE` scancode from `glfwGetKeyScancode` did not
match event scancode (#1993)
- [Win32] Bugfix: Instance-local operations used executable instance (#469,#1296,#1395)
- [Win32] Bugfix: The OSMesa library was not unloaded on termination
- [Cocoa] Added support for `VK_EXT_metal_surface` (#1619) - [Cocoa] Added support for `VK_EXT_metal_surface` (#1619)
- [Cocoa] Added locating the Vulkan loader at runtime in an application bundle - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle
- [Cocoa] Moved main menu creation to GLFW initialization time (#1649) - [Cocoa] Moved main menu creation to GLFW initialization time (#1649)
@ -235,6 +248,8 @@ information on what to include when reporting a bug.
a fraction of a second (#1962) a fraction of a second (#1962)
- [Cocoa] Bugfix: `kIOMasterPortDefault` was deprecated in macOS 12.0 (#1980) - [Cocoa] Bugfix: `kIOMasterPortDefault` was deprecated in macOS 12.0 (#1980)
- [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003) - [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003)
- [Cocoa] Bugfix: A connected Apple AirPlay would emit a useless error (#1791)
- [Cocoa] Bugfix: The EGL and OSMesa libraries were not unloaded on termination
- [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)
@ -266,8 +281,19 @@ information on what to include when reporting a bug.
- [X11] Bugfix: Icon pixel format conversion worked only by accident, relying on - [X11] Bugfix: Icon pixel format conversion worked only by accident, relying on
undefined behavior (#1986) undefined behavior (#1986)
- [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences - [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences
- [X11] Bugfix: Waiting for events would fail if file descriptor was too large
(#2024)
- [X11] Bugfix: Joystick events could lead to busy-waiting (#1872)
- [X11] Bugfix: `glfwWaitEvents*` did not continue for joystick events
- [X11] Bugfix: `glfwPostEmptyEvent` could be ignored due to race condition
(#379,#1281,#1285,#2033)
- [X11] Bugfix: Dynamic loading on NetBSD failed due to soname differences
- [X11] Bugfix: Left shift of int constant relied on undefined behavior (#1951)
- [X11] Bugfix: The OSMesa libray was not unloaded on termination
- [X11] Bugfix: A malformed response during selection transfer could cause a segfault
- [Wayland] Added dynamic loading of all Wayland libraries - [Wayland] Added dynamic loading of all Wayland libraries
- [Wayland] Added support for key names via xkbcommon - [Wayland] Added support for key names via xkbcommon
- [Wayland] Added support for file path drop events (#2040)
- [Wayland] Removed support for `wl_shell` (#1443) - [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 - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
@ -290,6 +316,16 @@ information on what to include when reporting a bug.
- [Wayland] Bugfix: Full screen window creation did not ignore `GLFW_VISIBLE` - [Wayland] Bugfix: Full screen window creation did not ignore `GLFW_VISIBLE`
- [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN` - [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN`
- [Wayland] Bugfix: Text input did not repeat along with key repeat - [Wayland] Bugfix: Text input did not repeat along with key repeat
- [Wayland] Bugfix: `glfwPostEmptyEvent` sometimes had no effect (#1520,#1521)
- [Wayland] Bugfix: `glfwSetClipboardString` would fail if set to result of
`glfwGetClipboardString`
- [Wayland] Bugfix: Data source creation error would cause double free at termination
- [Wayland] Bugfix: Partial writes of clipboard string would cause beginning to repeat
- [Wayland] Bugfix: Some errors would cause clipboard string transfer to hang
- [Wayland] Bugfix: Drag and drop data was misinterpreted as clipboard string
- [Wayland] Bugfix: MIME type matching was not performed for clipboard string
- [Wayland] Bugfix: The OSMesa library was not unloaded on termination
- [Wayland] Bugfix: `glfwCreateWindow` could emit `GLFW_FEATURE_UNAVAILABLE`
- [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Removed use of deprecated function `gettimeofday`
- [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled
- [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072)
@ -304,6 +340,7 @@ information on what to include when reporting a bug.
- [EGL] Added ANGLE backend selection via `EGL_ANGLE_platform_angle` extension - [EGL] Added ANGLE backend selection via `EGL_ANGLE_platform_angle` extension
(#1380) (#1380)
- [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843) - [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843)
- [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library
## Contact ## Contact

910
deps/stb_image_write.h vendored

File diff suppressed because it is too large Load Diff

View File

@ -68,8 +68,10 @@ install the `xorgproto` package.
pkg install xorgproto pkg install xorgproto
@endcode @endcode
On Cygwin the `xorgproto` package in the Devel section of the GUI installer will On Cygwin the `libXcursor-devel`, `libXi-devel`, `libXinerama-devel`,
install the headers and other development related files for all of X11. `libXrandr-devel` and `libXrender-devel` packages in the Libs section of the GUI
installer will install all the headers and other development related files GLFW
requires for X11.
Once you have the required dependencies, move on to @ref compile_generate. Once you have the required dependencies, move on to @ref compile_generate.

View File

@ -821,7 +821,7 @@ The second value is always the human-readable name of the gamepad.
All subsequent values are in the form `<field>:<value>` and describe the layout All subsequent values are in the form `<field>:<value>` and describe the layout
of the mapping. These fields may not all be present and may occur in any order. of the mapping. These fields may not all be present and may occur in any order.
The button fields are `a`, `b`, `c`, `d`, `back`, `start`, `guide`, `dpup`, The button fields are `a`, `b`, `x`, `y`, `back`, `start`, `guide`, `dpup`,
`dpright`, `dpdown`, `dpleft`, `leftshoulder`, `rightshoulder`, `leftstick` and `dpright`, `dpdown`, `dpleft`, `leftshoulder`, `rightshoulder`, `leftstick` and
`rightstick`. `rightstick`.

View File

@ -138,6 +138,12 @@ GLFW_TRANSPARENT_FRAMEBUFFER on Windows 7 if DWM transparency is off
(the Transparency setting under Personalization > Window Color). (the Transparency setting under Personalization > Window Color).
@subsubsection emptyevents_34 Empty events on X11 no longer roundtrip to server
Events posted with @ref glfwPostEmptyEvent now use a separate unnamed pipe
instead of sending an X11 client event to the helper window.
@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

@ -50,11 +50,6 @@ set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
C_STANDARD 99 C_STANDARD 99
FOLDER "GLFW3/Examples") FOLDER "GLFW3/Examples")
if (GLFW_USE_OSMESA)
find_package(OSMesa REQUIRED)
target_compile_definitions(offscreen PRIVATE USE_NATIVE_OSMESA)
endif()
if (MSVC) if (MSVC)
# Tell MSVC to use main instead of WinMain # Tell MSVC to use main instead of WinMain
set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES

View File

@ -28,11 +28,6 @@
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#if USE_NATIVE_OSMESA
#define GLFW_EXPOSE_NATIVE_OSMESA
#include <GLFW/glfw3native.h>
#endif
#include "linmath.h" #include "linmath.h"
#include <stdlib.h> #include <stdlib.h>
@ -151,12 +146,8 @@ int main(void)
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
glFinish(); glFinish();
#if USE_NATIVE_OSMESA
glfwGetOSMesaColorBuffer(window, &width, &height, NULL, (void**) &buffer);
#else
buffer = calloc(4, width * height); buffer = calloc(4, width * height);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
#endif
// Write image Y-flipped because OpenGL // Write image Y-flipped because OpenGL
stbi_write_png("offscreen.png", stbi_write_png("offscreen.png",
@ -164,11 +155,7 @@ int main(void)
buffer + (width * 4 * (height - 1)), buffer + (width * 4 * (height - 1)),
-width * 4); -width * 4);
#if USE_NATIVE_OSMESA
// Here is where there's nothing
#else
free(buffer); free(buffer);
#endif
glfwDestroyWindow(window); glfwDestroyWindow(window);

View File

@ -262,13 +262,12 @@ extern "C" {
/* We are building GLFW as a Win32 DLL */ /* We are building GLFW as a Win32 DLL */
#define GLFWAPI __declspec(dllexport) #define GLFWAPI __declspec(dllexport)
#elif defined(_WIN32) && defined(GLFW_DLL) #elif defined(_WIN32) && defined(GLFW_DLL)
/* We are calling GLFW as a Win32 DLL */ /* We are calling a GLFW Win32 DLL */
#define GLFWAPI __declspec(dllimport) #define GLFWAPI __declspec(dllimport)
#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
/* We are building GLFW as a shared / dynamic library */ /* We are building GLFW as a Unix shared library */
#define GLFWAPI __attribute__((visibility("default"))) #define GLFWAPI __attribute__((visibility("default")))
#else #else
/* We are building or calling GLFW as a static library */
#define GLFWAPI #define GLFWAPI
#endif #endif
@ -3258,7 +3257,8 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
* count is zero. * count is zero.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). * GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR and @ref
* GLFW_FEATURE_UNAVAILABLE (see remarks).
* *
* @pointer_lifetime The specified image data is copied before this function * @pointer_lifetime The specified image data is copied before this function
* returns. * returns.
@ -4892,8 +4892,8 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
* @return The handle of the created cursor, or `NULL` if an * @return The handle of the created cursor, or `NULL` if an
* [error](@ref error_handling) occurred. * [error](@ref error_handling) occurred.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_PLATFORM_ERROR. * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
* *
* @pointer_lifetime The specified image data is copied before this function * @pointer_lifetime The specified image data is copied before this function
* returns. * returns.
@ -6383,6 +6383,7 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window
*/ */
#ifndef GLAPIENTRY #ifndef GLAPIENTRY
#define GLAPIENTRY APIENTRY #define GLAPIENTRY APIENTRY
#define GLFW_GLAPIENTRY_DEFINED
#endif #endif
/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ /* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */

View File

@ -82,9 +82,10 @@ extern "C" {
*************************************************************************/ *************************************************************************/
#if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL) #if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL)
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for /* This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
// example to allow applications to correctly declare a GL_KHR_debug callback) * example to allow applications to correctly declare a GL_KHR_debug callback)
// but windows.h assumes no one will define APIENTRY before it does * but windows.h assumes no one will define APIENTRY before it does
*/
#if defined(GLFW_APIENTRY_DEFINED) #if defined(GLFW_APIENTRY_DEFINED)
#undef APIENTRY #undef APIENTRY
#undef GLFW_APIENTRY_DEFINED #undef GLFW_APIENTRY_DEFINED
@ -111,12 +112,28 @@ extern "C" {
/* NSGL is declared by Cocoa.h */ /* NSGL is declared by Cocoa.h */
#endif #endif
#if defined(GLFW_EXPOSE_NATIVE_GLX) #if defined(GLFW_EXPOSE_NATIVE_GLX)
/* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by
* default it also acts as an OpenGL header
* However, glx.h will include gl.h, which will define it unconditionally
*/
#if defined(GLFW_GLAPIENTRY_DEFINED)
#undef GLAPIENTRY
#undef GLFW_GLAPIENTRY_DEFINED
#endif
#include <GL/glx.h> #include <GL/glx.h>
#endif #endif
#if defined(GLFW_EXPOSE_NATIVE_EGL) #if defined(GLFW_EXPOSE_NATIVE_EGL)
#include <EGL/egl.h> #include <EGL/egl.h>
#endif #endif
#if defined(GLFW_EXPOSE_NATIVE_OSMESA) #if defined(GLFW_EXPOSE_NATIVE_OSMESA)
/* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by
* default it also acts as an OpenGL header
* However, osmesa.h will include gl.h, which will define it unconditionally
*/
#if defined(GLFW_GLAPIENTRY_DEFINED)
#undef GLAPIENTRY
#undef GLFW_GLAPIENTRY_DEFINED
#endif
#include <GL/osmesa.h> #include <GL/osmesa.h>
#endif #endif
@ -489,6 +506,9 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
* *
* @remark Because EGL is initialized on demand, this function will return
* `EGL_NO_DISPLAY` until the first context has been created via EGL.
*
* @thread_safety This function may be called from any thread. Access is not * @thread_safety This function may be called from any thread. Access is not
* synchronized. * synchronized.
* *

View File

@ -60,6 +60,7 @@ if (GLFW_BUILD_X11 OR GLFW_BUILD_WAYLAND)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux") if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c) target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c)
endif() endif()
target_sources(glfw PRIVATE posix_poll.h posix_poll.c)
endif() endif()
if (GLFW_BUILD_WAYLAND) if (GLFW_BUILD_WAYLAND)

View File

@ -676,6 +676,8 @@ void _glfwTerminateCocoa(void)
_glfw_free(_glfw.ns.clipboardString); _glfw_free(_glfw.ns.clipboardString);
_glfwTerminateNSGL(); _glfwTerminateNSGL();
_glfwTerminateEGL();
_glfwTerminateOSMesa();
} // autoreleasepool } // autoreleasepool
} }

View File

@ -98,11 +98,7 @@ static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen)
IOObjectRelease(it); IOObjectRelease(it);
if (!service) if (!service)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to find service port for display");
return _glfw_strdup("Display"); return _glfw_strdup("Display");
}
CFDictionaryRef names = CFDictionaryRef names =
CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); CFDictionaryGetValue(info, CFSTR(kDisplayProductName));

View File

@ -973,13 +973,31 @@ int _glfwCreateWindowCocoa(_GLFWwindow* window,
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
} }
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
} }
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughCocoa(window, GLFW_TRUE);
if (window->monitor) if (window->monitor)
{ {
_glfwShowWindowCocoa(window); _glfwShowWindowCocoa(window);
_glfwFocusWindowCocoa(window); _glfwFocusWindowCocoa(window);
acquireMonitor(window); acquireMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowCocoa(window);
if (wndconfig->focused)
_glfwFocusWindowCocoa(window);
}
} }
return GLFW_TRUE; return GLFW_TRUE;

View File

@ -609,10 +609,12 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
{ {
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;
_GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot); _GLFWwindow* previous;
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
if (window && window->context.client == GLFW_NO_API) if (window && window->context.client == GLFW_NO_API)
{ {
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, _glfwInputError(GLFW_NO_WINDOW_CONTEXT,

View File

@ -325,7 +325,7 @@ GLFWbool _glfwInitEGL(void)
"libEGL.dylib", "libEGL.dylib",
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
"libEGL-1.so", "libEGL-1.so",
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
"libEGL.so", "libEGL.so",
#else #else
"libEGL.so.1", "libEGL.so.1",
@ -506,7 +506,7 @@ void _glfwTerminateEGL(void)
} }
} }
#define setAttrib(a, v) \ #define SET_ATTRIB(a, v) \
{ \ { \
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \ attribs[index++] = a; \
@ -584,12 +584,12 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
{ {
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{ {
setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
EGL_NO_RESET_NOTIFICATION_KHR); EGL_NO_RESET_NOTIFICATION_KHR);
} }
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{ {
setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
EGL_LOSE_CONTEXT_ON_RESET_KHR); EGL_LOSE_CONTEXT_ON_RESET_KHR);
} }
@ -599,42 +599,42 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
if (ctxconfig->noerror) if (ctxconfig->noerror)
{ {
if (_glfw.egl.KHR_create_context_no_error) if (_glfw.egl.KHR_create_context_no_error)
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
} }
if (ctxconfig->major != 1 || ctxconfig->minor != 0) if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{ {
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); SET_ATTRIB(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); SET_ATTRIB(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
} }
if (mask) if (mask)
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
if (flags) if (flags)
setAttrib(EGL_CONTEXT_FLAGS_KHR, flags); SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags);
} }
else else
{ {
if (ctxconfig->client == GLFW_OPENGL_ES_API) if (ctxconfig->client == GLFW_OPENGL_ES_API)
setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); SET_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
} }
if (_glfw.egl.KHR_context_flush_control) if (_glfw.egl.KHR_context_flush_control)
{ {
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{ {
setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
} }
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{ {
setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
} }
} }
setAttrib(EGL_NONE, EGL_NONE); SET_ATTRIB(EGL_NONE, EGL_NONE);
window->context.egl.handle = eglCreateContext(_glfw.egl.display, window->context.egl.handle = eglCreateContext(_glfw.egl.display,
config, share, attribs); config, share, attribs);
@ -653,16 +653,16 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
if (fbconfig->sRGB) if (fbconfig->sRGB)
{ {
if (_glfw.egl.KHR_gl_colorspace) if (_glfw.egl.KHR_gl_colorspace)
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); SET_ATTRIB(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
} }
if (!fbconfig->doublebuffer) if (!fbconfig->doublebuffer)
setAttrib(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
if (_glfw.egl.EXT_present_opaque) if (_glfw.egl.EXT_present_opaque)
setAttrib(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent); SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent);
setAttrib(EGL_NONE, EGL_NONE); SET_ATTRIB(EGL_NONE, EGL_NONE);
native = _glfw.platform.getEGLNativeWindow(window); native = _glfw.platform.getEGLNativeWindow(window);
// HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
@ -702,7 +702,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
"libGLES_CM.dll", "libGLES_CM.dll",
#elif defined(_GLFW_COCOA) #elif defined(_GLFW_COCOA)
"libGLESv1_CM.dylib", "libGLESv1_CM.dylib",
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGLESv1_CM.so", "libGLESv1_CM.so",
#else #else
"libGLESv1_CM.so.1", "libGLESv1_CM.so.1",
@ -721,7 +721,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
"libGLESv2.dylib", "libGLESv2.dylib",
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
"libGLESv2-2.so", "libGLESv2-2.so",
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGLESv2.so", "libGLESv2.so",
#else #else
"libGLESv2.so.2", "libGLESv2.so.2",
@ -734,7 +734,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
_GLFW_OPENGL_LIBRARY, _GLFW_OPENGL_LIBRARY,
#elif defined(_GLFW_WIN32) #elif defined(_GLFW_WIN32)
#elif defined(_GLFW_COCOA) #elif defined(_GLFW_COCOA)
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGL.so", "libGL.so",
#else #else
"libGL.so.1", "libGL.so.1",
@ -782,7 +782,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
return GLFW_TRUE; return GLFW_TRUE;
} }
#undef setAttrib #undef SET_ATTRIB
// Returns the Visual and depth of the chosen EGLConfig // Returns the Visual and depth of the chosen EGLConfig
// //

View File

@ -259,7 +259,7 @@ GLFWbool _glfwInitGLX(void)
_GLFW_GLX_LIBRARY, _GLFW_GLX_LIBRARY,
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
"libGL-1.so", "libGL-1.so",
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGL.so", "libGL.so",
#else #else
"libGL.so.1", "libGL.so.1",
@ -308,10 +308,6 @@ GLFWbool _glfwInitGLX(void)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXCreateWindow"); _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXCreateWindow");
_glfw.glx.DestroyWindow = (PFNGLXDESTROYWINDOWPROC) _glfw.glx.DestroyWindow = (PFNGLXDESTROYWINDOWPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXDestroyWindow"); _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXDestroyWindow");
_glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddress");
_glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddressARB");
_glfw.glx.GetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) _glfw.glx.GetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetVisualFromFBConfig"); _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetVisualFromFBConfig");
@ -327,8 +323,6 @@ GLFWbool _glfwInitGLX(void)
!_glfw.glx.CreateNewContext || !_glfw.glx.CreateNewContext ||
!_glfw.glx.CreateWindow || !_glfw.glx.CreateWindow ||
!_glfw.glx.DestroyWindow || !_glfw.glx.DestroyWindow ||
!_glfw.glx.GetProcAddress ||
!_glfw.glx.GetProcAddressARB ||
!_glfw.glx.GetVisualFromFBConfig) !_glfw.glx.GetVisualFromFBConfig)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
@ -336,6 +330,12 @@ GLFWbool _glfwInitGLX(void)
return GLFW_FALSE; return GLFW_FALSE;
} }
// NOTE: Unlike GLX 1.3 entry points these are not required to be present
_glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddress");
_glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddressARB");
if (!glXQueryExtension(_glfw.x11.display, if (!glXQueryExtension(_glfw.x11.display,
&_glfw.glx.errorBase, &_glfw.glx.errorBase,
&_glfw.glx.eventBase)) &_glfw.glx.eventBase))
@ -435,7 +435,7 @@ void _glfwTerminateGLX(void)
} }
} }
#define setAttrib(a, v) \ #define SET_ATTRIB(a, v) \
{ \ { \
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \ attribs[index++] = a; \
@ -523,12 +523,12 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
{ {
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{ {
setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
GLX_NO_RESET_NOTIFICATION_ARB); GLX_NO_RESET_NOTIFICATION_ARB);
} }
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{ {
setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
GLX_LOSE_CONTEXT_ON_RESET_ARB); GLX_LOSE_CONTEXT_ON_RESET_ARB);
} }
@ -542,12 +542,12 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
{ {
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{ {
setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
} }
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{ {
setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
} }
} }
@ -556,7 +556,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
if (ctxconfig->noerror) if (ctxconfig->noerror)
{ {
if (_glfw.glx.ARB_create_context_no_error) if (_glfw.glx.ARB_create_context_no_error)
setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); SET_ATTRIB(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
} }
// NOTE: Only request an explicitly versioned context when necessary, as // NOTE: Only request an explicitly versioned context when necessary, as
@ -564,17 +564,17 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
// highest version supported by the driver // highest version supported by the driver
if (ctxconfig->major != 1 || ctxconfig->minor != 0) if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{ {
setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); SET_ATTRIB(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); SET_ATTRIB(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
} }
if (mask) if (mask)
setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); SET_ATTRIB(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
if (flags) if (flags)
setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); SET_ATTRIB(GLX_CONTEXT_FLAGS_ARB, flags);
setAttrib(None, None); SET_ATTRIB(None, None);
window->context.glx.handle = window->context.glx.handle =
_glfw.glx.CreateContextAttribsARB(_glfw.x11.display, _glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
@ -631,7 +631,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
return GLFW_TRUE; return GLFW_TRUE;
} }
#undef setAttrib #undef SET_ATTRIB
// Returns the Visual and depth of the chosen GLXFBConfig // Returns the Visual and depth of the chosen GLXFBConfig
// //

View File

@ -171,6 +171,59 @@ size_t _glfwEncodeUTF8(char* s, uint32_t codepoint)
return count; return count;
} }
// Splits and translates a text/uri-list into separate file paths
// NOTE: This function destroys the provided string
//
char** _glfwParseUriList(char* text, int* count)
{
const char* prefix = "file://";
char** paths = NULL;
char* line;
*count = 0;
while ((line = strtok(text, "\r\n")))
{
char* path;
text = NULL;
if (line[0] == '#')
continue;
if (strncmp(line, prefix, strlen(prefix)) == 0)
{
line += strlen(prefix);
// TODO: Validate hostname
while (*line != '/')
line++;
}
(*count)++;
path = _glfw_calloc(strlen(line) + 1, 1);
paths = _glfw_realloc(paths, *count * sizeof(char*));
paths[*count - 1] = path;
while (*line)
{
if (line[0] == '%' && line[1] && line[2])
{
const char digits[3] = { line[1], line[2], '\0' };
*path = (char) strtol(digits, NULL, 16);
line += 2;
}
else
*path = *line;
path++;
line++;
}
}
return paths;
}
char* _glfw_strdup(const char* source) char* _glfw_strdup(const char* source)
{ {
const size_t length = strlen(source); const size_t length = strlen(source);
@ -179,6 +232,16 @@ char* _glfw_strdup(const char* source)
return result; return result;
} }
int _glfw_min(int a, int b)
{
return a < b ? a : b;
}
int _glfw_max(int a, int b)
{
return a > b ? a : b;
}
float _glfw_fminf(float a, float b) float _glfw_fminf(float a, float b)
{ {
if (a != a) if (a != a)

View File

@ -764,9 +764,16 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
_GLFWcursor* cursor; _GLFWcursor* cursor;
assert(image != NULL); assert(image != NULL);
assert(image->pixels != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (image->width <= 0 || image->height <= 0)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid image dimensions for cursor");
return NULL;
}
cursor = _glfw_calloc(1, sizeof(_GLFWcursor)); cursor = _glfw_calloc(1, sizeof(_GLFWcursor));
cursor->next = _glfw.cursorListHead; cursor->next = _glfw.cursorListHead;
_glfw.cursorListHead = cursor; _glfw.cursorListHead = cursor;
@ -1421,3 +1428,4 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void)
_GLFW_REQUIRE_INIT_OR_RETURN(0); _GLFW_REQUIRE_INIT_OR_RETURN(0);
return _glfwPlatformGetTimerFrequency(); return _glfwPlatformGetTimerFrequency();
} }

View File

@ -996,8 +996,11 @@ void _glfwTerminateVulkan(void);
const char* _glfwGetVulkanResultString(VkResult result); const char* _glfwGetVulkanResultString(VkResult result);
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint); size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);
char** _glfwParseUriList(char* text, int* count);
char* _glfw_strdup(const char* source); char* _glfw_strdup(const char* source);
int _glfw_min(int a, int b);
int _glfw_max(int a, int b);
float _glfw_fminf(float a, float b); float _glfw_fminf(float a, float b);
float _glfw_fmaxf(float a, float b); float _glfw_fmaxf(float a, float b);

View File

@ -522,6 +522,8 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
assert(ramp->green != NULL); assert(ramp->green != NULL);
assert(ramp->blue != NULL); assert(ramp->blue != NULL);
_GLFW_REQUIRE_INIT();
if (ramp->size <= 0) if (ramp->size <= 0)
{ {
_glfwInputError(GLFW_INVALID_VALUE, _glfwInputError(GLFW_INVALID_VALUE,
@ -530,8 +532,6 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
return; return;
} }
_GLFW_REQUIRE_INIT();
if (!monitor->originalRamp.size) if (!monitor->originalRamp.size)
{ {
if (!_glfw.platform.getGammaRamp(monitor, &monitor->originalRamp)) if (!_glfw.platform.getGammaRamp(monitor, &monitor->originalRamp))

View File

@ -188,45 +188,45 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
// No-error contexts (GL_KHR_no_error) are not yet supported by macOS but // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but
// are not a hard constraint, so ignore and continue // are not a hard constraint, so ignore and continue
#define addAttrib(a) \ #define ADD_ATTRIB(a) \
{ \ { \
assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \ attribs[index++] = a; \
} }
#define setAttrib(a, v) { addAttrib(a); addAttrib(v); } #define SET_ATTRIB(a, v) { ADD_ATTRIB(a); ADD_ATTRIB(v); }
NSOpenGLPixelFormatAttribute attribs[40]; NSOpenGLPixelFormatAttribute attribs[40];
int index = 0; int index = 0;
addAttrib(NSOpenGLPFAAccelerated); ADD_ATTRIB(NSOpenGLPFAAccelerated);
addAttrib(NSOpenGLPFAClosestPolicy); ADD_ATTRIB(NSOpenGLPFAClosestPolicy);
if (ctxconfig->nsgl.offline) if (ctxconfig->nsgl.offline)
{ {
addAttrib(NSOpenGLPFAAllowOfflineRenderers); ADD_ATTRIB(NSOpenGLPFAAllowOfflineRenderers);
// NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in
// Info.plist for unbundled applications // Info.plist for unbundled applications
// HACK: This assumes that NSOpenGLPixelFormat will remain // HACK: This assumes that NSOpenGLPixelFormat will remain
// a straightforward wrapper of its CGL counterpart // a straightforward wrapper of its CGL counterpart
addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching); ADD_ATTRIB(kCGLPFASupportsAutomaticGraphicsSwitching);
} }
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
if (ctxconfig->major >= 4) if (ctxconfig->major >= 4)
{ {
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
} }
else else
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
if (ctxconfig->major >= 3) if (ctxconfig->major >= 3)
{ {
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
} }
if (ctxconfig->major <= 2) if (ctxconfig->major <= 2)
{ {
if (fbconfig->auxBuffers != GLFW_DONT_CARE) if (fbconfig->auxBuffers != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); SET_ATTRIB(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
if (fbconfig->accumRedBits != GLFW_DONT_CARE && if (fbconfig->accumRedBits != GLFW_DONT_CARE &&
fbconfig->accumGreenBits != GLFW_DONT_CARE && fbconfig->accumGreenBits != GLFW_DONT_CARE &&
@ -238,7 +238,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
fbconfig->accumBlueBits + fbconfig->accumBlueBits +
fbconfig->accumAlphaBits; fbconfig->accumAlphaBits;
setAttrib(NSOpenGLPFAAccumSize, accumBits); SET_ATTRIB(NSOpenGLPFAAccumSize, accumBits);
} }
} }
@ -256,17 +256,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
else if (colorBits < 15) else if (colorBits < 15)
colorBits = 15; colorBits = 15;
setAttrib(NSOpenGLPFAColorSize, colorBits); SET_ATTRIB(NSOpenGLPFAColorSize, colorBits);
} }
if (fbconfig->alphaBits != GLFW_DONT_CARE) if (fbconfig->alphaBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); SET_ATTRIB(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
if (fbconfig->depthBits != GLFW_DONT_CARE) if (fbconfig->depthBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits); SET_ATTRIB(NSOpenGLPFADepthSize, fbconfig->depthBits);
if (fbconfig->stencilBits != GLFW_DONT_CARE) if (fbconfig->stencilBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits); SET_ATTRIB(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
if (fbconfig->stereo) if (fbconfig->stereo)
{ {
@ -275,33 +275,33 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
"NSGL: Stereo rendering is deprecated"); "NSGL: Stereo rendering is deprecated");
return GLFW_FALSE; return GLFW_FALSE;
#else #else
addAttrib(NSOpenGLPFAStereo); ADD_ATTRIB(NSOpenGLPFAStereo);
#endif #endif
} }
if (fbconfig->doublebuffer) if (fbconfig->doublebuffer)
addAttrib(NSOpenGLPFADoubleBuffer); ADD_ATTRIB(NSOpenGLPFADoubleBuffer);
if (fbconfig->samples != GLFW_DONT_CARE) if (fbconfig->samples != GLFW_DONT_CARE)
{ {
if (fbconfig->samples == 0) if (fbconfig->samples == 0)
{ {
setAttrib(NSOpenGLPFASampleBuffers, 0); SET_ATTRIB(NSOpenGLPFASampleBuffers, 0);
} }
else else
{ {
setAttrib(NSOpenGLPFASampleBuffers, 1); SET_ATTRIB(NSOpenGLPFASampleBuffers, 1);
setAttrib(NSOpenGLPFASamples, fbconfig->samples); SET_ATTRIB(NSOpenGLPFASamples, fbconfig->samples);
} }
} }
// NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
// framebuffer, so there's no need (and no way) to request it // framebuffer, so there's no need (and no way) to request it
addAttrib(0); ADD_ATTRIB(0);
#undef addAttrib #undef ADD_ATTRIB
#undef setAttrib #undef SET_ATTRIB
window->context.nsgl.pixelFormat = window->context.nsgl.pixelFormat =
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];

View File

@ -39,15 +39,15 @@ static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
*height = (int) (*width / ratio); *height = (int) (*width / ratio);
} }
if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth) if (window->minwidth != GLFW_DONT_CARE)
*width = window->minwidth; *width = _glfw_max(*width, window->minwidth);
else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth) else if (window->maxwidth != GLFW_DONT_CARE)
*width = window->maxwidth; *width = _glfw_min(*width, window->maxwidth);
if (window->minheight != GLFW_DONT_CARE && *height < window->minheight) if (window->minheight != GLFW_DONT_CARE)
*height = window->minheight; *height = _glfw_min(*height, window->minheight);
else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight) else if (window->maxheight != GLFW_DONT_CARE)
*height = window->maxheight; *height = _glfw_max(*height, window->maxheight);
} }
static void fitToMonitor(_GLFWwindow* window) static void fitToMonitor(_GLFWwindow* window)
@ -128,13 +128,31 @@ int _glfwCreateWindowNull(_GLFWwindow* window,
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
} }
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
} }
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughNull(window, GLFW_TRUE);
if (window->monitor) if (window->monitor)
{ {
_glfwShowWindowNull(window); _glfwShowWindowNull(window);
_glfwFocusWindowNull(window); _glfwFocusWindowNull(window);
acquireMonitor(window); acquireMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowNull(window);
if (wndconfig->focused)
_glfwFocusWindowNull(window);
}
} }
return GLFW_TRUE; return GLFW_TRUE;

View File

@ -124,7 +124,7 @@ GLFWbool _glfwInitOSMesa(void)
"libOSMesa.8.dylib", "libOSMesa.8.dylib",
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
"libOSMesa-8.so", "libOSMesa-8.so",
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
"libOSMesa.so", "libOSMesa.so",
#else #else
"libOSMesa.so.8", "libOSMesa.so.8",
@ -190,7 +190,7 @@ void _glfwTerminateOSMesa(void)
} }
} }
#define setAttrib(a, v) \ #define SET_ATTRIB(a, v) \
{ \ { \
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \ attribs[index++] = a; \
@ -221,24 +221,24 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
{ {
int index = 0, attribs[40]; int index = 0, attribs[40];
setAttrib(OSMESA_FORMAT, OSMESA_RGBA); SET_ATTRIB(OSMESA_FORMAT, OSMESA_RGBA);
setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits); SET_ATTRIB(OSMESA_DEPTH_BITS, fbconfig->depthBits);
setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits); SET_ATTRIB(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
setAttrib(OSMESA_ACCUM_BITS, accumBits); SET_ATTRIB(OSMESA_ACCUM_BITS, accumBits);
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
{ {
setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE); SET_ATTRIB(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
} }
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
{ {
setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
} }
if (ctxconfig->major != 1 || ctxconfig->minor != 0) if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{ {
setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
} }
if (ctxconfig->forward) if (ctxconfig->forward)
@ -248,7 +248,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
setAttrib(0, 0); SET_ATTRIB(0, 0);
window->context.osmesa.handle = window->context.osmesa.handle =
OSMesaCreateContextAttribs(attribs, share); OSMesaCreateContextAttribs(attribs, share);
@ -287,7 +287,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
return GLFW_TRUE; return GLFW_TRUE;
} }
#undef setAttrib #undef SET_ATTRIB
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -92,30 +92,6 @@
#define GLFW_LINUX_LIBRARY_JOYSTICK_STATE #define GLFW_LINUX_LIBRARY_JOYSTICK_STATE
#endif #endif
#if defined(_WIN32)
#include "win32_thread.h"
#define GLFW_POSIX_TLS_STATE
#define GLFW_POSIX_MUTEX_STATE
#else
#include "posix_thread.h"
#define GLFW_WIN32_TLS_STATE
#define GLFW_WIN32_MUTEX_STATE
#endif
#if defined(_WIN32)
#include "win32_time.h"
#define GLFW_POSIX_LIBRARY_TIMER_STATE
#define GLFW_COCOA_LIBRARY_TIMER_STATE
#elif defined(__APPLE__)
#include "cocoa_time.h"
#define GLFW_WIN32_LIBRARY_TIMER_STATE
#define GLFW_POSIX_LIBRARY_TIMER_STATE
#else
#include "posix_time.h"
#define GLFW_WIN32_LIBRARY_TIMER_STATE
#define GLFW_COCOA_LIBRARY_TIMER_STATE
#endif
#define GLFW_PLATFORM_WINDOW_STATE \ #define GLFW_PLATFORM_WINDOW_STATE \
GLFW_WIN32_WINDOW_STATE \ GLFW_WIN32_WINDOW_STATE \
GLFW_COCOA_WINDOW_STATE \ GLFW_COCOA_WINDOW_STATE \
@ -142,14 +118,6 @@
GLFW_COCOA_JOYSTICK_STATE \ GLFW_COCOA_JOYSTICK_STATE \
GLFW_LINUX_JOYSTICK_STATE GLFW_LINUX_JOYSTICK_STATE
#define GLFW_PLATFORM_TLS_STATE \
GLFW_WIN32_TLS_STATE \
GLFW_POSIX_TLS_STATE \
#define GLFW_PLATFORM_MUTEX_STATE \
GLFW_WIN32_MUTEX_STATE \
GLFW_POSIX_MUTEX_STATE \
#define GLFW_PLATFORM_LIBRARY_WINDOW_STATE \ #define GLFW_PLATFORM_LIBRARY_WINDOW_STATE \
GLFW_WIN32_LIBRARY_WINDOW_STATE \ GLFW_WIN32_LIBRARY_WINDOW_STATE \
GLFW_COCOA_LIBRARY_WINDOW_STATE \ GLFW_COCOA_LIBRARY_WINDOW_STATE \
@ -162,11 +130,6 @@
GLFW_COCOA_LIBRARY_JOYSTICK_STATE \ GLFW_COCOA_LIBRARY_JOYSTICK_STATE \
GLFW_LINUX_LIBRARY_JOYSTICK_STATE GLFW_LINUX_LIBRARY_JOYSTICK_STATE
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE \
GLFW_WIN32_LIBRARY_TIMER_STATE \
GLFW_COCOA_LIBRARY_TIMER_STATE \
GLFW_POSIX_LIBRARY_TIMER_STATE \
#define GLFW_PLATFORM_CONTEXT_STATE \ #define GLFW_PLATFORM_CONTEXT_STATE \
GLFW_WGL_CONTEXT_STATE \ GLFW_WGL_CONTEXT_STATE \
GLFW_NSGL_CONTEXT_STATE \ GLFW_NSGL_CONTEXT_STATE \
@ -177,3 +140,24 @@
GLFW_NSGL_LIBRARY_CONTEXT_STATE \ GLFW_NSGL_LIBRARY_CONTEXT_STATE \
GLFW_GLX_LIBRARY_CONTEXT_STATE GLFW_GLX_LIBRARY_CONTEXT_STATE
#if defined(_WIN32)
#include "win32_thread.h"
#define GLFW_PLATFORM_TLS_STATE GLFW_WIN32_TLS_STATE
#define GLFW_PLATFORM_MUTEX_STATE GLFW_WIN32_MUTEX_STATE
#else
#include "posix_thread.h"
#define GLFW_PLATFORM_TLS_STATE GLFW_POSIX_TLS_STATE
#define GLFW_PLATFORM_MUTEX_STATE GLFW_POSIX_MUTEX_STATE
#endif
#if defined(_WIN32)
#include "win32_time.h"
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_WIN32_LIBRARY_TIMER_STATE
#elif defined(__APPLE__)
#include "cocoa_time.h"
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_COCOA_LIBRARY_TIMER_STATE
#else
#include "posix_time.h"
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_POSIX_LIBRARY_TIMER_STATE
#endif

81
src/posix_poll.c Normal file
View File

@ -0,0 +1,81 @@
//========================================================================
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2022 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#define _GNU_SOURCE
#include "internal.h"
#include <signal.h>
#include <time.h>
#include <errno.h>
GLFWbool _glfwPollPOSIX(struct pollfd* fds, nfds_t count, double* timeout)
{
for (;;)
{
if (timeout)
{
const uint64_t base = _glfwPlatformGetTimerValue();
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)
const time_t seconds = (time_t) *timeout;
const long nanoseconds = (long) ((*timeout - seconds) * 1e9);
const struct timespec ts = { seconds, nanoseconds };
const int result = ppoll(fds, count, &ts, NULL);
#elif defined(__NetBSD__)
const time_t seconds = (time_t) *timeout;
const long nanoseconds = (long) ((*timeout - seconds) * 1e9);
const struct timespec ts = { seconds, nanoseconds };
const int result = pollts(fds, count, &ts, NULL);
#else
const int milliseconds = (int) (*timeout * 1e3);
const int result = poll(fds, count, milliseconds);
#endif
const int error = errno; // clock_gettime may overwrite our error
*timeout -= (_glfwPlatformGetTimerValue() - base) /
(double) _glfwPlatformGetTimerFrequency();
if (result > 0)
return GLFW_TRUE;
else if (result == -1 && error != EINTR && error != EAGAIN)
return GLFW_FALSE;
else if (*timeout <= 0.0)
return GLFW_FALSE;
}
else
{
const int result = poll(fds, count, -1);
if (result > 0)
return GLFW_TRUE;
else if (result == -1 && errno != EINTR && errno != EAGAIN)
return GLFW_FALSE;
}
}
}

32
src/posix_poll.h Normal file
View File

@ -0,0 +1,32 @@
//========================================================================
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2022 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include <poll.h>
GLFWbool _glfwPollPOSIX(struct pollfd* fds, nfds_t count, double* timeout);

View File

@ -63,7 +63,7 @@ GLFWbool _glfwInitVulkan(int mode)
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib"); _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
if (!_glfw.vk.handle) if (!_glfw.vk.handle)
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa(); _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so"); _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so");
#else #else
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1"); _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1");

View File

@ -52,12 +52,12 @@ static int findPixelFormatAttribValueWGL(const int* attribs,
return 0; return 0;
} }
#define addAttrib(a) \ #define ADD_ATTRIB(a) \
{ \ { \
assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \ assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \
attribs[attribCount++] = a; \ attribs[attribCount++] = a; \
} }
#define findAttribValue(a) \ #define FIND_ATTRIB_VALUE(a) \
findPixelFormatAttribValueWGL(attribs, attribCount, values, a) findPixelFormatAttribValueWGL(attribs, attribCount, values, a)
// Return a list of available and usable framebuffer configs // Return a list of available and usable framebuffer configs
@ -84,41 +84,41 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
return 0; return 0;
} }
addAttrib(WGL_SUPPORT_OPENGL_ARB); ADD_ATTRIB(WGL_SUPPORT_OPENGL_ARB);
addAttrib(WGL_DRAW_TO_WINDOW_ARB); ADD_ATTRIB(WGL_DRAW_TO_WINDOW_ARB);
addAttrib(WGL_PIXEL_TYPE_ARB); ADD_ATTRIB(WGL_PIXEL_TYPE_ARB);
addAttrib(WGL_ACCELERATION_ARB); ADD_ATTRIB(WGL_ACCELERATION_ARB);
addAttrib(WGL_RED_BITS_ARB); ADD_ATTRIB(WGL_RED_BITS_ARB);
addAttrib(WGL_RED_SHIFT_ARB); ADD_ATTRIB(WGL_RED_SHIFT_ARB);
addAttrib(WGL_GREEN_BITS_ARB); ADD_ATTRIB(WGL_GREEN_BITS_ARB);
addAttrib(WGL_GREEN_SHIFT_ARB); ADD_ATTRIB(WGL_GREEN_SHIFT_ARB);
addAttrib(WGL_BLUE_BITS_ARB); ADD_ATTRIB(WGL_BLUE_BITS_ARB);
addAttrib(WGL_BLUE_SHIFT_ARB); ADD_ATTRIB(WGL_BLUE_SHIFT_ARB);
addAttrib(WGL_ALPHA_BITS_ARB); ADD_ATTRIB(WGL_ALPHA_BITS_ARB);
addAttrib(WGL_ALPHA_SHIFT_ARB); ADD_ATTRIB(WGL_ALPHA_SHIFT_ARB);
addAttrib(WGL_DEPTH_BITS_ARB); ADD_ATTRIB(WGL_DEPTH_BITS_ARB);
addAttrib(WGL_STENCIL_BITS_ARB); ADD_ATTRIB(WGL_STENCIL_BITS_ARB);
addAttrib(WGL_ACCUM_BITS_ARB); ADD_ATTRIB(WGL_ACCUM_BITS_ARB);
addAttrib(WGL_ACCUM_RED_BITS_ARB); ADD_ATTRIB(WGL_ACCUM_RED_BITS_ARB);
addAttrib(WGL_ACCUM_GREEN_BITS_ARB); ADD_ATTRIB(WGL_ACCUM_GREEN_BITS_ARB);
addAttrib(WGL_ACCUM_BLUE_BITS_ARB); ADD_ATTRIB(WGL_ACCUM_BLUE_BITS_ARB);
addAttrib(WGL_ACCUM_ALPHA_BITS_ARB); ADD_ATTRIB(WGL_ACCUM_ALPHA_BITS_ARB);
addAttrib(WGL_AUX_BUFFERS_ARB); ADD_ATTRIB(WGL_AUX_BUFFERS_ARB);
addAttrib(WGL_STEREO_ARB); ADD_ATTRIB(WGL_STEREO_ARB);
addAttrib(WGL_DOUBLE_BUFFER_ARB); ADD_ATTRIB(WGL_DOUBLE_BUFFER_ARB);
if (_glfw.wgl.ARB_multisample) if (_glfw.wgl.ARB_multisample)
addAttrib(WGL_SAMPLES_ARB); ADD_ATTRIB(WGL_SAMPLES_ARB);
if (ctxconfig->client == GLFW_OPENGL_API) if (ctxconfig->client == GLFW_OPENGL_API)
{ {
if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB)
addAttrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); ADD_ATTRIB(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
} }
else else
{ {
if (_glfw.wgl.EXT_colorspace) if (_glfw.wgl.EXT_colorspace)
addAttrib(WGL_COLORSPACE_EXT); ADD_ATTRIB(WGL_COLORSPACE_EXT);
} }
} }
else else
@ -152,48 +152,48 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
return 0; return 0;
} }
if (!findAttribValue(WGL_SUPPORT_OPENGL_ARB) || if (!FIND_ATTRIB_VALUE(WGL_SUPPORT_OPENGL_ARB) ||
!findAttribValue(WGL_DRAW_TO_WINDOW_ARB)) !FIND_ATTRIB_VALUE(WGL_DRAW_TO_WINDOW_ARB))
{ {
continue; continue;
} }
if (findAttribValue(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB)
continue; continue;
if (findAttribValue(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB)
continue; continue;
if (findAttribValue(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer) if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer)
continue; continue;
u->redBits = findAttribValue(WGL_RED_BITS_ARB); u->redBits = FIND_ATTRIB_VALUE(WGL_RED_BITS_ARB);
u->greenBits = findAttribValue(WGL_GREEN_BITS_ARB); u->greenBits = FIND_ATTRIB_VALUE(WGL_GREEN_BITS_ARB);
u->blueBits = findAttribValue(WGL_BLUE_BITS_ARB); u->blueBits = FIND_ATTRIB_VALUE(WGL_BLUE_BITS_ARB);
u->alphaBits = findAttribValue(WGL_ALPHA_BITS_ARB); u->alphaBits = FIND_ATTRIB_VALUE(WGL_ALPHA_BITS_ARB);
u->depthBits = findAttribValue(WGL_DEPTH_BITS_ARB); u->depthBits = FIND_ATTRIB_VALUE(WGL_DEPTH_BITS_ARB);
u->stencilBits = findAttribValue(WGL_STENCIL_BITS_ARB); u->stencilBits = FIND_ATTRIB_VALUE(WGL_STENCIL_BITS_ARB);
u->accumRedBits = findAttribValue(WGL_ACCUM_RED_BITS_ARB); u->accumRedBits = FIND_ATTRIB_VALUE(WGL_ACCUM_RED_BITS_ARB);
u->accumGreenBits = findAttribValue(WGL_ACCUM_GREEN_BITS_ARB); u->accumGreenBits = FIND_ATTRIB_VALUE(WGL_ACCUM_GREEN_BITS_ARB);
u->accumBlueBits = findAttribValue(WGL_ACCUM_BLUE_BITS_ARB); u->accumBlueBits = FIND_ATTRIB_VALUE(WGL_ACCUM_BLUE_BITS_ARB);
u->accumAlphaBits = findAttribValue(WGL_ACCUM_ALPHA_BITS_ARB); u->accumAlphaBits = FIND_ATTRIB_VALUE(WGL_ACCUM_ALPHA_BITS_ARB);
u->auxBuffers = findAttribValue(WGL_AUX_BUFFERS_ARB); u->auxBuffers = FIND_ATTRIB_VALUE(WGL_AUX_BUFFERS_ARB);
if (findAttribValue(WGL_STEREO_ARB)) if (FIND_ATTRIB_VALUE(WGL_STEREO_ARB))
u->stereo = GLFW_TRUE; u->stereo = GLFW_TRUE;
if (_glfw.wgl.ARB_multisample) if (_glfw.wgl.ARB_multisample)
u->samples = findAttribValue(WGL_SAMPLES_ARB); u->samples = FIND_ATTRIB_VALUE(WGL_SAMPLES_ARB);
if (ctxconfig->client == GLFW_OPENGL_API) if (ctxconfig->client == GLFW_OPENGL_API)
{ {
if (_glfw.wgl.ARB_framebuffer_sRGB || if (_glfw.wgl.ARB_framebuffer_sRGB ||
_glfw.wgl.EXT_framebuffer_sRGB) _glfw.wgl.EXT_framebuffer_sRGB)
{ {
if (findAttribValue(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) if (FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
u->sRGB = GLFW_TRUE; u->sRGB = GLFW_TRUE;
} }
} }
@ -201,7 +201,7 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
{ {
if (_glfw.wgl.EXT_colorspace) if (_glfw.wgl.EXT_colorspace)
{ {
if (findAttribValue(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT) if (FIND_ATTRIB_VALUE(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT)
u->sRGB = GLFW_TRUE; u->sRGB = GLFW_TRUE;
} }
} }
@ -290,8 +290,8 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
return pixelFormat; return pixelFormat;
} }
#undef addAttrib #undef ADD_ATTRIB
#undef findAttribValue #undef FIND_ATTRIB_VALUE
static void makeContextCurrentWGL(_GLFWwindow* window) static void makeContextCurrentWGL(_GLFWwindow* window)
{ {
@ -523,7 +523,7 @@ void _glfwTerminateWGL(void)
_glfwPlatformFreeModule(_glfw.wgl.instance); _glfwPlatformFreeModule(_glfw.wgl.instance);
} }
#define setAttrib(a, v) \ #define SET_ATTRIB(a, v) \
{ \ { \
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \ attribs[index++] = a; \
@ -631,12 +631,12 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
{ {
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{ {
setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
WGL_NO_RESET_NOTIFICATION_ARB); WGL_NO_RESET_NOTIFICATION_ARB);
} }
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{ {
setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
WGL_LOSE_CONTEXT_ON_RESET_ARB); WGL_LOSE_CONTEXT_ON_RESET_ARB);
} }
@ -650,12 +650,12 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
{ {
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{ {
setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
} }
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{ {
setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
} }
} }
@ -664,7 +664,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
if (ctxconfig->noerror) if (ctxconfig->noerror)
{ {
if (_glfw.wgl.ARB_create_context_no_error) if (_glfw.wgl.ARB_create_context_no_error)
setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
} }
// NOTE: Only request an explicitly versioned context when necessary, as // NOTE: Only request an explicitly versioned context when necessary, as
@ -672,17 +672,17 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
// highest version supported by the driver // highest version supported by the driver
if (ctxconfig->major != 1 || ctxconfig->minor != 0) if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{ {
setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
} }
if (flags) if (flags)
setAttrib(WGL_CONTEXT_FLAGS_ARB, flags); SET_ATTRIB(WGL_CONTEXT_FLAGS_ARB, flags);
if (mask) if (mask)
setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
setAttrib(0, 0); SET_ATTRIB(0, 0);
window->context.wgl.handle = window->context.wgl.handle =
wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs); wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs);
@ -765,7 +765,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
return GLFW_TRUE; return GLFW_TRUE;
} }
#undef setAttrib #undef SET_ATTRIB
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
{ {

View File

@ -71,6 +71,16 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
// //
static GLFWbool loadLibraries(void) static GLFWbool loadLibraries(void)
{ {
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(const WCHAR*) &_glfw,
(HMODULE*) &_glfw.win32.instance))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to retrieve own module handle");
return GLFW_FALSE;
}
_glfw.win32.user32.instance = _glfwPlatformLoadModule("user32.dll"); _glfw.win32.user32.instance = _glfwPlatformLoadModule("user32.dll");
if (!_glfw.win32.user32.instance) if (!_glfw.win32.user32.instance)
{ {
@ -91,6 +101,8 @@ static GLFWbool loadLibraries(void)
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetDpiForWindow"); _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetDpiForWindow");
_glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi) _glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi)
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi"); _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");
_glfw.win32.user32.GetSystemMetricsForDpi_ = (PFN_GetSystemMetricsForDpi)
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetSystemMetricsForDpi");
_glfw.win32.dinput8.instance = _glfwPlatformLoadModule("dinput8.dll"); _glfw.win32.dinput8.instance = _glfwPlatformLoadModule("dinput8.dll");
if (_glfw.win32.dinput8.instance) if (_glfw.win32.dinput8.instance)
@ -251,7 +263,6 @@ static void createKeyTables(void)
_glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN; _glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN;
_glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP; _glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP;
_glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE; _glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE;
_glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE;
_glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE; _glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE;
_glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB; _glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB;
_glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK; _glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK;
@ -333,7 +344,7 @@ static GLFWbool createHelperWindow(void)
WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0, 0, 1, 1, 0, 0, 1, 1,
NULL, NULL, NULL, NULL,
GetModuleHandleW(NULL), _glfw.win32.instance,
NULL); NULL);
if (!_glfw.win32.helperWindowHandle) if (!_glfw.win32.helperWindowHandle)
@ -483,7 +494,7 @@ void _glfwUpdateKeyNamesWin32(void)
vk = vks[key - GLFW_KEY_KP_0]; vk = vks[key - GLFW_KEY_KP_0];
} }
else else
vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK); vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK);
length = ToUnicode(vk, scancode, state, length = ToUnicode(vk, scancode, state,
chars, sizeof(chars) / sizeof(WCHAR), chars, sizeof(chars) / sizeof(WCHAR),
@ -491,6 +502,8 @@ void _glfwUpdateKeyNamesWin32(void)
if (length == -1) if (length == -1)
{ {
// This is a dead key, so we need a second simulated key press
// to make it output its own character (usually a diacritic)
length = ToUnicode(vk, scancode, state, length = ToUnicode(vk, scancode, state,
chars, sizeof(chars) / sizeof(WCHAR), chars, sizeof(chars) / sizeof(WCHAR),
0); 0);
@ -506,7 +519,8 @@ void _glfwUpdateKeyNamesWin32(void)
} }
} }
// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h // Replacement for IsWindowsVersionOrGreater, as we cannot rely on the
// application having a correct embedded manifest
// //
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp) BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp)
{ {
@ -626,7 +640,7 @@ int _glfwInitWin32(void)
createKeyTables(); createKeyTables();
_glfwUpdateKeyNamesWin32(); _glfwUpdateKeyNamesWin32();
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1703OrGreaterWin32())
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
else if (IsWindows8Point1OrGreater()) else if (IsWindows8Point1OrGreater())
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
@ -658,6 +672,7 @@ void _glfwTerminateWin32(void)
_glfwTerminateWGL(); _glfwTerminateWGL();
_glfwTerminateEGL(); _glfwTerminateEGL();
_glfwTerminateOSMesa();
freeLibraries(); freeLibraries();
} }

View File

@ -574,7 +574,7 @@ GLFWbool _glfwInitJoysticksWin32(void)
{ {
if (_glfw.win32.dinput8.instance) if (_glfw.win32.dinput8.instance)
{ {
if (FAILED(DirectInput8Create(GetModuleHandle(NULL), if (FAILED(DirectInput8Create(_glfw.win32.instance,
DIRECTINPUT_VERSION, DIRECTINPUT_VERSION,
&IID_IDirectInput8W, &IID_IDirectInput8W,
(void**) &_glfw.win32.dinput8.api, (void**) &_glfw.win32.dinput8.api,
@ -607,7 +607,7 @@ int _glfwPollJoystickWin32(_GLFWjoystick* js, int mode)
{ {
int i, ai = 0, bi = 0, pi = 0; int i, ai = 0, bi = 0, pi = 0;
HRESULT result; HRESULT result;
DIJOYSTATE state; DIJOYSTATE state = {0};
IDirectInputDevice8_Poll(js->win32.device); IDirectInputDevice8_Poll(js->win32.device);
result = IDirectInputDevice8_GetDeviceState(js->win32.device, result = IDirectInputDevice8_GetDeviceState(js->win32.device,

View File

@ -381,7 +381,7 @@ void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor,
int* width, int* height) int* width, int* height)
{ {
MONITORINFO mi = { sizeof(mi) }; MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(monitor->win32.handle, &mi); GetMonitorInfoW(monitor->win32.handle, &mi);
if (xpos) if (xpos)
*xpos = mi.rcWork.left; *xpos = mi.rcWork.left;

View File

@ -162,7 +162,9 @@ typedef enum
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4) #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4)
#endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/ #endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header // Replacement for versionhelpers.h macros, as we cannot rely on the
// application having a correct embedded manifest
//
#define IsWindowsVistaOrGreater() \ #define IsWindowsVistaOrGreater() \
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \
LOBYTE(_WIN32_WINNT_VISTA), 0) LOBYTE(_WIN32_WINNT_VISTA), 0)
@ -176,9 +178,11 @@ typedef enum
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \
LOBYTE(_WIN32_WINNT_WINBLUE), 0) LOBYTE(_WIN32_WINNT_WINBLUE), 0)
#define _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() \ // Windows 10 Anniversary Update
#define _glfwIsWindows10Version1607OrGreaterWin32() \
_glfwIsWindows10BuildOrGreaterWin32(14393) _glfwIsWindows10BuildOrGreaterWin32(14393)
#define _glfwIsWindows10CreatorsUpdateOrGreaterWin32() \ // Windows 10 Creators Update
#define _glfwIsWindows10Version1703OrGreaterWin32() \
_glfwIsWindows10BuildOrGreaterWin32(15063) _glfwIsWindows10BuildOrGreaterWin32(15063)
// HACK: Define macros that some xinput.h variants don't // HACK: Define macros that some xinput.h variants don't
@ -283,12 +287,14 @@ typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND);
typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE); typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE);
typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND); typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND);
typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT);
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
#define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_ #define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_
#define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_ #define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_
#define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_ #define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_
#define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_ #define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_
#define GetSystemMetricsForDpi _glfw.win32.user32.GetSystemMetricsForDpi_
// dwmapi.dll function pointer typedefs // dwmapi.dll function pointer typedefs
typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
@ -436,6 +442,7 @@ typedef struct _GLFWwindowWin32
// //
typedef struct _GLFWlibraryWin32 typedef struct _GLFWlibraryWin32
{ {
HINSTANCE instance;
HWND helperWindowHandle; HWND helperWindowHandle;
HDEVNOTIFY deviceNotificationHandle; HDEVNOTIFY deviceNotificationHandle;
int acquiredMonitorCount; int acquiredMonitorCount;
@ -471,6 +478,7 @@ typedef struct _GLFWlibraryWin32
PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_; PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_;
PFN_GetDpiForWindow GetDpiForWindow_; PFN_GetDpiForWindow GetDpiForWindow_;
PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_; PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_;
PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_;
} user32; } user32;
struct { struct {

View File

@ -97,8 +97,7 @@ static const GLFWimage* chooseImage(int count, const GLFWimage* images,
// Creates an RGBA icon or cursor // Creates an RGBA icon or cursor
// //
static HICON createIcon(const GLFWimage* image, static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon)
int xhot, int yhot, GLFWbool icon)
{ {
int i; int i;
HDC dc; HDC dc;
@ -194,7 +193,7 @@ static void getFullWindowSize(DWORD style, DWORD exStyle,
{ {
RECT rect = { 0, 0, contentWidth, contentHeight }; RECT rect = { 0, 0, contentWidth, contentHeight };
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi); AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
else else
AdjustWindowRectEx(&rect, style, FALSE, exStyle); AdjustWindowRectEx(&rect, style, FALSE, exStyle);
@ -211,7 +210,7 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
UINT dpi = USER_DEFAULT_SCREEN_DPI; UINT dpi = USER_DEFAULT_SCREEN_DPI;
const float ratio = (float) window->numer / (float) window->denom; const float ratio = (float) window->numer / (float) window->denom;
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
dpi = GetDpiForWindow(window->win32.handle); dpi = GetDpiForWindow(window->win32.handle);
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
@ -354,7 +353,7 @@ static void updateWindowStyles(const _GLFWwindow* window)
GetClientRect(window->win32.handle, &rect); GetClientRect(window->win32.handle, &rect);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
{ {
AdjustWindowRectExForDpi(&rect, style, FALSE, AdjustWindowRectExForDpi(&rect, style, FALSE,
getWindowExStyle(window), getWindowExStyle(window),
@ -434,7 +433,7 @@ static int getKeyMods(void)
static void fitToMonitor(_GLFWwindow* window) static void fitToMonitor(_GLFWwindow* window)
{ {
MONITORINFO mi = { sizeof(mi) }; MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(window->monitor->win32.handle, &mi); GetMonitorInfoW(window->monitor->win32.handle, &mi);
SetWindowPos(window->win32.handle, HWND_TOPMOST, SetWindowPos(window->win32.handle, HWND_TOPMOST,
mi.rcMonitor.left, mi.rcMonitor.left,
mi.rcMonitor.top, mi.rcMonitor.top,
@ -453,8 +452,8 @@ static void acquireMonitor(_GLFWwindow* window)
// HACK: When mouse trails are enabled the cursor becomes invisible when // HACK: When mouse trails are enabled the cursor becomes invisible when
// the OpenGL ICD switches to page flipping // the OpenGL ICD switches to page flipping
SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0); SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0); SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0);
} }
if (!window->monitor->window) if (!window->monitor->window)
@ -477,17 +476,66 @@ static void releaseMonitor(_GLFWwindow* window)
SetThreadExecutionState(ES_CONTINUOUS); SetThreadExecutionState(ES_CONTINUOUS);
// HACK: Restore mouse trail length saved in acquireMonitor // HACK: Restore mouse trail length saved in acquireMonitor
SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
} }
_glfwInputMonitorWindow(window->monitor, NULL); _glfwInputMonitorWindow(window->monitor, NULL);
_glfwRestoreVideoModeWin32(window->monitor); _glfwRestoreVideoModeWin32(window->monitor);
} }
// Manually maximize the window, for when SW_MAXIMIZE cannot be used
//
static void maximizeWindowManually(_GLFWwindow* window)
{
RECT rect;
DWORD style;
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfoW(MonitorFromWindow(window->win32.handle,
MONITOR_DEFAULTTONEAREST), &mi);
rect = mi.rcWork;
if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)
{
rect.right = _glfw_min(rect.right, rect.left + window->maxwidth);
rect.bottom = _glfw_min(rect.bottom, rect.top + window->maxheight);
}
style = GetWindowLongW(window->win32.handle, GWL_STYLE);
style |= WS_MAXIMIZE;
SetWindowLongW(window->win32.handle, GWL_STYLE, style);
if (window->decorated)
{
const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
const UINT dpi = GetDpiForWindow(window->win32.handle);
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
OffsetRect(&rect, 0, GetSystemMetricsForDpi(SM_CYCAPTION, dpi));
}
else
{
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION));
}
rect.bottom = _glfw_min(rect.bottom, mi.rcWork.bottom);
}
SetWindowPos(window->win32.handle, HWND_TOP,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
// Window callback function (handles window messages) // Window callback function (handles window messages)
// //
static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
WPARAM wParam, LPARAM lParam)
{ {
_GLFWwindow* window = GetPropW(hWnd, L"GLFW"); _GLFWwindow* window = GetPropW(hWnd, L"GLFW");
if (!window) if (!window)
@ -499,7 +547,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
{ {
case WM_NCCREATE: case WM_NCCREATE:
{ {
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
{ {
const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam; const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam;
const _GLFWwndconfig* wndconfig = cs->lpCreateParams; const _GLFWwndconfig* wndconfig = cs->lpCreateParams;
@ -704,6 +752,14 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC); scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC);
} }
// HACK: Alt+PrtSc has a different scancode than just PrtSc
if (scancode == 0x54)
scancode = 0x137;
// HACK: Ctrl+Pause has a different scancode than just Pause
if (scancode == 0x146)
scancode = 0x45;
key = _glfw.win32.keycodes[scancode]; key = _glfw.win32.keycodes[scancode];
// The Ctrl keys require special handling // The Ctrl keys require special handling
@ -1045,7 +1101,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
if (window->monitor) if (window->monitor)
break; break;
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
dpi = GetDpiForWindow(window->win32.handle); dpi = GetDpiForWindow(window->win32.handle);
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
@ -1073,7 +1129,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
ZeroMemory(&mi, sizeof(mi)); ZeroMemory(&mi, sizeof(mi));
mi.cbSize = sizeof(mi); mi.cbSize = sizeof(mi);
GetMonitorInfo(mh, &mi); GetMonitorInfoW(mh, &mi);
mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left;
mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top;
@ -1120,7 +1176,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
break; break;
// Adjust the window size to keep the content area size constant // Adjust the window size to keep the content area size constant
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1703OrGreaterWin32())
{ {
RECT source = {0}, target = {0}; RECT source = {0}, target = {0};
SIZE* size = (SIZE*) lParam; SIZE* size = (SIZE*) lParam;
@ -1151,7 +1207,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
// need it to compensate for non-client area scaling // need it to compensate for non-client area scaling
if (!window->monitor && if (!window->monitor &&
(window->win32.scaleToMonitor || (window->win32.scaleToMonitor ||
_glfwIsWindows10CreatorsUpdateOrGreaterWin32())) _glfwIsWindows10Version1703OrGreaterWin32()))
{ {
RECT* suggested = (RECT*) lParam; RECT* suggested = (RECT*) lParam;
SetWindowPos(window->win32.handle, HWND_TOP, SetWindowPos(window->win32.handle, HWND_TOP,
@ -1228,15 +1284,16 @@ static int createNativeWindow(_GLFWwindow* window,
if (window->monitor) if (window->monitor)
{ {
GLFWvidmode mode; MONITORINFO mi = { sizeof(mi) };
GetMonitorInfoW(window->monitor->win32.handle, &mi);
// NOTE: This window placement is temporary and approximate, as the // NOTE: This window placement is temporary and approximate, as the
// correct position and size cannot be known until the monitor // correct position and size cannot be known until the monitor
// video mode has been picked in _glfwSetVideoModeWin32 // video mode has been picked in _glfwSetVideoModeWin32
_glfwGetMonitorPosWin32(window->monitor, &xpos, &ypos); xpos = mi.rcMonitor.left;
_glfwGetVideoModeWin32(window->monitor, &mode); ypos = mi.rcMonitor.top;
fullWidth = mode.width; fullWidth = mi.rcMonitor.right - mi.rcMonitor.left;
fullHeight = mode.height; fullHeight = mi.rcMonitor.bottom - mi.rcMonitor.top;
} }
else else
{ {
@ -1265,7 +1322,7 @@ static int createNativeWindow(_GLFWwindow* window,
fullWidth, fullHeight, fullWidth, fullHeight,
NULL, // No parent window NULL, // No parent window
NULL, // No window menu NULL, // No window menu
GetModuleHandleW(NULL), _glfw.win32.instance,
(LPVOID) wndconfig); (LPVOID) wndconfig);
_glfw_free(wideTitle); _glfw_free(wideTitle);
@ -1292,18 +1349,22 @@ static int createNativeWindow(_GLFWwindow* window,
window->win32.scaleToMonitor = wndconfig->scaleToMonitor; window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
window->win32.keymenu = wndconfig->win32.keymenu; window->win32.keymenu = wndconfig->win32.keymenu;
// Adjust window rect to account for DPI scaling of the window frame and
// (if enabled) DPI scaling of the content area
// This cannot be done until we know what monitor the window was placed on
if (!window->monitor) if (!window->monitor)
{ {
RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
WINDOWPLACEMENT wp = { sizeof(wp) }; WINDOWPLACEMENT wp = { sizeof(wp) };
const HMONITOR mh = MonitorFromWindow(window->win32.handle,
MONITOR_DEFAULTTONEAREST);
// Adjust window rect to account for DPI scaling of the window frame and
// (if enabled) DPI scaling of the content area
// This cannot be done until we know what monitor the window was placed on
// Only update the restored window rect as the window may be maximized
if (wndconfig->scaleToMonitor) if (wndconfig->scaleToMonitor)
{ {
float xscale, yscale; float xscale, yscale;
_glfwGetWindowContentScaleWin32(window, &xscale, &yscale); _glfwGetHMONITORContentScaleWin32(mh, &xscale, &yscale);
if (xscale > 0.f && yscale > 0.f) if (xscale > 0.f && yscale > 0.f)
{ {
@ -1312,10 +1373,7 @@ static int createNativeWindow(_GLFWwindow* window,
} }
} }
ClientToScreen(window->win32.handle, (POINT*) &rect.left); if (_glfwIsWindows10Version1607OrGreaterWin32())
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{ {
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
GetDpiForWindow(window->win32.handle)); GetDpiForWindow(window->win32.handle));
@ -1323,11 +1381,30 @@ static int createNativeWindow(_GLFWwindow* window,
else else
AdjustWindowRectEx(&rect, style, FALSE, exStyle); AdjustWindowRectEx(&rect, style, FALSE, exStyle);
// Only update the restored window rect as the window may be maximized
GetWindowPlacement(window->win32.handle, &wp); GetWindowPlacement(window->win32.handle, &wp);
OffsetRect(&rect,
wp.rcNormalPosition.left - rect.left,
wp.rcNormalPosition.top - rect.top);
wp.rcNormalPosition = rect; wp.rcNormalPosition = rect;
wp.showCmd = SW_HIDE; wp.showCmd = SW_HIDE;
SetWindowPlacement(window->win32.handle, &wp); SetWindowPlacement(window->win32.handle, &wp);
// Adjust rect of maximized undecorated window, because by default Windows will
// make such a window cover the whole monitor instead of its workarea
if (wndconfig->maximized && !wndconfig->decorated)
{
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfoW(mh, &mi);
SetWindowPos(window->win32.handle, HWND_TOP,
mi.rcWork.left,
mi.rcWork.top,
mi.rcWork.right - mi.rcWork.left,
mi.rcWork.bottom - mi.rcWork.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
} }
DragAcceptFiles(window->win32.handle, TRUE); DragAcceptFiles(window->win32.handle, TRUE);
@ -1352,8 +1429,8 @@ GLFWbool _glfwRegisterWindowClassWin32(void)
ZeroMemory(&wc, sizeof(wc)); ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc); wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) windowProc; wc.lpfnWndProc = windowProc;
wc.hInstance = GetModuleHandleW(NULL); wc.hInstance = _glfw.win32.instance;
wc.hCursor = LoadCursorW(NULL, IDC_ARROW); wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.lpszClassName = _GLFW_WNDCLASSNAME; wc.lpszClassName = _GLFW_WNDCLASSNAME;
@ -1383,7 +1460,7 @@ GLFWbool _glfwRegisterWindowClassWin32(void)
// //
void _glfwUnregisterWindowClassWin32(void) void _glfwUnregisterWindowClassWin32(void)
{ {
UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); UnregisterClassW(_GLFW_WNDCLASSNAME, _glfw.win32.instance);
} }
int _glfwCreateWindowWin32(_GLFWwindow* window, int _glfwCreateWindowWin32(_GLFWwindow* window,
@ -1417,14 +1494,32 @@ int _glfwCreateWindowWin32(_GLFWwindow* window,
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
} }
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
} }
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughWin32(window, GLFW_TRUE);
if (window->monitor) if (window->monitor)
{ {
_glfwShowWindowWin32(window); _glfwShowWindowWin32(window);
_glfwFocusWindowWin32(window); _glfwFocusWindowWin32(window);
acquireMonitor(window); acquireMonitor(window);
fitToMonitor(window); fitToMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowWin32(window);
if (wndconfig->focused)
_glfwFocusWindowWin32(window);
}
} }
return GLFW_TRUE; return GLFW_TRUE;
@ -1465,8 +1560,7 @@ void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title)
_glfw_free(wideTitle); _glfw_free(wideTitle);
} }
void _glfwSetWindowIconWin32(_GLFWwindow* window, void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images)
int count, const GLFWimage* images)
{ {
HICON bigIcon = NULL, smallIcon = NULL; HICON bigIcon = NULL, smallIcon = NULL;
@ -1488,8 +1582,8 @@ void _glfwSetWindowIconWin32(_GLFWwindow* window,
smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
} }
SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
if (window->win32.bigIcon) if (window->win32.bigIcon)
DestroyIcon(window->win32.bigIcon); DestroyIcon(window->win32.bigIcon);
@ -1519,7 +1613,7 @@ void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos)
{ {
RECT rect = { xpos, ypos, xpos, ypos }; RECT rect = { xpos, ypos, xpos, ypos };
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
{ {
AdjustWindowRectExForDpi(&rect, getWindowStyle(window), AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window), FALSE, getWindowExStyle(window),
@ -1560,7 +1654,7 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height)
{ {
RECT rect = { 0, 0, width, height }; RECT rect = { 0, 0, width, height };
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
{ {
AdjustWindowRectExForDpi(&rect, getWindowStyle(window), AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window), FALSE, getWindowExStyle(window),
@ -1627,7 +1721,7 @@ void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window,
_glfwGetWindowSizeWin32(window, &width, &height); _glfwGetWindowSizeWin32(window, &width, &height);
SetRect(&rect, 0, 0, width, height); SetRect(&rect, 0, 0, width, height);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
{ {
AdjustWindowRectExForDpi(&rect, getWindowStyle(window), AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window), FALSE, getWindowExStyle(window),
@ -1668,7 +1762,10 @@ void _glfwRestoreWindowWin32(_GLFWwindow* window)
void _glfwMaximizeWindowWin32(_GLFWwindow* window) void _glfwMaximizeWindowWin32(_GLFWwindow* window)
{ {
if (IsWindowVisible(window->win32.handle))
ShowWindow(window->win32.handle, SW_MAXIMIZE); ShowWindow(window->win32.handle, SW_MAXIMIZE);
else
maximizeWindowManually(window);
} }
void _glfwShowWindowWin32(_GLFWwindow* window) void _glfwShowWindowWin32(_GLFWwindow* window)
@ -1713,7 +1810,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
{ {
RECT rect = { xpos, ypos, xpos + width, ypos + height }; RECT rect = { xpos, ypos, xpos + width, ypos + height };
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
{ {
AdjustWindowRectExForDpi(&rect, getWindowStyle(window), AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window), FALSE, getWindowExStyle(window),
@ -1755,7 +1852,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
acquireMonitor(window); acquireMonitor(window);
GetMonitorInfo(window->monitor->win32.handle, &mi); GetMonitorInfoW(window->monitor->win32.handle, &mi);
SetWindowPos(window->win32.handle, HWND_TOPMOST, SetWindowPos(window->win32.handle, HWND_TOPMOST,
mi.rcMonitor.left, mi.rcMonitor.left,
mi.rcMonitor.top, mi.rcMonitor.top,
@ -1784,7 +1881,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
else else
after = HWND_NOTOPMOST; after = HWND_NOTOPMOST;
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) if (_glfwIsWindows10Version1607OrGreaterWin32())
{ {
AdjustWindowRectExForDpi(&rect, getWindowStyle(window), AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window), FALSE, getWindowExStyle(window),
@ -2052,7 +2149,7 @@ void _glfwWaitEventsTimeoutWin32(double timeout)
void _glfwPostEmptyEventWin32(void) void _glfwPostEmptyEventWin32(void)
{ {
PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
} }
void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos) void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos)
@ -2369,7 +2466,7 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance,
memset(&sci, 0, sizeof(sci)); memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
sci.hinstance = GetModuleHandle(NULL); sci.hinstance = _glfw.win32.instance;
sci.hwnd = window->win32.handle; sci.hwnd = window->win32.handle;
err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);

View File

@ -215,40 +215,12 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
window->numer = GLFW_DONT_CARE; window->numer = GLFW_DONT_CARE;
window->denom = GLFW_DONT_CARE; window->denom = GLFW_DONT_CARE;
// Open the actual window and create its context
if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig)) if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig))
{ {
glfwDestroyWindow((GLFWwindow*) window); glfwDestroyWindow((GLFWwindow*) window);
return NULL; return NULL;
} }
if (ctxconfig.client != GLFW_NO_API)
{
if (!_glfwRefreshContextAttribs(window, &ctxconfig))
{
glfwDestroyWindow((GLFWwindow*) window);
return NULL;
}
}
if (wndconfig.mousePassthrough)
_glfw.platform.setWindowMousePassthrough(window, GLFW_TRUE);
if (window->monitor)
{
if (wndconfig.centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig.visible)
{
_glfw.platform.showWindow(window);
if (wndconfig.focused)
_glfw.platform.focusWindow(window);
}
}
return (GLFWwindow*) window; return (GLFWwindow*) window;
} }
@ -514,12 +486,33 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title)
GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle,
int count, const GLFWimage* images) int count, const GLFWimage* images)
{ {
int i;
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL); assert(window != NULL);
assert(count >= 0); assert(count >= 0);
assert(count == 0 || images != NULL); assert(count == 0 || images != NULL);
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
if (count < 0)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid image count for window icon");
return;
}
for (i = 0; i < count; i++)
{
assert(images[i].pixels != NULL);
if (images[i].width <= 0 || images[i].height <= 0)
{
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid image dimensions for window icon");
return;
}
}
_glfw.platform.setWindowIcon(window, count, images); _glfw.platform.setWindowIcon(window, count, images);
} }

View File

@ -28,7 +28,6 @@
#include "internal.h" #include "internal.h"
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <linux/input.h> #include <linux/input.h>
@ -48,739 +47,52 @@
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
// NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of
// wl_interface pointers 'types', making it impossible to combine several unmodified
// private-code files into a single compilation unit
// HACK: We override this name with a macro for each file, allowing them to coexist
#define types _glfw_wayland_types
#include "wayland-client-protocol-code.h" #include "wayland-client-protocol-code.h"
#undef types
#define types _glfw_xdg_shell_types
#include "wayland-xdg-shell-client-protocol-code.h" #include "wayland-xdg-shell-client-protocol-code.h"
#undef types
#define types _glfw_xdg_decoration_types
#include "wayland-xdg-decoration-client-protocol-code.h" #include "wayland-xdg-decoration-client-protocol-code.h"
#undef types
#define types _glfw_viewporter_types
#include "wayland-viewporter-client-protocol-code.h" #include "wayland-viewporter-client-protocol-code.h"
#undef types
#define types _glfw_relative_pointer_types
#include "wayland-relative-pointer-unstable-v1-client-protocol-code.h" #include "wayland-relative-pointer-unstable-v1-client-protocol-code.h"
#undef types
#define types _glfw_pointer_constraints_types
#include "wayland-pointer-constraints-unstable-v1-client-protocol-code.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol-code.h"
#undef types
#define types _glfw_idle_inhibit_types
#include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h"
#undef types
static void wmBaseHandlePing(void* userData,
static inline int min(int n1, int n2)
{
return n1 < n2 ? n1 : n2;
}
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
int* which)
{
int focus;
_GLFWwindow* window = _glfw.windowListHead;
if (!which)
which = &focus;
while (window)
{
if (surface == window->wl.decorations.top.surface)
{
*which = topDecoration;
break;
}
if (surface == window->wl.decorations.left.surface)
{
*which = leftDecoration;
break;
}
if (surface == window->wl.decorations.right.surface)
{
*which = rightDecoration;
break;
}
if (surface == window->wl.decorations.bottom.surface)
{
*which = bottomDecoration;
break;
}
window = window->next;
}
return window;
}
static void pointerHandleEnter(void* data,
struct wl_pointer* pointer,
uint32_t serial,
struct wl_surface* surface,
wl_fixed_t sx,
wl_fixed_t sy)
{
// Happens in the case we just destroyed the surface.
if (!surface)
return;
int focus = 0;
_GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window)
{
window = findWindowFromDecorationSurface(surface, &focus);
if (!window)
return;
}
window->wl.decorations.focus = focus;
_glfw.wl.serial = serial;
_glfw.wl.pointerEnterSerial = serial;
_glfw.wl.pointerFocus = window;
window->wl.hovered = GLFW_TRUE;
_glfwSetCursorWayland(window, window->wl.currentCursor);
_glfwInputCursorEnter(window, GLFW_TRUE);
}
static void pointerHandleLeave(void* data,
struct wl_pointer* pointer,
uint32_t serial,
struct wl_surface* surface)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
if (!window)
return;
window->wl.hovered = GLFW_FALSE;
_glfw.wl.serial = serial;
_glfw.wl.pointerFocus = NULL;
_glfwInputCursorEnter(window, GLFW_FALSE);
_glfw.wl.cursorPreviousName = NULL;
}
static void setCursor(_GLFWwindow* window, const char* name)
{
struct wl_buffer* buffer;
struct wl_cursor* cursor;
struct wl_cursor_image* image;
struct wl_surface* surface = _glfw.wl.cursorSurface;
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
int scale = 1;
if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI)
{
// We only support up to scale=2 for now, since libwayland-cursor
// requires us to load a different theme for each size.
scale = 2;
theme = _glfw.wl.cursorThemeHiDPI;
}
cursor = wl_cursor_theme_get_cursor(theme, name);
if (!cursor)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Standard cursor not found");
return;
}
// TODO: handle animated cursors too.
image = cursor->images[0];
if (!image)
return;
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
surface,
image->hotspot_x / scale,
image->hotspot_y / scale);
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
image->width, image->height);
wl_surface_commit(surface);
_glfw.wl.cursorPreviousName = name;
}
static void pointerHandleMotion(void* data,
struct wl_pointer* pointer,
uint32_t time,
wl_fixed_t sx,
wl_fixed_t sy)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
const char* cursorName = NULL;
double x, y;
if (!window)
return;
if (window->cursorMode == GLFW_CURSOR_DISABLED)
return;
x = wl_fixed_to_double(sx);
y = wl_fixed_to_double(sy);
window->wl.cursorPosX = x;
window->wl.cursorPosY = y;
switch (window->wl.decorations.focus)
{
case mainWindow:
_glfwInputCursorPos(window, x, y);
_glfw.wl.cursorPreviousName = NULL;
return;
case topDecoration:
if (y < _GLFW_DECORATION_WIDTH)
cursorName = "n-resize";
else
cursorName = "left_ptr";
break;
case leftDecoration:
if (y < _GLFW_DECORATION_WIDTH)
cursorName = "nw-resize";
else
cursorName = "w-resize";
break;
case rightDecoration:
if (y < _GLFW_DECORATION_WIDTH)
cursorName = "ne-resize";
else
cursorName = "e-resize";
break;
case bottomDecoration:
if (x < _GLFW_DECORATION_WIDTH)
cursorName = "sw-resize";
else if (x > window->wl.width + _GLFW_DECORATION_WIDTH)
cursorName = "se-resize";
else
cursorName = "s-resize";
break;
default:
assert(0);
}
if (_glfw.wl.cursorPreviousName != cursorName)
setCursor(window, cursorName);
}
static void pointerHandleButton(void* data,
struct wl_pointer* pointer,
uint32_t serial,
uint32_t time,
uint32_t button,
uint32_t state)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
int glfwButton;
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
if (!window)
return;
if (button == BTN_LEFT)
{
switch (window->wl.decorations.focus)
{
case mainWindow:
break;
case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
break;
case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
break;
case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
break;
case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
break;
default:
assert(0);
}
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
{
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
serial, edges);
return;
}
}
else if (button == BTN_RIGHT)
{
if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel)
{
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial,
window->wl.cursorPosX,
window->wl.cursorPosY);
return;
}
}
// Dont pass the button to the user if it was related to a decoration.
if (window->wl.decorations.focus != mainWindow)
return;
_glfw.wl.serial = serial;
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
* codes. */
glfwButton = button - BTN_LEFT;
_glfwInputMouseClick(window,
glfwButton,
state == WL_POINTER_BUTTON_STATE_PRESSED
? GLFW_PRESS
: GLFW_RELEASE,
_glfw.wl.xkb.modifiers);
}
static void pointerHandleAxis(void* data,
struct wl_pointer* pointer,
uint32_t time,
uint32_t axis,
wl_fixed_t value)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
double x = 0.0, y = 0.0;
// Wayland scroll events are in pointer motion coordinate space (think two
// finger scroll). The factor 10 is commonly used to convert to "scroll
// step means 1.0.
const double scrollFactor = 1.0 / 10.0;
if (!window)
return;
assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
x = -wl_fixed_to_double(value) * scrollFactor;
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
y = -wl_fixed_to_double(value) * scrollFactor;
_glfwInputScroll(window, x, y);
}
static const struct wl_pointer_listener pointerListener = {
pointerHandleEnter,
pointerHandleLeave,
pointerHandleMotion,
pointerHandleButton,
pointerHandleAxis,
};
static void keyboardHandleKeymap(void* data,
struct wl_keyboard* keyboard,
uint32_t format,
int fd,
uint32_t size)
{
struct xkb_keymap* keymap;
struct xkb_state* state;
struct xkb_compose_table* composeTable;
struct xkb_compose_state* composeState;
char* mapStr;
const char* locale;
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
{
close(fd);
return;
}
mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (mapStr == MAP_FAILED) {
close(fd);
return;
}
keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
mapStr,
XKB_KEYMAP_FORMAT_TEXT_V1,
0);
munmap(mapStr, size);
close(fd);
if (!keymap)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to compile keymap");
return;
}
state = xkb_state_new(keymap);
if (!state)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create XKB state");
xkb_keymap_unref(keymap);
return;
}
// Look up the preferred locale, falling back to "C" as default.
locale = getenv("LC_ALL");
if (!locale)
locale = getenv("LC_CTYPE");
if (!locale)
locale = getenv("LANG");
if (!locale)
locale = "C";
composeTable =
xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,
XKB_COMPOSE_COMPILE_NO_FLAGS);
if (composeTable)
{
composeState =
xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
xkb_compose_table_unref(composeTable);
if (composeState)
_glfw.wl.xkb.composeState = composeState;
else
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create XKB compose state");
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create XKB compose table");
}
xkb_keymap_unref(_glfw.wl.xkb.keymap);
xkb_state_unref(_glfw.wl.xkb.state);
_glfw.wl.xkb.keymap = keymap;
_glfw.wl.xkb.state = state;
_glfw.wl.xkb.controlMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");
_glfw.wl.xkb.altMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
_glfw.wl.xkb.shiftMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
_glfw.wl.xkb.superMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
_glfw.wl.xkb.capsLockMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
_glfw.wl.xkb.numLockMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
}
static void keyboardHandleEnter(void* data,
struct wl_keyboard* keyboard,
uint32_t serial,
struct wl_surface* surface,
struct wl_array* keys)
{
// Happens in the case we just destroyed the surface.
if (!surface)
return;
_GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window)
{
window = findWindowFromDecorationSurface(surface, NULL);
if (!window)
return;
}
_glfw.wl.serial = serial;
_glfw.wl.keyboardFocus = window;
_glfwInputWindowFocus(window, GLFW_TRUE);
}
static void keyboardHandleLeave(void* data,
struct wl_keyboard* keyboard,
uint32_t serial,
struct wl_surface* surface)
{
_GLFWwindow* window = _glfw.wl.keyboardFocus;
if (!window)
return;
struct itimerspec timer = {};
timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);
_glfw.wl.serial = serial;
_glfw.wl.keyboardFocus = NULL;
_glfwInputWindowFocus(window, GLFW_FALSE);
}
static int translateKey(uint32_t scancode)
{
if (scancode < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0]))
return _glfw.wl.keycodes[scancode];
return GLFW_KEY_UNKNOWN;
}
static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
{
if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState)
return sym;
if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)
!= XKB_COMPOSE_FEED_ACCEPTED)
return sym;
switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))
{
case XKB_COMPOSE_COMPOSED:
return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);
case XKB_COMPOSE_COMPOSING:
case XKB_COMPOSE_CANCELLED:
return XKB_KEY_NoSymbol;
case XKB_COMPOSE_NOTHING:
default:
return sym;
}
}
GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode)
{
const xkb_keysym_t* keysyms;
const xkb_keycode_t keycode = scancode + 8;
if (xkb_state_key_get_syms(_glfw.wl.xkb.state, keycode, &keysyms) == 1)
{
const xkb_keysym_t keysym = composeSymbol(keysyms[0]);
const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
if (codepoint != GLFW_INVALID_CODEPOINT)
{
const int mods = _glfw.wl.xkb.modifiers;
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
_glfwInputChar(window, codepoint, mods, plain);
}
}
return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, keycode);
}
static void keyboardHandleKey(void* data,
struct wl_keyboard* keyboard,
uint32_t serial,
uint32_t time,
uint32_t scancode,
uint32_t state)
{
_GLFWwindow* window = _glfw.wl.keyboardFocus;
if (!window)
return;
const int key = translateKey(scancode);
const int action =
state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
_glfw.wl.serial = serial;
_glfwInputKey(window, key, scancode, action, _glfw.wl.xkb.modifiers);
struct itimerspec timer = {};
if (action == GLFW_PRESS)
{
const GLFWbool shouldRepeat = _glfwInputTextWayland(window, scancode);
if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0)
{
_glfw.wl.keyboardLastKey = key;
_glfw.wl.keyboardLastScancode = scancode;
if (_glfw.wl.keyboardRepeatRate > 1)
timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyboardRepeatRate;
else
timer.it_interval.tv_sec = 1;
timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000;
timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000;
}
}
timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);
}
static void keyboardHandleModifiers(void* data,
struct wl_keyboard* keyboard,
uint32_t serial,
uint32_t modsDepressed,
uint32_t modsLatched,
uint32_t modsLocked,
uint32_t group)
{
_glfw.wl.serial = serial;
if (!_glfw.wl.xkb.keymap)
return;
xkb_state_update_mask(_glfw.wl.xkb.state,
modsDepressed,
modsLatched,
modsLocked,
0,
0,
group);
const xkb_mod_mask_t mask =
xkb_state_serialize_mods(_glfw.wl.xkb.state,
XKB_STATE_MODS_DEPRESSED |
XKB_STATE_LAYOUT_DEPRESSED |
XKB_STATE_MODS_LATCHED |
XKB_STATE_LAYOUT_LATCHED);
unsigned int mods = 0;
if (mask & _glfw.wl.xkb.controlMask)
mods |= GLFW_MOD_CONTROL;
if (mask & _glfw.wl.xkb.altMask)
mods |= GLFW_MOD_ALT;
if (mask & _glfw.wl.xkb.shiftMask)
mods |= GLFW_MOD_SHIFT;
if (mask & _glfw.wl.xkb.superMask)
mods |= GLFW_MOD_SUPER;
if (mask & _glfw.wl.xkb.capsLockMask)
mods |= GLFW_MOD_CAPS_LOCK;
if (mask & _glfw.wl.xkb.numLockMask)
mods |= GLFW_MOD_NUM_LOCK;
_glfw.wl.xkb.modifiers = mods;
}
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
static void keyboardHandleRepeatInfo(void* data,
struct wl_keyboard* keyboard,
int32_t rate,
int32_t delay)
{
if (keyboard != _glfw.wl.keyboard)
return;
_glfw.wl.keyboardRepeatRate = rate;
_glfw.wl.keyboardRepeatDelay = delay;
}
#endif
static const struct wl_keyboard_listener keyboardListener = {
keyboardHandleKeymap,
keyboardHandleEnter,
keyboardHandleLeave,
keyboardHandleKey,
keyboardHandleModifiers,
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
keyboardHandleRepeatInfo,
#endif
};
static void seatHandleCapabilities(void* data,
struct wl_seat* seat,
enum wl_seat_capability caps)
{
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)
{
_glfw.wl.pointer = wl_seat_get_pointer(seat);
wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);
}
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
{
wl_pointer_destroy(_glfw.wl.pointer);
_glfw.wl.pointer = NULL;
}
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)
{
_glfw.wl.keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
}
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
{
wl_keyboard_destroy(_glfw.wl.keyboard);
_glfw.wl.keyboard = NULL;
}
}
static void seatHandleName(void* data,
struct wl_seat* seat,
const char* name)
{
}
static const struct wl_seat_listener seatListener = {
seatHandleCapabilities,
seatHandleName,
};
static void dataOfferHandleOffer(void* data,
struct wl_data_offer* dataOffer,
const char* mimeType)
{
}
static const struct wl_data_offer_listener dataOfferListener = {
dataOfferHandleOffer,
};
static void dataDeviceHandleDataOffer(void* data,
struct wl_data_device* dataDevice,
struct wl_data_offer* id)
{
if (_glfw.wl.dataOffer)
wl_data_offer_destroy(_glfw.wl.dataOffer);
_glfw.wl.dataOffer = id;
wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL);
}
static void dataDeviceHandleEnter(void* data,
struct wl_data_device* dataDevice,
uint32_t serial,
struct wl_surface *surface,
wl_fixed_t x,
wl_fixed_t y,
struct wl_data_offer *id)
{
}
static void dataDeviceHandleLeave(void* data,
struct wl_data_device* dataDevice)
{
}
static void dataDeviceHandleMotion(void* data,
struct wl_data_device* dataDevice,
uint32_t time,
wl_fixed_t x,
wl_fixed_t y)
{
}
static void dataDeviceHandleDrop(void* data,
struct wl_data_device* dataDevice)
{
}
static void dataDeviceHandleSelection(void* data,
struct wl_data_device* dataDevice,
struct wl_data_offer* id)
{
}
static const struct wl_data_device_listener dataDeviceListener = {
dataDeviceHandleDataOffer,
dataDeviceHandleEnter,
dataDeviceHandleLeave,
dataDeviceHandleMotion,
dataDeviceHandleDrop,
dataDeviceHandleSelection,
};
static void wmBaseHandlePing(void* data,
struct xdg_wm_base* wmBase, struct xdg_wm_base* wmBase,
uint32_t serial) uint32_t serial)
{ {
xdg_wm_base_pong(wmBase, serial); xdg_wm_base_pong(wmBase, serial);
} }
static const struct xdg_wm_base_listener wmBaseListener = { static const struct xdg_wm_base_listener wmBaseListener =
{
wmBaseHandlePing wmBaseHandlePing
}; };
static void registryHandleGlobal(void* data, static void registryHandleGlobal(void* userData,
struct wl_registry* registry, struct wl_registry* registry,
uint32_t name, uint32_t name,
const char* interface, const char* interface,
@ -788,7 +100,7 @@ static void registryHandleGlobal(void* data,
{ {
if (strcmp(interface, "wl_compositor") == 0) if (strcmp(interface, "wl_compositor") == 0)
{ {
_glfw.wl.compositorVersion = min(3, version); _glfw.wl.compositorVersion = _glfw_min(3, version);
_glfw.wl.compositor = _glfw.wl.compositor =
wl_registry_bind(registry, name, &wl_compositor_interface, wl_registry_bind(registry, name, &wl_compositor_interface,
_glfw.wl.compositorVersion); _glfw.wl.compositorVersion);
@ -811,11 +123,11 @@ static void registryHandleGlobal(void* data,
{ {
if (!_glfw.wl.seat) if (!_glfw.wl.seat)
{ {
_glfw.wl.seatVersion = min(4, version); _glfw.wl.seatVersion = _glfw_min(4, version);
_glfw.wl.seat = _glfw.wl.seat =
wl_registry_bind(registry, name, &wl_seat_interface, wl_registry_bind(registry, name, &wl_seat_interface,
_glfw.wl.seatVersion); _glfw.wl.seatVersion);
wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); _glfwAddSeatListenerWayland(_glfw.wl.seat);
} }
} }
else if (strcmp(interface, "wl_data_device_manager") == 0) else if (strcmp(interface, "wl_data_device_manager") == 0)
@ -868,8 +180,8 @@ static void registryHandleGlobal(void* data,
} }
} }
static void registryHandleGlobalRemove(void *data, static void registryHandleGlobalRemove(void* userData,
struct wl_registry *registry, struct wl_registry* registry,
uint32_t name) uint32_t name)
{ {
_GLFWmonitor* monitor; _GLFWmonitor* monitor;
@ -886,7 +198,8 @@ static void registryHandleGlobalRemove(void *data,
} }
static const struct wl_registry_listener registryListener = { static const struct wl_registry_listener registryListener =
{
registryHandleGlobal, registryHandleGlobal,
registryHandleGlobalRemove registryHandleGlobalRemove
}; };
@ -1121,7 +434,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
if (platformID == GLFW_PLATFORM_WAYLAND) if (platformID == GLFW_PLATFORM_WAYLAND)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libwayland-client"); "Wayland: Failed to load libwayland-client");
} }
return GLFW_FALSE; return GLFW_FALSE;
@ -1160,9 +473,9 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
int _glfwInitWayland(void) int _glfwInitWayland(void)
{ {
const char *cursorTheme; const char* cursorTheme;
const char *cursorSizeStr; const char* cursorSizeStr;
char *cursorSizeEnd; char* cursorSizeEnd;
long cursorSizeLong; long cursorSizeLong;
int cursorSize; int cursorSize;
@ -1226,7 +539,7 @@ int _glfwInitWayland(void)
if (!_glfw.wl.cursor.handle) if (!_glfw.wl.cursor.handle)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libwayland-cursor"); "Wayland: Failed to load libwayland-cursor");
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1243,7 +556,7 @@ int _glfwInitWayland(void)
if (!_glfw.wl.egl.handle) if (!_glfw.wl.egl.handle)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libwayland-egl"); "Wayland: Failed to load libwayland-egl");
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1258,7 +571,7 @@ int _glfwInitWayland(void)
if (!_glfw.wl.xkb.handle) if (!_glfw.wl.xkb.handle)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libxkbcommon"); "Wayland: Failed to load libxkbcommon");
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1350,7 +663,7 @@ int _glfwInitWayland(void)
if (!_glfw.wl.cursorTheme) if (!_glfw.wl.cursorTheme)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unable to load default cursor theme"); "Wayland: Failed to load default cursor theme");
return GLFW_FALSE; return GLFW_FALSE;
} }
// If this happens to be NULL, we just fallback to the scale=1 version. // If this happens to be NULL, we just fallback to the scale=1 version.
@ -1366,15 +679,7 @@ int _glfwInitWayland(void)
_glfw.wl.dataDevice = _glfw.wl.dataDevice =
wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager, wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
_glfw.wl.seat); _glfw.wl.seat);
wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL); _glfwAddDataDeviceListenerWayland(_glfw.wl.dataDevice);
_glfw.wl.clipboardString = _glfw_calloc(4096, 1);
if (!_glfw.wl.clipboardString)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unable to allocate clipboard memory");
return GLFW_FALSE;
}
_glfw.wl.clipboardSize = 4096;
} }
return GLFW_TRUE; return GLFW_TRUE;
@ -1383,6 +688,8 @@ int _glfwInitWayland(void)
void _glfwTerminateWayland(void) void _glfwTerminateWayland(void)
{ {
_glfwTerminateEGL(); _glfwTerminateEGL();
_glfwTerminateOSMesa();
if (_glfw.wl.egl.handle) if (_glfw.wl.egl.handle)
{ {
_glfwPlatformFreeModule(_glfw.wl.egl.handle); _glfwPlatformFreeModule(_glfw.wl.egl.handle);
@ -1413,6 +720,11 @@ void _glfwTerminateWayland(void)
_glfw.wl.cursor.handle = NULL; _glfw.wl.cursor.handle = NULL;
} }
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
wl_data_offer_destroy(_glfw.wl.offers[i].offer);
_glfw_free(_glfw.wl.offers);
if (_glfw.wl.cursorSurface) if (_glfw.wl.cursorSurface)
wl_surface_destroy(_glfw.wl.cursorSurface); wl_surface_destroy(_glfw.wl.cursorSurface);
if (_glfw.wl.subcompositor) if (_glfw.wl.subcompositor)
@ -1427,12 +739,14 @@ void _glfwTerminateWayland(void)
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager); zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
if (_glfw.wl.wmBase) if (_glfw.wl.wmBase)
xdg_wm_base_destroy(_glfw.wl.wmBase); xdg_wm_base_destroy(_glfw.wl.wmBase);
if (_glfw.wl.dataSource) if (_glfw.wl.selectionOffer)
wl_data_source_destroy(_glfw.wl.dataSource); wl_data_offer_destroy(_glfw.wl.selectionOffer);
if (_glfw.wl.dragOffer)
wl_data_offer_destroy(_glfw.wl.dragOffer);
if (_glfw.wl.selectionSource)
wl_data_source_destroy(_glfw.wl.selectionSource);
if (_glfw.wl.dataDevice) if (_glfw.wl.dataDevice)
wl_data_device_destroy(_glfw.wl.dataDevice); wl_data_device_destroy(_glfw.wl.dataDevice);
if (_glfw.wl.dataOffer)
wl_data_offer_destroy(_glfw.wl.dataOffer);
if (_glfw.wl.dataDeviceManager) if (_glfw.wl.dataDeviceManager)
wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager); wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
if (_glfw.wl.pointer) if (_glfw.wl.pointer)
@ -1460,9 +774,6 @@ void _glfwTerminateWayland(void)
if (_glfw.wl.cursorTimerfd >= 0) if (_glfw.wl.cursorTimerfd >= 0)
close(_glfw.wl.cursorTimerfd); close(_glfw.wl.cursorTimerfd);
if (_glfw.wl.clipboardString)
_glfw_free(_glfw.wl.clipboardString); _glfw_free(_glfw.wl.clipboardString);
if (_glfw.wl.clipboardSendString)
_glfw_free(_glfw.wl.clipboardSendString);
} }

View File

@ -37,7 +37,7 @@
#include "wayland-client-protocol.h" #include "wayland-client-protocol.h"
static void outputHandleGeometry(void* data, static void outputHandleGeometry(void* userData,
struct wl_output* output, struct wl_output* output,
int32_t x, int32_t x,
int32_t y, int32_t y,
@ -48,7 +48,7 @@ static void outputHandleGeometry(void* data,
const char* model, const char* model,
int32_t transform) int32_t transform)
{ {
struct _GLFWmonitor *monitor = data; struct _GLFWmonitor* monitor = userData;
monitor->wl.x = x; monitor->wl.x = x;
monitor->wl.y = y; monitor->wl.y = y;
@ -58,14 +58,14 @@ static void outputHandleGeometry(void* data,
snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model); snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model);
} }
static void outputHandleMode(void* data, static void outputHandleMode(void* userData,
struct wl_output* output, struct wl_output* output,
uint32_t flags, uint32_t flags,
int32_t width, int32_t width,
int32_t height, int32_t height,
int32_t refresh) int32_t refresh)
{ {
struct _GLFWmonitor *monitor = data; struct _GLFWmonitor* monitor = userData;
GLFWvidmode mode; GLFWvidmode mode;
mode.width = width; mode.width = width;
@ -84,9 +84,9 @@ static void outputHandleMode(void* data,
monitor->wl.currentMode = monitor->modeCount - 1; monitor->wl.currentMode = monitor->modeCount - 1;
} }
static void outputHandleDone(void* data, struct wl_output* output) static void outputHandleDone(void* userData, struct wl_output* output)
{ {
struct _GLFWmonitor *monitor = data; struct _GLFWmonitor* monitor = userData;
if (monitor->widthMM <= 0 || monitor->heightMM <= 0) if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
{ {
@ -99,16 +99,17 @@ static void outputHandleDone(void* data, struct wl_output* output)
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
} }
static void outputHandleScale(void* data, static void outputHandleScale(void* userData,
struct wl_output* output, struct wl_output* output,
int32_t factor) int32_t factor)
{ {
struct _GLFWmonitor *monitor = data; struct _GLFWmonitor* monitor = userData;
monitor->wl.scale = factor; monitor->wl.scale = factor;
} }
static const struct wl_output_listener outputListener = { static const struct wl_output_listener outputListener =
{
outputHandleGeometry, outputHandleGeometry,
outputHandleMode, outputHandleMode,
outputHandleDone, outputHandleDone,
@ -122,8 +123,8 @@ static const struct wl_output_listener outputListener = {
void _glfwAddOutputWayland(uint32_t name, uint32_t version) void _glfwAddOutputWayland(uint32_t name, uint32_t version)
{ {
_GLFWmonitor *monitor; _GLFWmonitor* monitor;
struct wl_output *output; struct wl_output* output;
if (version < 2) if (version < 2)
{ {

View File

@ -43,11 +43,12 @@ typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWa
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
#include "xkb_unicode.h" #include "xkb_unicode.h"
#include "posix_poll.h"
typedef int (* PFN_wl_display_flush)(struct wl_display *display); typedef int (* PFN_wl_display_flush)(struct wl_display* display);
typedef void (* PFN_wl_display_cancel_read)(struct wl_display *display); typedef void (* PFN_wl_display_cancel_read)(struct wl_display* display);
typedef int (* PFN_wl_display_dispatch_pending)(struct wl_display *display); typedef int (* PFN_wl_display_dispatch_pending)(struct wl_display* display);
typedef int (* PFN_wl_display_read_events)(struct wl_display *display); typedef int (* PFN_wl_display_read_events)(struct wl_display* display);
typedef struct wl_display* (* PFN_wl_display_connect)(const char*); typedef struct wl_display* (* PFN_wl_display_connect)(const char*);
typedef void (* PFN_wl_display_disconnect)(struct wl_display*); typedef void (* PFN_wl_display_disconnect)(struct wl_display*);
typedef int (* PFN_wl_display_roundtrip)(struct wl_display*); typedef int (* PFN_wl_display_roundtrip)(struct wl_display*);
@ -218,6 +219,13 @@ typedef struct _GLFWdecorationWayland
struct wp_viewport* viewport; struct wp_viewport* viewport;
} _GLFWdecorationWayland; } _GLFWdecorationWayland;
typedef struct _GLFWofferWayland
{
struct wl_data_offer* offer;
GLFWbool text_plain_utf8;
GLFWbool text_uri_list;
} _GLFWofferWayland;
// Wayland-specific per-window data // Wayland-specific per-window data
// //
typedef struct _GLFWwindowWayland typedef struct _GLFWwindowWayland
@ -280,8 +288,6 @@ typedef struct _GLFWlibraryWayland
struct wl_keyboard* keyboard; struct wl_keyboard* keyboard;
struct wl_data_device_manager* dataDeviceManager; struct wl_data_device_manager* dataDeviceManager;
struct wl_data_device* dataDevice; struct wl_data_device* dataDevice;
struct wl_data_offer* dataOffer;
struct wl_data_source* dataSource;
struct xdg_wm_base* wmBase; struct xdg_wm_base* wmBase;
struct zxdg_decoration_manager_v1* decorationManager; struct zxdg_decoration_manager_v1* decorationManager;
struct wp_viewporter* viewporter; struct wp_viewporter* viewporter;
@ -289,6 +295,16 @@ typedef struct _GLFWlibraryWayland
struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_pointer_constraints_v1* pointerConstraints;
struct zwp_idle_inhibit_manager_v1* idleInhibitManager; struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
_GLFWofferWayland* offers;
unsigned int offerCount;
struct wl_data_offer* selectionOffer;
struct wl_data_source* selectionSource;
struct wl_data_offer* dragOffer;
_GLFWwindow* dragFocus;
uint32_t dragSerial;
int compositorVersion; int compositorVersion;
int seatVersion; int seatVersion;
@ -305,9 +321,6 @@ typedef struct _GLFWlibraryWayland
int keyboardLastKey; int keyboardLastKey;
int keyboardLastScancode; int keyboardLastScancode;
char* clipboardString; char* clipboardString;
size_t clipboardSize;
char* clipboardSendString;
size_t clipboardSendSize;
int timerfd; int timerfd;
short int keycodes[256]; short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1]; short int scancodes[GLFW_KEY_LAST + 1];
@ -457,7 +470,7 @@ float _glfwGetWindowOpacityWayland(_GLFWwindow* window);
void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity); void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity);
void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled); void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetRawMouseMotionWayland(_GLFWwindow *window, GLFWbool enabled); void _glfwSetRawMouseMotionWayland(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwRawMouseMotionSupportedWayland(void); GLFWbool _glfwRawMouseMotionSupportedWayland(void);
void _glfwPollEventsWayland(void); void _glfwPollEventsWayland(void);
@ -497,3 +510,6 @@ void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwAddOutputWayland(uint32_t name, uint32_t version); void _glfwAddOutputWayland(uint32_t name, uint32_t version);
GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode); GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode);
void _glfwAddSeatListenerWayland(struct wl_seat* seat);
void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,8 @@
#include <stdio.h> #include <stdio.h>
#include <locale.h> #include <locale.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h>
#include <errno.h>
// Translate the X11 KeySyms for a key to a GLFW key code // Translate the X11 KeySyms for a key to a GLFW key code
@ -601,7 +603,7 @@ static void detectEWMH(void)
// //
static GLFWbool initExtensions(void) static GLFWbool initExtensions(void)
{ {
#if defined(__OpenBSD__) #if defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so"); _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so");
#else #else
_glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so.1"); _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so.1");
@ -625,7 +627,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi-6.so"); _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi-6.so");
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so"); _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so");
#else #else
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so.6"); _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so.6");
@ -657,7 +659,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so"); _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so");
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so"); _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so");
#else #else
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2"); _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2");
@ -751,7 +753,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so"); _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so");
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so"); _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so");
#else #else
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1"); _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1");
@ -774,7 +776,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so"); _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so");
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so"); _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so");
#else #else
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1"); _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1");
@ -829,7 +831,7 @@ static GLFWbool initExtensions(void)
{ {
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
_glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb-1.so"); _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb-1.so");
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so"); _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so");
#else #else
_glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1"); _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1");
@ -844,7 +846,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so"); _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so");
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so"); _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so");
#else #else
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1"); _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1");
@ -873,7 +875,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext-6.so"); _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext-6.so");
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so"); _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so");
#else #else
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6"); _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6");
@ -1042,6 +1044,37 @@ static Window createHelperWindow(void)
CWEventMask, &wa); CWEventMask, &wa);
} }
// Create the pipe for empty events without assumuing the OS has pipe2(2)
//
static GLFWbool createEmptyEventPipe(void)
{
if (pipe(_glfw.x11.emptyEventPipe) != 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to create empty event pipe: %s",
strerror(errno));
return GLFW_FALSE;
}
for (int i = 0; i < 2; i++)
{
const int sf = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFL, 0);
const int df = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFD, 0);
if (sf == -1 || df == -1 ||
fcntl(_glfw.x11.emptyEventPipe[i], F_SETFL, sf | O_NONBLOCK) == -1 ||
fcntl(_glfw.x11.emptyEventPipe[i], F_SETFD, df | FD_CLOEXEC) == -1)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to set flags for empty event pipe: %s",
strerror(errno));
return GLFW_FALSE;
}
}
return GLFW_TRUE;
}
// X error handler // X error handler
// //
static int errorHandler(Display *display, XErrorEvent* event) static int errorHandler(Display *display, XErrorEvent* event)
@ -1221,7 +1254,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
void* module = _glfwPlatformLoadModule("libX11-6.so"); void* module = _glfwPlatformLoadModule("libX11-6.so");
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
void* module = _glfwPlatformLoadModule("libX11.so"); void* module = _glfwPlatformLoadModule("libX11.so");
#else #else
void* module = _glfwPlatformLoadModule("libX11.so.6"); void* module = _glfwPlatformLoadModule("libX11.so.6");
@ -1491,6 +1524,9 @@ int _glfwInitX11(void)
getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY);
if (!createEmptyEventPipe())
return GLFW_FALSE;
if (!initExtensions()) if (!initExtensions())
return GLFW_FALSE; return GLFW_FALSE;
@ -1594,6 +1630,7 @@ void _glfwTerminateX11(void)
_glfw.x11.xi.handle = NULL; _glfw.x11.xi.handle = NULL;
} }
_glfwTerminateOSMesa();
// NOTE: These need to be unloaded after XCloseDisplay, as they register // NOTE: These need to be unloaded after XCloseDisplay, as they register
// cleanup callbacks that get called by that function // cleanup callbacks that get called by that function
_glfwTerminateEGL(); _glfwTerminateEGL();
@ -1604,5 +1641,11 @@ void _glfwTerminateX11(void)
_glfwPlatformFreeModule(_glfw.x11.xlib.handle); _glfwPlatformFreeModule(_glfw.x11.xlib.handle);
_glfw.x11.xlib.handle = NULL; _glfw.x11.xlib.handle = NULL;
} }
if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1])
{
close(_glfw.x11.emptyEventPipe[0]);
close(_glfw.x11.emptyEventPipe[1]);
}
} }

View File

@ -453,6 +453,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSur
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
#include "xkb_unicode.h" #include "xkb_unicode.h"
#include "posix_poll.h"
#define GLFW_X11_WINDOW_STATE _GLFWwindowX11 x11; #define GLFW_X11_WINDOW_STATE _GLFWwindowX11 x11;
#define GLFW_X11_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11; #define GLFW_X11_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11;
@ -582,6 +583,7 @@ typedef struct _GLFWlibraryX11
double restoreCursorPosX, restoreCursorPosY; double restoreCursorPosX, restoreCursorPosY;
// The window whose disabled cursor mode is active // The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow; _GLFWwindow* disabledCursorWindow;
int emptyEventPipe[2];
// Window manager atoms // Window manager atoms
Atom NET_SUPPORTED; Atom NET_SUPPORTED;

View File

@ -32,7 +32,7 @@
#include <X11/cursorfont.h> #include <X11/cursorfont.h>
#include <X11/Xmd.h> #include <X11/Xmd.h>
#include <sys/select.h> #include <poll.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -56,50 +56,79 @@
#define _GLFW_XDND_VERSION 5 #define _GLFW_XDND_VERSION 5
// Wait for event data to arrive on the X11 display socket
// Wait for data to arrive using select
// This avoids blocking other threads via the per-display Xlib lock that also // This avoids blocking other threads via the per-display Xlib lock that also
// covers GLX functions // covers GLX functions
// //
static GLFWbool waitForEvent(double* timeout) static GLFWbool waitForX11Event(double* timeout)
{ {
fd_set fds; struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN };
const int fd = ConnectionNumber(_glfw.x11.display);
int count = fd + 1;
#if defined(__linux__) while (!XPending(_glfw.x11.display))
if (_glfw.linjs.inotify > fd)
count = _glfw.linjs.inotify + 1;
#endif
for (;;)
{ {
FD_ZERO(&fds); if (!_glfwPollPOSIX(&fd, 1, timeout))
FD_SET(fd, &fds);
#if defined(__linux__)
if (_glfw.linjs.inotify > 0)
FD_SET(_glfw.linjs.inotify, &fds);
#endif
if (timeout)
{
const long seconds = (long) *timeout;
const long microseconds = (long) ((*timeout - seconds) * 1e6);
struct timeval tv = { seconds, microseconds };
const uint64_t base = _glfwPlatformGetTimerValue();
const int result = select(count, &fds, NULL, NULL, &tv);
const int error = errno;
*timeout -= (_glfwPlatformGetTimerValue() - base) /
(double) _glfwPlatformGetTimerFrequency();
if (result > 0)
return GLFW_TRUE;
if ((result == -1 && error == EINTR) || *timeout <= 0.0)
return GLFW_FALSE; return GLFW_FALSE;
} }
else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)
return GLFW_TRUE; return GLFW_TRUE;
}
// Wait for event data to arrive on any event file descriptor
// This avoids blocking other threads via the per-display Xlib lock that also
// covers GLX functions
//
static GLFWbool waitForAnyEvent(double* timeout)
{
nfds_t count = 2;
struct pollfd fds[3] =
{
{ ConnectionNumber(_glfw.x11.display), POLLIN },
{ _glfw.x11.emptyEventPipe[0], POLLIN }
};
#if defined(__linux__)
if (_glfw.joysticksInitialized)
fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
#endif
while (!XPending(_glfw.x11.display))
{
if (!_glfwPollPOSIX(fds, count, timeout))
return GLFW_FALSE;
for (int i = 1; i < count; i++)
{
if (fds[i].revents & POLLIN)
return GLFW_TRUE;
}
}
return GLFW_TRUE;
}
// Writes a byte to the empty event pipe
//
static void writeEmptyEvent(void)
{
for (;;)
{
const char byte = 0;
const ssize_t result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);
if (result == 1 || (result == -1 && errno != EINTR))
break;
}
}
// Drains available data from the empty event pipe
//
static void drainEmptyEvents(void)
{
for (;;)
{
char dummy[64];
const ssize_t result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));
if (result == -1 && errno != EINTR)
break;
} }
} }
@ -116,7 +145,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
VisibilityNotify, VisibilityNotify,
&dummy)) &dummy))
{ {
if (!waitForEvent(&timeout)) if (!waitForX11Event(&timeout))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -378,57 +407,6 @@ static void updateWindowMode(_GLFWwindow* window)
} }
} }
// Splits and translates a text/uri-list into separate file paths
// NOTE: This function destroys the provided string
//
static char** parseUriList(char* text, int* count)
{
const char* prefix = "file://";
char** paths = NULL;
char* line;
*count = 0;
while ((line = strtok(text, "\r\n")))
{
text = NULL;
if (line[0] == '#')
continue;
if (strncmp(line, prefix, strlen(prefix)) == 0)
{
line += strlen(prefix);
// TODO: Validate hostname
while (*line != '/')
line++;
}
(*count)++;
char* path = _glfw_calloc(strlen(line) + 1, 1);
paths = _glfw_realloc(paths, *count * sizeof(char*));
paths[*count - 1] = path;
while (*line)
{
if (line[0] == '%' && line[1] && line[2])
{
const char digits[3] = { line[1], line[2], '\0' };
*path = strtol(digits, NULL, 16);
line += 2;
}
else
*path = *line;
path++;
line++;
}
}
return paths;
}
// Decode a Unicode code point from a UTF-8 stream // Decode a Unicode code point from a UTF-8 stream
// Based on cutef8 by Jeff Bezanson (Public Domain) // Based on cutef8 by Jeff Bezanson (Public Domain)
// //
@ -887,20 +865,6 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
return None; return None;
} }
static void handleSelectionClear(XEvent* event)
{
if (event->xselectionclear.selection == _glfw.x11.PRIMARY)
{
_glfw_free(_glfw.x11.primarySelectionString);
_glfw.x11.primarySelectionString = NULL;
}
else
{
_glfw_free(_glfw.x11.clipboardString);
_glfw.x11.clipboardString = NULL;
}
}
static void handleSelectionRequest(XEvent* event) static void handleSelectionRequest(XEvent* event)
{ {
const XSelectionRequestEvent* request = &event->xselectionrequest; const XSelectionRequestEvent* request = &event->xselectionrequest;
@ -958,7 +922,7 @@ static const char* getSelectionString(Atom selection)
SelectionNotify, SelectionNotify,
&notification)) &notification))
{ {
waitForEvent(NULL); waitForX11Event(NULL);
} }
if (notification.xselection.property == None) if (notification.xselection.property == None)
@ -994,7 +958,7 @@ static const char* getSelectionString(Atom selection)
isSelPropNewValueNotify, isSelPropNewValueNotify,
(XPointer) &notification)) (XPointer) &notification))
{ {
waitForEvent(NULL); waitForX11Event(NULL);
} }
XFree(data); XFree(data);
@ -1020,6 +984,8 @@ static const char* getSelectionString(Atom selection)
} }
if (!itemCount) if (!itemCount)
{
if (string)
{ {
if (targets[i] == XA_STRING) if (targets[i] == XA_STRING)
{ {
@ -1028,6 +994,7 @@ static const char* getSelectionString(Atom selection)
} }
else else
*selectionString = string; *selectionString = string;
}
break; break;
} }
@ -1193,12 +1160,7 @@ static void processEvent(XEvent *event)
return; return;
} }
if (event->type == SelectionClear) if (event->type == SelectionRequest)
{
handleSelectionClear(event);
return;
}
else if (event->type == SelectionRequest)
{ {
handleSelectionRequest(event); handleSelectionRequest(event);
return; return;
@ -1238,7 +1200,7 @@ static void processEvent(XEvent *event)
// (the server never sends a timestamp of zero) // (the server never sends a timestamp of zero)
// NOTE: Timestamp difference is compared to handle wrap-around // NOTE: Timestamp difference is compared to handle wrap-around
Time diff = event->xkey.time - window->x11.keyPressTimes[keycode]; Time diff = event->xkey.time - window->x11.keyPressTimes[keycode];
if (diff == event->xkey.time || (diff > 0 && diff < (1 << 31))) if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31)))
{ {
if (keycode) if (keycode)
_glfwInputKey(window, key, keycode, GLFW_PRESS, mods); _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
@ -1686,7 +1648,7 @@ static void processEvent(XEvent *event)
if (result) if (result)
{ {
int count; int count;
char** paths = parseUriList(data, &count); char** paths = _glfwParseUriList(data, &count);
_glfwInputDrop(window, count, (const char**) paths); _glfwInputDrop(window, count, (const char**) paths);
@ -1875,10 +1837,6 @@ void _glfwPushSelectionToManagerX11(void)
handleSelectionRequest(&event); handleSelectionRequest(&event);
break; break;
case SelectionClear:
handleSelectionClear(&event);
break;
case SelectionNotify: case SelectionNotify:
{ {
if (event.xselection.target == _glfw.x11.SAVE_TARGETS) if (event.xselection.target == _glfw.x11.SAVE_TARGETS)
@ -1896,7 +1854,7 @@ void _glfwPushSelectionToManagerX11(void)
} }
} }
waitForEvent(NULL); waitForX11Event(NULL);
} }
} }
@ -1994,13 +1952,31 @@ int _glfwCreateWindowX11(_GLFWwindow* window,
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
} }
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
} }
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughX11(window, GLFW_TRUE);
if (window->monitor) if (window->monitor)
{ {
_glfwShowWindowX11(window); _glfwShowWindowX11(window);
updateWindowMode(window); updateWindowMode(window);
acquireMonitor(window); acquireMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowX11(window);
if (wndconfig->focused)
_glfwFocusWindowX11(window);
}
} }
XFlush(_glfw.x11.display); XFlush(_glfw.x11.display);
@ -2238,7 +2214,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow* window,
isFrameExtentsEvent, isFrameExtentsEvent,
(XPointer) window)) (XPointer) window))
{ {
if (!waitForEvent(&timeout)) if (!waitForX11Event(&timeout))
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
@ -2744,7 +2720,7 @@ GLFWbool _glfwRawMouseMotionSupportedX11(void)
void _glfwPollEventsX11(void) void _glfwPollEventsX11(void)
{ {
_GLFWwindow* window; drainEmptyEvents();
#if defined(__linux__) #if defined(__linux__)
if (_glfw.joysticksInitialized) if (_glfw.joysticksInitialized)
@ -2759,7 +2735,7 @@ void _glfwPollEventsX11(void)
processEvent(&event); processEvent(&event);
} }
window = _glfw.x11.disabledCursorWindow; _GLFWwindow* window = _glfw.x11.disabledCursorWindow;
if (window) if (window)
{ {
int width, height; int width, height;
@ -2779,32 +2755,19 @@ void _glfwPollEventsX11(void)
void _glfwWaitEventsX11(void) void _glfwWaitEventsX11(void)
{ {
while (!XPending(_glfw.x11.display)) waitForAnyEvent(NULL);
waitForEvent(NULL);
_glfwPollEventsX11(); _glfwPollEventsX11();
} }
void _glfwWaitEventsTimeoutX11(double timeout) void _glfwWaitEventsTimeoutX11(double timeout)
{ {
while (!XPending(_glfw.x11.display)) waitForAnyEvent(&timeout);
{
if (!waitForEvent(&timeout))
break;
}
_glfwPollEventsX11(); _glfwPollEventsX11();
} }
void _glfwPostEmptyEventX11(void) void _glfwPostEmptyEventX11(void)
{ {
XEvent event = { ClientMessage }; writeEmptyEvent();
event.xclient.window = _glfw.x11.helperWindowHandle;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = _glfw.x11.NULL_;
XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event);
XFlush(_glfw.x11.display);
} }
void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos) void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos)