Merge branch 'master' into merge-request-egl-config

This commit is contained in:
Tim 2022-04-01 15:30:43 +02:00 committed by GitHub
commit 55d398da97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 732 additions and 349 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ń
@ -68,6 +70,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 +84,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
@ -183,13 +190,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 +212,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

@ -205,6 +205,16 @@ 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)
- [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 +245,7 @@ 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)
- [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,6 +277,14 @@ 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)
- [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] Removed support for `wl_shell` (#1443) - [Wayland] Removed support for `wl_shell` (#1443)
@ -290,6 +309,7 @@ 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)
- [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)
@ -305,6 +325,7 @@ information on what to include when reporting a bug.
(#1380) (#1380)
- [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843) - [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843)
- [EGL] Made it possible to query the `EGLConfig` that was chosen to create a given window via `glfwGetEGLConfig` - [EGL] Made it possible to query the `EGLConfig` that was chosen to create a given window via `glfwGetEGLConfig`
- [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library
## Contact ## Contact

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

@ -144,6 +144,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

@ -3258,7 +3258,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 +4893,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.

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,22 @@ 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
*/
#undef GLAPIENTRY
#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
*/
#undef GLAPIENTRY
#include <GL/osmesa.h> #include <GL/osmesa.h>
#endif #endif

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

@ -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

@ -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,13 +584,13 @@ 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);
} }
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_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,13 +523,13 @@ 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);
} }
flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
@ -542,13 +542,13 @@ 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

@ -179,6 +179,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;

View File

@ -998,6 +998,8 @@ const char* _glfwGetVulkanResultString(VkResult result);
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint); size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);
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

@ -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)

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
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

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,13 +631,13 @@ 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);
} }
flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
@ -650,13 +650,13 @@ 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),
@ -506,7 +517,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 +638,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);

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,

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,
@ -1265,7 +1321,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 +1348,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 +1372,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 +1380,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);
@ -1353,7 +1429,7 @@ GLFWbool _glfwRegisterWindowClassWin32(void)
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 = (WNDPROC) 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 +1459,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,
@ -1465,8 +1541,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 +1563,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 +1594,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 +1635,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),
@ -1579,8 +1654,8 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height)
} }
void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window, void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window,
int minwidth, int minheight, int minwidth, int minheight,
int maxwidth, int maxheight) int maxwidth, int maxheight)
{ {
RECT area; RECT area;
@ -1618,8 +1693,8 @@ void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height)
} }
void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window, void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window,
int* left, int* top, int* left, int* top,
int* right, int* bottom) int* right, int* bottom)
{ {
RECT rect; RECT rect;
int width, height; int width, height;
@ -1627,7 +1702,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 +1743,10 @@ void _glfwRestoreWindowWin32(_GLFWwindow* window)
void _glfwMaximizeWindowWin32(_GLFWwindow* window) void _glfwMaximizeWindowWin32(_GLFWwindow* window)
{ {
ShowWindow(window->win32.handle, SW_MAXIMIZE); if (IsWindowVisible(window->win32.handle))
ShowWindow(window->win32.handle, SW_MAXIMIZE);
else
maximizeWindowManually(window);
} }
void _glfwShowWindowWin32(_GLFWwindow* window) void _glfwShowWindowWin32(_GLFWwindow* window)
@ -1713,7 +1791,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 +1833,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 +1862,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 +2130,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)
@ -2113,8 +2191,8 @@ int _glfwGetKeyScancodeWin32(int key)
} }
int _glfwCreateCursorWin32(_GLFWcursor* cursor, int _glfwCreateCursorWin32(_GLFWcursor* cursor,
const GLFWimage* image, const GLFWimage* image,
int xhot, int yhot) int xhot, int yhot)
{ {
cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE);
if (!cursor->win32.handle) if (!cursor->win32.handle)
@ -2369,7 +2447,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

@ -514,12 +514,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

@ -57,11 +57,6 @@
#include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h"
static inline int min(int n1, int n2)
{
return n1 < n2 ? n1 : n2;
}
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
int* which) int* which)
{ {
@ -788,7 +783,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,7 +806,7 @@ 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);
@ -1367,14 +1362,15 @@ int _glfwInitWayland(void)
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); wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
_glfw.wl.clipboardString = _glfw_calloc(4096, 1);
_glfw.wl.clipboardSize = 4096;
_glfw.wl.clipboardString = _glfw_calloc(_glfw.wl.clipboardSize, 1);
if (!_glfw.wl.clipboardString) if (!_glfw.wl.clipboardString)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_OUT_OF_MEMORY,
"Wayland: Unable to allocate clipboard memory"); "Wayland: Unable to allocate clipboard memory");
return GLFW_FALSE; return GLFW_FALSE;
} }
_glfw.wl.clipboardSize = 4096;
} }
return GLFW_TRUE; return GLFW_TRUE;
@ -1460,9 +1456,7 @@ 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); _glfw_free(_glfw.wl.clipboardSendString);
if (_glfw.wl.clipboardSendString)
_glfw_free(_glfw.wl.clipboardSendString);
} }

View File

@ -43,6 +43,7 @@ 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);

View File

@ -345,26 +345,21 @@ static void resizeWindow(_GLFWwindow* window)
static void checkScaleChange(_GLFWwindow* window) static void checkScaleChange(_GLFWwindow* window)
{ {
int scale = 1;
int monitorScale;
// Check if we will be able to set the buffer scale or not. // Check if we will be able to set the buffer scale or not.
if (_glfw.wl.compositorVersion < 3) if (_glfw.wl.compositorVersion < 3)
return; return;
// Get the scale factor from the highest scale monitor. // Get the scale factor from the highest scale monitor.
for (int i = 0; i < window->wl.monitorsCount; ++i) int maxScale = 1;
{
monitorScale = window->wl.monitors[i]->wl.scale; for (int i = 0; i < window->wl.monitorsCount; i++)
if (scale < monitorScale) maxScale = _glfw_max(window->wl.monitors[i]->wl.scale, maxScale);
scale = monitorScale;
}
// Only change the framebuffer size if the scale changed. // Only change the framebuffer size if the scale changed.
if (scale != window->wl.scale) if (window->wl.scale != maxScale)
{ {
window->wl.scale = scale; window->wl.scale = maxScale;
wl_surface_set_buffer_scale(window->wl.surface, scale); wl_surface_set_buffer_scale(window->wl.surface, maxScale);
resizeWindow(window); resizeWindow(window);
} }
} }
@ -717,8 +712,28 @@ static void incrementCursorImage(_GLFWwindow* window)
} }
} }
static void handleEvents(int timeout) static GLFWbool flushDisplay(void)
{ {
while (wl_display_flush(_glfw.wl.display) == -1)
{
if (errno != EAGAIN)
return GLFW_FALSE;
struct pollfd fd = { wl_display_get_fd(_glfw.wl.display), POLLOUT };
while (poll(&fd, 1, -1) == -1)
{
if (errno != EINTR && errno != EAGAIN)
return GLFW_FALSE;
}
}
return GLFW_TRUE;
}
static void handleEvents(double* timeout)
{
GLFWbool event = GLFW_FALSE;
struct pollfd fds[] = struct pollfd fds[] =
{ {
{ wl_display_get_fd(_glfw.wl.display), POLLIN }, { wl_display_get_fd(_glfw.wl.display), POLLIN },
@ -726,30 +741,38 @@ static void handleEvents(int timeout)
{ _glfw.wl.cursorTimerfd, POLLIN }, { _glfw.wl.cursorTimerfd, POLLIN },
}; };
while (wl_display_prepare_read(_glfw.wl.display) != 0) while (!event)
wl_display_dispatch_pending(_glfw.wl.display);
// If an error other than EAGAIN happens, we have likely been disconnected
// from the Wayland session; try to handle that the best we can.
if (wl_display_flush(_glfw.wl.display) < 0 && errno != EAGAIN)
{ {
_GLFWwindow* window = _glfw.windowListHead; while (wl_display_prepare_read(_glfw.wl.display) != 0)
while (window) wl_display_dispatch_pending(_glfw.wl.display);
// If an error other than EAGAIN happens, we have likely been disconnected
// from the Wayland session; try to handle that the best we can.
if (!flushDisplay())
{ {
_glfwInputWindowCloseRequest(window); wl_display_cancel_read(_glfw.wl.display);
window = window->next;
_GLFWwindow* window = _glfw.windowListHead;
while (window)
{
_glfwInputWindowCloseRequest(window);
window = window->next;
}
return;
} }
wl_display_cancel_read(_glfw.wl.display); if (!_glfwPollPOSIX(fds, 3, timeout))
return; {
} wl_display_cancel_read(_glfw.wl.display);
return;
}
if (poll(fds, 3, timeout) > 0)
{
if (fds[0].revents & POLLIN) if (fds[0].revents & POLLIN)
{ {
wl_display_read_events(_glfw.wl.display); wl_display_read_events(_glfw.wl.display);
wl_display_dispatch_pending(_glfw.wl.display); if (wl_display_dispatch_pending(_glfw.wl.display) > 0)
event = GLFW_TRUE;
} }
else else
wl_display_cancel_read(_glfw.wl.display); wl_display_cancel_read(_glfw.wl.display);
@ -770,6 +793,8 @@ static void handleEvents(int timeout)
_glfwInputTextWayland(_glfw.wl.keyboardFocus, _glfwInputTextWayland(_glfw.wl.keyboardFocus,
_glfw.wl.keyboardLastScancode); _glfw.wl.keyboardLastScancode);
} }
event = GLFW_TRUE;
} }
} }
@ -778,11 +803,12 @@ static void handleEvents(int timeout)
uint64_t repeats; uint64_t repeats;
if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8) if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8)
{
incrementCursorImage(_glfw.wl.pointerFocus); incrementCursorImage(_glfw.wl.pointerFocus);
event = GLFW_TRUE;
}
} }
} }
else
wl_display_cancel_read(_glfw.wl.display);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -1149,22 +1175,24 @@ GLFWbool _glfwRawMouseMotionSupportedWayland(void)
void _glfwPollEventsWayland(void) void _glfwPollEventsWayland(void)
{ {
handleEvents(0); double timeout = 0.0;
handleEvents(&timeout);
} }
void _glfwWaitEventsWayland(void) void _glfwWaitEventsWayland(void)
{ {
handleEvents(-1); handleEvents(NULL);
} }
void _glfwWaitEventsTimeoutWayland(double timeout) void _glfwWaitEventsTimeoutWayland(double timeout)
{ {
handleEvents((int) (timeout * 1e3)); handleEvents(&timeout);
} }
void _glfwPostEmptyEventWayland(void) void _glfwPostEmptyEventWayland(void)
{ {
wl_display_sync(_glfw.wl.display); wl_display_sync(_glfw.wl.display);
flushDisplay();
} }
void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos) void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos)
@ -1675,7 +1703,7 @@ static GLFWbool growClipboardString(void)
clipboard = _glfw_realloc(clipboard, _glfw.wl.clipboardSize * 2); clipboard = _glfw_realloc(clipboard, _glfw.wl.clipboardSize * 2);
if (!clipboard) if (!clipboard)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_OUT_OF_MEMORY,
"Wayland: Impossible to grow clipboard string"); "Wayland: Impossible to grow clipboard string");
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1710,9 +1738,9 @@ const char* _glfwGetClipboardStringWayland(void)
close(fds[1]); close(fds[1]);
// XXX: this is a huge hack, this function shouldnt be synchronous! // XXX: this is a huge hack, this function shouldnt be synchronous!
handleEvents(-1); handleEvents(NULL);
while (1) for (;;)
{ {
// Grow the clipboard if we need to paste something bigger, there is no // Grow the clipboard if we need to paste something bigger, there is no
// shrink operation yet. // shrink operation yet.

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;
@ -1604,5 +1640,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; while (!XPending(_glfw.x11.display))
{
if (!_glfwPollPOSIX(&fd, 1, timeout))
return GLFW_FALSE;
}
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 defined(__linux__)
if (_glfw.linjs.inotify > fd) if (_glfw.joysticksInitialized)
count = _glfw.linjs.inotify + 1; fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
#endif #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 (;;) for (;;)
{ {
FD_ZERO(&fds); const char byte = 0;
FD_SET(fd, &fds); const int result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);
#if defined(__linux__) if (result == 1 || (result == -1 && errno != EINTR))
if (_glfw.linjs.inotify > 0) break;
FD_SET(_glfw.linjs.inotify, &fds); }
#endif }
if (timeout) // Drains available data from the empty event pipe
{ //
const long seconds = (long) *timeout; static void drainEmptyEvents(void)
const long microseconds = (long) ((*timeout - seconds) * 1e6); {
struct timeval tv = { seconds, microseconds }; for (;;)
const uint64_t base = _glfwPlatformGetTimerValue(); {
char dummy[64];
const int result = select(count, &fds, NULL, NULL, &tv); const int result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));
const int error = errno; if (result == -1 && errno != EINTR)
break;
*timeout -= (_glfwPlatformGetTimerValue() - base) /
(double) _glfwPlatformGetTimerFrequency();
if (result > 0)
return GLFW_TRUE;
if ((result == -1 && error == EINTR) || *timeout <= 0.0)
return GLFW_FALSE;
}
else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)
return GLFW_TRUE;
} }
} }
@ -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;
} }
@ -958,7 +987,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 +1023,7 @@ static const char* getSelectionString(Atom selection)
isSelPropNewValueNotify, isSelPropNewValueNotify,
(XPointer) &notification)) (XPointer) &notification))
{ {
waitForEvent(NULL); waitForX11Event(NULL);
} }
XFree(data); XFree(data);
@ -1238,7 +1267,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);
@ -1896,7 +1925,7 @@ void _glfwPushSelectionToManagerX11(void)
} }
} }
waitForEvent(NULL); waitForX11Event(NULL);
} }
} }
@ -2238,7 +2267,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 +2773,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 +2788,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 +2808,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)