diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 157a4820..dfff8d3d 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2358,7 +2358,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * icons, the window will inherit the one defined in the application's * desktop file, so this function emits @ref GLFW_PLATFORM_ERROR. * - * @remark @wayland Screensaver inhibition is currently unimplemented. + * @remark @wayland Screensaver inhibition requires the idle-inhibit protocol + * to be implemented in the user's compositor. * * @thread_safety This function must only be called from the main thread. * diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b14512cc..01c01053 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,10 @@ elseif (_GLFW_WAYLAND) PROTOCOL "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" BASENAME pointer-constraints-unstable-v1) + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml + BASENAME idle-inhibit-unstable-v1) elseif (_GLFW_MIR) set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h posix_time.h posix_thread.h xkb_unicode.h egl_context.h diff --git a/src/wl_init.c b/src/wl_init.c index d6832aaa..ec25f206 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -501,6 +501,13 @@ static void registryHandleGlobal(void* data, &zwp_pointer_constraints_v1_interface, 1); } + else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) + { + _glfw.wl.idleInhibitManager = + wl_registry_bind(registry, name, + &zwp_idle_inhibit_manager_v1_interface, + 1); + } } static void registryHandleGlobalRemove(void *data, @@ -786,6 +793,8 @@ void _glfwPlatformTerminate(void) zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager); if (_glfw.wl.pointerConstraints) zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints); + if (_glfw.wl.idleInhibitManager) + zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager); if (_glfw.wl.registry) wl_registry_destroy(_glfw.wl.registry); if (_glfw.wl.display) diff --git a/src/wl_platform.h b/src/wl_platform.h index 96c0a991..516c84be 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -54,6 +54,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" +#include "wayland-idle-inhibit-unstable-v1-client-protocol.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -138,6 +139,9 @@ typedef struct _GLFWwindowWayland struct zwp_relative_pointer_v1* relativePointer; struct zwp_locked_pointer_v1* lockedPointer; } pointerLock; + + struct zwp_idle_inhibitor_v1* idleInhibitor; + } _GLFWwindowWayland; // Wayland-specific global data @@ -154,6 +158,7 @@ typedef struct _GLFWlibraryWayland struct wl_keyboard* keyboard; struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_pointer_constraints_v1* pointerConstraints; + struct zwp_idle_inhibit_manager_v1* idleInhibitManager; int compositorVersion; diff --git a/src/wl_window.c b/src/wl_window.c index b2ae7aae..9759ba26 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -189,6 +189,24 @@ static void setOpaqueRegion(_GLFWwindow* window) wl_region_destroy(region); } +static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) +{ + if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager) + { + window->wl.idleInhibitor = + zwp_idle_inhibit_manager_v1_create_inhibitor( + _glfw.wl.idleInhibitManager, window->wl.surface); + if (!window->wl.idleInhibitor) + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Idle inhibitor creation failed"); + } + else if (!enable && window->wl.idleInhibitor) + { + zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); + window->wl.idleInhibitor = NULL; + } +} + static GLFWbool createSurface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { @@ -239,14 +257,17 @@ static GLFWbool createShellSurface(_GLFWwindow* window) WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, window->monitor->wl.output); + setIdleInhibitor(window, GLFW_TRUE); } else if (window->wl.maximized) { wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); + setIdleInhibitor(window, GLFW_FALSE); } else { wl_shell_surface_set_toplevel(window->wl.shellSurface); + setIdleInhibitor(window, GLFW_FALSE); } wl_surface_commit(window->wl.surface); @@ -452,6 +473,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) _glfwInputWindowFocus(window, GLFW_FALSE); } + if (window->wl.idleInhibitor) + zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); + if (window->context.destroy) window->context.destroy(window); @@ -637,10 +661,12 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, refreshRate * 1000, // Convert Hz to mHz. monitor->wl.output); + setIdleInhibitor(window, GLFW_TRUE); } else { wl_shell_surface_set_toplevel(window->wl.shellSurface); + setIdleInhibitor(window, GLFW_FALSE); } _glfwInputWindowMonitor(window, monitor); }