Implement support for inhibiting the screensaver on Wayland
We support both the org.freedesktop.ScreenSaver D-Bus API (same as the X11
backend) and the Wayland idle_inhibit_unstable_v1 protocol.
Some Wayland compositors only support one or the other, so we need both to
for broad compatibility.
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index e5be532..addd006 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -50,6 +50,7 @@
#include "xdg-decoration-unstable-v1-client-protocol.h"
#include "org-kde-kwin-server-decoration-manager-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
+#include "idle-inhibit-unstable-v1-client-protocol.h"
#define WAYLANDVID_DRIVER_NAME "wayland"
@@ -179,6 +180,7 @@
device->SetDisplayMode = Wayland_SetDisplayMode;
device->GetDisplayModes = Wayland_GetDisplayModes;
device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
+ device->SuspendScreenSaver = Wayland_SuspendScreenSaver;
device->PumpEvents = Wayland_PumpEvents;
@@ -397,6 +399,8 @@
Wayland_display_add_pointer_constraints(d, id);
} else if (strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0) {
d->key_inhibitor_manager = wl_registry_bind(d->registry, id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1);
+ } else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) {
+ d->idle_inhibit_manager = wl_registry_bind(d->registry, id, &zwp_idle_inhibit_manager_v1_interface, 1);
} else if (strcmp(interface, "wl_data_device_manager") == 0) {
d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, SDL_min(3, version));
} else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
@@ -456,6 +460,10 @@
WAYLAND_wl_display_flush(data->display);
+#if SDL_USE_LIBDBUS
+ SDL_DBus_Init();
+#endif
+
return 0;
}
@@ -497,6 +505,9 @@
Wayland_display_destroy_pointer_constraints(data);
Wayland_display_destroy_relative_pointer_manager(data);
+ if (data->idle_inhibit_manager)
+ zwp_idle_inhibit_manager_v1_destroy(data->idle_inhibit_manager);
+
if (data->key_inhibitor_manager)
zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(data->key_inhibitor_manager);
@@ -535,6 +546,12 @@
if (data->registry)
wl_registry_destroy(data->registry);
+/* !!! FIXME: other subsystems use D-Bus, so we shouldn't quit it here;
+ have SDL.c do this at a higher level, or add refcounting. */
+#if SDL_USE_LIBDBUS
+ SDL_DBus_Quit();
+#endif
+
SDL_free(data->classname);
}
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index 99e3c01..ea7e140 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -37,6 +37,8 @@
#include <EGL/egl.h>
#include "wayland-util.h"
+#include "../../core/linux/SDL_dbus.h"
+
struct xkb_context;
struct SDL_WaylandInput;
@@ -65,6 +67,7 @@
struct zxdg_decoration_manager_v1 *decoration_manager;
struct org_kde_kwin_server_decoration_manager *kwin_server_decoration_manager;
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *key_inhibitor_manager;
+ struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
EGLDisplay edpy;
EGLContext context;
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index cba97fd..9f9cf6c 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -37,6 +37,7 @@
#include "xdg-shell-unstable-v6-client-protocol.h"
#include "xdg-decoration-unstable-v1-client-protocol.h"
#include "org-kde-kwin-server-decoration-manager-client-protocol.h"
+#include "idle-inhibit-unstable-v1-client-protocol.h"
static float get_window_scale_factor(SDL_Window *window) {
return ((SDL_WindowData*)window->driverdata)->scale_factor;
@@ -838,6 +839,9 @@
}
}
+ /* We may need to create an idle inhibitor for this new window */
+ Wayland_SuspendScreenSaver(_this);
+
return 0;
}
@@ -916,6 +920,44 @@
WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
}
+void
+Wayland_SuspendScreenSaver(_THIS)
+{
+ SDL_VideoData *data = (SDL_VideoData *)_this->driverdata;
+
+#if SDL_USE_LIBDBUS
+ if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) {
+ return;
+ }
+#endif
+
+ /* The idle_inhibit_unstable_v1 protocol suspends the screensaver
+ on a per wl_surface basis, but SDL assumes that suspending
+ the screensaver can be done independently of any window.
+
+ To reconcile these differences, we propagate the idle inhibit
+ state to each window. If there is no window active, we will
+ be able to inhibit idle once the first window is created.
+ */
+ if (data->idle_inhibit_manager) {
+ SDL_Window *window = _this->windows;
+ while (window) {
+ SDL_WindowData *win_data = window->driverdata;
+
+ if (_this->suspend_screensaver && !win_data->idle_inhibitor) {
+ win_data->idle_inhibitor =
+ zwp_idle_inhibit_manager_v1_create_inhibitor(data->idle_inhibit_manager,
+ win_data->surface);
+ } else if (!_this->suspend_screensaver && win_data->idle_inhibitor) {
+ zwp_idle_inhibitor_v1_destroy(win_data->idle_inhibitor);
+ win_data->idle_inhibitor = NULL;
+ }
+
+ window = window->next;
+ }
+ }
+}
+
void Wayland_DestroyWindow(_THIS, SDL_Window *window)
{
SDL_VideoData *data = _this->driverdata;
@@ -937,6 +979,10 @@
org_kde_kwin_server_decoration_release(wind->kwin_server_decoration);
}
+ if (wind->idle_inhibitor) {
+ zwp_idle_inhibitor_v1_destroy(wind->idle_inhibitor);
+ }
+
if (data->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel) {
xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel);
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index 4a7472c..88a9768 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -66,6 +66,7 @@
struct zxdg_toplevel_decoration_v1 *server_decoration;
struct org_kde_kwin_server_decoration *kwin_server_decoration;
struct zwp_keyboard_shortcuts_inhibitor_v1 *key_inhibitor;
+ struct zwp_idle_inhibitor_v1 *idle_inhibitor;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct qt_extended_surface *extended_surface;
@@ -97,6 +98,7 @@
extern void Wayland_SetWindowSize(_THIS, SDL_Window * window);
extern void Wayland_SetWindowTitle(_THIS, SDL_Window * window);
extern void Wayland_DestroyWindow(_THIS, SDL_Window *window);
+extern void Wayland_SuspendScreenSaver(_THIS);
extern SDL_bool
Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
diff --git a/wayland-protocols/idle-inhibit-unstable-v1.xml b/wayland-protocols/idle-inhibit-unstable-v1.xml
new file mode 100644
index 0000000..9c06cdc
--- /dev/null
+++ b/wayland-protocols/idle-inhibit-unstable-v1.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="idle_inhibit_unstable_v1">
+
+ <copyright>
+ Copyright © 2015 Samsung Electronics Co., Ltd
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="zwp_idle_inhibit_manager_v1" version="1">
+ <description summary="control behavior when display idles">
+ This interface permits inhibiting the idle behavior such as screen
+ blanking, locking, and screensaving. The client binds the idle manager
+ globally, then creates idle-inhibitor objects for each surface.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the idle inhibitor object">
+ Destroy the inhibit manager.
+ </description>
+ </request>
+
+ <request name="create_inhibitor">
+ <description summary="create a new inhibitor object">
+ Create a new inhibitor object associated with the given surface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_idle_inhibitor_v1"/>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the surface that inhibits the idle behavior"/>
+ </request>
+
+ </interface>
+
+ <interface name="zwp_idle_inhibitor_v1" version="1">
+ <description summary="context object for inhibiting idle behavior">
+ An idle inhibitor prevents the output that the associated surface is
+ visible on from being set to a state where it is not visually usable due
+ to lack of user interaction (e.g. blanked, dimmed, locked, set to power
+ save, etc.) Any screensaver processes are also blocked from displaying.
+
+ If the surface is destroyed, unmapped, becomes occluded, loses
+ visibility, or otherwise becomes not visually relevant for the user, the
+ idle inhibitor will not be honored by the compositor; if the surface
+ subsequently regains visibility the inhibitor takes effect once again.
+ Likewise, the inhibitor isn't honored if the system was already idled at
+ the time the inhibitor was established, although if the system later
+ de-idles and re-idles the inhibitor will take effect.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the idle inhibitor object">
+ Remove the inhibitor effect from the associated wl_surface.
+ </description>
+ </request>
+
+ </interface>
+</protocol>