mirror of
https://github.com/glfw/glfw.git
synced 2025-06-08 08:45:02 +00:00
Merge branch 'glfw:master' into master
This commit is contained in:
commit
3db230c23b
0
docs/CODEOWNERS → .github/CODEOWNERS
vendored
0
docs/CODEOWNERS → .github/CODEOWNERS
vendored
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@ -73,8 +73,8 @@ jobs:
|
||||
- name: Build shared library
|
||||
run: cmake --build build-shared --parallel
|
||||
|
||||
build-windows-win32-vs2019:
|
||||
name: Win32 (Windows, VS2019)
|
||||
build-windows-win32-vs2022:
|
||||
name: Win32 (Windows, VS2022)
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
CFLAGS: /WX
|
||||
@ -82,12 +82,12 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- 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
|
||||
run: cmake --build build-static --parallel
|
||||
|
||||
- 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
|
||||
run: cmake --build build-shared --parallel
|
||||
|
||||
|
@ -10,6 +10,7 @@ video tutorials.
|
||||
- Matt Arsenault
|
||||
- ashishgamedev
|
||||
- David Avedissian
|
||||
- Luca Bacci
|
||||
- Keith Bauer
|
||||
- John Bartholomew
|
||||
- Coşku Baş
|
||||
@ -29,6 +30,7 @@ video tutorials.
|
||||
- David Carlier
|
||||
- Arturo Castro
|
||||
- Chi-kwan Chan
|
||||
- TheChocolateOre
|
||||
- Joseph Chua
|
||||
- Ian Clarkson
|
||||
- Michał Cichoń
|
||||
@ -42,6 +44,7 @@ video tutorials.
|
||||
- Noel Cower
|
||||
- CuriouserThing
|
||||
- Jason Daly
|
||||
- danhambleton
|
||||
- Jarrod Davis
|
||||
- Olivier Delannoy
|
||||
- Paul R. Deppe
|
||||
@ -68,6 +71,7 @@ video tutorials.
|
||||
- Ryan C. Gordon
|
||||
- Stephen Gowen
|
||||
- Kovid Goyal
|
||||
- Kevin Grandemange
|
||||
- Eloi Marín Gratacós
|
||||
- Stefan Gustavson
|
||||
- Andrew Gutekanst
|
||||
@ -81,10 +85,14 @@ video tutorials.
|
||||
- Paul Holden
|
||||
- Warren Hu
|
||||
- Charles Huber
|
||||
- Brent Huisman
|
||||
- illustris
|
||||
- InKryption
|
||||
- IntellectualKitty
|
||||
- Aaron Jacobs
|
||||
- JannikGM
|
||||
- Erik S. V. Jansson
|
||||
- jjYBdx4IL
|
||||
- Toni Jovanoski
|
||||
- Arseny Kapoulkine
|
||||
- Cem Karan
|
||||
@ -155,6 +163,7 @@ video tutorials.
|
||||
- Orson Peters
|
||||
- Emmanuel Gil Peyrot
|
||||
- Cyril Pichard
|
||||
- Pilzschaf
|
||||
- Keith Pitt
|
||||
- Stanislav Podgorskiy
|
||||
- Konstantin Podsvirov
|
||||
@ -183,13 +192,16 @@ video tutorials.
|
||||
- Ali Sherief
|
||||
- Yoshiki Shibukawa
|
||||
- Dmitri Shuralyov
|
||||
- Joao da Silva
|
||||
- Daniel Sieger
|
||||
- Daniel Skorupski
|
||||
- Slemmie
|
||||
- Anthony Smith
|
||||
- Bradley Smith
|
||||
- Cliff Smolinsky
|
||||
- Patrick Snape
|
||||
- Erlend Sogge Heggen
|
||||
- Olivier Sohn
|
||||
- Julian Squires
|
||||
- Johannes Stein
|
||||
- Pontus Stenetorp
|
||||
@ -202,6 +214,7 @@ video tutorials.
|
||||
- Jared Tiala
|
||||
- Sergey Tikhomirov
|
||||
- Arthur Tombs
|
||||
- TronicLabs
|
||||
- Ioannis Tsakpinis
|
||||
- Samuli Tuomola
|
||||
- Matthew Turner
|
||||
|
37
README.md
37
README.md
@ -172,6 +172,8 @@ information on what to include when reporting a bug.
|
||||
- Bugfix: Gamepad mapping updates could spam `GLFW_INVALID_VALUE` due to
|
||||
incompatible controllers sharing hardware ID (#1763)
|
||||
- Bugfix: Native access functions for context handles did not check that the API matched
|
||||
- Bugfix: `glfwMakeContextCurrent` would access TLS slot before initialization
|
||||
- Bugfix: `glfwSetGammaRamp` could emit `GLFW_INVALID_VALUE` before initialization
|
||||
- [Win32] Added the `GLFW_WIN32_KEYBOARD_MENU` window hint for enabling access
|
||||
to the window menu
|
||||
- [Win32] Added a version info resource to the GLFW DLL
|
||||
@ -205,6 +207,17 @@ information on what to include when reporting a bug.
|
||||
- [Win32] Bugfix: Content scale queries could fail silently (#1615)
|
||||
- [Win32] Bugfix: Content scales could have garbage values if monitor was recently
|
||||
disconnected (#1615)
|
||||
- [Win32] Bugfix: A window created maximized and undecorated would cover the whole
|
||||
monitor (#1806)
|
||||
- [Win32] Bugfix: The default restored window position was lost when creating a maximized
|
||||
window
|
||||
- [Win32] Bugfix: `glfwMaximizeWindow` would make a hidden window visible
|
||||
- [Win32] Bugfix: `Alt+PrtSc` would emit `GLFW_KEY_UNKNOWN` and a different
|
||||
scancode than `PrtSc` (#1993)
|
||||
- [Win32] Bugfix: `GLFW_KEY_PAUSE` scancode from `glfwGetKeyScancode` did not
|
||||
match event scancode (#1993)
|
||||
- [Win32] Bugfix: Instance-local operations used executable instance (#469,#1296,#1395)
|
||||
- [Win32] Bugfix: The OSMesa library was not unloaded on termination
|
||||
- [Cocoa] Added support for `VK_EXT_metal_surface` (#1619)
|
||||
- [Cocoa] Added locating the Vulkan loader at runtime in an application bundle
|
||||
- [Cocoa] Moved main menu creation to GLFW initialization time (#1649)
|
||||
@ -235,6 +248,8 @@ information on what to include when reporting a bug.
|
||||
a fraction of a second (#1962)
|
||||
- [Cocoa] Bugfix: `kIOMasterPortDefault` was deprecated in macOS 12.0 (#1980)
|
||||
- [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003)
|
||||
- [Cocoa] Bugfix: A connected Apple AirPlay would emit a useless error (#1791)
|
||||
- [Cocoa] Bugfix: The EGL and OSMesa libraries were not unloaded on termination
|
||||
- [X11] Bugfix: The CMake files did not check for the XInput headers (#1480)
|
||||
- [X11] Bugfix: Key names were not updated when the keyboard layout changed
|
||||
(#1462,#1528)
|
||||
@ -266,8 +281,19 @@ information on what to include when reporting a bug.
|
||||
- [X11] Bugfix: Icon pixel format conversion worked only by accident, relying on
|
||||
undefined behavior (#1986)
|
||||
- [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences
|
||||
- [X11] Bugfix: Waiting for events would fail if file descriptor was too large
|
||||
(#2024)
|
||||
- [X11] Bugfix: Joystick events could lead to busy-waiting (#1872)
|
||||
- [X11] Bugfix: `glfwWaitEvents*` did not continue for joystick events
|
||||
- [X11] Bugfix: `glfwPostEmptyEvent` could be ignored due to race condition
|
||||
(#379,#1281,#1285,#2033)
|
||||
- [X11] Bugfix: Dynamic loading on NetBSD failed due to soname differences
|
||||
- [X11] Bugfix: Left shift of int constant relied on undefined behavior (#1951)
|
||||
- [X11] Bugfix: The OSMesa libray was not unloaded on termination
|
||||
- [X11] Bugfix: A malformed response during selection transfer could cause a segfault
|
||||
- [Wayland] Added dynamic loading of all Wayland libraries
|
||||
- [Wayland] Added support for key names via xkbcommon
|
||||
- [Wayland] Added support for file path drop events (#2040)
|
||||
- [Wayland] Removed support for `wl_shell` (#1443)
|
||||
- [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432)
|
||||
- [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
|
||||
@ -290,6 +316,16 @@ information on what to include when reporting a bug.
|
||||
- [Wayland] Bugfix: Full screen window creation did not ignore `GLFW_VISIBLE`
|
||||
- [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN`
|
||||
- [Wayland] Bugfix: Text input did not repeat along with key repeat
|
||||
- [Wayland] Bugfix: `glfwPostEmptyEvent` sometimes had no effect (#1520,#1521)
|
||||
- [Wayland] Bugfix: `glfwSetClipboardString` would fail if set to result of
|
||||
`glfwGetClipboardString`
|
||||
- [Wayland] Bugfix: Data source creation error would cause double free at termination
|
||||
- [Wayland] Bugfix: Partial writes of clipboard string would cause beginning to repeat
|
||||
- [Wayland] Bugfix: Some errors would cause clipboard string transfer to hang
|
||||
- [Wayland] Bugfix: Drag and drop data was misinterpreted as clipboard string
|
||||
- [Wayland] Bugfix: MIME type matching was not performed for clipboard string
|
||||
- [Wayland] Bugfix: The OSMesa library was not unloaded on termination
|
||||
- [Wayland] Bugfix: `glfwCreateWindow` could emit `GLFW_FEATURE_UNAVAILABLE`
|
||||
- [POSIX] Removed use of deprecated function `gettimeofday`
|
||||
- [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled
|
||||
- [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072)
|
||||
@ -304,6 +340,7 @@ information on what to include when reporting a bug.
|
||||
- [EGL] Added ANGLE backend selection via `EGL_ANGLE_platform_angle` extension
|
||||
(#1380)
|
||||
- [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843)
|
||||
- [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library
|
||||
|
||||
|
||||
## Contact
|
||||
|
910
deps/stb_image_write.h
vendored
910
deps/stb_image_write.h
vendored
File diff suppressed because it is too large
Load Diff
@ -68,8 +68,10 @@ install the `xorgproto` package.
|
||||
pkg install xorgproto
|
||||
@endcode
|
||||
|
||||
On Cygwin the `xorgproto` package in the Devel section of the GUI installer will
|
||||
install the headers and other development related files for all of X11.
|
||||
On Cygwin the `libXcursor-devel`, `libXi-devel`, `libXinerama-devel`,
|
||||
`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.
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
`rightstick`.
|
||||
|
||||
|
@ -138,6 +138,12 @@ GLFW_TRANSPARENT_FRAMEBUFFER on Windows 7 if DWM transparency is off
|
||||
(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 removals_34 Removals in 3.4
|
||||
|
@ -50,11 +50,6 @@ set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
|
||||
C_STANDARD 99
|
||||
FOLDER "GLFW3/Examples")
|
||||
|
||||
if (GLFW_USE_OSMESA)
|
||||
find_package(OSMesa REQUIRED)
|
||||
target_compile_definitions(offscreen PRIVATE USE_NATIVE_OSMESA)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
# Tell MSVC to use main instead of WinMain
|
||||
set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES
|
||||
|
@ -28,11 +28,6 @@
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#if USE_NATIVE_OSMESA
|
||||
#define GLFW_EXPOSE_NATIVE_OSMESA
|
||||
#include <GLFW/glfw3native.h>
|
||||
#endif
|
||||
|
||||
#include "linmath.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -151,12 +146,8 @@ int main(void)
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glFinish();
|
||||
|
||||
#if USE_NATIVE_OSMESA
|
||||
glfwGetOSMesaColorBuffer(window, &width, &height, NULL, (void**) &buffer);
|
||||
#else
|
||||
buffer = calloc(4, width * height);
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
#endif
|
||||
|
||||
// Write image Y-flipped because OpenGL
|
||||
stbi_write_png("offscreen.png",
|
||||
@ -164,11 +155,7 @@ int main(void)
|
||||
buffer + (width * 4 * (height - 1)),
|
||||
-width * 4);
|
||||
|
||||
#if USE_NATIVE_OSMESA
|
||||
// Here is where there's nothing
|
||||
#else
|
||||
free(buffer);
|
||||
#endif
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
||||
|
@ -262,13 +262,12 @@ extern "C" {
|
||||
/* We are building GLFW as a Win32 DLL */
|
||||
#define GLFWAPI __declspec(dllexport)
|
||||
#elif defined(_WIN32) && defined(GLFW_DLL)
|
||||
/* We are calling GLFW as a Win32 DLL */
|
||||
/* We are calling a GLFW Win32 DLL */
|
||||
#define GLFWAPI __declspec(dllimport)
|
||||
#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
|
||||
/* We are building GLFW as a shared / dynamic library */
|
||||
/* We are building GLFW as a Unix shared library */
|
||||
#define GLFWAPI __attribute__((visibility("default")))
|
||||
#else
|
||||
/* We are building or calling GLFW as a static library */
|
||||
#define GLFWAPI
|
||||
#endif
|
||||
|
||||
@ -3258,7 +3257,8 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
|
||||
* count is zero.
|
||||
*
|
||||
* @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
|
||||
* returns.
|
||||
@ -4892,8 +4892,8 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
|
||||
* @return The handle of the created cursor, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||
* GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @pointer_lifetime The specified image data is copied before this function
|
||||
* returns.
|
||||
@ -6383,6 +6383,7 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window
|
||||
*/
|
||||
#ifndef GLAPIENTRY
|
||||
#define GLAPIENTRY APIENTRY
|
||||
#define GLFW_GLAPIENTRY_DEFINED
|
||||
#endif
|
||||
|
||||
/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */
|
||||
|
@ -82,9 +82,10 @@ extern "C" {
|
||||
*************************************************************************/
|
||||
|
||||
#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
|
||||
// example to allow applications to correctly declare a GL_KHR_debug callback)
|
||||
// but windows.h assumes no one will define APIENTRY before it does
|
||||
/* 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)
|
||||
* but windows.h assumes no one will define APIENTRY before it does
|
||||
*/
|
||||
#if defined(GLFW_APIENTRY_DEFINED)
|
||||
#undef APIENTRY
|
||||
#undef GLFW_APIENTRY_DEFINED
|
||||
@ -111,12 +112,28 @@ extern "C" {
|
||||
/* NSGL is declared by Cocoa.h */
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
/* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by
|
||||
* default it also acts as an OpenGL header
|
||||
* However, glx.h will include gl.h, which will define it unconditionally
|
||||
*/
|
||||
#if defined(GLFW_GLAPIENTRY_DEFINED)
|
||||
#undef GLAPIENTRY
|
||||
#undef GLFW_GLAPIENTRY_DEFINED
|
||||
#endif
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
|
||||
/* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by
|
||||
* default it also acts as an OpenGL header
|
||||
* However, osmesa.h will include gl.h, which will define it unconditionally
|
||||
*/
|
||||
#if defined(GLFW_GLAPIENTRY_DEFINED)
|
||||
#undef GLAPIENTRY
|
||||
#undef GLFW_GLAPIENTRY_DEFINED
|
||||
#endif
|
||||
#include <GL/osmesa.h>
|
||||
#endif
|
||||
|
||||
@ -489,6 +506,9 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @remark Because EGL is initialized on demand, this function will return
|
||||
* `EGL_NO_DISPLAY` until the first context has been created via EGL.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
|
@ -60,6 +60,7 @@ if (GLFW_BUILD_X11 OR GLFW_BUILD_WAYLAND)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c)
|
||||
endif()
|
||||
target_sources(glfw PRIVATE posix_poll.h posix_poll.c)
|
||||
endif()
|
||||
|
||||
if (GLFW_BUILD_WAYLAND)
|
||||
|
@ -676,6 +676,8 @@ void _glfwTerminateCocoa(void)
|
||||
_glfw_free(_glfw.ns.clipboardString);
|
||||
|
||||
_glfwTerminateNSGL();
|
||||
_glfwTerminateEGL();
|
||||
_glfwTerminateOSMesa();
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
@ -98,11 +98,7 @@ static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen)
|
||||
IOObjectRelease(it);
|
||||
|
||||
if (!service)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to find service port for display");
|
||||
return _glfw_strdup("Display");
|
||||
}
|
||||
|
||||
CFDictionaryRef names =
|
||||
CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
|
||||
|
@ -973,13 +973,31 @@ int _glfwCreateWindowCocoa(_GLFWwindow* window,
|
||||
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!_glfwRefreshContextAttribs(window, ctxconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (wndconfig->mousePassthrough)
|
||||
_glfwSetWindowMousePassthroughCocoa(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
_glfwShowWindowCocoa(window);
|
||||
_glfwFocusWindowCocoa(window);
|
||||
acquireMonitor(window);
|
||||
|
||||
if (wndconfig->centerCursor)
|
||||
_glfwCenterCursorInContentArea(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wndconfig->visible)
|
||||
{
|
||||
_glfwShowWindowCocoa(window);
|
||||
if (wndconfig->focused)
|
||||
_glfwFocusWindowCocoa(window);
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
|
@ -609,10 +609,12 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions
|
||||
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
_GLFWwindow* previous;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
if (window && window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,
|
||||
|
@ -325,7 +325,7 @@ GLFWbool _glfwInitEGL(void)
|
||||
"libEGL.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libEGL-1.so",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libEGL.so",
|
||||
#else
|
||||
"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])); \
|
||||
attribs[index++] = a; \
|
||||
@ -584,12 +584,12 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -599,42 +599,42 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
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)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||
SET_ATTRIB(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||
SET_ATTRIB(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (mask)
|
||||
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
||||
SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
||||
|
||||
if (flags)
|
||||
setAttrib(EGL_CONTEXT_FLAGS_KHR, flags);
|
||||
SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
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 (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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
setAttrib(EGL_NONE, EGL_NONE);
|
||||
SET_ATTRIB(EGL_NONE, EGL_NONE);
|
||||
|
||||
window->context.egl.handle = eglCreateContext(_glfw.egl.display,
|
||||
config, share, attribs);
|
||||
@ -653,16 +653,16 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
if (fbconfig->sRGB)
|
||||
{
|
||||
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)
|
||||
setAttrib(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
|
||||
SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
|
||||
|
||||
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);
|
||||
// HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
|
||||
@ -702,7 +702,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
"libGLES_CM.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
"libGLESv1_CM.dylib",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGLESv1_CM.so",
|
||||
#else
|
||||
"libGLESv1_CM.so.1",
|
||||
@ -721,7 +721,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
"libGLESv2.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libGLESv2-2.so",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGLESv2.so",
|
||||
#else
|
||||
"libGLESv2.so.2",
|
||||
@ -734,7 +734,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
_GLFW_OPENGL_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_GLFW_COCOA)
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGL.so",
|
||||
#else
|
||||
"libGL.so.1",
|
||||
@ -782,7 +782,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
#undef SET_ATTRIB
|
||||
|
||||
// Returns the Visual and depth of the chosen EGLConfig
|
||||
//
|
||||
|
@ -259,7 +259,7 @@ GLFWbool _glfwInitGLX(void)
|
||||
_GLFW_GLX_LIBRARY,
|
||||
#elif defined(__CYGWIN__)
|
||||
"libGL-1.so",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGL.so",
|
||||
#else
|
||||
"libGL.so.1",
|
||||
@ -308,10 +308,6 @@ GLFWbool _glfwInitGLX(void)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXCreateWindow");
|
||||
_glfw.glx.DestroyWindow = (PFNGLXDESTROYWINDOWPROC)
|
||||
_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)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetVisualFromFBConfig");
|
||||
|
||||
@ -327,8 +323,6 @@ GLFWbool _glfwInitGLX(void)
|
||||
!_glfw.glx.CreateNewContext ||
|
||||
!_glfw.glx.CreateWindow ||
|
||||
!_glfw.glx.DestroyWindow ||
|
||||
!_glfw.glx.GetProcAddress ||
|
||||
!_glfw.glx.GetProcAddressARB ||
|
||||
!_glfw.glx.GetVisualFromFBConfig)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
@ -336,6 +330,12 @@ GLFWbool _glfwInitGLX(void)
|
||||
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,
|
||||
&_glfw.glx.errorBase,
|
||||
&_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])); \
|
||||
attribs[index++] = a; \
|
||||
@ -523,12 +523,12 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -542,12 +542,12 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -556,7 +556,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
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
|
||||
@ -564,17 +564,17 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
// highest version supported by the driver
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
SET_ATTRIB(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
SET_ATTRIB(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (mask)
|
||||
setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
|
||||
SET_ATTRIB(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
|
||||
|
||||
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 =
|
||||
_glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
|
||||
@ -631,7 +631,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
#undef SET_ATTRIB
|
||||
|
||||
// Returns the Visual and depth of the chosen GLXFBConfig
|
||||
//
|
||||
|
63
src/init.c
63
src/init.c
@ -171,6 +171,59 @@ size_t _glfwEncodeUTF8(char* s, uint32_t codepoint)
|
||||
return count;
|
||||
}
|
||||
|
||||
// Splits and translates a text/uri-list into separate file paths
|
||||
// NOTE: This function destroys the provided string
|
||||
//
|
||||
char** _glfwParseUriList(char* text, int* count)
|
||||
{
|
||||
const char* prefix = "file://";
|
||||
char** paths = NULL;
|
||||
char* line;
|
||||
|
||||
*count = 0;
|
||||
|
||||
while ((line = strtok(text, "\r\n")))
|
||||
{
|
||||
char* path;
|
||||
|
||||
text = NULL;
|
||||
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
||||
{
|
||||
line += strlen(prefix);
|
||||
// TODO: Validate hostname
|
||||
while (*line != '/')
|
||||
line++;
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
|
||||
path = _glfw_calloc(strlen(line) + 1, 1);
|
||||
paths = _glfw_realloc(paths, *count * sizeof(char*));
|
||||
paths[*count - 1] = path;
|
||||
|
||||
while (*line)
|
||||
{
|
||||
if (line[0] == '%' && line[1] && line[2])
|
||||
{
|
||||
const char digits[3] = { line[1], line[2], '\0' };
|
||||
*path = (char) strtol(digits, NULL, 16);
|
||||
line += 2;
|
||||
}
|
||||
else
|
||||
*path = *line;
|
||||
|
||||
path++;
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
char* _glfw_strdup(const char* source)
|
||||
{
|
||||
const size_t length = strlen(source);
|
||||
@ -179,6 +232,16 @@ char* _glfw_strdup(const char* source)
|
||||
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)
|
||||
{
|
||||
if (a != a)
|
||||
|
@ -764,9 +764,16 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
|
||||
_GLFWcursor* cursor;
|
||||
|
||||
assert(image != NULL);
|
||||
assert(image->pixels != 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->next = _glfw.cursorListHead;
|
||||
_glfw.cursorListHead = cursor;
|
||||
@ -1421,3 +1428,4 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void)
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||
return _glfwPlatformGetTimerFrequency();
|
||||
}
|
||||
|
||||
|
@ -996,8 +996,11 @@ void _glfwTerminateVulkan(void);
|
||||
const char* _glfwGetVulkanResultString(VkResult result);
|
||||
|
||||
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);
|
||||
char** _glfwParseUriList(char* text, int* count);
|
||||
|
||||
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_fmaxf(float a, float b);
|
||||
|
||||
|
@ -522,6 +522,8 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
|
||||
assert(ramp->green != NULL);
|
||||
assert(ramp->blue != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (ramp->size <= 0)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
@ -530,8 +532,6 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
|
||||
return;
|
||||
}
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (!monitor->originalRamp.size)
|
||||
{
|
||||
if (!_glfw.platform.getGammaRamp(monitor, &monitor->originalRamp))
|
||||
|
@ -188,45 +188,45 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
// No-error contexts (GL_KHR_no_error) are not yet supported by macOS but
|
||||
// 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])); \
|
||||
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];
|
||||
int index = 0;
|
||||
|
||||
addAttrib(NSOpenGLPFAAccelerated);
|
||||
addAttrib(NSOpenGLPFAClosestPolicy);
|
||||
ADD_ATTRIB(NSOpenGLPFAAccelerated);
|
||||
ADD_ATTRIB(NSOpenGLPFAClosestPolicy);
|
||||
|
||||
if (ctxconfig->nsgl.offline)
|
||||
{
|
||||
addAttrib(NSOpenGLPFAAllowOfflineRenderers);
|
||||
ADD_ATTRIB(NSOpenGLPFAAllowOfflineRenderers);
|
||||
// NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in
|
||||
// Info.plist for unbundled applications
|
||||
// HACK: This assumes that NSOpenGLPixelFormat will remain
|
||||
// a straightforward wrapper of its CGL counterpart
|
||||
addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching);
|
||||
ADD_ATTRIB(kCGLPFASupportsAutomaticGraphicsSwitching);
|
||||
}
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
|
||||
if (ctxconfig->major >= 4)
|
||||
{
|
||||
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
|
||||
SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
|
||||
}
|
||||
else
|
||||
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
|
||||
if (ctxconfig->major >= 3)
|
||||
{
|
||||
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
|
||||
SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
|
||||
}
|
||||
|
||||
if (ctxconfig->major <= 2)
|
||||
{
|
||||
if (fbconfig->auxBuffers != GLFW_DONT_CARE)
|
||||
setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
|
||||
SET_ATTRIB(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
|
||||
|
||||
if (fbconfig->accumRedBits != GLFW_DONT_CARE &&
|
||||
fbconfig->accumGreenBits != GLFW_DONT_CARE &&
|
||||
@ -238,7 +238,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
fbconfig->accumBlueBits +
|
||||
fbconfig->accumAlphaBits;
|
||||
|
||||
setAttrib(NSOpenGLPFAAccumSize, accumBits);
|
||||
SET_ATTRIB(NSOpenGLPFAAccumSize, accumBits);
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,17 +256,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
else if (colorBits < 15)
|
||||
colorBits = 15;
|
||||
|
||||
setAttrib(NSOpenGLPFAColorSize, colorBits);
|
||||
SET_ATTRIB(NSOpenGLPFAColorSize, colorBits);
|
||||
}
|
||||
|
||||
if (fbconfig->alphaBits != GLFW_DONT_CARE)
|
||||
setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
|
||||
SET_ATTRIB(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
|
||||
|
||||
if (fbconfig->depthBits != GLFW_DONT_CARE)
|
||||
setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits);
|
||||
SET_ATTRIB(NSOpenGLPFADepthSize, fbconfig->depthBits);
|
||||
|
||||
if (fbconfig->stencilBits != GLFW_DONT_CARE)
|
||||
setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
|
||||
SET_ATTRIB(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
|
||||
|
||||
if (fbconfig->stereo)
|
||||
{
|
||||
@ -275,33 +275,33 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
"NSGL: Stereo rendering is deprecated");
|
||||
return GLFW_FALSE;
|
||||
#else
|
||||
addAttrib(NSOpenGLPFAStereo);
|
||||
ADD_ATTRIB(NSOpenGLPFAStereo);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (fbconfig->doublebuffer)
|
||||
addAttrib(NSOpenGLPFADoubleBuffer);
|
||||
ADD_ATTRIB(NSOpenGLPFADoubleBuffer);
|
||||
|
||||
if (fbconfig->samples != GLFW_DONT_CARE)
|
||||
{
|
||||
if (fbconfig->samples == 0)
|
||||
{
|
||||
setAttrib(NSOpenGLPFASampleBuffers, 0);
|
||||
SET_ATTRIB(NSOpenGLPFASampleBuffers, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
setAttrib(NSOpenGLPFASampleBuffers, 1);
|
||||
setAttrib(NSOpenGLPFASamples, fbconfig->samples);
|
||||
SET_ATTRIB(NSOpenGLPFASampleBuffers, 1);
|
||||
SET_ATTRIB(NSOpenGLPFASamples, fbconfig->samples);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
|
||||
// framebuffer, so there's no need (and no way) to request it
|
||||
|
||||
addAttrib(0);
|
||||
ADD_ATTRIB(0);
|
||||
|
||||
#undef addAttrib
|
||||
#undef setAttrib
|
||||
#undef ADD_ATTRIB
|
||||
#undef SET_ATTRIB
|
||||
|
||||
window->context.nsgl.pixelFormat =
|
||||
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||
|
@ -39,15 +39,15 @@ static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
|
||||
*height = (int) (*width / ratio);
|
||||
}
|
||||
|
||||
if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth)
|
||||
*width = window->minwidth;
|
||||
else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth)
|
||||
*width = window->maxwidth;
|
||||
if (window->minwidth != GLFW_DONT_CARE)
|
||||
*width = _glfw_max(*width, window->minwidth);
|
||||
else if (window->maxwidth != GLFW_DONT_CARE)
|
||||
*width = _glfw_min(*width, window->maxwidth);
|
||||
|
||||
if (window->minheight != GLFW_DONT_CARE && *height < window->minheight)
|
||||
*height = window->minheight;
|
||||
else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight)
|
||||
*height = window->maxheight;
|
||||
if (window->minheight != GLFW_DONT_CARE)
|
||||
*height = _glfw_min(*height, window->minheight);
|
||||
else if (window->maxheight != GLFW_DONT_CARE)
|
||||
*height = _glfw_max(*height, window->maxheight);
|
||||
}
|
||||
|
||||
static void fitToMonitor(_GLFWwindow* window)
|
||||
@ -128,13 +128,31 @@ int _glfwCreateWindowNull(_GLFWwindow* window,
|
||||
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!_glfwRefreshContextAttribs(window, ctxconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (wndconfig->mousePassthrough)
|
||||
_glfwSetWindowMousePassthroughNull(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
_glfwShowWindowNull(window);
|
||||
_glfwFocusWindowNull(window);
|
||||
acquireMonitor(window);
|
||||
|
||||
if (wndconfig->centerCursor)
|
||||
_glfwCenterCursorInContentArea(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wndconfig->visible)
|
||||
{
|
||||
_glfwShowWindowNull(window);
|
||||
if (wndconfig->focused)
|
||||
_glfwFocusWindowNull(window);
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
|
@ -124,7 +124,7 @@ GLFWbool _glfwInitOSMesa(void)
|
||||
"libOSMesa.8.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libOSMesa-8.so",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libOSMesa.so",
|
||||
#else
|
||||
"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])); \
|
||||
attribs[index++] = a; \
|
||||
@ -221,24 +221,24 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
|
||||
{
|
||||
int index = 0, attribs[40];
|
||||
|
||||
setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
|
||||
setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
|
||||
setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
|
||||
setAttrib(OSMESA_ACCUM_BITS, accumBits);
|
||||
SET_ATTRIB(OSMESA_FORMAT, OSMESA_RGBA);
|
||||
SET_ATTRIB(OSMESA_DEPTH_BITS, fbconfig->depthBits);
|
||||
SET_ATTRIB(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
|
||||
SET_ATTRIB(OSMESA_ACCUM_BITS, accumBits);
|
||||
|
||||
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)
|
||||
{
|
||||
setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
|
||||
SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
|
||||
setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
|
||||
SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
|
||||
SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (ctxconfig->forward)
|
||||
@ -248,7 +248,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
setAttrib(0, 0);
|
||||
SET_ATTRIB(0, 0);
|
||||
|
||||
window->context.osmesa.handle =
|
||||
OSMesaCreateContextAttribs(attribs, share);
|
||||
@ -287,7 +287,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
#undef SET_ATTRIB
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -92,30 +92,6 @@
|
||||
#define GLFW_LINUX_LIBRARY_JOYSTICK_STATE
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "win32_thread.h"
|
||||
#define GLFW_POSIX_TLS_STATE
|
||||
#define GLFW_POSIX_MUTEX_STATE
|
||||
#else
|
||||
#include "posix_thread.h"
|
||||
#define GLFW_WIN32_TLS_STATE
|
||||
#define GLFW_WIN32_MUTEX_STATE
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "win32_time.h"
|
||||
#define GLFW_POSIX_LIBRARY_TIMER_STATE
|
||||
#define GLFW_COCOA_LIBRARY_TIMER_STATE
|
||||
#elif defined(__APPLE__)
|
||||
#include "cocoa_time.h"
|
||||
#define GLFW_WIN32_LIBRARY_TIMER_STATE
|
||||
#define GLFW_POSIX_LIBRARY_TIMER_STATE
|
||||
#else
|
||||
#include "posix_time.h"
|
||||
#define GLFW_WIN32_LIBRARY_TIMER_STATE
|
||||
#define GLFW_COCOA_LIBRARY_TIMER_STATE
|
||||
#endif
|
||||
|
||||
#define GLFW_PLATFORM_WINDOW_STATE \
|
||||
GLFW_WIN32_WINDOW_STATE \
|
||||
GLFW_COCOA_WINDOW_STATE \
|
||||
@ -142,14 +118,6 @@
|
||||
GLFW_COCOA_JOYSTICK_STATE \
|
||||
GLFW_LINUX_JOYSTICK_STATE
|
||||
|
||||
#define GLFW_PLATFORM_TLS_STATE \
|
||||
GLFW_WIN32_TLS_STATE \
|
||||
GLFW_POSIX_TLS_STATE \
|
||||
|
||||
#define GLFW_PLATFORM_MUTEX_STATE \
|
||||
GLFW_WIN32_MUTEX_STATE \
|
||||
GLFW_POSIX_MUTEX_STATE \
|
||||
|
||||
#define GLFW_PLATFORM_LIBRARY_WINDOW_STATE \
|
||||
GLFW_WIN32_LIBRARY_WINDOW_STATE \
|
||||
GLFW_COCOA_LIBRARY_WINDOW_STATE \
|
||||
@ -162,11 +130,6 @@
|
||||
GLFW_COCOA_LIBRARY_JOYSTICK_STATE \
|
||||
GLFW_LINUX_LIBRARY_JOYSTICK_STATE
|
||||
|
||||
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE \
|
||||
GLFW_WIN32_LIBRARY_TIMER_STATE \
|
||||
GLFW_COCOA_LIBRARY_TIMER_STATE \
|
||||
GLFW_POSIX_LIBRARY_TIMER_STATE \
|
||||
|
||||
#define GLFW_PLATFORM_CONTEXT_STATE \
|
||||
GLFW_WGL_CONTEXT_STATE \
|
||||
GLFW_NSGL_CONTEXT_STATE \
|
||||
@ -177,3 +140,24 @@
|
||||
GLFW_NSGL_LIBRARY_CONTEXT_STATE \
|
||||
GLFW_GLX_LIBRARY_CONTEXT_STATE
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "win32_thread.h"
|
||||
#define GLFW_PLATFORM_TLS_STATE GLFW_WIN32_TLS_STATE
|
||||
#define GLFW_PLATFORM_MUTEX_STATE GLFW_WIN32_MUTEX_STATE
|
||||
#else
|
||||
#include "posix_thread.h"
|
||||
#define GLFW_PLATFORM_TLS_STATE GLFW_POSIX_TLS_STATE
|
||||
#define GLFW_PLATFORM_MUTEX_STATE GLFW_POSIX_MUTEX_STATE
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "win32_time.h"
|
||||
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_WIN32_LIBRARY_TIMER_STATE
|
||||
#elif defined(__APPLE__)
|
||||
#include "cocoa_time.h"
|
||||
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_COCOA_LIBRARY_TIMER_STATE
|
||||
#else
|
||||
#include "posix_time.h"
|
||||
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_POSIX_LIBRARY_TIMER_STATE
|
||||
#endif
|
||||
|
||||
|
81
src/posix_poll.c
Normal file
81
src/posix_poll.c
Normal 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
32
src/posix_poll.h
Normal 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);
|
||||
|
@ -63,7 +63,7 @@ GLFWbool _glfwInitVulkan(int mode)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
|
||||
if (!_glfw.vk.handle)
|
||||
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so");
|
||||
#else
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1");
|
||||
|
@ -52,12 +52,12 @@ static int findPixelFormatAttribValueWGL(const int* attribs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define addAttrib(a) \
|
||||
#define ADD_ATTRIB(a) \
|
||||
{ \
|
||||
assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[attribCount++] = a; \
|
||||
}
|
||||
#define findAttribValue(a) \
|
||||
#define FIND_ATTRIB_VALUE(a) \
|
||||
findPixelFormatAttribValueWGL(attribs, attribCount, values, a)
|
||||
|
||||
// Return a list of available and usable framebuffer configs
|
||||
@ -84,41 +84,41 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
|
||||
return 0;
|
||||
}
|
||||
|
||||
addAttrib(WGL_SUPPORT_OPENGL_ARB);
|
||||
addAttrib(WGL_DRAW_TO_WINDOW_ARB);
|
||||
addAttrib(WGL_PIXEL_TYPE_ARB);
|
||||
addAttrib(WGL_ACCELERATION_ARB);
|
||||
addAttrib(WGL_RED_BITS_ARB);
|
||||
addAttrib(WGL_RED_SHIFT_ARB);
|
||||
addAttrib(WGL_GREEN_BITS_ARB);
|
||||
addAttrib(WGL_GREEN_SHIFT_ARB);
|
||||
addAttrib(WGL_BLUE_BITS_ARB);
|
||||
addAttrib(WGL_BLUE_SHIFT_ARB);
|
||||
addAttrib(WGL_ALPHA_BITS_ARB);
|
||||
addAttrib(WGL_ALPHA_SHIFT_ARB);
|
||||
addAttrib(WGL_DEPTH_BITS_ARB);
|
||||
addAttrib(WGL_STENCIL_BITS_ARB);
|
||||
addAttrib(WGL_ACCUM_BITS_ARB);
|
||||
addAttrib(WGL_ACCUM_RED_BITS_ARB);
|
||||
addAttrib(WGL_ACCUM_GREEN_BITS_ARB);
|
||||
addAttrib(WGL_ACCUM_BLUE_BITS_ARB);
|
||||
addAttrib(WGL_ACCUM_ALPHA_BITS_ARB);
|
||||
addAttrib(WGL_AUX_BUFFERS_ARB);
|
||||
addAttrib(WGL_STEREO_ARB);
|
||||
addAttrib(WGL_DOUBLE_BUFFER_ARB);
|
||||
ADD_ATTRIB(WGL_SUPPORT_OPENGL_ARB);
|
||||
ADD_ATTRIB(WGL_DRAW_TO_WINDOW_ARB);
|
||||
ADD_ATTRIB(WGL_PIXEL_TYPE_ARB);
|
||||
ADD_ATTRIB(WGL_ACCELERATION_ARB);
|
||||
ADD_ATTRIB(WGL_RED_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_RED_SHIFT_ARB);
|
||||
ADD_ATTRIB(WGL_GREEN_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_GREEN_SHIFT_ARB);
|
||||
ADD_ATTRIB(WGL_BLUE_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_BLUE_SHIFT_ARB);
|
||||
ADD_ATTRIB(WGL_ALPHA_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ALPHA_SHIFT_ARB);
|
||||
ADD_ATTRIB(WGL_DEPTH_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_STENCIL_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_RED_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_GREEN_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_BLUE_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_ALPHA_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_AUX_BUFFERS_ARB);
|
||||
ADD_ATTRIB(WGL_STEREO_ARB);
|
||||
ADD_ATTRIB(WGL_DOUBLE_BUFFER_ARB);
|
||||
|
||||
if (_glfw.wgl.ARB_multisample)
|
||||
addAttrib(WGL_SAMPLES_ARB);
|
||||
ADD_ATTRIB(WGL_SAMPLES_ARB);
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (_glfw.wgl.EXT_colorspace)
|
||||
addAttrib(WGL_COLORSPACE_EXT);
|
||||
ADD_ATTRIB(WGL_COLORSPACE_EXT);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -152,48 +152,48 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!findAttribValue(WGL_SUPPORT_OPENGL_ARB) ||
|
||||
!findAttribValue(WGL_DRAW_TO_WINDOW_ARB))
|
||||
if (!FIND_ATTRIB_VALUE(WGL_SUPPORT_OPENGL_ARB) ||
|
||||
!FIND_ATTRIB_VALUE(WGL_DRAW_TO_WINDOW_ARB))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (findAttribValue(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB)
|
||||
if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB)
|
||||
continue;
|
||||
|
||||
if (findAttribValue(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB)
|
||||
if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB)
|
||||
continue;
|
||||
|
||||
if (findAttribValue(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer)
|
||||
if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer)
|
||||
continue;
|
||||
|
||||
u->redBits = findAttribValue(WGL_RED_BITS_ARB);
|
||||
u->greenBits = findAttribValue(WGL_GREEN_BITS_ARB);
|
||||
u->blueBits = findAttribValue(WGL_BLUE_BITS_ARB);
|
||||
u->alphaBits = findAttribValue(WGL_ALPHA_BITS_ARB);
|
||||
u->redBits = FIND_ATTRIB_VALUE(WGL_RED_BITS_ARB);
|
||||
u->greenBits = FIND_ATTRIB_VALUE(WGL_GREEN_BITS_ARB);
|
||||
u->blueBits = FIND_ATTRIB_VALUE(WGL_BLUE_BITS_ARB);
|
||||
u->alphaBits = FIND_ATTRIB_VALUE(WGL_ALPHA_BITS_ARB);
|
||||
|
||||
u->depthBits = findAttribValue(WGL_DEPTH_BITS_ARB);
|
||||
u->stencilBits = findAttribValue(WGL_STENCIL_BITS_ARB);
|
||||
u->depthBits = FIND_ATTRIB_VALUE(WGL_DEPTH_BITS_ARB);
|
||||
u->stencilBits = FIND_ATTRIB_VALUE(WGL_STENCIL_BITS_ARB);
|
||||
|
||||
u->accumRedBits = findAttribValue(WGL_ACCUM_RED_BITS_ARB);
|
||||
u->accumGreenBits = findAttribValue(WGL_ACCUM_GREEN_BITS_ARB);
|
||||
u->accumBlueBits = findAttribValue(WGL_ACCUM_BLUE_BITS_ARB);
|
||||
u->accumAlphaBits = findAttribValue(WGL_ACCUM_ALPHA_BITS_ARB);
|
||||
u->accumRedBits = FIND_ATTRIB_VALUE(WGL_ACCUM_RED_BITS_ARB);
|
||||
u->accumGreenBits = FIND_ATTRIB_VALUE(WGL_ACCUM_GREEN_BITS_ARB);
|
||||
u->accumBlueBits = FIND_ATTRIB_VALUE(WGL_ACCUM_BLUE_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;
|
||||
|
||||
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 (_glfw.wgl.ARB_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;
|
||||
}
|
||||
}
|
||||
@ -201,7 +201,7 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -290,8 +290,8 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
|
||||
return pixelFormat;
|
||||
}
|
||||
|
||||
#undef addAttrib
|
||||
#undef findAttribValue
|
||||
#undef ADD_ATTRIB
|
||||
#undef FIND_ATTRIB_VALUE
|
||||
|
||||
static void makeContextCurrentWGL(_GLFWwindow* window)
|
||||
{
|
||||
@ -523,7 +523,7 @@ void _glfwTerminateWGL(void)
|
||||
_glfwPlatformFreeModule(_glfw.wgl.instance);
|
||||
}
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
#define SET_ATTRIB(a, v) \
|
||||
{ \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
@ -631,12 +631,12 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -650,12 +650,12 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -664,7 +664,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
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
|
||||
@ -672,17 +672,17 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
// highest version supported by the driver
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (flags)
|
||||
setAttrib(WGL_CONTEXT_FLAGS_ARB, flags);
|
||||
SET_ATTRIB(WGL_CONTEXT_FLAGS_ARB, flags);
|
||||
|
||||
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 =
|
||||
wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs);
|
||||
@ -765,7 +765,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
#undef SET_ATTRIB
|
||||
|
||||
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
|
||||
{
|
||||
|
@ -71,6 +71,16 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
|
||||
//
|
||||
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");
|
||||
if (!_glfw.win32.user32.instance)
|
||||
{
|
||||
@ -91,6 +101,8 @@ static GLFWbool loadLibraries(void)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetDpiForWindow");
|
||||
_glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_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");
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
@ -251,7 +263,6 @@ static void createKeyTables(void)
|
||||
_glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN;
|
||||
_glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP;
|
||||
_glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE;
|
||||
_glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE;
|
||||
_glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE;
|
||||
_glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB;
|
||||
_glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK;
|
||||
@ -333,7 +344,7 @@ static GLFWbool createHelperWindow(void)
|
||||
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
||||
0, 0, 1, 1,
|
||||
NULL, NULL,
|
||||
GetModuleHandleW(NULL),
|
||||
_glfw.win32.instance,
|
||||
NULL);
|
||||
|
||||
if (!_glfw.win32.helperWindowHandle)
|
||||
@ -483,7 +494,7 @@ void _glfwUpdateKeyNamesWin32(void)
|
||||
vk = vks[key - GLFW_KEY_KP_0];
|
||||
}
|
||||
else
|
||||
vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);
|
||||
vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK);
|
||||
|
||||
length = ToUnicode(vk, scancode, state,
|
||||
chars, sizeof(chars) / sizeof(WCHAR),
|
||||
@ -491,6 +502,8 @@ void _glfwUpdateKeyNamesWin32(void)
|
||||
|
||||
if (length == -1)
|
||||
{
|
||||
// This is a dead key, so we need a second simulated key press
|
||||
// to make it output its own character (usually a diacritic)
|
||||
length = ToUnicode(vk, scancode, state,
|
||||
chars, sizeof(chars) / sizeof(WCHAR),
|
||||
0);
|
||||
@ -506,7 +519,8 @@ void _glfwUpdateKeyNamesWin32(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h
|
||||
// Replacement for IsWindowsVersionOrGreater, as we cannot rely on the
|
||||
// application having a correct embedded manifest
|
||||
//
|
||||
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp)
|
||||
{
|
||||
@ -626,7 +640,7 @@ int _glfwInitWin32(void)
|
||||
createKeyTables();
|
||||
_glfwUpdateKeyNamesWin32();
|
||||
|
||||
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1703OrGreaterWin32())
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
else if (IsWindows8Point1OrGreater())
|
||||
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||
@ -658,6 +672,7 @@ void _glfwTerminateWin32(void)
|
||||
|
||||
_glfwTerminateWGL();
|
||||
_glfwTerminateEGL();
|
||||
_glfwTerminateOSMesa();
|
||||
|
||||
freeLibraries();
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ GLFWbool _glfwInitJoysticksWin32(void)
|
||||
{
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
{
|
||||
if (FAILED(DirectInput8Create(GetModuleHandle(NULL),
|
||||
if (FAILED(DirectInput8Create(_glfw.win32.instance,
|
||||
DIRECTINPUT_VERSION,
|
||||
&IID_IDirectInput8W,
|
||||
(void**) &_glfw.win32.dinput8.api,
|
||||
@ -607,7 +607,7 @@ int _glfwPollJoystickWin32(_GLFWjoystick* js, int mode)
|
||||
{
|
||||
int i, ai = 0, bi = 0, pi = 0;
|
||||
HRESULT result;
|
||||
DIJOYSTATE state;
|
||||
DIJOYSTATE state = {0};
|
||||
|
||||
IDirectInputDevice8_Poll(js->win32.device);
|
||||
result = IDirectInputDevice8_GetDeviceState(js->win32.device,
|
||||
|
@ -381,7 +381,7 @@ void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor,
|
||||
int* width, int* height)
|
||||
{
|
||||
MONITORINFO mi = { sizeof(mi) };
|
||||
GetMonitorInfo(monitor->win32.handle, &mi);
|
||||
GetMonitorInfoW(monitor->win32.handle, &mi);
|
||||
|
||||
if (xpos)
|
||||
*xpos = mi.rcWork.left;
|
||||
|
@ -162,7 +162,9 @@ typedef enum
|
||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4)
|
||||
#endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/
|
||||
|
||||
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
|
||||
// Replacement for versionhelpers.h macros, as we cannot rely on the
|
||||
// application having a correct embedded manifest
|
||||
//
|
||||
#define IsWindowsVistaOrGreater() \
|
||||
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \
|
||||
LOBYTE(_WIN32_WINNT_VISTA), 0)
|
||||
@ -176,9 +178,11 @@ typedef enum
|
||||
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \
|
||||
LOBYTE(_WIN32_WINNT_WINBLUE), 0)
|
||||
|
||||
#define _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() \
|
||||
// Windows 10 Anniversary Update
|
||||
#define _glfwIsWindows10Version1607OrGreaterWin32() \
|
||||
_glfwIsWindows10BuildOrGreaterWin32(14393)
|
||||
#define _glfwIsWindows10CreatorsUpdateOrGreaterWin32() \
|
||||
// Windows 10 Creators Update
|
||||
#define _glfwIsWindows10Version1703OrGreaterWin32() \
|
||||
_glfwIsWindows10BuildOrGreaterWin32(15063)
|
||||
|
||||
// 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 UINT (WINAPI * PFN_GetDpiForWindow)(HWND);
|
||||
typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
|
||||
typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT);
|
||||
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
|
||||
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
|
||||
#define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_
|
||||
#define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_
|
||||
#define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_
|
||||
#define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_
|
||||
#define GetSystemMetricsForDpi _glfw.win32.user32.GetSystemMetricsForDpi_
|
||||
|
||||
// dwmapi.dll function pointer typedefs
|
||||
typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
|
||||
@ -436,6 +442,7 @@ typedef struct _GLFWwindowWin32
|
||||
//
|
||||
typedef struct _GLFWlibraryWin32
|
||||
{
|
||||
HINSTANCE instance;
|
||||
HWND helperWindowHandle;
|
||||
HDEVNOTIFY deviceNotificationHandle;
|
||||
int acquiredMonitorCount;
|
||||
@ -471,6 +478,7 @@ typedef struct _GLFWlibraryWin32
|
||||
PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_;
|
||||
PFN_GetDpiForWindow GetDpiForWindow_;
|
||||
PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_;
|
||||
PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_;
|
||||
} user32;
|
||||
|
||||
struct {
|
||||
|
@ -97,8 +97,7 @@ static const GLFWimage* chooseImage(int count, const GLFWimage* images,
|
||||
|
||||
// Creates an RGBA icon or cursor
|
||||
//
|
||||
static HICON createIcon(const GLFWimage* image,
|
||||
int xhot, int yhot, GLFWbool icon)
|
||||
static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon)
|
||||
{
|
||||
int i;
|
||||
HDC dc;
|
||||
@ -194,7 +193,7 @@ static void getFullWindowSize(DWORD style, DWORD exStyle,
|
||||
{
|
||||
RECT rect = { 0, 0, contentWidth, contentHeight };
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
|
||||
else
|
||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
||||
@ -211,7 +210,7 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
|
||||
UINT dpi = USER_DEFAULT_SCREEN_DPI;
|
||||
const float ratio = (float) window->numer / (float) window->denom;
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
dpi = GetDpiForWindow(window->win32.handle);
|
||||
|
||||
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
|
||||
@ -354,7 +353,7 @@ static void updateWindowStyles(const _GLFWwindow* window)
|
||||
|
||||
GetClientRect(window->win32.handle, &rect);
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE,
|
||||
getWindowExStyle(window),
|
||||
@ -434,7 +433,7 @@ static int getKeyMods(void)
|
||||
static void fitToMonitor(_GLFWwindow* window)
|
||||
{
|
||||
MONITORINFO mi = { sizeof(mi) };
|
||||
GetMonitorInfo(window->monitor->win32.handle, &mi);
|
||||
GetMonitorInfoW(window->monitor->win32.handle, &mi);
|
||||
SetWindowPos(window->win32.handle, HWND_TOPMOST,
|
||||
mi.rcMonitor.left,
|
||||
mi.rcMonitor.top,
|
||||
@ -453,8 +452,8 @@ static void acquireMonitor(_GLFWwindow* window)
|
||||
|
||||
// HACK: When mouse trails are enabled the cursor becomes invisible when
|
||||
// the OpenGL ICD switches to page flipping
|
||||
SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
|
||||
SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0);
|
||||
SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
|
||||
SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (!window->monitor->window)
|
||||
@ -477,17 +476,66 @@ static void releaseMonitor(_GLFWwindow* window)
|
||||
SetThreadExecutionState(ES_CONTINUOUS);
|
||||
|
||||
// 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);
|
||||
_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)
|
||||
//
|
||||
static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
_GLFWwindow* window = GetPropW(hWnd, L"GLFW");
|
||||
if (!window)
|
||||
@ -499,7 +547,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
{
|
||||
case WM_NCCREATE:
|
||||
{
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
{
|
||||
const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam;
|
||||
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);
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
// The Ctrl keys require special handling
|
||||
@ -1045,7 +1101,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
if (window->monitor)
|
||||
break;
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
dpi = GetDpiForWindow(window->win32.handle);
|
||||
|
||||
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
|
||||
@ -1073,7 +1129,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
|
||||
ZeroMemory(&mi, sizeof(mi));
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(mh, &mi);
|
||||
GetMonitorInfoW(mh, &mi);
|
||||
|
||||
mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left;
|
||||
mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top;
|
||||
@ -1120,7 +1176,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
break;
|
||||
|
||||
// Adjust the window size to keep the content area size constant
|
||||
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1703OrGreaterWin32())
|
||||
{
|
||||
RECT source = {0}, target = {0};
|
||||
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
|
||||
if (!window->monitor &&
|
||||
(window->win32.scaleToMonitor ||
|
||||
_glfwIsWindows10CreatorsUpdateOrGreaterWin32()))
|
||||
_glfwIsWindows10Version1703OrGreaterWin32()))
|
||||
{
|
||||
RECT* suggested = (RECT*) lParam;
|
||||
SetWindowPos(window->win32.handle, HWND_TOP,
|
||||
@ -1228,15 +1284,16 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
GLFWvidmode mode;
|
||||
MONITORINFO mi = { sizeof(mi) };
|
||||
GetMonitorInfoW(window->monitor->win32.handle, &mi);
|
||||
|
||||
// NOTE: This window placement is temporary and approximate, as the
|
||||
// correct position and size cannot be known until the monitor
|
||||
// video mode has been picked in _glfwSetVideoModeWin32
|
||||
_glfwGetMonitorPosWin32(window->monitor, &xpos, &ypos);
|
||||
_glfwGetVideoModeWin32(window->monitor, &mode);
|
||||
fullWidth = mode.width;
|
||||
fullHeight = mode.height;
|
||||
xpos = mi.rcMonitor.left;
|
||||
ypos = mi.rcMonitor.top;
|
||||
fullWidth = mi.rcMonitor.right - mi.rcMonitor.left;
|
||||
fullHeight = mi.rcMonitor.bottom - mi.rcMonitor.top;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1265,7 +1322,7 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
fullWidth, fullHeight,
|
||||
NULL, // No parent window
|
||||
NULL, // No window menu
|
||||
GetModuleHandleW(NULL),
|
||||
_glfw.win32.instance,
|
||||
(LPVOID) wndconfig);
|
||||
|
||||
_glfw_free(wideTitle);
|
||||
@ -1292,18 +1349,22 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
|
||||
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)
|
||||
{
|
||||
RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
|
||||
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)
|
||||
{
|
||||
float xscale, yscale;
|
||||
_glfwGetWindowContentScaleWin32(window, &xscale, &yscale);
|
||||
_glfwGetHMONITORContentScaleWin32(mh, &xscale, &yscale);
|
||||
|
||||
if (xscale > 0.f && yscale > 0.f)
|
||||
{
|
||||
@ -1312,10 +1373,7 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
|
||||
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
@ -1323,11 +1381,30 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
else
|
||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
||||
|
||||
// Only update the restored window rect as the window may be maximized
|
||||
GetWindowPlacement(window->win32.handle, &wp);
|
||||
OffsetRect(&rect,
|
||||
wp.rcNormalPosition.left - rect.left,
|
||||
wp.rcNormalPosition.top - rect.top);
|
||||
|
||||
wp.rcNormalPosition = rect;
|
||||
wp.showCmd = SW_HIDE;
|
||||
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);
|
||||
@ -1352,8 +1429,8 @@ GLFWbool _glfwRegisterWindowClassWin32(void)
|
||||
ZeroMemory(&wc, sizeof(wc));
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
wc.lpfnWndProc = (WNDPROC) windowProc;
|
||||
wc.hInstance = GetModuleHandleW(NULL);
|
||||
wc.lpfnWndProc = windowProc;
|
||||
wc.hInstance = _glfw.win32.instance;
|
||||
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
|
||||
wc.lpszClassName = _GLFW_WNDCLASSNAME;
|
||||
|
||||
@ -1383,7 +1460,7 @@ GLFWbool _glfwRegisterWindowClassWin32(void)
|
||||
//
|
||||
void _glfwUnregisterWindowClassWin32(void)
|
||||
{
|
||||
UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
|
||||
UnregisterClassW(_GLFW_WNDCLASSNAME, _glfw.win32.instance);
|
||||
}
|
||||
|
||||
int _glfwCreateWindowWin32(_GLFWwindow* window,
|
||||
@ -1417,14 +1494,32 @@ int _glfwCreateWindowWin32(_GLFWwindow* window,
|
||||
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!_glfwRefreshContextAttribs(window, ctxconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (wndconfig->mousePassthrough)
|
||||
_glfwSetWindowMousePassthroughWin32(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
_glfwShowWindowWin32(window);
|
||||
_glfwFocusWindowWin32(window);
|
||||
acquireMonitor(window);
|
||||
fitToMonitor(window);
|
||||
|
||||
if (wndconfig->centerCursor)
|
||||
_glfwCenterCursorInContentArea(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wndconfig->visible)
|
||||
{
|
||||
_glfwShowWindowWin32(window);
|
||||
if (wndconfig->focused)
|
||||
_glfwFocusWindowWin32(window);
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
@ -1465,8 +1560,7 @@ void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title)
|
||||
_glfw_free(wideTitle);
|
||||
}
|
||||
|
||||
void _glfwSetWindowIconWin32(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images)
|
||||
{
|
||||
HICON bigIcon = NULL, smallIcon = NULL;
|
||||
|
||||
@ -1488,8 +1582,8 @@ void _glfwSetWindowIconWin32(_GLFWwindow* window,
|
||||
smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
|
||||
}
|
||||
|
||||
SendMessage(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_BIG, (LPARAM) bigIcon);
|
||||
SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
|
||||
|
||||
if (window->win32.bigIcon)
|
||||
DestroyIcon(window->win32.bigIcon);
|
||||
@ -1519,7 +1613,7 @@ void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos)
|
||||
{
|
||||
RECT rect = { xpos, ypos, xpos, ypos };
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
@ -1560,7 +1654,7 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
RECT rect = { 0, 0, width, height };
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
@ -1627,7 +1721,7 @@ void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window,
|
||||
_glfwGetWindowSizeWin32(window, &width, &height);
|
||||
SetRect(&rect, 0, 0, width, height);
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
@ -1668,7 +1762,10 @@ void _glfwRestoreWindowWin32(_GLFWwindow* window)
|
||||
|
||||
void _glfwMaximizeWindowWin32(_GLFWwindow* window)
|
||||
{
|
||||
if (IsWindowVisible(window->win32.handle))
|
||||
ShowWindow(window->win32.handle, SW_MAXIMIZE);
|
||||
else
|
||||
maximizeWindowManually(window);
|
||||
}
|
||||
|
||||
void _glfwShowWindowWin32(_GLFWwindow* window)
|
||||
@ -1713,7 +1810,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
|
||||
{
|
||||
RECT rect = { xpos, ypos, xpos + width, ypos + height };
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
@ -1755,7 +1852,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
|
||||
|
||||
acquireMonitor(window);
|
||||
|
||||
GetMonitorInfo(window->monitor->win32.handle, &mi);
|
||||
GetMonitorInfoW(window->monitor->win32.handle, &mi);
|
||||
SetWindowPos(window->win32.handle, HWND_TOPMOST,
|
||||
mi.rcMonitor.left,
|
||||
mi.rcMonitor.top,
|
||||
@ -1784,7 +1881,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
|
||||
else
|
||||
after = HWND_NOTOPMOST;
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
if (_glfwIsWindows10Version1607OrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
@ -2052,7 +2149,7 @@ void _glfwWaitEventsTimeoutWin32(double timeout)
|
||||
|
||||
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)
|
||||
@ -2369,7 +2466,7 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance,
|
||||
|
||||
memset(&sci, 0, sizeof(sci));
|
||||
sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
sci.hinstance = GetModuleHandle(NULL);
|
||||
sci.hinstance = _glfw.win32.instance;
|
||||
sci.hwnd = window->win32.handle;
|
||||
|
||||
err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
|
||||
|
49
src/window.c
49
src/window.c
@ -215,40 +215,12 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
||||
window->numer = GLFW_DONT_CARE;
|
||||
window->denom = GLFW_DONT_CARE;
|
||||
|
||||
// Open the actual window and create its context
|
||||
if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig))
|
||||
{
|
||||
glfwDestroyWindow((GLFWwindow*) window);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ctxconfig.client != GLFW_NO_API)
|
||||
{
|
||||
if (!_glfwRefreshContextAttribs(window, &ctxconfig))
|
||||
{
|
||||
glfwDestroyWindow((GLFWwindow*) window);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (wndconfig.mousePassthrough)
|
||||
_glfw.platform.setWindowMousePassthrough(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
if (wndconfig.centerCursor)
|
||||
_glfwCenterCursorInContentArea(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wndconfig.visible)
|
||||
{
|
||||
_glfw.platform.showWindow(window);
|
||||
if (wndconfig.focused)
|
||||
_glfw.platform.focusWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
return (GLFWwindow*) window;
|
||||
}
|
||||
|
||||
@ -514,12 +486,33 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title)
|
||||
GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle,
|
||||
int count, const GLFWimage* images)
|
||||
{
|
||||
int i;
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
|
||||
assert(window != NULL);
|
||||
assert(count >= 0);
|
||||
assert(count == 0 || images != NULL);
|
||||
|
||||
_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);
|
||||
}
|
||||
|
||||
|
797
src/wl_init.c
797
src/wl_init.c
@ -28,7 +28,6 @@
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <linux/input.h>
|
||||
@ -48,739 +47,52 @@
|
||||
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
|
||||
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
|
||||
|
||||
// NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of
|
||||
// wl_interface pointers 'types', making it impossible to combine several unmodified
|
||||
// private-code files into a single compilation unit
|
||||
// HACK: We override this name with a macro for each file, allowing them to coexist
|
||||
|
||||
#define types _glfw_wayland_types
|
||||
#include "wayland-client-protocol-code.h"
|
||||
#undef types
|
||||
|
||||
#define types _glfw_xdg_shell_types
|
||||
#include "wayland-xdg-shell-client-protocol-code.h"
|
||||
#undef types
|
||||
|
||||
#define types _glfw_xdg_decoration_types
|
||||
#include "wayland-xdg-decoration-client-protocol-code.h"
|
||||
#undef types
|
||||
|
||||
#define types _glfw_viewporter_types
|
||||
#include "wayland-viewporter-client-protocol-code.h"
|
||||
#undef types
|
||||
|
||||
#define types _glfw_relative_pointer_types
|
||||
#include "wayland-relative-pointer-unstable-v1-client-protocol-code.h"
|
||||
#undef types
|
||||
|
||||
#define types _glfw_pointer_constraints_types
|
||||
#include "wayland-pointer-constraints-unstable-v1-client-protocol-code.h"
|
||||
#undef types
|
||||
|
||||
#define types _glfw_idle_inhibit_types
|
||||
#include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h"
|
||||
#undef types
|
||||
|
||||
|
||||
static inline int min(int n1, int n2)
|
||||
{
|
||||
return n1 < n2 ? n1 : n2;
|
||||
}
|
||||
|
||||
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
|
||||
int* which)
|
||||
{
|
||||
int focus;
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
if (!which)
|
||||
which = &focus;
|
||||
while (window)
|
||||
{
|
||||
if (surface == window->wl.decorations.top.surface)
|
||||
{
|
||||
*which = topDecoration;
|
||||
break;
|
||||
}
|
||||
if (surface == window->wl.decorations.left.surface)
|
||||
{
|
||||
*which = leftDecoration;
|
||||
break;
|
||||
}
|
||||
if (surface == window->wl.decorations.right.surface)
|
||||
{
|
||||
*which = rightDecoration;
|
||||
break;
|
||||
}
|
||||
if (surface == window->wl.decorations.bottom.surface)
|
||||
{
|
||||
*which = bottomDecoration;
|
||||
break;
|
||||
}
|
||||
window = window->next;
|
||||
}
|
||||
return window;
|
||||
}
|
||||
|
||||
static void pointerHandleEnter(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface,
|
||||
wl_fixed_t sx,
|
||||
wl_fixed_t sy)
|
||||
{
|
||||
// Happens in the case we just destroyed the surface.
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
int focus = 0;
|
||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||
if (!window)
|
||||
{
|
||||
window = findWindowFromDecorationSurface(surface, &focus);
|
||||
if (!window)
|
||||
return;
|
||||
}
|
||||
|
||||
window->wl.decorations.focus = focus;
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.pointerEnterSerial = serial;
|
||||
_glfw.wl.pointerFocus = window;
|
||||
|
||||
window->wl.hovered = GLFW_TRUE;
|
||||
|
||||
_glfwSetCursorWayland(window, window->wl.currentCursor);
|
||||
_glfwInputCursorEnter(window, GLFW_TRUE);
|
||||
}
|
||||
|
||||
static void pointerHandleLeave(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
window->wl.hovered = GLFW_FALSE;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.pointerFocus = NULL;
|
||||
_glfwInputCursorEnter(window, GLFW_FALSE);
|
||||
_glfw.wl.cursorPreviousName = NULL;
|
||||
}
|
||||
|
||||
static void setCursor(_GLFWwindow* window, const char* name)
|
||||
{
|
||||
struct wl_buffer* buffer;
|
||||
struct wl_cursor* cursor;
|
||||
struct wl_cursor_image* image;
|
||||
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
|
||||
int scale = 1;
|
||||
|
||||
if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI)
|
||||
{
|
||||
// We only support up to scale=2 for now, since libwayland-cursor
|
||||
// requires us to load a different theme for each size.
|
||||
scale = 2;
|
||||
theme = _glfw.wl.cursorThemeHiDPI;
|
||||
}
|
||||
|
||||
cursor = wl_cursor_theme_get_cursor(theme, name);
|
||||
if (!cursor)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Standard cursor not found");
|
||||
return;
|
||||
}
|
||||
// TODO: handle animated cursors too.
|
||||
image = cursor->images[0];
|
||||
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer)
|
||||
return;
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
|
||||
surface,
|
||||
image->hotspot_x / scale,
|
||||
image->hotspot_y / scale);
|
||||
wl_surface_set_buffer_scale(surface, scale);
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0,
|
||||
image->width, image->height);
|
||||
wl_surface_commit(surface);
|
||||
_glfw.wl.cursorPreviousName = name;
|
||||
}
|
||||
|
||||
static void pointerHandleMotion(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t time,
|
||||
wl_fixed_t sx,
|
||||
wl_fixed_t sy)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
const char* cursorName = NULL;
|
||||
double x, y;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
x = wl_fixed_to_double(sx);
|
||||
y = wl_fixed_to_double(sy);
|
||||
window->wl.cursorPosX = x;
|
||||
window->wl.cursorPosY = y;
|
||||
|
||||
switch (window->wl.decorations.focus)
|
||||
{
|
||||
case mainWindow:
|
||||
_glfwInputCursorPos(window, x, y);
|
||||
_glfw.wl.cursorPreviousName = NULL;
|
||||
return;
|
||||
case topDecoration:
|
||||
if (y < _GLFW_DECORATION_WIDTH)
|
||||
cursorName = "n-resize";
|
||||
else
|
||||
cursorName = "left_ptr";
|
||||
break;
|
||||
case leftDecoration:
|
||||
if (y < _GLFW_DECORATION_WIDTH)
|
||||
cursorName = "nw-resize";
|
||||
else
|
||||
cursorName = "w-resize";
|
||||
break;
|
||||
case rightDecoration:
|
||||
if (y < _GLFW_DECORATION_WIDTH)
|
||||
cursorName = "ne-resize";
|
||||
else
|
||||
cursorName = "e-resize";
|
||||
break;
|
||||
case bottomDecoration:
|
||||
if (x < _GLFW_DECORATION_WIDTH)
|
||||
cursorName = "sw-resize";
|
||||
else if (x > window->wl.width + _GLFW_DECORATION_WIDTH)
|
||||
cursorName = "se-resize";
|
||||
else
|
||||
cursorName = "s-resize";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (_glfw.wl.cursorPreviousName != cursorName)
|
||||
setCursor(window, cursorName);
|
||||
}
|
||||
|
||||
static void pointerHandleButton(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t button,
|
||||
uint32_t state)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
int glfwButton;
|
||||
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
if (button == BTN_LEFT)
|
||||
{
|
||||
switch (window->wl.decorations.focus)
|
||||
{
|
||||
case mainWindow:
|
||||
break;
|
||||
case topDecoration:
|
||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
|
||||
else
|
||||
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
|
||||
break;
|
||||
case leftDecoration:
|
||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
|
||||
break;
|
||||
case rightDecoration:
|
||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
|
||||
break;
|
||||
case bottomDecoration:
|
||||
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
|
||||
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
|
||||
{
|
||||
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
|
||||
serial, edges);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (button == BTN_RIGHT)
|
||||
{
|
||||
if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel)
|
||||
{
|
||||
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
|
||||
_glfw.wl.seat, serial,
|
||||
window->wl.cursorPosX,
|
||||
window->wl.cursorPosY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Don’t pass the button to the user if it was related to a decoration.
|
||||
if (window->wl.decorations.focus != mainWindow)
|
||||
return;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
|
||||
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
|
||||
* codes. */
|
||||
glfwButton = button - BTN_LEFT;
|
||||
|
||||
_glfwInputMouseClick(window,
|
||||
glfwButton,
|
||||
state == WL_POINTER_BUTTON_STATE_PRESSED
|
||||
? GLFW_PRESS
|
||||
: GLFW_RELEASE,
|
||||
_glfw.wl.xkb.modifiers);
|
||||
}
|
||||
|
||||
static void pointerHandleAxis(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t time,
|
||||
uint32_t axis,
|
||||
wl_fixed_t value)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
double x = 0.0, y = 0.0;
|
||||
// Wayland scroll events are in pointer motion coordinate space (think two
|
||||
// finger scroll). The factor 10 is commonly used to convert to "scroll
|
||||
// step means 1.0.
|
||||
const double scrollFactor = 1.0 / 10.0;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||
|
||||
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
|
||||
|
||||
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
|
||||
x = -wl_fixed_to_double(value) * scrollFactor;
|
||||
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
||||
y = -wl_fixed_to_double(value) * scrollFactor;
|
||||
|
||||
_glfwInputScroll(window, x, y);
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener pointerListener = {
|
||||
pointerHandleEnter,
|
||||
pointerHandleLeave,
|
||||
pointerHandleMotion,
|
||||
pointerHandleButton,
|
||||
pointerHandleAxis,
|
||||
};
|
||||
|
||||
static void keyboardHandleKeymap(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t format,
|
||||
int fd,
|
||||
uint32_t size)
|
||||
{
|
||||
struct xkb_keymap* keymap;
|
||||
struct xkb_state* state;
|
||||
struct xkb_compose_table* composeTable;
|
||||
struct xkb_compose_state* composeState;
|
||||
|
||||
char* mapStr;
|
||||
const char* locale;
|
||||
|
||||
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
|
||||
{
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (mapStr == MAP_FAILED) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
|
||||
mapStr,
|
||||
XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
0);
|
||||
munmap(mapStr, size);
|
||||
close(fd);
|
||||
|
||||
if (!keymap)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to compile keymap");
|
||||
return;
|
||||
}
|
||||
|
||||
state = xkb_state_new(keymap);
|
||||
if (!state)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to create XKB state");
|
||||
xkb_keymap_unref(keymap);
|
||||
return;
|
||||
}
|
||||
|
||||
// Look up the preferred locale, falling back to "C" as default.
|
||||
locale = getenv("LC_ALL");
|
||||
if (!locale)
|
||||
locale = getenv("LC_CTYPE");
|
||||
if (!locale)
|
||||
locale = getenv("LANG");
|
||||
if (!locale)
|
||||
locale = "C";
|
||||
|
||||
composeTable =
|
||||
xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,
|
||||
XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
if (composeTable)
|
||||
{
|
||||
composeState =
|
||||
xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||
xkb_compose_table_unref(composeTable);
|
||||
if (composeState)
|
||||
_glfw.wl.xkb.composeState = composeState;
|
||||
else
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to create XKB compose state");
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to create XKB compose table");
|
||||
}
|
||||
|
||||
xkb_keymap_unref(_glfw.wl.xkb.keymap);
|
||||
xkb_state_unref(_glfw.wl.xkb.state);
|
||||
_glfw.wl.xkb.keymap = keymap;
|
||||
_glfw.wl.xkb.state = state;
|
||||
|
||||
_glfw.wl.xkb.controlMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");
|
||||
_glfw.wl.xkb.altMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
|
||||
_glfw.wl.xkb.shiftMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
|
||||
_glfw.wl.xkb.superMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
|
||||
_glfw.wl.xkb.capsLockMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
|
||||
_glfw.wl.xkb.numLockMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
|
||||
}
|
||||
|
||||
static void keyboardHandleEnter(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface,
|
||||
struct wl_array* keys)
|
||||
{
|
||||
// Happens in the case we just destroyed the surface.
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||
if (!window)
|
||||
{
|
||||
window = findWindowFromDecorationSurface(surface, NULL);
|
||||
if (!window)
|
||||
return;
|
||||
}
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.keyboardFocus = window;
|
||||
_glfwInputWindowFocus(window, GLFW_TRUE);
|
||||
}
|
||||
|
||||
static void keyboardHandleLeave(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
struct itimerspec timer = {};
|
||||
timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.keyboardFocus = NULL;
|
||||
_glfwInputWindowFocus(window, GLFW_FALSE);
|
||||
}
|
||||
|
||||
static int translateKey(uint32_t scancode)
|
||||
{
|
||||
if (scancode < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0]))
|
||||
return _glfw.wl.keycodes[scancode];
|
||||
|
||||
return GLFW_KEY_UNKNOWN;
|
||||
}
|
||||
|
||||
static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
|
||||
{
|
||||
if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState)
|
||||
return sym;
|
||||
if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)
|
||||
!= XKB_COMPOSE_FEED_ACCEPTED)
|
||||
return sym;
|
||||
switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))
|
||||
{
|
||||
case XKB_COMPOSE_COMPOSED:
|
||||
return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);
|
||||
case XKB_COMPOSE_COMPOSING:
|
||||
case XKB_COMPOSE_CANCELLED:
|
||||
return XKB_KEY_NoSymbol;
|
||||
case XKB_COMPOSE_NOTHING:
|
||||
default:
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
|
||||
GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode)
|
||||
{
|
||||
const xkb_keysym_t* keysyms;
|
||||
const xkb_keycode_t keycode = scancode + 8;
|
||||
|
||||
if (xkb_state_key_get_syms(_glfw.wl.xkb.state, keycode, &keysyms) == 1)
|
||||
{
|
||||
const xkb_keysym_t keysym = composeSymbol(keysyms[0]);
|
||||
const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
|
||||
if (codepoint != GLFW_INVALID_CODEPOINT)
|
||||
{
|
||||
const int mods = _glfw.wl.xkb.modifiers;
|
||||
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||
_glfwInputChar(window, codepoint, mods, plain);
|
||||
}
|
||||
}
|
||||
|
||||
return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, keycode);
|
||||
}
|
||||
|
||||
static void keyboardHandleKey(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t scancode,
|
||||
uint32_t state)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
const int key = translateKey(scancode);
|
||||
const int action =
|
||||
state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfwInputKey(window, key, scancode, action, _glfw.wl.xkb.modifiers);
|
||||
|
||||
struct itimerspec timer = {};
|
||||
|
||||
if (action == GLFW_PRESS)
|
||||
{
|
||||
const GLFWbool shouldRepeat = _glfwInputTextWayland(window, scancode);
|
||||
|
||||
if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0)
|
||||
{
|
||||
_glfw.wl.keyboardLastKey = key;
|
||||
_glfw.wl.keyboardLastScancode = scancode;
|
||||
if (_glfw.wl.keyboardRepeatRate > 1)
|
||||
timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyboardRepeatRate;
|
||||
else
|
||||
timer.it_interval.tv_sec = 1;
|
||||
|
||||
timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000;
|
||||
timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);
|
||||
}
|
||||
|
||||
static void keyboardHandleModifiers(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t modsDepressed,
|
||||
uint32_t modsLatched,
|
||||
uint32_t modsLocked,
|
||||
uint32_t group)
|
||||
{
|
||||
_glfw.wl.serial = serial;
|
||||
|
||||
if (!_glfw.wl.xkb.keymap)
|
||||
return;
|
||||
|
||||
xkb_state_update_mask(_glfw.wl.xkb.state,
|
||||
modsDepressed,
|
||||
modsLatched,
|
||||
modsLocked,
|
||||
0,
|
||||
0,
|
||||
group);
|
||||
|
||||
const xkb_mod_mask_t mask =
|
||||
xkb_state_serialize_mods(_glfw.wl.xkb.state,
|
||||
XKB_STATE_MODS_DEPRESSED |
|
||||
XKB_STATE_LAYOUT_DEPRESSED |
|
||||
XKB_STATE_MODS_LATCHED |
|
||||
XKB_STATE_LAYOUT_LATCHED);
|
||||
|
||||
unsigned int mods = 0;
|
||||
|
||||
if (mask & _glfw.wl.xkb.controlMask)
|
||||
mods |= GLFW_MOD_CONTROL;
|
||||
if (mask & _glfw.wl.xkb.altMask)
|
||||
mods |= GLFW_MOD_ALT;
|
||||
if (mask & _glfw.wl.xkb.shiftMask)
|
||||
mods |= GLFW_MOD_SHIFT;
|
||||
if (mask & _glfw.wl.xkb.superMask)
|
||||
mods |= GLFW_MOD_SUPER;
|
||||
if (mask & _glfw.wl.xkb.capsLockMask)
|
||||
mods |= GLFW_MOD_CAPS_LOCK;
|
||||
if (mask & _glfw.wl.xkb.numLockMask)
|
||||
mods |= GLFW_MOD_NUM_LOCK;
|
||||
|
||||
_glfw.wl.xkb.modifiers = mods;
|
||||
}
|
||||
|
||||
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
|
||||
static void keyboardHandleRepeatInfo(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
int32_t rate,
|
||||
int32_t delay)
|
||||
{
|
||||
if (keyboard != _glfw.wl.keyboard)
|
||||
return;
|
||||
|
||||
_glfw.wl.keyboardRepeatRate = rate;
|
||||
_glfw.wl.keyboardRepeatDelay = delay;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct wl_keyboard_listener keyboardListener = {
|
||||
keyboardHandleKeymap,
|
||||
keyboardHandleEnter,
|
||||
keyboardHandleLeave,
|
||||
keyboardHandleKey,
|
||||
keyboardHandleModifiers,
|
||||
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
|
||||
keyboardHandleRepeatInfo,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void seatHandleCapabilities(void* data,
|
||||
struct wl_seat* seat,
|
||||
enum wl_seat_capability caps)
|
||||
{
|
||||
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)
|
||||
{
|
||||
_glfw.wl.pointer = wl_seat_get_pointer(seat);
|
||||
wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);
|
||||
}
|
||||
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
|
||||
{
|
||||
wl_pointer_destroy(_glfw.wl.pointer);
|
||||
_glfw.wl.pointer = NULL;
|
||||
}
|
||||
|
||||
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)
|
||||
{
|
||||
_glfw.wl.keyboard = wl_seat_get_keyboard(seat);
|
||||
wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
|
||||
}
|
||||
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
|
||||
{
|
||||
wl_keyboard_destroy(_glfw.wl.keyboard);
|
||||
_glfw.wl.keyboard = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void seatHandleName(void* data,
|
||||
struct wl_seat* seat,
|
||||
const char* name)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener seatListener = {
|
||||
seatHandleCapabilities,
|
||||
seatHandleName,
|
||||
};
|
||||
|
||||
static void dataOfferHandleOffer(void* data,
|
||||
struct wl_data_offer* dataOffer,
|
||||
const char* mimeType)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_listener dataOfferListener = {
|
||||
dataOfferHandleOffer,
|
||||
};
|
||||
|
||||
static void dataDeviceHandleDataOffer(void* data,
|
||||
struct wl_data_device* dataDevice,
|
||||
struct wl_data_offer* id)
|
||||
{
|
||||
if (_glfw.wl.dataOffer)
|
||||
wl_data_offer_destroy(_glfw.wl.dataOffer);
|
||||
|
||||
_glfw.wl.dataOffer = id;
|
||||
wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL);
|
||||
}
|
||||
|
||||
static void dataDeviceHandleEnter(void* data,
|
||||
struct wl_data_device* dataDevice,
|
||||
uint32_t serial,
|
||||
struct wl_surface *surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y,
|
||||
struct wl_data_offer *id)
|
||||
{
|
||||
}
|
||||
|
||||
static void dataDeviceHandleLeave(void* data,
|
||||
struct wl_data_device* dataDevice)
|
||||
{
|
||||
}
|
||||
|
||||
static void dataDeviceHandleMotion(void* data,
|
||||
struct wl_data_device* dataDevice,
|
||||
uint32_t time,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y)
|
||||
{
|
||||
}
|
||||
|
||||
static void dataDeviceHandleDrop(void* data,
|
||||
struct wl_data_device* dataDevice)
|
||||
{
|
||||
}
|
||||
|
||||
static void dataDeviceHandleSelection(void* data,
|
||||
struct wl_data_device* dataDevice,
|
||||
struct wl_data_offer* id)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_data_device_listener dataDeviceListener = {
|
||||
dataDeviceHandleDataOffer,
|
||||
dataDeviceHandleEnter,
|
||||
dataDeviceHandleLeave,
|
||||
dataDeviceHandleMotion,
|
||||
dataDeviceHandleDrop,
|
||||
dataDeviceHandleSelection,
|
||||
};
|
||||
|
||||
static void wmBaseHandlePing(void* data,
|
||||
static void wmBaseHandlePing(void* userData,
|
||||
struct xdg_wm_base* wmBase,
|
||||
uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(wmBase, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener wmBaseListener = {
|
||||
static const struct xdg_wm_base_listener wmBaseListener =
|
||||
{
|
||||
wmBaseHandlePing
|
||||
};
|
||||
|
||||
static void registryHandleGlobal(void* data,
|
||||
static void registryHandleGlobal(void* userData,
|
||||
struct wl_registry* registry,
|
||||
uint32_t name,
|
||||
const char* interface,
|
||||
@ -788,7 +100,7 @@ static void registryHandleGlobal(void* data,
|
||||
{
|
||||
if (strcmp(interface, "wl_compositor") == 0)
|
||||
{
|
||||
_glfw.wl.compositorVersion = min(3, version);
|
||||
_glfw.wl.compositorVersion = _glfw_min(3, version);
|
||||
_glfw.wl.compositor =
|
||||
wl_registry_bind(registry, name, &wl_compositor_interface,
|
||||
_glfw.wl.compositorVersion);
|
||||
@ -811,11 +123,11 @@ static void registryHandleGlobal(void* data,
|
||||
{
|
||||
if (!_glfw.wl.seat)
|
||||
{
|
||||
_glfw.wl.seatVersion = min(4, version);
|
||||
_glfw.wl.seatVersion = _glfw_min(4, version);
|
||||
_glfw.wl.seat =
|
||||
wl_registry_bind(registry, name, &wl_seat_interface,
|
||||
_glfw.wl.seatVersion);
|
||||
wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
|
||||
_glfwAddSeatListenerWayland(_glfw.wl.seat);
|
||||
}
|
||||
}
|
||||
else if (strcmp(interface, "wl_data_device_manager") == 0)
|
||||
@ -868,7 +180,7 @@ static void registryHandleGlobal(void* data,
|
||||
}
|
||||
}
|
||||
|
||||
static void registryHandleGlobalRemove(void *data,
|
||||
static void registryHandleGlobalRemove(void* userData,
|
||||
struct wl_registry* registry,
|
||||
uint32_t name)
|
||||
{
|
||||
@ -886,7 +198,8 @@ static void registryHandleGlobalRemove(void *data,
|
||||
}
|
||||
|
||||
|
||||
static const struct wl_registry_listener registryListener = {
|
||||
static const struct wl_registry_listener registryListener =
|
||||
{
|
||||
registryHandleGlobal,
|
||||
registryHandleGlobalRemove
|
||||
};
|
||||
@ -1121,7 +434,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
|
||||
if (platformID == GLFW_PLATFORM_WAYLAND)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to open libwayland-client");
|
||||
"Wayland: Failed to load libwayland-client");
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
@ -1226,7 +539,7 @@ int _glfwInitWayland(void)
|
||||
if (!_glfw.wl.cursor.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to open libwayland-cursor");
|
||||
"Wayland: Failed to load libwayland-cursor");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
@ -1243,7 +556,7 @@ int _glfwInitWayland(void)
|
||||
if (!_glfw.wl.egl.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to open libwayland-egl");
|
||||
"Wayland: Failed to load libwayland-egl");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
@ -1258,7 +571,7 @@ int _glfwInitWayland(void)
|
||||
if (!_glfw.wl.xkb.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to open libxkbcommon");
|
||||
"Wayland: Failed to load libxkbcommon");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
@ -1350,7 +663,7 @@ int _glfwInitWayland(void)
|
||||
if (!_glfw.wl.cursorTheme)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Unable to load default cursor theme");
|
||||
"Wayland: Failed to load default cursor theme");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
// If this happens to be NULL, we just fallback to the scale=1 version.
|
||||
@ -1366,15 +679,7 @@ int _glfwInitWayland(void)
|
||||
_glfw.wl.dataDevice =
|
||||
wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
|
||||
_glfw.wl.seat);
|
||||
wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
|
||||
_glfw.wl.clipboardString = _glfw_calloc(4096, 1);
|
||||
if (!_glfw.wl.clipboardString)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Unable to allocate clipboard memory");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
_glfw.wl.clipboardSize = 4096;
|
||||
_glfwAddDataDeviceListenerWayland(_glfw.wl.dataDevice);
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
@ -1383,6 +688,8 @@ int _glfwInitWayland(void)
|
||||
void _glfwTerminateWayland(void)
|
||||
{
|
||||
_glfwTerminateEGL();
|
||||
_glfwTerminateOSMesa();
|
||||
|
||||
if (_glfw.wl.egl.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.wl.egl.handle);
|
||||
@ -1413,6 +720,11 @@ void _glfwTerminateWayland(void)
|
||||
_glfw.wl.cursor.handle = NULL;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
||||
wl_data_offer_destroy(_glfw.wl.offers[i].offer);
|
||||
|
||||
_glfw_free(_glfw.wl.offers);
|
||||
|
||||
if (_glfw.wl.cursorSurface)
|
||||
wl_surface_destroy(_glfw.wl.cursorSurface);
|
||||
if (_glfw.wl.subcompositor)
|
||||
@ -1427,12 +739,14 @@ void _glfwTerminateWayland(void)
|
||||
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
|
||||
if (_glfw.wl.wmBase)
|
||||
xdg_wm_base_destroy(_glfw.wl.wmBase);
|
||||
if (_glfw.wl.dataSource)
|
||||
wl_data_source_destroy(_glfw.wl.dataSource);
|
||||
if (_glfw.wl.selectionOffer)
|
||||
wl_data_offer_destroy(_glfw.wl.selectionOffer);
|
||||
if (_glfw.wl.dragOffer)
|
||||
wl_data_offer_destroy(_glfw.wl.dragOffer);
|
||||
if (_glfw.wl.selectionSource)
|
||||
wl_data_source_destroy(_glfw.wl.selectionSource);
|
||||
if (_glfw.wl.dataDevice)
|
||||
wl_data_device_destroy(_glfw.wl.dataDevice);
|
||||
if (_glfw.wl.dataOffer)
|
||||
wl_data_offer_destroy(_glfw.wl.dataOffer);
|
||||
if (_glfw.wl.dataDeviceManager)
|
||||
wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
|
||||
if (_glfw.wl.pointer)
|
||||
@ -1460,9 +774,6 @@ void _glfwTerminateWayland(void)
|
||||
if (_glfw.wl.cursorTimerfd >= 0)
|
||||
close(_glfw.wl.cursorTimerfd);
|
||||
|
||||
if (_glfw.wl.clipboardString)
|
||||
_glfw_free(_glfw.wl.clipboardString);
|
||||
if (_glfw.wl.clipboardSendString)
|
||||
_glfw_free(_glfw.wl.clipboardSendString);
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "wayland-client-protocol.h"
|
||||
|
||||
|
||||
static void outputHandleGeometry(void* data,
|
||||
static void outputHandleGeometry(void* userData,
|
||||
struct wl_output* output,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
@ -48,7 +48,7 @@ static void outputHandleGeometry(void* data,
|
||||
const char* model,
|
||||
int32_t transform)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
struct _GLFWmonitor* monitor = userData;
|
||||
|
||||
monitor->wl.x = x;
|
||||
monitor->wl.y = y;
|
||||
@ -58,14 +58,14 @@ static void outputHandleGeometry(void* data,
|
||||
snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model);
|
||||
}
|
||||
|
||||
static void outputHandleMode(void* data,
|
||||
static void outputHandleMode(void* userData,
|
||||
struct wl_output* output,
|
||||
uint32_t flags,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t refresh)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
struct _GLFWmonitor* monitor = userData;
|
||||
GLFWvidmode mode;
|
||||
|
||||
mode.width = width;
|
||||
@ -84,9 +84,9 @@ static void outputHandleMode(void* data,
|
||||
monitor->wl.currentMode = monitor->modeCount - 1;
|
||||
}
|
||||
|
||||
static void outputHandleDone(void* data, struct wl_output* output)
|
||||
static void outputHandleDone(void* userData, struct wl_output* output)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
struct _GLFWmonitor* monitor = userData;
|
||||
|
||||
if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
|
||||
{
|
||||
@ -99,16 +99,17 @@ static void outputHandleDone(void* data, struct wl_output* output)
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||
}
|
||||
|
||||
static void outputHandleScale(void* data,
|
||||
static void outputHandleScale(void* userData,
|
||||
struct wl_output* output,
|
||||
int32_t factor)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
struct _GLFWmonitor* monitor = userData;
|
||||
|
||||
monitor->wl.scale = factor;
|
||||
}
|
||||
|
||||
static const struct wl_output_listener outputListener = {
|
||||
static const struct wl_output_listener outputListener =
|
||||
{
|
||||
outputHandleGeometry,
|
||||
outputHandleMode,
|
||||
outputHandleDone,
|
||||
|
@ -43,6 +43,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWa
|
||||
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
|
||||
|
||||
#include "xkb_unicode.h"
|
||||
#include "posix_poll.h"
|
||||
|
||||
typedef int (* PFN_wl_display_flush)(struct wl_display* display);
|
||||
typedef void (* PFN_wl_display_cancel_read)(struct wl_display* display);
|
||||
@ -218,6 +219,13 @@ typedef struct _GLFWdecorationWayland
|
||||
struct wp_viewport* viewport;
|
||||
} _GLFWdecorationWayland;
|
||||
|
||||
typedef struct _GLFWofferWayland
|
||||
{
|
||||
struct wl_data_offer* offer;
|
||||
GLFWbool text_plain_utf8;
|
||||
GLFWbool text_uri_list;
|
||||
} _GLFWofferWayland;
|
||||
|
||||
// Wayland-specific per-window data
|
||||
//
|
||||
typedef struct _GLFWwindowWayland
|
||||
@ -280,8 +288,6 @@ typedef struct _GLFWlibraryWayland
|
||||
struct wl_keyboard* keyboard;
|
||||
struct wl_data_device_manager* dataDeviceManager;
|
||||
struct wl_data_device* dataDevice;
|
||||
struct wl_data_offer* dataOffer;
|
||||
struct wl_data_source* dataSource;
|
||||
struct xdg_wm_base* wmBase;
|
||||
struct zxdg_decoration_manager_v1* decorationManager;
|
||||
struct wp_viewporter* viewporter;
|
||||
@ -289,6 +295,16 @@ typedef struct _GLFWlibraryWayland
|
||||
struct zwp_pointer_constraints_v1* pointerConstraints;
|
||||
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
|
||||
|
||||
_GLFWofferWayland* offers;
|
||||
unsigned int offerCount;
|
||||
|
||||
struct wl_data_offer* selectionOffer;
|
||||
struct wl_data_source* selectionSource;
|
||||
|
||||
struct wl_data_offer* dragOffer;
|
||||
_GLFWwindow* dragFocus;
|
||||
uint32_t dragSerial;
|
||||
|
||||
int compositorVersion;
|
||||
int seatVersion;
|
||||
|
||||
@ -305,9 +321,6 @@ typedef struct _GLFWlibraryWayland
|
||||
int keyboardLastKey;
|
||||
int keyboardLastScancode;
|
||||
char* clipboardString;
|
||||
size_t clipboardSize;
|
||||
char* clipboardSendString;
|
||||
size_t clipboardSendSize;
|
||||
int timerfd;
|
||||
short int keycodes[256];
|
||||
short int scancodes[GLFW_KEY_LAST + 1];
|
||||
@ -497,3 +510,6 @@ void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
|
||||
void _glfwAddOutputWayland(uint32_t name, uint32_t version);
|
||||
GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode);
|
||||
|
||||
void _glfwAddSeatListenerWayland(struct wl_seat* seat);
|
||||
void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);
|
||||
|
||||
|
1213
src/wl_window.c
1213
src/wl_window.c
File diff suppressed because it is too large
Load Diff
@ -35,6 +35,8 @@
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
// Translate the X11 KeySyms for a key to a GLFW key code
|
||||
@ -601,7 +603,7 @@ static void detectEWMH(void)
|
||||
//
|
||||
static GLFWbool initExtensions(void)
|
||||
{
|
||||
#if defined(__OpenBSD__)
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so");
|
||||
#else
|
||||
_glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so.1");
|
||||
@ -625,7 +627,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi-6.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so");
|
||||
#else
|
||||
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so.6");
|
||||
@ -657,7 +659,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so");
|
||||
#else
|
||||
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2");
|
||||
@ -751,7 +753,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so");
|
||||
#else
|
||||
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1");
|
||||
@ -774,7 +776,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so");
|
||||
#else
|
||||
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1");
|
||||
@ -829,7 +831,7 @@ static GLFWbool initExtensions(void)
|
||||
{
|
||||
#if defined(__CYGWIN__)
|
||||
_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");
|
||||
#else
|
||||
_glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1");
|
||||
@ -844,7 +846,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so");
|
||||
#else
|
||||
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1");
|
||||
@ -873,7 +875,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext-6.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so");
|
||||
#else
|
||||
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6");
|
||||
@ -1042,6 +1044,37 @@ static Window createHelperWindow(void)
|
||||
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
|
||||
//
|
||||
static int errorHandler(Display *display, XErrorEvent* event)
|
||||
@ -1221,7 +1254,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
void* module = _glfwPlatformLoadModule("libX11-6.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
void* module = _glfwPlatformLoadModule("libX11.so");
|
||||
#else
|
||||
void* module = _glfwPlatformLoadModule("libX11.so.6");
|
||||
@ -1491,6 +1524,9 @@ int _glfwInitX11(void)
|
||||
|
||||
getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY);
|
||||
|
||||
if (!createEmptyEventPipe())
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!initExtensions())
|
||||
return GLFW_FALSE;
|
||||
|
||||
@ -1594,6 +1630,7 @@ void _glfwTerminateX11(void)
|
||||
_glfw.x11.xi.handle = NULL;
|
||||
}
|
||||
|
||||
_glfwTerminateOSMesa();
|
||||
// NOTE: These need to be unloaded after XCloseDisplay, as they register
|
||||
// cleanup callbacks that get called by that function
|
||||
_glfwTerminateEGL();
|
||||
@ -1604,5 +1641,11 @@ void _glfwTerminateX11(void)
|
||||
_glfwPlatformFreeModule(_glfw.x11.xlib.handle);
|
||||
_glfw.x11.xlib.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1])
|
||||
{
|
||||
close(_glfw.x11.emptyEventPipe[0]);
|
||||
close(_glfw.x11.emptyEventPipe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
#include "xkb_unicode.h"
|
||||
#include "posix_poll.h"
|
||||
|
||||
#define GLFW_X11_WINDOW_STATE _GLFWwindowX11 x11;
|
||||
#define GLFW_X11_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11;
|
||||
@ -582,6 +583,7 @@ typedef struct _GLFWlibraryX11
|
||||
double restoreCursorPosX, restoreCursorPosY;
|
||||
// The window whose disabled cursor mode is active
|
||||
_GLFWwindow* disabledCursorWindow;
|
||||
int emptyEventPipe[2];
|
||||
|
||||
// Window manager atoms
|
||||
Atom NET_SUPPORTED;
|
||||
|
235
src/x11_window.c
235
src/x11_window.c
@ -32,7 +32,7 @@
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/Xmd.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@ -56,51 +56,80 @@
|
||||
|
||||
#define _GLFW_XDND_VERSION 5
|
||||
|
||||
|
||||
// Wait for data to arrive using select
|
||||
// Wait for event data to arrive on the X11 display socket
|
||||
// This avoids blocking other threads via the per-display Xlib lock that also
|
||||
// covers GLX functions
|
||||
//
|
||||
static GLFWbool waitForEvent(double* timeout)
|
||||
static GLFWbool waitForX11Event(double* timeout)
|
||||
{
|
||||
fd_set fds;
|
||||
const int fd = ConnectionNumber(_glfw.x11.display);
|
||||
int count = fd + 1;
|
||||
struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN };
|
||||
|
||||
#if defined(__linux__)
|
||||
if (_glfw.linjs.inotify > fd)
|
||||
count = _glfw.linjs.inotify + 1;
|
||||
#endif
|
||||
for (;;)
|
||||
while (!XPending(_glfw.x11.display))
|
||||
{
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
#if defined(__linux__)
|
||||
if (_glfw.linjs.inotify > 0)
|
||||
FD_SET(_glfw.linjs.inotify, &fds);
|
||||
#endif
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
const long seconds = (long) *timeout;
|
||||
const long microseconds = (long) ((*timeout - seconds) * 1e6);
|
||||
struct timeval tv = { seconds, microseconds };
|
||||
const uint64_t base = _glfwPlatformGetTimerValue();
|
||||
|
||||
const int result = select(count, &fds, NULL, NULL, &tv);
|
||||
const int error = errno;
|
||||
|
||||
*timeout -= (_glfwPlatformGetTimerValue() - base) /
|
||||
(double) _glfwPlatformGetTimerFrequency();
|
||||
|
||||
if (result > 0)
|
||||
return GLFW_TRUE;
|
||||
if ((result == -1 && error == EINTR) || *timeout <= 0.0)
|
||||
if (!_glfwPollPOSIX(&fd, 1, timeout))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Wait for event data to arrive on any event file descriptor
|
||||
// This avoids blocking other threads via the per-display Xlib lock that also
|
||||
// covers GLX functions
|
||||
//
|
||||
static GLFWbool waitForAnyEvent(double* timeout)
|
||||
{
|
||||
nfds_t count = 2;
|
||||
struct pollfd fds[3] =
|
||||
{
|
||||
{ ConnectionNumber(_glfw.x11.display), POLLIN },
|
||||
{ _glfw.x11.emptyEventPipe[0], POLLIN }
|
||||
};
|
||||
|
||||
#if defined(__linux__)
|
||||
if (_glfw.joysticksInitialized)
|
||||
fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
|
||||
#endif
|
||||
|
||||
while (!XPending(_glfw.x11.display))
|
||||
{
|
||||
if (!_glfwPollPOSIX(fds, count, timeout))
|
||||
return GLFW_FALSE;
|
||||
|
||||
for (int i = 1; i < count; i++)
|
||||
{
|
||||
if (fds[i].revents & POLLIN)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Writes a byte to the empty event pipe
|
||||
//
|
||||
static void writeEmptyEvent(void)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const char byte = 0;
|
||||
const ssize_t result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);
|
||||
if (result == 1 || (result == -1 && errno != EINTR))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Drains available data from the empty event pipe
|
||||
//
|
||||
static void drainEmptyEvents(void)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
char dummy[64];
|
||||
const ssize_t result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));
|
||||
if (result == -1 && errno != EINTR)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Waits until a VisibilityNotify event arrives for the specified window or the
|
||||
@ -116,7 +145,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
|
||||
VisibilityNotify,
|
||||
&dummy))
|
||||
{
|
||||
if (!waitForEvent(&timeout))
|
||||
if (!waitForX11Event(&timeout))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
@ -378,57 +407,6 @@ static void updateWindowMode(_GLFWwindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
// Splits and translates a text/uri-list into separate file paths
|
||||
// NOTE: This function destroys the provided string
|
||||
//
|
||||
static char** parseUriList(char* text, int* count)
|
||||
{
|
||||
const char* prefix = "file://";
|
||||
char** paths = NULL;
|
||||
char* line;
|
||||
|
||||
*count = 0;
|
||||
|
||||
while ((line = strtok(text, "\r\n")))
|
||||
{
|
||||
text = NULL;
|
||||
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
||||
{
|
||||
line += strlen(prefix);
|
||||
// TODO: Validate hostname
|
||||
while (*line != '/')
|
||||
line++;
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
|
||||
char* path = _glfw_calloc(strlen(line) + 1, 1);
|
||||
paths = _glfw_realloc(paths, *count * sizeof(char*));
|
||||
paths[*count - 1] = path;
|
||||
|
||||
while (*line)
|
||||
{
|
||||
if (line[0] == '%' && line[1] && line[2])
|
||||
{
|
||||
const char digits[3] = { line[1], line[2], '\0' };
|
||||
*path = strtol(digits, NULL, 16);
|
||||
line += 2;
|
||||
}
|
||||
else
|
||||
*path = *line;
|
||||
|
||||
path++;
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
// Decode a Unicode code point from a UTF-8 stream
|
||||
// Based on cutef8 by Jeff Bezanson (Public Domain)
|
||||
//
|
||||
@ -887,20 +865,6 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
|
||||
return None;
|
||||
}
|
||||
|
||||
static void handleSelectionClear(XEvent* event)
|
||||
{
|
||||
if (event->xselectionclear.selection == _glfw.x11.PRIMARY)
|
||||
{
|
||||
_glfw_free(_glfw.x11.primarySelectionString);
|
||||
_glfw.x11.primarySelectionString = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfw_free(_glfw.x11.clipboardString);
|
||||
_glfw.x11.clipboardString = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleSelectionRequest(XEvent* event)
|
||||
{
|
||||
const XSelectionRequestEvent* request = &event->xselectionrequest;
|
||||
@ -958,7 +922,7 @@ static const char* getSelectionString(Atom selection)
|
||||
SelectionNotify,
|
||||
¬ification))
|
||||
{
|
||||
waitForEvent(NULL);
|
||||
waitForX11Event(NULL);
|
||||
}
|
||||
|
||||
if (notification.xselection.property == None)
|
||||
@ -994,7 +958,7 @@ static const char* getSelectionString(Atom selection)
|
||||
isSelPropNewValueNotify,
|
||||
(XPointer) ¬ification))
|
||||
{
|
||||
waitForEvent(NULL);
|
||||
waitForX11Event(NULL);
|
||||
}
|
||||
|
||||
XFree(data);
|
||||
@ -1020,6 +984,8 @@ static const char* getSelectionString(Atom selection)
|
||||
}
|
||||
|
||||
if (!itemCount)
|
||||
{
|
||||
if (string)
|
||||
{
|
||||
if (targets[i] == XA_STRING)
|
||||
{
|
||||
@ -1028,6 +994,7 @@ static const char* getSelectionString(Atom selection)
|
||||
}
|
||||
else
|
||||
*selectionString = string;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1193,12 +1160,7 @@ static void processEvent(XEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->type == SelectionClear)
|
||||
{
|
||||
handleSelectionClear(event);
|
||||
return;
|
||||
}
|
||||
else if (event->type == SelectionRequest)
|
||||
if (event->type == SelectionRequest)
|
||||
{
|
||||
handleSelectionRequest(event);
|
||||
return;
|
||||
@ -1238,7 +1200,7 @@ static void processEvent(XEvent *event)
|
||||
// (the server never sends a timestamp of zero)
|
||||
// NOTE: Timestamp difference is compared to handle wrap-around
|
||||
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)
|
||||
_glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
|
||||
@ -1686,7 +1648,7 @@ static void processEvent(XEvent *event)
|
||||
if (result)
|
||||
{
|
||||
int count;
|
||||
char** paths = parseUriList(data, &count);
|
||||
char** paths = _glfwParseUriList(data, &count);
|
||||
|
||||
_glfwInputDrop(window, count, (const char**) paths);
|
||||
|
||||
@ -1875,10 +1837,6 @@ void _glfwPushSelectionToManagerX11(void)
|
||||
handleSelectionRequest(&event);
|
||||
break;
|
||||
|
||||
case SelectionClear:
|
||||
handleSelectionClear(&event);
|
||||
break;
|
||||
|
||||
case SelectionNotify:
|
||||
{
|
||||
if (event.xselection.target == _glfw.x11.SAVE_TARGETS)
|
||||
@ -1896,7 +1854,7 @@ void _glfwPushSelectionToManagerX11(void)
|
||||
}
|
||||
}
|
||||
|
||||
waitForEvent(NULL);
|
||||
waitForX11Event(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1994,13 +1952,31 @@ int _glfwCreateWindowX11(_GLFWwindow* window,
|
||||
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!_glfwRefreshContextAttribs(window, ctxconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (wndconfig->mousePassthrough)
|
||||
_glfwSetWindowMousePassthroughX11(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
_glfwShowWindowX11(window);
|
||||
updateWindowMode(window);
|
||||
acquireMonitor(window);
|
||||
|
||||
if (wndconfig->centerCursor)
|
||||
_glfwCenterCursorInContentArea(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wndconfig->visible)
|
||||
{
|
||||
_glfwShowWindowX11(window);
|
||||
if (wndconfig->focused)
|
||||
_glfwFocusWindowX11(window);
|
||||
}
|
||||
}
|
||||
|
||||
XFlush(_glfw.x11.display);
|
||||
@ -2238,7 +2214,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow* window,
|
||||
isFrameExtentsEvent,
|
||||
(XPointer) window))
|
||||
{
|
||||
if (!waitForEvent(&timeout))
|
||||
if (!waitForX11Event(&timeout))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
|
||||
@ -2744,7 +2720,7 @@ GLFWbool _glfwRawMouseMotionSupportedX11(void)
|
||||
|
||||
void _glfwPollEventsX11(void)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
drainEmptyEvents();
|
||||
|
||||
#if defined(__linux__)
|
||||
if (_glfw.joysticksInitialized)
|
||||
@ -2759,7 +2735,7 @@ void _glfwPollEventsX11(void)
|
||||
processEvent(&event);
|
||||
}
|
||||
|
||||
window = _glfw.x11.disabledCursorWindow;
|
||||
_GLFWwindow* window = _glfw.x11.disabledCursorWindow;
|
||||
if (window)
|
||||
{
|
||||
int width, height;
|
||||
@ -2779,32 +2755,19 @@ void _glfwPollEventsX11(void)
|
||||
|
||||
void _glfwWaitEventsX11(void)
|
||||
{
|
||||
while (!XPending(_glfw.x11.display))
|
||||
waitForEvent(NULL);
|
||||
|
||||
waitForAnyEvent(NULL);
|
||||
_glfwPollEventsX11();
|
||||
}
|
||||
|
||||
void _glfwWaitEventsTimeoutX11(double timeout)
|
||||
{
|
||||
while (!XPending(_glfw.x11.display))
|
||||
{
|
||||
if (!waitForEvent(&timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
waitForAnyEvent(&timeout);
|
||||
_glfwPollEventsX11();
|
||||
}
|
||||
|
||||
void _glfwPostEmptyEventX11(void)
|
||||
{
|
||||
XEvent event = { ClientMessage };
|
||||
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);
|
||||
writeEmptyEvent();
|
||||
}
|
||||
|
||||
void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
|
Loading…
Reference in New Issue
Block a user