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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
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 @@ Wayland_CreateDevice(int devindex)
device->SetDisplayMode = Wayland_SetDisplayMode;
device->GetDisplayModes = Wayland_GetDisplayModes;
device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
+ device->SuspendScreenSaver = Wayland_SuspendScreenSaver;
device->PumpEvents = Wayland_PumpEvents;
@@ -397,6 +399,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
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_VideoInit(_THIS)
WAYLAND_wl_display_flush(data->display);
+#if SDL_USE_LIBDBUS
+ SDL_DBus_Init();
+#endif
+
return 0;
}
@@ -497,6 +505,9 @@ Wayland_VideoQuit(_THIS)
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 @@ Wayland_VideoQuit(_THIS)
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 @@ typedef struct {
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 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
}
}
+ /* We may need to create an idle inhibitor for this new window */
+ Wayland_SuspendScreenSaver(_this);
+
return 0;
}
@@ -916,6 +920,44 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
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 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window)
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 @@ typedef struct {
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 int Wayland_CreateWindow(_THIS, SDL_Window *window);
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>