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.
This commit is contained in:
Cameron Gutman
2021-01-20 21:17:20 -06:00
parent 7ff3832e4d
commit bd553ea868
5 changed files with 151 additions and 0 deletions

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);