mirror of
https://github.com/glfw/glfw.git
synced 2026-09-23 00:59:48 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 413ba1dceb | |||
| e59b5e1fda | |||
| 7c9ea95233 | |||
| abfbf07830 | |||
| 99cdcfb0a4 | |||
| 001f94eaa7 | |||
| 3f14b6feed | |||
| f0b2992b3a | |||
| b579ea6792 | |||
| a3095e1aa5 | |||
| a98badf088 | |||
| c4684b288d | |||
| 232164f62b | |||
| abb9db0d75 | |||
| 0aa77a9a3a | |||
| 7b370d8df0 | |||
| f871f14d5e | |||
| bafb134769 | |||
| 2d7ae8f2d0 | |||
| 96e0f49395 | |||
| 9352d8fe93 | |||
| a228a8b447 | |||
| dbadda2683 | |||
| 08449b7183 | |||
| 1ce855b0b1 | |||
| ebff6606ee | |||
| 162896e5b9 | |||
| 936307558e | |||
| 4df5129529 | |||
| 6de70d8252 |
+1
-5
@@ -38,11 +38,7 @@ set(GLFW_LIBRARY_TYPE "${GLFW_LIBRARY_TYPE}" CACHE STRING
|
||||
"Library type override for GLFW (SHARED, STATIC, OBJECT, or empty to follow BUILD_SHARED_LIBS)")
|
||||
|
||||
if (GLFW_LIBRARY_TYPE)
|
||||
if (GLFW_LIBRARY_TYPE STREQUAL "SHARED")
|
||||
set(GLFW_BUILD_SHARED_LIBRARY TRUE)
|
||||
else()
|
||||
set(GLFW_BUILD_SHARED_LIBRARY FALSE)
|
||||
endif()
|
||||
string(COMPARE EQUAL "${GLFW_LIBRARY_TYPE}" "SHARED" GLFW_BUILD_SHARED_LIBRARY)
|
||||
else()
|
||||
set(GLFW_BUILD_SHARED_LIBRARY ${BUILD_SHARED_LIBS})
|
||||
endif()
|
||||
|
||||
@@ -79,6 +79,7 @@ video tutorials.
|
||||
- Jason Francis
|
||||
- Gerald Franz
|
||||
- Mário Freitas
|
||||
- Friz64
|
||||
- GeO4d
|
||||
- Marcus Geelnard
|
||||
- Gegy
|
||||
@@ -162,6 +163,7 @@ video tutorials.
|
||||
- Marcel Metz
|
||||
- Liam Middlebrook
|
||||
- mightgoyardstill
|
||||
- Mihail
|
||||
- Ave Milia
|
||||
- Icyllis Milica
|
||||
- Jonathan Miller
|
||||
@@ -282,10 +284,12 @@ video tutorials.
|
||||
- Corentin Wallez
|
||||
- Torsten Walluhn
|
||||
- Patrick Walton
|
||||
- Ivor Wanders
|
||||
- Jim Wang
|
||||
- Xo Wang
|
||||
- Andre Weissflog
|
||||
- Jay Weisskopf
|
||||
- Drew Weymouth
|
||||
- Frank Wille
|
||||
- Andy Williams
|
||||
- Joel Winarske
|
||||
|
||||
@@ -144,7 +144,24 @@ information on what to include when reporting a bug.
|
||||
a modal to a fallback decoration
|
||||
- [Wayland] Bugfix: The cursor position was not updated when clicking through
|
||||
from a modal to the content area
|
||||
- [Wayland] Bugfix: free modules at end of terminate function to resolve
|
||||
potential segmentation fault (#2744)
|
||||
- [Wayland] Bugfix: Confining or disabling the cursor could segfault on
|
||||
compositors without `pointer-constraints-unstable-v1`
|
||||
- [Wayland] Bugfix: Key repeat did not function on very old compositors
|
||||
- [Wayland] Bugfix: The `libwayland-client` library was not unloaded at termination
|
||||
- [Wayland] Bugfix: Scroll events were sent twice on some versions of GNOME (#2494)
|
||||
- [Wayland] Bugfix: Two-dimensional scroll input was emitted as separate axes
|
||||
- [Wayland] Bugfix: `glfwSwapBuffers` would halt with nonzero swap interval when window
|
||||
was suspended (#1350,#2582,#2640,#2719,#2723,#2800)
|
||||
- [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631)
|
||||
- [X11] Bugfix: Occasional crash when an idle display awakes (#2766)
|
||||
- [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale
|
||||
less than 1 (#2754)
|
||||
- [X11] Bugfix: Clamp width and height to >= 1 to prevent BadValue error and app exit
|
||||
- [X11] Bugfix: Floating windows silently became non-floating when hidden (#2276)
|
||||
- [X11] Bugfix: The `libXext` library was not unloaded at termination
|
||||
- [Linux] Bugfix: The header for `ioctl` was only implicitly included (#2778)
|
||||
- [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface`
|
||||
- [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`
|
||||
- [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to
|
||||
|
||||
@@ -4520,7 +4520,8 @@ GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow*
|
||||
* GLFW will pass those events on to the application callbacks before
|
||||
* returning.
|
||||
*
|
||||
* Event processing is not required for joystick input to work.
|
||||
* Event processing is not required to receive joystick input. Joystick state
|
||||
* is polled when a joystick input or gamepad input function is called.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
@@ -4565,7 +4566,8 @@ GLFWAPI void glfwPollEvents(void);
|
||||
* GLFW will pass those events on to the application callbacks before
|
||||
* returning.
|
||||
*
|
||||
* Event processing is not required for joystick input to work.
|
||||
* Event processing is not required to receive joystick input. Joystick state
|
||||
* is polled when a joystick input or gamepad input function is called.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
@@ -4612,7 +4614,8 @@ GLFWAPI void glfwWaitEvents(void);
|
||||
* GLFW will pass those events on to the application callbacks before
|
||||
* returning.
|
||||
*
|
||||
* Event processing is not required for joystick input to work.
|
||||
* Event processing is not required to receive joystick input. Joystick state
|
||||
* is polled when a joystick input or gamepad input function is called.
|
||||
*
|
||||
* @param[in] timeout The maximum amount of time, in seconds, to wait.
|
||||
*
|
||||
|
||||
@@ -688,6 +688,8 @@ void _glfwTerminateCocoa(void)
|
||||
_glfwTerminateEGL();
|
||||
_glfwTerminateOSMesa();
|
||||
|
||||
memset(&_glfw.ns, 0, sizeof(_glfw.ns));
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -368,7 +368,12 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
window->context.getProcAddress("glGetIntegerv");
|
||||
window->context.GetString = (PFNGLGETSTRINGPROC)
|
||||
window->context.getProcAddress("glGetString");
|
||||
if (!window->context.GetIntegerv || !window->context.GetString)
|
||||
window->context.Flush = (PFNGLFLUSHPROC)
|
||||
window->context.getProcAddress("glFlush");
|
||||
|
||||
if (!window->context.GetIntegerv ||
|
||||
!window->context.GetString ||
|
||||
!window->context.Flush)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
|
||||
+43
-26
@@ -32,7 +32,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// Return a description of the specified EGL error
|
||||
//
|
||||
static const char* getEGLErrorString(EGLint error)
|
||||
@@ -254,6 +253,12 @@ static void makeContextCurrentEGL(_GLFWwindow* window)
|
||||
getEGLErrorString(eglGetError()));
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(_GLFW_WAYLAND)
|
||||
// NOTE: Disable EGL vsync so we can substitute our own that includes a timeout
|
||||
if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
|
||||
eglSwapInterval(_glfw.egl.display, 0);
|
||||
#endif // _GLFW_WAYLAND
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -287,6 +292,15 @@ static void swapBuffersEGL(_GLFWwindow* window)
|
||||
// NOTE: Swapping buffers on a hidden window on Wayland makes it visible
|
||||
if (!window->wl.visible)
|
||||
return;
|
||||
|
||||
// NOTE: We wait for a frame manually so we can add a timeout,
|
||||
// as the EGL implementation will wait indefinitely
|
||||
if (window->wl.egl.interval > 0)
|
||||
{
|
||||
window->context.Flush();
|
||||
if (!_glfwWaitForEGLFrameWayland(window))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -295,6 +309,16 @@ static void swapBuffersEGL(_GLFWwindow* window)
|
||||
|
||||
static void swapIntervalEGL(int interval)
|
||||
{
|
||||
#if defined(_GLFW_WAYLAND)
|
||||
if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
assert(window != NULL);
|
||||
window->wl.egl.interval = interval;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
eglSwapInterval(_glfw.egl.display, interval);
|
||||
}
|
||||
|
||||
@@ -311,19 +335,20 @@ static int extensionSupportedEGL(const char* extension)
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||
{
|
||||
const GLFWglproc proc = (GLFWglproc) eglGetProcAddress(procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
|
||||
if (!_glfw.egl.KHR_get_all_proc_addresses)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
assert(window != NULL);
|
||||
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
GLFWglproc proc = (GLFWglproc)
|
||||
_glfwPlatformGetModuleSymbol(window->context.egl.client, procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
return _glfwPlatformGetModuleSymbol(window->context.egl.client, procname);
|
||||
}
|
||||
|
||||
return eglGetProcAddress(procname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void destroyContextEGL(_GLFWwindow* window)
|
||||
@@ -332,13 +357,10 @@ static void destroyContextEGL(_GLFWwindow* window)
|
||||
// as it will make XCloseDisplay segfault
|
||||
if (_glfw.platform.platformID != GLFW_PLATFORM_X11 ||
|
||||
window->context.client != GLFW_OPENGL_API)
|
||||
{
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
_glfwPlatformFreeModule(window->context.egl.client);
|
||||
window->context.egl.client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (window->context.egl.surface)
|
||||
{
|
||||
@@ -358,8 +380,6 @@ static void destroyContextEGL(_GLFWwindow* window)
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize EGL
|
||||
//
|
||||
GLFWbool _glfwInitEGL(void)
|
||||
{
|
||||
int i;
|
||||
@@ -369,10 +389,10 @@ GLFWbool _glfwInitEGL(void)
|
||||
{
|
||||
#if defined(_GLFW_EGL_LIBRARY)
|
||||
_GLFW_EGL_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_WIN32)
|
||||
"libEGL.dll",
|
||||
"EGL.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
#elif defined(__APPLE__)
|
||||
"libEGL.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libEGL-1.so",
|
||||
@@ -545,8 +565,6 @@ GLFWbool _glfwInitEGL(void)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate EGL
|
||||
//
|
||||
void _glfwTerminateEGL(void)
|
||||
{
|
||||
if (_glfw.egl.display)
|
||||
@@ -555,7 +573,8 @@ void _glfwTerminateEGL(void)
|
||||
_glfw.egl.display = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
||||
if (_glfw.egl.handle)
|
||||
// Free modules only after all wayland termination functions are called
|
||||
if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.egl.handle);
|
||||
_glfw.egl.handle = NULL;
|
||||
@@ -569,8 +588,6 @@ void _glfwTerminateEGL(void)
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
// Create the OpenGL or OpenGL ES context
|
||||
//
|
||||
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
@@ -768,10 +785,10 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
{
|
||||
#if defined(_GLFW_GLESV1_LIBRARY)
|
||||
_GLFW_GLESV1_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_WIN32)
|
||||
"GLESv1_CM.dll",
|
||||
"libGLES_CM.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
#elif defined(__APPLE__)
|
||||
"libGLESv1_CM.dylib",
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGLESv1_CM.so",
|
||||
@@ -785,10 +802,10 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
{
|
||||
#if defined(_GLFW_GLESV2_LIBRARY)
|
||||
_GLFW_GLESV2_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_WIN32)
|
||||
"GLESv2.dll",
|
||||
"libGLESv2.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
#elif defined(__APPLE__)
|
||||
"libGLESv2.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libGLESv2-2.so",
|
||||
@@ -803,8 +820,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
{
|
||||
#if defined(_GLFW_OPENGL_LIBRARY)
|
||||
_GLFW_OPENGL_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_GLFW_COCOA)
|
||||
#elif defined(_WIN32)
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGL.so",
|
||||
#else
|
||||
|
||||
@@ -253,8 +253,6 @@ static void destroyContextGLX(_GLFWwindow* window)
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize GLX
|
||||
//
|
||||
GLFWbool _glfwInitGLX(void)
|
||||
{
|
||||
const char* sonames[] =
|
||||
@@ -426,19 +424,14 @@ GLFWbool _glfwInitGLX(void)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate GLX
|
||||
//
|
||||
void _glfwTerminateGLX(void)
|
||||
{
|
||||
// NOTE: This function must not call any X11 functions, as it is called
|
||||
// after XCloseDisplay (see _glfwTerminateX11 for details)
|
||||
|
||||
if (_glfw.glx.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.glx.handle);
|
||||
_glfw.glx.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define SET_ATTRIB(a, v) \
|
||||
{ \
|
||||
@@ -447,8 +440,6 @@ void _glfwTerminateGLX(void)
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
// Create the OpenGL or OpenGL ES context
|
||||
//
|
||||
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
|
||||
@@ -109,6 +109,7 @@ typedef void (APIENTRY * PFNGLCLEARPROC)(GLbitfield);
|
||||
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum);
|
||||
typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*);
|
||||
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint);
|
||||
typedef void (APIENTRY * PFNGLFLUSHPROC)(void);
|
||||
|
||||
#define EGL_SUCCESS 0x3000
|
||||
#define EGL_NOT_INITIALIZED 0x3001
|
||||
@@ -498,6 +499,7 @@ struct _GLFWcontext
|
||||
PFNGLGETSTRINGIPROC GetStringi;
|
||||
PFNGLGETINTEGERVPROC GetIntegerv;
|
||||
PFNGLGETSTRINGPROC GetString;
|
||||
PFNGLFLUSHPROC Flush;
|
||||
|
||||
void (*makeCurrent)(_GLFWwindow*);
|
||||
void (*swapBuffers)(_GLFWwindow*);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
|
||||
@@ -128,8 +128,6 @@ static void destroyContextNSGL(_GLFWwindow* window)
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize OpenGL support
|
||||
//
|
||||
GLFWbool _glfwInitNSGL(void)
|
||||
{
|
||||
if (_glfw.nsgl.framework)
|
||||
@@ -147,14 +145,10 @@ GLFWbool _glfwInitNSGL(void)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate OpenGL support
|
||||
//
|
||||
void _glfwTerminateNSGL(void)
|
||||
{
|
||||
}
|
||||
|
||||
// Create the OpenGL context
|
||||
//
|
||||
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
|
||||
@@ -260,5 +260,6 @@ void _glfwTerminateNull(void)
|
||||
free(_glfw.null.clipboardString);
|
||||
_glfwTerminateOSMesa();
|
||||
_glfwTerminateEGL();
|
||||
memset(&_glfw.null, 0, sizeof(_glfw.null));
|
||||
}
|
||||
|
||||
|
||||
@@ -179,13 +179,10 @@ GLFWbool _glfwInitOSMesa(void)
|
||||
}
|
||||
|
||||
void _glfwTerminateOSMesa(void)
|
||||
{
|
||||
if (_glfw.osmesa.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.osmesa.handle);
|
||||
_glfw.osmesa.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define SET_ATTRIB(a, v) \
|
||||
{ \
|
||||
|
||||
@@ -41,6 +41,7 @@ void* _glfwPlatformLoadModule(const char* path)
|
||||
|
||||
void _glfwPlatformFreeModule(void* module)
|
||||
{
|
||||
if (module)
|
||||
dlclose(module);
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -55,12 +55,13 @@ GLFWbool _glfwInitVulkan(int mode)
|
||||
{
|
||||
#if defined(_GLFW_VULKAN_LIBRARY)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY);
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_WIN32)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll");
|
||||
#elif defined(_GLFW_COCOA)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
|
||||
if (!_glfw.vk.handle)
|
||||
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so");
|
||||
#else
|
||||
@@ -157,8 +158,8 @@ GLFWbool _glfwInitVulkan(int mode)
|
||||
|
||||
void _glfwTerminateVulkan(void)
|
||||
{
|
||||
if (_glfw.vk.handle)
|
||||
_glfwPlatformFreeModule(_glfw.vk.handle);
|
||||
_glfw.vk.handle = NULL;
|
||||
}
|
||||
|
||||
const char* _glfwGetVulkanResultString(VkResult result)
|
||||
|
||||
+1
-7
@@ -401,8 +401,6 @@ static void destroyContextWGL(_GLFWwindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize WGL
|
||||
//
|
||||
GLFWbool _glfwInitWGL(void)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
@@ -521,12 +519,10 @@ GLFWbool _glfwInitWGL(void)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate WGL
|
||||
//
|
||||
void _glfwTerminateWGL(void)
|
||||
{
|
||||
if (_glfw.wgl.instance)
|
||||
_glfwPlatformFreeModule(_glfw.wgl.instance);
|
||||
_glfw.wgl.instance = NULL;
|
||||
}
|
||||
|
||||
#define SET_ATTRIB(a, v) \
|
||||
@@ -536,8 +532,6 @@ void _glfwTerminateWGL(void)
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
// Create the OpenGL or OpenGL ES context
|
||||
//
|
||||
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
|
||||
+10
-25
@@ -166,29 +166,6 @@ static GLFWbool loadLibraries(void)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Unload used libraries (DLLs)
|
||||
//
|
||||
static void freeLibraries(void)
|
||||
{
|
||||
if (_glfw.win32.xinput.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.xinput.instance);
|
||||
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.dinput8.instance);
|
||||
|
||||
if (_glfw.win32.user32.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.user32.instance);
|
||||
|
||||
if (_glfw.win32.dwmapi.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.dwmapi.instance);
|
||||
|
||||
if (_glfw.win32.shcore.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.shcore.instance);
|
||||
|
||||
if (_glfw.win32.ntdll.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
//
|
||||
static void createKeyTables(void)
|
||||
@@ -528,7 +505,8 @@ void _glfwUpdateKeyNamesWin32(void)
|
||||
|
||||
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD)
|
||||
{
|
||||
const UINT vks[] = {
|
||||
const UINT vks[] =
|
||||
{
|
||||
VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
|
||||
VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
|
||||
VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE,
|
||||
@@ -720,7 +698,14 @@ void _glfwTerminateWin32(void)
|
||||
_glfwTerminateEGL();
|
||||
_glfwTerminateOSMesa();
|
||||
|
||||
freeLibraries();
|
||||
_glfwPlatformFreeModule(_glfw.win32.xinput.instance);
|
||||
_glfwPlatformFreeModule(_glfw.win32.dinput8.instance);
|
||||
_glfwPlatformFreeModule(_glfw.win32.user32.instance);
|
||||
_glfwPlatformFreeModule(_glfw.win32.dwmapi.instance);
|
||||
_glfwPlatformFreeModule(_glfw.win32.shcore.instance);
|
||||
_glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
|
||||
|
||||
memset(&_glfw.win32, 0, sizeof(_glfw.win32));
|
||||
}
|
||||
|
||||
#endif // _GLFW_WIN32
|
||||
|
||||
@@ -39,6 +39,7 @@ void* _glfwPlatformLoadModule(const char* path)
|
||||
|
||||
void _glfwPlatformFreeModule(void* module)
|
||||
{
|
||||
if (module)
|
||||
FreeLibrary((HMODULE) module);
|
||||
}
|
||||
|
||||
|
||||
+45
-32
@@ -135,15 +135,8 @@ static void registryHandleGlobal(void* userData,
|
||||
{
|
||||
_glfw.wl.seat =
|
||||
wl_registry_bind(registry, name, &wl_seat_interface,
|
||||
_glfw_min(4, version));
|
||||
_glfw_min(5, version));
|
||||
_glfwAddSeatListenerWayland(_glfw.wl.seat);
|
||||
|
||||
if (wl_seat_get_version(_glfw.wl.seat) >=
|
||||
WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
|
||||
{
|
||||
_glfw.wl.keyRepeatTimerfd =
|
||||
timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp(interface, "wl_data_device_manager") == 0)
|
||||
@@ -585,6 +578,14 @@ int _glfwInitWayland(void)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_get_fd");
|
||||
_glfw.wl.client.display_prepare_read = (PFN_wl_display_prepare_read)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_prepare_read");
|
||||
_glfw.wl.client.display_create_queue = (PFN_wl_display_create_queue)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_create_queue");
|
||||
_glfw.wl.client.display_prepare_read_queue = (PFN_wl_display_prepare_read_queue)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_prepare_read_queue");
|
||||
_glfw.wl.client.display_dispatch_queue_pending = (PFN_wl_display_dispatch_queue_pending)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_dispatch_queue_pending");
|
||||
_glfw.wl.client.event_queue_destroy = (PFN_wl_event_queue_destroy)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_event_queue_destroy");
|
||||
_glfw.wl.client.proxy_marshal = (PFN_wl_proxy_marshal)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal");
|
||||
_glfw.wl.client.proxy_add_listener = (PFN_wl_proxy_add_listener)
|
||||
@@ -607,6 +608,12 @@ int _glfwInitWayland(void)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_version");
|
||||
_glfw.wl.client.proxy_marshal_flags = (PFN_wl_proxy_marshal_flags)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal_flags");
|
||||
_glfw.wl.client.proxy_create_wrapper = (PFN_wl_proxy_create_wrapper)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_create_wrapper");
|
||||
_glfw.wl.client.proxy_wrapper_destroy = (PFN_wl_proxy_wrapper_destroy)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_wrapper_destroy");
|
||||
_glfw.wl.client.proxy_set_queue = (PFN_wl_proxy_set_queue)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_queue");
|
||||
|
||||
if (!_glfw.wl.client.display_flush ||
|
||||
!_glfw.wl.client.display_cancel_read ||
|
||||
@@ -616,6 +623,10 @@ int _glfwInitWayland(void)
|
||||
!_glfw.wl.client.display_roundtrip ||
|
||||
!_glfw.wl.client.display_get_fd ||
|
||||
!_glfw.wl.client.display_prepare_read ||
|
||||
!_glfw.wl.client.display_create_queue ||
|
||||
!_glfw.wl.client.display_prepare_read_queue ||
|
||||
!_glfw.wl.client.display_dispatch_queue_pending ||
|
||||
!_glfw.wl.client.event_queue_destroy ||
|
||||
!_glfw.wl.client.proxy_marshal ||
|
||||
!_glfw.wl.client.proxy_add_listener ||
|
||||
!_glfw.wl.client.proxy_destroy ||
|
||||
@@ -624,7 +635,10 @@ int _glfwInitWayland(void)
|
||||
!_glfw.wl.client.proxy_get_user_data ||
|
||||
!_glfw.wl.client.proxy_set_user_data ||
|
||||
!_glfw.wl.client.proxy_get_tag ||
|
||||
!_glfw.wl.client.proxy_set_tag)
|
||||
!_glfw.wl.client.proxy_set_tag ||
|
||||
!_glfw.wl.client.proxy_create_wrapper ||
|
||||
!_glfw.wl.client.proxy_wrapper_destroy ||
|
||||
!_glfw.wl.client.proxy_set_queue)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to load libwayland-client entry point");
|
||||
@@ -834,7 +848,17 @@ int _glfwInitWayland(void)
|
||||
|
||||
createKeyTables();
|
||||
|
||||
_glfw.wl.xkb.context = xkb_context_new(0);
|
||||
_glfw.wl.keyRepeatTimerfd =
|
||||
timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
if (_glfw.wl.keyRepeatTimerfd == -1)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to create timerfd: %s",
|
||||
strerror(errno));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.wl.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!_glfw.wl.xkb.context)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
@@ -907,18 +931,6 @@ void _glfwTerminateWayland(void)
|
||||
libdecor_unref(_glfw.wl.libdecor.context);
|
||||
}
|
||||
|
||||
if (_glfw.wl.libdecor.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
|
||||
_glfw.wl.libdecor.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.wl.egl.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.wl.egl.handle);
|
||||
_glfw.wl.egl.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.wl.xkb.composeState)
|
||||
xkb_compose_state_unref(_glfw.wl.xkb.composeState);
|
||||
if (_glfw.wl.xkb.keymap)
|
||||
@@ -927,21 +939,11 @@ void _glfwTerminateWayland(void)
|
||||
xkb_state_unref(_glfw.wl.xkb.state);
|
||||
if (_glfw.wl.xkb.context)
|
||||
xkb_context_unref(_glfw.wl.xkb.context);
|
||||
if (_glfw.wl.xkb.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.wl.xkb.handle);
|
||||
_glfw.wl.xkb.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.wl.cursorTheme)
|
||||
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
|
||||
if (_glfw.wl.cursorThemeHiDPI)
|
||||
wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);
|
||||
if (_glfw.wl.cursor.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.wl.cursor.handle);
|
||||
_glfw.wl.cursor.handle = NULL;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
||||
wl_data_offer_destroy(_glfw.wl.offers[i].offer);
|
||||
@@ -1001,7 +1003,18 @@ void _glfwTerminateWayland(void)
|
||||
if (_glfw.wl.cursorTimerfd >= 0)
|
||||
close(_glfw.wl.cursorTimerfd);
|
||||
|
||||
// Free modules only after all Wayland termination functions are called
|
||||
|
||||
_glfwPlatformFreeModule(_glfw.egl.handle);
|
||||
_glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
|
||||
_glfwPlatformFreeModule(_glfw.wl.egl.handle);
|
||||
_glfwPlatformFreeModule(_glfw.wl.xkb.handle);
|
||||
_glfwPlatformFreeModule(_glfw.wl.cursor.handle);
|
||||
_glfwPlatformFreeModule(_glfw.wl.client.handle);
|
||||
|
||||
_glfw_free(_glfw.wl.clipboardString);
|
||||
|
||||
memset(&_glfw.wl, 0, sizeof(_glfw.wl));
|
||||
}
|
||||
|
||||
#endif // _GLFW_WAYLAND
|
||||
|
||||
+47
-7
@@ -53,6 +53,10 @@ typedef void (* PFN_wl_display_disconnect)(struct wl_display*);
|
||||
typedef int (* PFN_wl_display_roundtrip)(struct wl_display*);
|
||||
typedef int (* PFN_wl_display_get_fd)(struct wl_display*);
|
||||
typedef int (* PFN_wl_display_prepare_read)(struct wl_display*);
|
||||
typedef struct wl_event_queue* (* PFN_wl_display_create_queue)(struct wl_display*);
|
||||
typedef void (* PFN_wl_event_queue_destroy)(struct wl_event_queue*);
|
||||
typedef int (* PFN_wl_display_prepare_read_queue)(struct wl_display*,struct wl_event_queue*);
|
||||
typedef int (* PFN_wl_display_dispatch_queue_pending)(struct wl_display*,struct wl_event_queue*);
|
||||
typedef void (* PFN_wl_proxy_marshal)(struct wl_proxy*,uint32_t,...);
|
||||
typedef int (* PFN_wl_proxy_add_listener)(struct wl_proxy*,void(**)(void),void*);
|
||||
typedef void (* PFN_wl_proxy_destroy)(struct wl_proxy*);
|
||||
@@ -64,6 +68,9 @@ typedef void (* PFN_wl_proxy_set_tag)(struct wl_proxy*,const char*const*);
|
||||
typedef const char* const* (* PFN_wl_proxy_get_tag)(struct wl_proxy*);
|
||||
typedef uint32_t (* PFN_wl_proxy_get_version)(struct wl_proxy*);
|
||||
typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_t,const struct wl_interface*,uint32_t,uint32_t,...);
|
||||
typedef void* (* PFN_wl_proxy_create_wrapper)(void*);
|
||||
typedef void (* PFN_wl_proxy_wrapper_destroy)(void*);
|
||||
typedef void (* PFN_wl_proxy_set_queue)(struct wl_proxy*,struct wl_event_queue*);
|
||||
#define wl_display_flush _glfw.wl.client.display_flush
|
||||
#define wl_display_cancel_read _glfw.wl.client.display_cancel_read
|
||||
#define wl_display_dispatch_pending _glfw.wl.client.display_dispatch_pending
|
||||
@@ -72,6 +79,10 @@ typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_
|
||||
#define wl_display_roundtrip _glfw.wl.client.display_roundtrip
|
||||
#define wl_display_get_fd _glfw.wl.client.display_get_fd
|
||||
#define wl_display_prepare_read _glfw.wl.client.display_prepare_read
|
||||
#define wl_display_create_queue _glfw.wl.client.display_create_queue
|
||||
#define wl_display_prepare_read_queue _glfw.wl.client.display_prepare_read_queue
|
||||
#define wl_display_dispatch_queue_pending _glfw.wl.client.display_dispatch_queue_pending
|
||||
#define wl_event_queue_destroy _glfw.wl.client.event_queue_destroy
|
||||
#define wl_proxy_marshal _glfw.wl.client.proxy_marshal
|
||||
#define wl_proxy_add_listener _glfw.wl.client.proxy_add_listener
|
||||
#define wl_proxy_destroy _glfw.wl.client.proxy_destroy
|
||||
@@ -83,6 +94,9 @@ typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_
|
||||
#define wl_proxy_set_tag _glfw.wl.client.proxy_set_tag
|
||||
#define wl_proxy_get_version _glfw.wl.client.proxy_get_version
|
||||
#define wl_proxy_marshal_flags _glfw.wl.client.proxy_marshal_flags
|
||||
#define wl_proxy_create_wrapper _glfw.wl.client.proxy_create_wrapper
|
||||
#define wl_proxy_wrapper_destroy _glfw.wl.client.proxy_wrapper_destroy
|
||||
#define wl_proxy_set_queue _glfw.wl.client.proxy_set_queue
|
||||
|
||||
struct wl_shm;
|
||||
struct wl_output;
|
||||
@@ -136,18 +150,22 @@ struct wl_output;
|
||||
#define GLFW_WAYLAND_MONITOR_STATE _GLFWmonitorWayland wl;
|
||||
#define GLFW_WAYLAND_CURSOR_STATE _GLFWcursorWayland wl;
|
||||
|
||||
struct wl_cursor_image {
|
||||
struct wl_cursor_image
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t hotspot_x;
|
||||
uint32_t hotspot_y;
|
||||
uint32_t delay;
|
||||
};
|
||||
struct wl_cursor {
|
||||
|
||||
struct wl_cursor
|
||||
{
|
||||
unsigned int image_count;
|
||||
struct wl_cursor_image** images;
|
||||
char* name;
|
||||
};
|
||||
|
||||
typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
|
||||
typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
|
||||
typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
|
||||
@@ -356,14 +374,17 @@ typedef struct _GLFWwindowWayland
|
||||
GLFWbool maximized;
|
||||
GLFWbool activated;
|
||||
GLFWbool fullscreen;
|
||||
GLFWbool hovered;
|
||||
GLFWbool transparent;
|
||||
GLFWbool scaleFramebuffer;
|
||||
struct wl_surface* surface;
|
||||
struct wl_callback* callback;
|
||||
|
||||
struct {
|
||||
struct wl_event_queue* queue;
|
||||
struct wl_egl_window* window;
|
||||
struct wl_callback* callback;
|
||||
struct wl_surface* wrapper;
|
||||
int interval;
|
||||
} egl;
|
||||
|
||||
struct {
|
||||
@@ -385,7 +406,6 @@ typedef struct _GLFWwindowWayland
|
||||
struct libdecor_frame* frame;
|
||||
} libdecor;
|
||||
|
||||
_GLFWcursor* currentCursor;
|
||||
double cursorPosX, cursorPosY;
|
||||
|
||||
char* appId;
|
||||
@@ -412,8 +432,8 @@ typedef struct _GLFWwindowWayland
|
||||
GLFWbool decorations;
|
||||
struct wl_buffer* buffer;
|
||||
_GLFWfallbackEdgeWayland top, left, right, bottom;
|
||||
struct wl_surface* focus;
|
||||
wl_fixed_t pointerX, pointerY;
|
||||
double pointerX, pointerY;
|
||||
uint32_t buttonPressSerial;
|
||||
const char* cursorName;
|
||||
} fallback;
|
||||
} _GLFWwindowWayland;
|
||||
@@ -453,6 +473,7 @@ typedef struct _GLFWlibraryWayland
|
||||
|
||||
const char* tag;
|
||||
|
||||
struct wl_surface* pointerSurface;
|
||||
struct wl_cursor_theme* cursorTheme;
|
||||
struct wl_cursor_theme* cursorThemeHiDPI;
|
||||
struct wl_surface* cursorSurface;
|
||||
@@ -470,6 +491,17 @@ typedef struct _GLFWlibraryWayland
|
||||
short int scancodes[GLFW_KEY_LAST + 1];
|
||||
char keynames[GLFW_KEY_LAST + 1][5];
|
||||
|
||||
struct {
|
||||
struct wl_surface* pointerSurface;
|
||||
unsigned int events;
|
||||
double pointerX;
|
||||
double pointerY;
|
||||
double scrollX;
|
||||
double scrollY;
|
||||
int button;
|
||||
int action;
|
||||
} pending;
|
||||
|
||||
struct {
|
||||
void* handle;
|
||||
struct xkb_context* context;
|
||||
@@ -511,7 +543,6 @@ typedef struct _GLFWlibraryWayland
|
||||
PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym;
|
||||
} xkb;
|
||||
|
||||
_GLFWwindow* pointerFocus;
|
||||
_GLFWwindow* keyboardFocus;
|
||||
|
||||
struct {
|
||||
@@ -524,6 +555,10 @@ typedef struct _GLFWlibraryWayland
|
||||
PFN_wl_display_roundtrip display_roundtrip;
|
||||
PFN_wl_display_get_fd display_get_fd;
|
||||
PFN_wl_display_prepare_read display_prepare_read;
|
||||
PFN_wl_display_create_queue display_create_queue;
|
||||
PFN_wl_display_prepare_read_queue display_prepare_read_queue;
|
||||
PFN_wl_display_dispatch_queue_pending display_dispatch_queue_pending;
|
||||
PFN_wl_event_queue_destroy event_queue_destroy;
|
||||
PFN_wl_proxy_marshal proxy_marshal;
|
||||
PFN_wl_proxy_add_listener proxy_add_listener;
|
||||
PFN_wl_proxy_destroy proxy_destroy;
|
||||
@@ -535,6 +570,9 @@ typedef struct _GLFWlibraryWayland
|
||||
PFN_wl_proxy_set_tag proxy_set_tag;
|
||||
PFN_wl_proxy_get_version proxy_get_version;
|
||||
PFN_wl_proxy_marshal_flags proxy_marshal_flags;
|
||||
PFN_wl_proxy_create_wrapper proxy_create_wrapper;
|
||||
PFN_wl_proxy_wrapper_destroy proxy_wrapper_destroy;
|
||||
PFN_wl_proxy_set_queue proxy_set_queue;
|
||||
} client;
|
||||
|
||||
struct {
|
||||
@@ -693,3 +731,5 @@ void _glfwUpdateBufferScaleFromOutputsWayland(_GLFWwindow* window);
|
||||
void _glfwAddSeatListenerWayland(struct wl_seat* seat);
|
||||
void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);
|
||||
|
||||
GLFWbool _glfwWaitForEGLFrameWayland(_GLFWwindow* window);
|
||||
|
||||
|
||||
+323
-109
@@ -55,6 +55,11 @@
|
||||
#define GLFW_BORDER_SIZE 4
|
||||
#define GLFW_CAPTION_HEIGHT 24
|
||||
|
||||
#define GLFW_PENDING_SURFACE 1
|
||||
#define GLFW_PENDING_BUTTON 2
|
||||
#define GLFW_PENDING_MOTION 4
|
||||
#define GLFW_PENDING_SCROLL 8
|
||||
|
||||
static int createTmpfileCloexec(char* tmpname)
|
||||
{
|
||||
int fd;
|
||||
@@ -253,6 +258,9 @@ static void createFallbackDecorations(_GLFWwindow* window)
|
||||
|
||||
static void destroyFallbackEdge(_GLFWfallbackEdgeWayland* edge)
|
||||
{
|
||||
if (edge->surface == _glfw.wl.pointerSurface)
|
||||
_glfw.wl.pointerSurface = NULL;
|
||||
|
||||
if (edge->subsurface)
|
||||
wl_subsurface_destroy(edge->subsurface);
|
||||
if (edge->surface)
|
||||
@@ -275,39 +283,35 @@ static void destroyFallbackDecorations(_GLFWwindow* window)
|
||||
destroyFallbackEdge(&window->wl.fallback.bottom);
|
||||
}
|
||||
|
||||
static void updateFallbackDecorationCursor(_GLFWwindow* window,
|
||||
wl_fixed_t sx,
|
||||
wl_fixed_t sy)
|
||||
static void updateFallbackDecorationCursor(_GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
window->wl.fallback.pointerX = sx;
|
||||
window->wl.fallback.pointerY = sy;
|
||||
window->wl.fallback.pointerX = xpos;
|
||||
window->wl.fallback.pointerY = ypos;
|
||||
|
||||
const double xpos = wl_fixed_to_double(sx);
|
||||
const double ypos = wl_fixed_to_double(sy);
|
||||
const char* cursorName = "left_ptr";
|
||||
|
||||
if (window->resizable)
|
||||
{
|
||||
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
|
||||
if (_glfw.wl.pointerSurface == window->wl.fallback.top.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "n-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
|
||||
else if (_glfw.wl.pointerSurface == window->wl.fallback.left.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "nw-resize";
|
||||
else
|
||||
cursorName = "w-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
|
||||
else if (_glfw.wl.pointerSurface == window->wl.fallback.right.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "ne-resize";
|
||||
else
|
||||
cursorName = "e-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
|
||||
else if (_glfw.wl.pointerSurface == window->wl.fallback.bottom.surface)
|
||||
{
|
||||
if (xpos < GLFW_BORDER_SIZE)
|
||||
cursorName = "sw-resize";
|
||||
@@ -358,39 +362,41 @@ static void updateFallbackDecorationCursor(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
static void handleFallbackDecorationButton(_GLFWwindow* window,
|
||||
uint32_t serial,
|
||||
uint32_t button)
|
||||
static void handleFallbackDecorationButton(_GLFWwindow* window, int button, int action)
|
||||
{
|
||||
const double xpos = wl_fixed_to_double(window->wl.fallback.pointerX);
|
||||
const double ypos = wl_fixed_to_double(window->wl.fallback.pointerY);
|
||||
if (action != GLFW_PRESS)
|
||||
return;
|
||||
|
||||
if (button == BTN_LEFT)
|
||||
const double xpos = window->wl.fallback.pointerX;
|
||||
const double ypos = window->wl.fallback.pointerY;
|
||||
const uint32_t serial = window->wl.fallback.buttonPressSerial;
|
||||
|
||||
if (button == GLFW_MOUSE_BUTTON_LEFT)
|
||||
{
|
||||
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
||||
|
||||
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
|
||||
if (_glfw.wl.pointerSurface == window->wl.fallback.top.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
|
||||
else
|
||||
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
|
||||
else if (_glfw.wl.pointerSurface == window->wl.fallback.left.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
|
||||
else if (_glfw.wl.pointerSurface == window->wl.fallback.right.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
|
||||
else if (_glfw.wl.pointerSurface == window->wl.fallback.bottom.surface)
|
||||
{
|
||||
if (xpos < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
|
||||
@@ -403,21 +409,19 @@ static void handleFallbackDecorationButton(_GLFWwindow* window,
|
||||
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
|
||||
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, serial, edges);
|
||||
}
|
||||
else if (button == BTN_RIGHT)
|
||||
else if (button == GLFW_MOUSE_BUTTON_RIGHT)
|
||||
{
|
||||
if (!window->wl.xdg.toplevel)
|
||||
return;
|
||||
|
||||
if (window->wl.fallback.focus != window->wl.fallback.top.surface)
|
||||
if (_glfw.wl.pointerSurface != window->wl.fallback.top.surface)
|
||||
return;
|
||||
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
return;
|
||||
|
||||
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
|
||||
_glfw.wl.seat, serial,
|
||||
xpos,
|
||||
ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE);
|
||||
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, _glfw.wl.seat, serial,
|
||||
xpos, ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1267,14 +1271,16 @@ static void setCursorImage(_GLFWwindow* window,
|
||||
wl_surface_commit(surface);
|
||||
}
|
||||
|
||||
static void incrementCursorImage(_GLFWwindow* window)
|
||||
static void incrementCursorImage(void)
|
||||
{
|
||||
_GLFWcursor* cursor;
|
||||
|
||||
if (!window || !window->wl.hovered)
|
||||
if (!_glfw.wl.pointerSurface)
|
||||
return;
|
||||
|
||||
cursor = window->wl.currentCursor;
|
||||
_GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
|
||||
if (window->wl.surface != _glfw.wl.pointerSurface)
|
||||
return;
|
||||
|
||||
_GLFWcursor* cursor = window->cursor;
|
||||
if (cursor && cursor->wl.cursor)
|
||||
{
|
||||
cursor->wl.currentImage += 1;
|
||||
@@ -1436,7 +1442,7 @@ static void handleEvents(double* timeout)
|
||||
uint64_t repeats;
|
||||
|
||||
if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8)
|
||||
incrementCursorImage(_glfw.wl.pointerFocus);
|
||||
incrementCursorImage();
|
||||
}
|
||||
|
||||
if (fds[LIBDECOR_FD].revents & POLLIN)
|
||||
@@ -1513,6 +1519,70 @@ static char* readDataOfferAsString(struct wl_data_offer* offer, const char* mime
|
||||
return string;
|
||||
}
|
||||
|
||||
static void processPointerEnterSurface(struct wl_surface* surface)
|
||||
{
|
||||
_glfw.wl.pointerSurface = surface;
|
||||
|
||||
_GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
|
||||
if (window->wl.surface == _glfw.wl.pointerSurface)
|
||||
{
|
||||
_glfwSetCursorWayland(window, window->cursor);
|
||||
_glfwInputCursorEnter(window, GLFW_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void processPointerLeaveSurface(struct wl_surface* surface)
|
||||
{
|
||||
_glfw.wl.pointerSurface = NULL;
|
||||
|
||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||
if (window->wl.surface == surface)
|
||||
_glfwInputCursorEnter(window, GLFW_FALSE);
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
window->wl.fallback.cursorName = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void processPointerMotion(double xpos, double ypos)
|
||||
{
|
||||
_GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
|
||||
if (window->wl.surface == _glfw.wl.pointerSurface)
|
||||
{
|
||||
if (window->cursorMode != GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
window->wl.cursorPosX = xpos;
|
||||
window->wl.cursorPosY = ypos;
|
||||
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
updateFallbackDecorationCursor(window, xpos, ypos);
|
||||
}
|
||||
}
|
||||
|
||||
static void processPointerButton(int button, int action)
|
||||
{
|
||||
_GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
|
||||
if (window->wl.surface == _glfw.wl.pointerSurface)
|
||||
_glfwInputMouseClick(window, button, action, _glfw.wl.xkb.modifiers);
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
handleFallbackDecorationButton(window, button, action);
|
||||
}
|
||||
}
|
||||
|
||||
static void processPointerScroll(double xoffset, double yoffset)
|
||||
{
|
||||
_GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
|
||||
if (window->wl.surface == _glfw.wl.pointerSurface)
|
||||
_glfwInputScroll(window, xoffset, yoffset);
|
||||
}
|
||||
|
||||
static void pointerHandleEnter(void* userData,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t serial,
|
||||
@@ -1527,32 +1597,23 @@ static void pointerHandleEnter(void* userData,
|
||||
if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
|
||||
return;
|
||||
|
||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.pointerEnterSerial = serial;
|
||||
_glfw.wl.pointerFocus = window;
|
||||
|
||||
if (surface == window->wl.surface)
|
||||
{
|
||||
window->wl.hovered = GLFW_TRUE;
|
||||
_glfwSetCursorWayland(window, window->wl.currentCursor);
|
||||
_glfwInputCursorEnter(window, GLFW_TRUE);
|
||||
const double xpos = wl_fixed_to_double(sx);
|
||||
const double ypos = wl_fixed_to_double(sy);
|
||||
|
||||
if (window->cursorMode != GLFW_CURSOR_DISABLED)
|
||||
if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
|
||||
{
|
||||
window->wl.cursorPosX = wl_fixed_to_double(sx);
|
||||
window->wl.cursorPosY = wl_fixed_to_double(sy);
|
||||
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
|
||||
}
|
||||
_glfw.wl.pending.events |= (GLFW_PENDING_SURFACE | GLFW_PENDING_MOTION);
|
||||
_glfw.wl.pending.pointerSurface = surface;
|
||||
_glfw.wl.pending.pointerX = xpos;
|
||||
_glfw.wl.pending.pointerY = ypos;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
{
|
||||
window->wl.fallback.focus = surface;
|
||||
updateFallbackDecorationCursor(window, sx, sy);
|
||||
}
|
||||
processPointerEnterSurface(surface);
|
||||
processPointerMotion(xpos, ypos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1567,26 +1628,15 @@ static void pointerHandleLeave(void* userData,
|
||||
if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
|
||||
return;
|
||||
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.pointerFocus = NULL;
|
||||
|
||||
if (window->wl.hovered)
|
||||
if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
|
||||
{
|
||||
window->wl.hovered = GLFW_FALSE;
|
||||
_glfwInputCursorEnter(window, GLFW_FALSE);
|
||||
_glfw.wl.pending.events |= GLFW_PENDING_SURFACE;
|
||||
_glfw.wl.pending.pointerSurface = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
{
|
||||
window->wl.fallback.focus = NULL;
|
||||
window->wl.fallback.cursorName = NULL;
|
||||
}
|
||||
}
|
||||
processPointerLeaveSurface(surface);
|
||||
}
|
||||
|
||||
static void pointerHandleMotion(void* userData,
|
||||
@@ -1595,51 +1645,52 @@ static void pointerHandleMotion(void* userData,
|
||||
wl_fixed_t sx,
|
||||
wl_fixed_t sy)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
if (!window)
|
||||
if (!_glfw.wl.pointerSurface)
|
||||
return;
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
const double xpos = wl_fixed_to_double(sx);
|
||||
const double ypos = wl_fixed_to_double(sy);
|
||||
|
||||
if (window->wl.hovered)
|
||||
if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
|
||||
{
|
||||
window->wl.cursorPosX = wl_fixed_to_double(sx);
|
||||
window->wl.cursorPosY = wl_fixed_to_double(sy);
|
||||
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
|
||||
_glfw.wl.pending.events |= GLFW_PENDING_MOTION;
|
||||
_glfw.wl.pending.pointerX = xpos;
|
||||
_glfw.wl.pending.pointerY = ypos;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
updateFallbackDecorationCursor(window, sx, sy);
|
||||
}
|
||||
processPointerMotion(xpos, ypos);
|
||||
}
|
||||
|
||||
static void pointerHandleButton(void* userData,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t button,
|
||||
uint32_t buttonID,
|
||||
uint32_t state)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
if (!window)
|
||||
if (!_glfw.wl.pointerSurface)
|
||||
return;
|
||||
|
||||
if (window->wl.hovered)
|
||||
{
|
||||
_glfw.wl.serial = serial;
|
||||
|
||||
_glfwInputMouseClick(window,
|
||||
button - BTN_LEFT,
|
||||
state == WL_POINTER_BUTTON_STATE_PRESSED,
|
||||
_glfw.wl.xkb.modifiers);
|
||||
const int button = buttonID - BTN_LEFT;
|
||||
const int action = (state == WL_POINTER_BUTTON_STATE_PRESSED);
|
||||
|
||||
_GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
|
||||
if (window->wl.fallback.decorations)
|
||||
{
|
||||
if (action == GLFW_PRESS)
|
||||
window->wl.fallback.buttonPressSerial = serial;
|
||||
}
|
||||
|
||||
if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
|
||||
{
|
||||
_glfw.wl.pending.events |= GLFW_PENDING_BUTTON;
|
||||
_glfw.wl.pending.button = button;
|
||||
_glfw.wl.pending.action = action;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
handleFallbackDecorationButton(window, serial, button);
|
||||
}
|
||||
processPointerButton(button, action);
|
||||
}
|
||||
|
||||
static void pointerHandleAxis(void* userData,
|
||||
@@ -1648,20 +1699,73 @@ static void pointerHandleAxis(void* userData,
|
||||
uint32_t axis,
|
||||
wl_fixed_t value)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
if (!window)
|
||||
if (!_glfw.wl.pointerSurface)
|
||||
return;
|
||||
|
||||
if (window->wl.hovered)
|
||||
if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
|
||||
{
|
||||
_glfw.wl.pending.events |= GLFW_PENDING_SCROLL;
|
||||
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
|
||||
_glfw.wl.pending.scrollX = -wl_fixed_to_double(value) / 10.0;
|
||||
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
||||
_glfw.wl.pending.scrollY = -wl_fixed_to_double(value) / 10.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: 10 units of motion per mouse wheel step seems to be a common ratio
|
||||
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
|
||||
_glfwInputScroll(window, -wl_fixed_to_double(value) / 10.0, 0.0);
|
||||
processPointerScroll(-wl_fixed_to_double(value) / 10.0, 0.0);
|
||||
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
||||
_glfwInputScroll(window, 0.0, -wl_fixed_to_double(value) / 10.0);
|
||||
processPointerScroll(0.0, -wl_fixed_to_double(value) / 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
static void pointerHandleFrame(void* userData, struct wl_pointer* pointer)
|
||||
{
|
||||
if (_glfw.wl.pending.events & GLFW_PENDING_SURFACE)
|
||||
{
|
||||
if (_glfw.wl.pointerSurface)
|
||||
processPointerLeaveSurface(_glfw.wl.pointerSurface);
|
||||
|
||||
if (_glfw.wl.pending.pointerSurface)
|
||||
processPointerEnterSurface(_glfw.wl.pending.pointerSurface);
|
||||
}
|
||||
|
||||
if (!_glfw.wl.pointerSurface)
|
||||
return;
|
||||
|
||||
if (_glfw.wl.pending.events & GLFW_PENDING_MOTION)
|
||||
processPointerMotion(_glfw.wl.pending.pointerX, _glfw.wl.pending.pointerY);
|
||||
|
||||
if (_glfw.wl.pending.events & GLFW_PENDING_BUTTON)
|
||||
processPointerButton(_glfw.wl.pending.button, _glfw.wl.pending.action);
|
||||
|
||||
if (_glfw.wl.pending.events & GLFW_PENDING_SCROLL)
|
||||
processPointerScroll(_glfw.wl.pending.scrollX, _glfw.wl.pending.scrollY);
|
||||
|
||||
memset(&_glfw.wl.pending, 0, sizeof(_glfw.wl.pending));
|
||||
}
|
||||
|
||||
static void pointerHandleAxisSource(void* userData,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t axisSource)
|
||||
{
|
||||
}
|
||||
|
||||
static void pointerHandleAxisStop(void* userData,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t time,
|
||||
uint32_t axis)
|
||||
{
|
||||
}
|
||||
|
||||
static void pointerHandleAxisDiscrete(void* userData,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t axis,
|
||||
int32_t discrete)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener pointerListener =
|
||||
{
|
||||
pointerHandleEnter,
|
||||
@@ -1669,6 +1773,10 @@ static const struct wl_pointer_listener pointerListener =
|
||||
pointerHandleMotion,
|
||||
pointerHandleButton,
|
||||
pointerHandleAxis,
|
||||
pointerHandleFrame,
|
||||
pointerHandleAxisSource,
|
||||
pointerHandleAxisStop,
|
||||
pointerHandleAxisDiscrete
|
||||
};
|
||||
|
||||
static void keyboardHandleKeymap(void* userData,
|
||||
@@ -1692,7 +1800,8 @@ static void keyboardHandleKeymap(void* userData,
|
||||
}
|
||||
|
||||
mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (mapStr == MAP_FAILED) {
|
||||
if (mapStr == MAP_FAILED)
|
||||
{
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
@@ -1700,7 +1809,7 @@ static void keyboardHandleKeymap(void* userData,
|
||||
keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
|
||||
mapStr,
|
||||
XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
0);
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
munmap(mapStr, size);
|
||||
close(fd);
|
||||
|
||||
@@ -1838,7 +1947,9 @@ static void keyboardHandleKey(void* userData,
|
||||
timer.it_value.tv_nsec = (_glfw.wl.keyRepeatDelay % 1000) * 1000000;
|
||||
timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
|
||||
}
|
||||
} else if (scancode == _glfw.wl.keyRepeatScancode) {
|
||||
}
|
||||
else if (scancode == _glfw.wl.keyRepeatScancode)
|
||||
{
|
||||
timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
|
||||
}
|
||||
|
||||
@@ -1929,7 +2040,11 @@ static void seatHandleCapabilities(void* userData,
|
||||
}
|
||||
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
|
||||
{
|
||||
if (wl_pointer_get_version(_glfw.wl.pointer) >= WL_POINTER_RELEASE_SINCE_VERSION)
|
||||
wl_pointer_release(_glfw.wl.pointer);
|
||||
else
|
||||
wl_pointer_destroy(_glfw.wl.pointer);
|
||||
|
||||
_glfw.wl.pointer = NULL;
|
||||
}
|
||||
|
||||
@@ -1937,10 +2052,21 @@ static void seatHandleCapabilities(void* userData,
|
||||
{
|
||||
_glfw.wl.keyboard = wl_seat_get_keyboard(seat);
|
||||
wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
|
||||
|
||||
if (wl_keyboard_get_version(_glfw.wl.keyboard) <
|
||||
WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
|
||||
{
|
||||
_glfw.wl.keyRepeatRate = 4;
|
||||
_glfw.wl.keyRepeatDelay = 500;
|
||||
}
|
||||
}
|
||||
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
|
||||
{
|
||||
if (wl_keyboard_get_version(_glfw.wl.keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
|
||||
wl_keyboard_release(_glfw.wl.keyboard);
|
||||
else
|
||||
wl_keyboard_destroy(_glfw.wl.keyboard);
|
||||
|
||||
_glfw.wl.keyboard = NULL;
|
||||
}
|
||||
}
|
||||
@@ -2151,6 +2277,18 @@ static const struct xdg_activation_token_v1_listener xdgActivationListener =
|
||||
xdgActivationHandleDone
|
||||
};
|
||||
|
||||
static void callbackHandleFrame(void* userData, struct wl_callback* callback, uint32_t data)
|
||||
{
|
||||
_GLFWwindow* window = userData;
|
||||
wl_callback_destroy(callback);
|
||||
window->wl.egl.callback = NULL;
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener frameCallbackListener =
|
||||
{
|
||||
callbackHandleFrame
|
||||
};
|
||||
|
||||
void _glfwAddSeatListenerWayland(struct wl_seat* seat)
|
||||
{
|
||||
wl_seat_add_listener(seat, &seatListener, NULL);
|
||||
@@ -2161,6 +2299,46 @@ void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device)
|
||||
wl_data_device_add_listener(device, &dataDeviceListener, NULL);
|
||||
}
|
||||
|
||||
GLFWbool _glfwWaitForEGLFrameWayland(_GLFWwindow* window)
|
||||
{
|
||||
for (int i = 0; i < window->wl.egl.interval; i++)
|
||||
{
|
||||
double timeout = 0.02;
|
||||
|
||||
while (window->wl.egl.callback)
|
||||
{
|
||||
while (wl_display_prepare_read_queue(_glfw.wl.display, window->wl.egl.queue) != 0)
|
||||
wl_display_dispatch_queue_pending(_glfw.wl.display, window->wl.egl.queue);
|
||||
|
||||
if (!flushDisplay())
|
||||
{
|
||||
wl_display_cancel_read(_glfw.wl.display);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
struct pollfd fd = { wl_display_get_fd(_glfw.wl.display), POLLIN };
|
||||
|
||||
if (!_glfwPollPOSIX(&fd, 1, &timeout))
|
||||
{
|
||||
wl_display_cancel_read(_glfw.wl.display);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
wl_display_read_events(_glfw.wl.display);
|
||||
wl_display_dispatch_queue_pending(_glfw.wl.display, window->wl.egl.queue);
|
||||
}
|
||||
|
||||
window->wl.egl.callback = wl_surface_frame(window->wl.egl.wrapper);
|
||||
wl_callback_add_listener(window->wl.egl.callback, &frameCallbackListener, window);
|
||||
|
||||
// Commit the old buffer for every frame but the last one so we get new callbacks
|
||||
if (i + 1 < window->wl.egl.interval)
|
||||
wl_surface_commit(window->wl.surface);
|
||||
}
|
||||
|
||||
// If the window is hidden when the wait is over then don't swap
|
||||
return window->wl.visible;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
@@ -2189,6 +2367,25 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window,
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->wl.egl.queue = wl_display_create_queue(_glfw.wl.display);
|
||||
if (!window->wl.egl.queue)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to create EGL frame queue");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->wl.egl.wrapper = wl_proxy_create_wrapper(window->wl.surface);
|
||||
if (!window->wl.egl.wrapper)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to create surface wrapper");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
wl_proxy_set_queue((struct wl_proxy*) window->wl.egl.wrapper,
|
||||
window->wl.egl.queue);
|
||||
|
||||
if (!_glfwInitEGL())
|
||||
return GLFW_FALSE;
|
||||
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
||||
@@ -2220,8 +2417,8 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window,
|
||||
|
||||
void _glfwDestroyWindowWayland(_GLFWwindow* window)
|
||||
{
|
||||
if (window == _glfw.wl.pointerFocus)
|
||||
_glfw.wl.pointerFocus = NULL;
|
||||
if (window->wl.surface == _glfw.wl.pointerSurface)
|
||||
_glfw.wl.pointerSurface = NULL;
|
||||
|
||||
if (window == _glfw.wl.keyboardFocus)
|
||||
{
|
||||
@@ -2260,6 +2457,15 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
|
||||
if (window->wl.fallback.buffer)
|
||||
wl_buffer_destroy(window->wl.fallback.buffer);
|
||||
|
||||
if (window->wl.egl.callback)
|
||||
wl_callback_destroy(window->wl.egl.callback);
|
||||
|
||||
if (window->wl.egl.wrapper)
|
||||
wl_proxy_wrapper_destroy(window->wl.egl.wrapper);
|
||||
|
||||
if (window->wl.egl.queue)
|
||||
wl_event_queue_destroy(window->wl.egl.queue);
|
||||
|
||||
if (window->wl.egl.window)
|
||||
wl_egl_window_destroy(window->wl.egl.window);
|
||||
|
||||
@@ -2597,7 +2803,7 @@ GLFWbool _glfwWindowMaximizedWayland(_GLFWwindow* window)
|
||||
|
||||
GLFWbool _glfwWindowHoveredWayland(_GLFWwindow* window)
|
||||
{
|
||||
return window->wl.hovered;
|
||||
return window->wl.surface == _glfw.wl.pointerSurface;
|
||||
}
|
||||
|
||||
GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window)
|
||||
@@ -2727,7 +2933,7 @@ void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y)
|
||||
|
||||
void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
|
||||
{
|
||||
_glfwSetCursorWayland(window, window->wl.currentCursor);
|
||||
_glfwSetCursorWayland(window, window->cursor);
|
||||
}
|
||||
|
||||
const char* _glfwGetScancodeNameWayland(int scancode)
|
||||
@@ -2974,10 +3180,16 @@ static void lockPointer(_GLFWwindow* window)
|
||||
if (!_glfw.wl.relativePointerManager)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||
"Wayland: The compositor does not support pointer locking");
|
||||
"Wayland: The compositor does not support relative pointer motion");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_glfw.wl.pointerConstraints)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||
"Wayland: The compositor does not support locking the pointer");
|
||||
}
|
||||
|
||||
window->wl.relativePointer =
|
||||
zwp_relative_pointer_manager_v1_get_relative_pointer(
|
||||
_glfw.wl.relativePointerManager,
|
||||
@@ -3025,6 +3237,12 @@ static const struct zwp_confined_pointer_v1_listener confinedPointerListener =
|
||||
|
||||
static void confinePointer(_GLFWwindow* window)
|
||||
{
|
||||
if (!_glfw.wl.pointerConstraints)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||
"Wayland: The compositor does not support confining the pointer");
|
||||
}
|
||||
|
||||
window->wl.confinedPointer =
|
||||
zwp_pointer_constraints_v1_confine_pointer(
|
||||
_glfw.wl.pointerConstraints,
|
||||
@@ -3049,11 +3267,7 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
if (!_glfw.wl.pointer)
|
||||
return;
|
||||
|
||||
window->wl.currentCursor = cursor;
|
||||
|
||||
// If we're not in the correct window just save the cursor
|
||||
// the next time the pointer enters the window the cursor will change
|
||||
if (!window->wl.hovered)
|
||||
if (window->wl.surface != _glfw.wl.pointerSurface)
|
||||
return;
|
||||
|
||||
// Update pointer lock to match cursor mode
|
||||
|
||||
+10
-46
@@ -1592,65 +1592,29 @@ void _glfwTerminateX11(void)
|
||||
_glfw.x11.display = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.x11.x11xcb.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.x11.x11xcb.handle);
|
||||
_glfw.x11.x11xcb.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.x11.xcursor.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.x11.xcursor.handle);
|
||||
_glfw.x11.xcursor.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.x11.randr.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.x11.randr.handle);
|
||||
_glfw.x11.randr.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.x11.xinerama.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.x11.xinerama.handle);
|
||||
_glfw.x11.xinerama.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.x11.xrender.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.x11.xrender.handle);
|
||||
_glfw.x11.xrender.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.x11.vidmode.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.x11.vidmode.handle);
|
||||
_glfw.x11.vidmode.handle = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.x11.xi.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.x11.xi.handle);
|
||||
_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();
|
||||
_glfwTerminateGLX();
|
||||
|
||||
if (_glfw.x11.xlib.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.x11.x11xcb.handle);
|
||||
_glfwPlatformFreeModule(_glfw.x11.xcursor.handle);
|
||||
_glfwPlatformFreeModule(_glfw.x11.randr.handle);
|
||||
_glfwPlatformFreeModule(_glfw.x11.xinerama.handle);
|
||||
_glfwPlatformFreeModule(_glfw.x11.xrender.handle);
|
||||
_glfwPlatformFreeModule(_glfw.x11.xshape.handle);
|
||||
_glfwPlatformFreeModule(_glfw.x11.vidmode.handle);
|
||||
_glfwPlatformFreeModule(_glfw.x11.xi.handle);
|
||||
_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]);
|
||||
}
|
||||
|
||||
memset(&_glfw.x11, 0, sizeof(_glfw.x11));
|
||||
}
|
||||
|
||||
#endif // _GLFW_X11
|
||||
|
||||
@@ -151,6 +151,12 @@ void _glfwPollMonitorsX11(void)
|
||||
}
|
||||
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
|
||||
if (!ci)
|
||||
{
|
||||
XRRFreeOutputInfo(oi);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
|
||||
{
|
||||
widthMM = oi->mm_height;
|
||||
|
||||
+47
-21
@@ -576,6 +576,10 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
||||
height *= _glfw.x11.contentScaleY;
|
||||
}
|
||||
|
||||
// The dimensions must be nonzero, or a BadValue error results.
|
||||
width = _glfw_max(1, width);
|
||||
height = _glfw_max(1, height);
|
||||
|
||||
int xpos = 0, ypos = 0;
|
||||
|
||||
if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
|
||||
@@ -2203,6 +2207,10 @@ void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height)
|
||||
|
||||
void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
// The dimensions must be nonzero, or a BadValue error results
|
||||
width = _glfw_max(1, width);
|
||||
height = _glfw_max(1, height);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
if (window->monitor->window == window)
|
||||
@@ -2430,6 +2438,38 @@ void _glfwShowWindowX11(_GLFWwindow* window)
|
||||
if (_glfwWindowVisibleX11(window))
|
||||
return;
|
||||
|
||||
if (window->floating && _glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE)
|
||||
{
|
||||
Atom* states = NULL;
|
||||
const unsigned long count =
|
||||
_glfwGetWindowPropertyX11(window->x11.handle,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
XA_ATOM, (unsigned char**) &states);
|
||||
|
||||
// NOTE: We don't check for failure as this property may not exist yet
|
||||
// and that's fine (and we'll create it implicitly with append)
|
||||
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == count)
|
||||
{
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
|
||||
PropModeAppend,
|
||||
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
|
||||
1);
|
||||
}
|
||||
|
||||
if (states)
|
||||
XFree(states);
|
||||
}
|
||||
|
||||
XMapWindow(_glfw.x11.display, window->x11.handle);
|
||||
waitForVisibilityNotify(window);
|
||||
}
|
||||
@@ -2659,6 +2699,10 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled)
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: _NET_WM_STATE_ABOVE is added when the window is shown
|
||||
if (enabled)
|
||||
return;
|
||||
|
||||
Atom* states = NULL;
|
||||
const unsigned long count =
|
||||
_glfwGetWindowPropertyX11(window->x11.handle,
|
||||
@@ -2669,8 +2713,6 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled)
|
||||
// NOTE: We don't check for failure as this property may not exist yet
|
||||
// and that's fine (and we'll create it implicitly with append)
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
@@ -2679,28 +2721,12 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == count)
|
||||
{
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
|
||||
PropModeAppend,
|
||||
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
|
||||
1);
|
||||
}
|
||||
}
|
||||
else if (states)
|
||||
{
|
||||
for (unsigned long i = 0; i < count; i++)
|
||||
{
|
||||
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
|
||||
if (i < count)
|
||||
{
|
||||
states[i] = states[count - 1];
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char*) states, count - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (states)
|
||||
@@ -3318,8 +3344,6 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* handle)
|
||||
|
||||
GLFWAPI void glfwSetX11SelectionString(const char* string)
|
||||
{
|
||||
assert(string != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
|
||||
@@ -3328,6 +3352,8 @@ GLFWAPI void glfwSetX11SelectionString(const char* string)
|
||||
return;
|
||||
}
|
||||
|
||||
assert(string != NULL);
|
||||
|
||||
_glfw_free(_glfw.x11.primarySelectionString);
|
||||
_glfw.x11.primarySelectionString = _glfw_strdup(string);
|
||||
|
||||
|
||||
@@ -146,6 +146,10 @@ int main(void)
|
||||
for (i = 0; i < count; i++)
|
||||
thrd_join(threads[i].id, &result);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
glfwDestroyWindow(threads[i].window);
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
+30
-1
@@ -36,6 +36,14 @@
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static bool needs_update;
|
||||
|
||||
static void window_close_callback(GLFWwindow* window)
|
||||
{
|
||||
needs_update = true;
|
||||
}
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
{
|
||||
@@ -45,7 +53,15 @@ static void error_callback(int error, const char* description)
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
||||
{
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
needs_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
needs_update = true;
|
||||
}
|
||||
|
||||
static float nrand(void)
|
||||
@@ -72,8 +88,11 @@ int main(void)
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(0);
|
||||
gladLoadGL(glfwGetProcAddress);
|
||||
glfwSetWindowCloseCallback(window, window_close_callback);
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
@@ -87,8 +106,18 @@ int main(void)
|
||||
glClearColor(r / l, g / l, b / l, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glfwSwapBuffers(window);
|
||||
needs_update = false;
|
||||
|
||||
glfwWaitEventsTimeout(1.0);
|
||||
const double start = glfwGetTime();
|
||||
|
||||
while (!needs_update)
|
||||
{
|
||||
const double elapsed = glfwGetTime() - start;
|
||||
if (elapsed >= 1.0)
|
||||
needs_update = true;
|
||||
else
|
||||
glfwWaitEventsTimeout(1.0 - elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
||||
Reference in New Issue
Block a user