diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index af2b3e13..2a1c688d 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -66,6 +66,7 @@ video tutorials. - Nikita Fediuchin - Felipe Ferreira - Michael Fogleman + - forworldm - Jason Francis - Gerald Franz - Mário Freitas @@ -78,6 +79,7 @@ video tutorials. - Kovid Goyal - Kevin Grandemange - Eloi Marín Gratacós + - Grzesiek11 - Stefan Gustavson - Andrew Gutekanst - Stephen Gutekanst @@ -102,6 +104,7 @@ video tutorials. - Andreas O. Jansen - Erik S. V. Jansson - jjYBdx4IL + - Peter Johnson - Toni Jovanoski - Arseny Kapoulkine - Cem Karan @@ -213,6 +216,7 @@ video tutorials. - Matt Sealey - Steve Sexton - Arkady Shapkin + - Mingjie Shen - Ali Sherief - Yoshiki Shibukawa - Dmitri Shuralyov @@ -250,6 +254,7 @@ video tutorials. - Jari Vetoniemi - Ricardo Vieira - Nicholas Vitovitch + - Vladimír Vondruš - Simon Voordouw - Corentin Wallez - Torsten Walluhn diff --git a/README.md b/README.md index 4e07c0e2..9b2d208a 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,8 @@ information on what to include when reporting a bug. - Bugfix: `glfwMakeContextCurrent` would access TLS slot before initialization - Bugfix: `glfwSetGammaRamp` could emit `GLFW_INVALID_VALUE` before initialization - Bugfix: `glfwGetJoystickUserPointer` returned `NULL` during disconnection (#2092) - - [Win32] Fix pkg-config for dynamic library on Windows (#2386, #2420) + - Bugfix: `glfwGetKeyScancode` returned `0` on error when initialized instead of `-1` + - Bugfix: Failure to make a newly created context current could cause segfault (#2327) - [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 @@ -232,6 +233,8 @@ information on what to include when reporting a bug. - [Win32] Bugfix: The OSMesa library was not unloaded on termination - [Win32] Bugfix: Right shift emitted `GLFW_KEY_UNKNOWN` when using a CJK IME (#2050) - [Win32] Bugfix: `glfwWaitEventsTimeout` did not return for some sent messages (#2408) + - [Win32] Bugfix: Fix pkg-config for dynamic library on Windows (#2386, #2420) + - [Win32] Bugfix: XInput could reportedly provide invalid DPad bit masks (#2291) - [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) @@ -272,6 +275,8 @@ information on what to include when reporting a bug. application (#2110) - [Cocoa] Bugfix: The Vulkan loader was not loaded from the `Frameworks` bundle subdirectory (#2113,#2120) + - [Cocoa] Bugfix: Compilation failed on OS X 10.8 due to unconditional use of 10.9+ + symbols (#2161) - [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) diff --git a/docs/input.dox b/docs/input.dox index d3904f46..f57520bb 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -95,7 +95,7 @@ new size before everything returns back out of the @ref glfwSetWindowSize call. GLFW divides keyboard input into two categories; key events and character events. Key events relate to actual physical keyboard keys, whereas character -events relate to the Unicode code points generated by pressing some of them. +events relate to the text that is generated by pressing some of them. Keys and characters do not map 1:1. A single key press may produce several characters, and a single character may require several keys to produce. This @@ -127,6 +127,10 @@ The action is one of `GLFW_PRESS`, `GLFW_REPEAT` or `GLFW_RELEASE`. Events with `GLFW_PRESS` and `GLFW_RELEASE` actions are emitted for every key press. Most keys will also emit events with `GLFW_REPEAT` actions while a key is held down. +Note that many keyboards have a limit on how many keys being simultaneous held +down that they can detect. This limit is called +[key rollover](https://en.wikipedia.org/wiki/Key_rollover). + Key events with `GLFW_REPEAT` actions are intended for text input. They are emitted at the rate set in the user's keyboard settings. At most one key is repeated even if several keys are held down. `GLFW_REPEAT` actions should not @@ -142,16 +146,16 @@ keys. The scancode is unique for every key, regardless of whether it has a key token. Scancodes are platform-specific but consistent over time, so keys will have different scancodes depending on the platform but they are safe to save to disk. -You can query the scancode for any [named key](@ref keys) on the current -platform with @ref glfwGetKeyScancode. +You can query the scancode for any [key token](@ref keys) supported on the +current platform with @ref glfwGetKeyScancode. @code const int scancode = glfwGetKeyScancode(GLFW_KEY_X); set_key_mapping(scancode, swap_weapons); @endcode -The last reported state for every [named key](@ref keys) is also saved in -per-window state arrays that can be polled with @ref glfwGetKey. +The last reported state for every physical key with a [key token](@ref keys) is +also saved in per-window state arrays that can be polled with @ref glfwGetKey. @code int state = glfwGetKey(window, GLFW_KEY_E); @@ -164,7 +168,8 @@ if (state == GLFW_PRESS) The returned state is one of `GLFW_PRESS` or `GLFW_RELEASE`. This function only returns cached key event state. It does not poll the -system for the current physical state of the key. +system for the current state of the physical key. It also does not provide any +key repeat information. @anchor GLFW_STICKY_KEYS Whenever you poll state, you risk missing the state change you are looking for. @@ -195,15 +200,15 @@ Lock was on when the event occurred and the @ref GLFW_MOD_NUM_LOCK bit set if Num Lock was on. The `GLFW_KEY_LAST` constant holds the highest value of any -[named key](@ref keys). +[key token](@ref keys). @subsection input_char Text input GLFW supports text input in the form of a stream of [Unicode code points](https://en.wikipedia.org/wiki/Unicode), as produced by the -operating system text input system. Unlike key input, text input obeys keyboard -layouts and modifier keys and supports composing characters using +operating system text input system. Unlike key input, text input is affected by +keyboard layouts and modifier keys and supports composing characters using [dead keys](https://en.wikipedia.org/wiki/Dead_key). Once received, you can encode the code points into UTF-8 or any other encoding you prefer. @@ -502,8 +507,9 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) The action is one of `GLFW_PRESS` or `GLFW_RELEASE`. -Mouse button states for [named buttons](@ref buttons) are also saved in -per-window state arrays that can be polled with @ref glfwGetMouseButton. +The last reported state for every [supported mouse button](@ref buttons) is also +saved in per-window state arrays that can be polled with @ref +glfwGetMouseButton. @code int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); @@ -536,7 +542,7 @@ had been processed in the meantime, the state will reset to `GLFW_RELEASE`, otherwise it will remain `GLFW_PRESS`. The `GLFW_MOUSE_BUTTON_LAST` constant holds the highest value of any -[named button](@ref buttons). +[supported mouse button](@ref buttons). @subsection scrolling Scroll input diff --git a/docs/news.dox b/docs/news.dox index e16267b2..28c500d9 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -277,6 +277,7 @@ then GLFW will fail to initialize. - @ref GLFW_POSITION_X - @ref GLFW_POSITION_Y - @ref GLFW_ANY_POSITION + - @ref GLFW_WAYLAND_APP_ID - @ref GLFW_WAYLAND_LIBDECOR - @ref GLFW_WAYLAND_PREFER_LIBDECOR - @ref GLFW_WAYLAND_DISABLE_LIBDECOR diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 5d6ce185..a468d06f 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -361,10 +361,15 @@ extern "C" { #define GLFW_HAT_RIGHT_DOWN (GLFW_HAT_RIGHT | GLFW_HAT_DOWN) #define GLFW_HAT_LEFT_UP (GLFW_HAT_LEFT | GLFW_HAT_UP) #define GLFW_HAT_LEFT_DOWN (GLFW_HAT_LEFT | GLFW_HAT_DOWN) + +/*! @ingroup input + */ +#define GLFW_KEY_UNKNOWN -1 + /*! @} */ -/*! @defgroup keys Keyboard keys - * @brief Keyboard key IDs. +/*! @defgroup keys Keyboard key tokens + * @brief Keyboard key tokens. * * See [key input](@ref input_key) for how these are used. * @@ -387,9 +392,6 @@ extern "C" { * @{ */ -/* The unknown key */ -#define GLFW_KEY_UNKNOWN -1 - /* Printable keys */ #define GLFW_KEY_SPACE 32 #define GLFW_KEY_APOSTROPHE 39 /* ' */ @@ -4811,8 +4813,8 @@ GLFWAPI int glfwRawMouseMotionSupported(void); * @param[in] scancode The scancode of the key to query. * @return The UTF-8 encoded, layout-specific name of the key, or `NULL`. * - * @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, @ref GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @remark The contents of the returned string may change when a keyboard * layout change event is received. @@ -4834,15 +4836,18 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode); * * This function returns the platform-specific scancode of the specified key. * - * If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this - * method will return `-1`. + * If the specified [key token](@ref keys) corresponds to a physical key not + * supported on the current platform then this method will return `-1`. + * Calling this function with anything other than a key token will return `-1` + * and generate a @ref GLFW_INVALID_ENUM error. * - * @param[in] key Any [named key](@ref keys). - * @return The platform-specific scancode for the key, or `-1` if an - * [error](@ref error_handling) occurred. + * @param[in] key Any [key token](@ref keys). + * @return The platform-specific scancode for the key, or `-1` if the key is + * not supported on the current platform or an [error](@ref error_handling) + * occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. * * @thread_safety This function may be called from any thread. * @@ -5151,9 +5156,9 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); * [character callback](@ref glfwSetCharCallback) instead. * * When a window loses input focus, it will generate synthetic key release - * events for all pressed keys. You can tell these events from user-generated - * events by the fact that the synthetic ones are generated after the focus - * loss event has been processed, i.e. after the + * events for all pressed keys with associated key tokens. You can tell these + * events from user-generated events by the fact that the synthetic ones are + * generated after the focus loss event has been processed, i.e. after the * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * The scancode of a key is specific to that platform or sometimes even to that @@ -6052,12 +6057,15 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void); * thread. * * This function makes the OpenGL or OpenGL ES context of the specified window - * current on the calling thread. A context must only be made current on - * a single thread at a time and each thread can have only a single current - * context at a time. + * current on the calling thread. It can also detach the current context from + * the calling thread without making a new one current by passing in `NULL`. * - * When moving a context between threads, you must make it non-current on the - * old thread before making it current on the new one. + * A context must only be made current on a single thread at a time and each + * thread can have only a single current context at a time. Making a context + * current detaches any previously current context on the calling thread. + * + * When moving a context between threads, you must detach it (make it + * non-current) on the old thread before making it current on the new one. * * By default, making a context non-current implicitly forces a pipeline flush. * On machines that support `GL_KHR_context_flush_control`, you can control @@ -6072,6 +6080,10 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void); * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. * + * @remarks If the previously current context was created via a different + * context creation API than the one passed to this function, GLFW will still + * detach the previous one from its API before making the new one current. + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. * diff --git a/src/cocoa_window.m b/src/cocoa_window.m index a921c12f..26d962d2 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -388,10 +388,15 @@ static void setDockProgressIndicator(int progressState, double value) - (void)windowDidChangeOcclusionState:(NSNotification* )notification { - if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible) - window->ns.occluded = GLFW_FALSE; - else - window->ns.occluded = GLFW_TRUE; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 + if ([window->ns.object respondsToSelector:@selector(occlusionState)]) + { + if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible) + window->ns.occluded = GLFW_FALSE; + else + window->ns.occluded = GLFW_TRUE; + } +#endif } @end diff --git a/src/context.c b/src/context.c index 33b399c9..f8610e1e 100644 --- a/src/context.c +++ b/src/context.c @@ -363,6 +363,8 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, previous = _glfwPlatformGetTls(&_glfw.contextSlot); glfwMakeContextCurrent((GLFWwindow*) window); + if (_glfwPlatformGetTls(&_glfw.contextSlot) != window) + return GLFW_FALSE; window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) window->context.getProcAddress("glGetIntegerv"); diff --git a/src/egl_context.c b/src/egl_context.c index 64dcdd6f..a18590b9 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -311,6 +311,7 @@ static int extensionSupportedEGL(const char* extension) static GLFWglproc getProcAddressEGL(const char* procname) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + assert(window != NULL); if (window->context.egl.client) { @@ -703,8 +704,11 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (!fbconfig->doublebuffer) SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); - if (_glfw.egl.EXT_present_opaque) - SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent); + if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND) + { + if (_glfw.egl.EXT_present_opaque) + SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent); + } SET_ATTRIB(EGL_NONE, EGL_NONE); diff --git a/src/glx_context.c b/src/glx_context.c index 4406dfd3..f3f4b3ec 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -192,6 +192,7 @@ static void swapBuffersGLX(_GLFWwindow* window) static void swapIntervalGLX(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + assert(window != NULL); if (_glfw.glx.EXT_swap_control) { diff --git a/src/input.c b/src/input.c index 36128e10..8b7ef29c 100644 --- a/src/input.c +++ b/src/input.c @@ -462,10 +462,11 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) assert(hat >= 0); assert(hat < js->hatCount); - // Valid hat values only use the least significant nibble and have at most two bits - // set, which can be considered adjacent plus an arbitrary rotation within the nibble + // Valid hat values only use the least significant nibble assert((value & 0xf0) == 0); - assert((value & ((value << 2) | (value >> 2))) == 0); + // Valid hat values do not have both bits of an axis set + assert((value & GLFW_HAT_LEFT) == 0 || (value & GLFW_HAT_RIGHT) == 0); + assert((value & GLFW_HAT_UP) == 0 || (value & GLFW_HAT_DOWN) == 0); base = js->buttonCount + hat * 4; @@ -701,6 +702,12 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode) if (key != GLFW_KEY_UNKNOWN) { + if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); + return NULL; + } + if (key != GLFW_KEY_KP_EQUAL && (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) && (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2)) @@ -721,7 +728,7 @@ GLFWAPI int glfwGetKeyScancode(int key) if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); - return GLFW_RELEASE; + return -1; } return _glfw.platform.getKeyScancode(key); diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 878f32ed..de89e421 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -83,11 +83,10 @@ static void swapIntervalNSGL(int interval) @autoreleasepool { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); - if (window) - { - [window->context.nsgl.object setValues:&interval - forParameter:NSOpenGLContextParameterSwapInterval]; - } + assert(window != NULL); + + [window->context.nsgl.object setValues:&interval + forParameter:NSOpenGLContextParameterSwapInterval]; } // autoreleasepool } diff --git a/src/wgl_context.c b/src/wgl_context.c index cfe24b27..08c499ff 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -332,6 +332,7 @@ static void swapBuffersWGL(_GLFWwindow* window) static void swapIntervalWGL(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + assert(window != NULL); window->context.wgl.interval = interval; diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 4e83577a..eae44edf 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -736,6 +736,13 @@ GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode) if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) dpad |= GLFW_HAT_LEFT; + // Treat invalid combinations as neither being pressed + // while preserving what data can be preserved + if ((dpad & GLFW_HAT_RIGHT) && (dpad & GLFW_HAT_LEFT)) + dpad &= ~(GLFW_HAT_RIGHT | GLFW_HAT_LEFT); + if ((dpad & GLFW_HAT_UP) && (dpad & GLFW_HAT_DOWN)) + dpad &= ~(GLFW_HAT_UP | GLFW_HAT_DOWN); + _glfwInputJoystickHat(js, 0, dpad); } diff --git a/src/wl_init.c b/src/wl_init.c index bf553a76..b5916bef 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "wayland-client-protocol.h" #include "wayland-xdg-shell-client-protocol.h" @@ -216,6 +217,22 @@ static const struct libdecor_interface libdecorInterface = libdecorHandleError }; +static void libdecorReadyCallback(void* userData, + struct wl_callback* callback, + uint32_t time) +{ + _glfw.wl.libdecor.ready = GLFW_TRUE; + + assert(_glfw.wl.libdecor.callback == callback); + wl_callback_destroy(_glfw.wl.libdecor.callback); + _glfw.wl.libdecor.callback = NULL; +} + +static const struct wl_callback_listener libdecorReadyListener = +{ + libdecorReadyCallback +}; + // Create key code translation tables // static void createKeyTables(void) @@ -778,10 +795,17 @@ int _glfwInitWayland(void) if (_glfw.wl.libdecor.handle) { _glfw.wl.libdecor.context = libdecor_new(_glfw.wl.display, &libdecorInterface); - - // Allow libdecor to receive its globals before proceeding if (_glfw.wl.libdecor.context) - libdecor_dispatch(_glfw.wl.libdecor.context, 1); + { + // Perform an initial dispatch and flush to get the init started + libdecor_dispatch(_glfw.wl.libdecor.context, 0); + + // Create sync point to "know" when libdecor is ready for use + _glfw.wl.libdecor.callback = wl_display_sync(_glfw.wl.display); + wl_callback_add_listener(_glfw.wl.libdecor.callback, + &libdecorReadyListener, + NULL); + } } #ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION @@ -825,6 +849,8 @@ void _glfwTerminateWayland(void) _glfwTerminateEGL(); _glfwTerminateOSMesa(); + if (_glfw.wl.libdecor.callback) + wl_callback_destroy(_glfw.wl.libdecor.callback); if (_glfw.wl.libdecor.context) libdecor_unref(_glfw.wl.libdecor.context); diff --git a/src/wl_platform.h b/src/wl_platform.h index 675146a5..550bc60c 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -550,6 +550,8 @@ typedef struct _GLFWlibraryWayland struct { void* handle; struct libdecor* context; + struct wl_callback* callback; + GLFWbool ready; PFN_libdecor_new libdecor_new_; PFN_libdecor_unref libdecor_unref_; PFN_libdecor_get_fd libdecor_get_fd_; diff --git a/src/wl_window.c b/src/wl_window.c index 7c02f31a..e89e2bc7 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -735,6 +735,10 @@ static const struct libdecor_frame_interface libdecorFrameInterface = static GLFWbool createLibdecorFrame(_GLFWwindow* window) { + // Allow libdecor to finish initialization of itself and its plugin + while (!_glfw.wl.libdecor.ready) + _glfwWaitEventsWayland(); + window->wl.libdecor.frame = libdecor_decorate(_glfw.wl.libdecor.context, window->wl.surface, &libdecorFrameInterface, @@ -746,6 +750,11 @@ static GLFWbool createLibdecorFrame(_GLFWwindow* window) return GLFW_FALSE; } + struct libdecor_state* frameState = + libdecor_state_new(window->wl.width, window->wl.height); + libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL); + libdecor_state_free(frameState); + if (strlen(window->wl.appId)) libdecor_frame_set_app_id(window->wl.libdecor.frame, window->wl.appId); @@ -776,12 +785,6 @@ static GLFWbool createLibdecorFrame(_GLFWwindow* window) if (window->monitor) { - // HACK: Allow libdecor to finish initialization of itself and its - // plugin so it will create the xdg_toplevel for the frame - // This needs to exist when setting the frame to fullscreen - while (!libdecor_frame_get_xdg_toplevel(window->wl.libdecor.frame)) - _glfwWaitEventsWayland(); - libdecor_frame_set_fullscreen(window->wl.libdecor.frame, window->monitor->wl.output); setIdleInhibitor(window, GLFW_TRUE); @@ -1115,7 +1118,10 @@ static void handleEvents(double* timeout) while (!event) { while (wl_display_prepare_read(_glfw.wl.display) != 0) - wl_display_dispatch_pending(_glfw.wl.display); + { + if (wl_display_dispatch_pending(_glfw.wl.display) > 0) + return; + } // If an error other than EAGAIN happens, we have likely been disconnected // from the Wayland session; try to handle that the best we can. @@ -1173,14 +1179,14 @@ static void handleEvents(double* timeout) uint64_t repeats; if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8) - { incrementCursorImage(_glfw.wl.pointerFocus); - event = GLFW_TRUE; - } } if (fds[3].revents & POLLIN) - libdecor_dispatch(_glfw.wl.libdecor.context, 0); + { + if (libdecor_dispatch(_glfw.wl.libdecor.context, 0) > 0) + event = GLFW_TRUE; + } } }