|
@@ -22,6 +22,7 @@
|
|
|
#include "SDL_hints.h"
|
|
|
#include "SDL_dbus.h"
|
|
|
#include "SDL_atomic.h"
|
|
|
+#include "SDL_sandbox.h"
|
|
|
#include "../../stdlib/SDL_vacopy.h"
|
|
|
|
|
|
#if SDL_USE_LIBDBUS
|
|
@@ -29,6 +30,7 @@
|
|
|
#include "SDL_loadso.h"
|
|
|
static const char *dbus_library = "libdbus-1.so.3";
|
|
|
static void *dbus_handle = NULL;
|
|
|
+static char *inhibit_handle = NULL;
|
|
|
static unsigned int screensaver_cookie = 0;
|
|
|
static SDL_DBusContext dbus;
|
|
|
|
|
@@ -192,6 +194,8 @@ SDL_DBus_Quit(void)
|
|
|
#endif
|
|
|
SDL_zero(dbus);
|
|
|
UnloadDBUSLibrary();
|
|
|
+ SDL_free(inhibit_handle);
|
|
|
+ inhibit_handle = NULL;
|
|
|
}
|
|
|
|
|
|
SDL_DBusContext *
|
|
@@ -363,20 +367,108 @@ SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface
|
|
|
void
|
|
|
SDL_DBus_ScreensaverTickle(void)
|
|
|
{
|
|
|
- if (screensaver_cookie == 0) { /* no need to tickle if we're inhibiting. */
|
|
|
+ if (screensaver_cookie == 0 && inhibit_handle == NULL) { /* no need to tickle if we're inhibiting. */
|
|
|
/* org.gnome.ScreenSaver is the legacy interface, but it'll either do nothing or just be a second harmless tickle on newer systems, so we leave it for now. */
|
|
|
SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
|
|
|
SDL_DBus_CallVoidMethod("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static SDL_bool
|
|
|
+SDL_DBus_AppendDictWithKeyValue(DBusMessageIter *iterInit, const char *key, const char *value)
|
|
|
+{
|
|
|
+ DBusMessageIter iterDict, iterEntry, iterValue;
|
|
|
+
|
|
|
+ if (!dbus.message_iter_open_container(iterInit, DBUS_TYPE_ARRAY, "{sv}", &iterDict))
|
|
|
+ goto failed;
|
|
|
+
|
|
|
+ if (!dbus.message_iter_open_container(&iterDict, DBUS_TYPE_DICT_ENTRY, NULL, &iterEntry))
|
|
|
+ goto failed;
|
|
|
+
|
|
|
+ if (!dbus.message_iter_append_basic(&iterEntry, DBUS_TYPE_STRING, &key))
|
|
|
+ goto failed;
|
|
|
+
|
|
|
+ if (!dbus.message_iter_open_container(&iterEntry, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &iterValue))
|
|
|
+ goto failed;
|
|
|
+
|
|
|
+ if (!dbus.message_iter_append_basic(&iterValue, DBUS_TYPE_STRING, &value))
|
|
|
+ goto failed;
|
|
|
+
|
|
|
+ if (!dbus.message_iter_close_container(&iterEntry, &iterValue)
|
|
|
+ || !dbus.message_iter_close_container(&iterDict, &iterEntry)
|
|
|
+ || !dbus.message_iter_close_container(iterInit, &iterDict)) {
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
+
|
|
|
+ return SDL_TRUE;
|
|
|
+
|
|
|
+failed:
|
|
|
+ /* message_iter_abandon_container_if_open() and message_iter_abandon_container() might be
|
|
|
+ * missing if libdbus is too old. Instead, we just return without cleaning up any eventual
|
|
|
+ * open container */
|
|
|
+ return SDL_FALSE;
|
|
|
+}
|
|
|
+
|
|
|
SDL_bool
|
|
|
SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
|
|
|
{
|
|
|
- if ( (inhibit && (screensaver_cookie != 0)) || (!inhibit && (screensaver_cookie == 0)) ) {
|
|
|
+ const char *default_inhibit_reason = "Playing a game";
|
|
|
+
|
|
|
+ if ( (inhibit && (screensaver_cookie != 0 || inhibit_handle != NULL))
|
|
|
+ || (!inhibit && (screensaver_cookie == 0 && inhibit_handle == NULL)) ) {
|
|
|
return SDL_TRUE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (SDL_DetectSandbox() != SDL_SANDBOX_NONE) {
|
|
|
+ const char *bus_name = "org.freedesktop.portal.Desktop";
|
|
|
+ const char *path = "/org/freedesktop/portal/desktop";
|
|
|
+ const char *interface = "org.freedesktop.portal.Inhibit";
|
|
|
+ const char *window = ""; /* As a future improvement we could gather the X11 XID or Wayland surface identifier */
|
|
|
+ static const unsigned int INHIBIT_IDLE = 8; /* Taken from the portal API reference */
|
|
|
+ DBusMessageIter iterInit;
|
|
|
+
|
|
|
+ if (inhibit) {
|
|
|
+ DBusMessage *msg;
|
|
|
+ SDL_bool retval = SDL_FALSE;
|
|
|
+ const char *key = "reason";
|
|
|
+ const char *reply = NULL;
|
|
|
+ const char *reason = SDL_GetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME);
|
|
|
+ if (!reason || !reason[0]) {
|
|
|
+ reason = default_inhibit_reason;
|
|
|
+ }
|
|
|
+
|
|
|
+ msg = dbus.message_new_method_call(bus_name, path, interface, "Inhibit");
|
|
|
+ if (!msg) {
|
|
|
+ return SDL_FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!dbus.message_append_args(msg, DBUS_TYPE_STRING, &window, DBUS_TYPE_UINT32, &INHIBIT_IDLE, DBUS_TYPE_INVALID)) {
|
|
|
+ dbus.message_unref(msg);
|
|
|
+ return SDL_FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ dbus.message_iter_init_append(msg, &iterInit);
|
|
|
+ if (!SDL_DBus_AppendDictWithKeyValue(&iterInit, key, reason)) {
|
|
|
+ dbus.message_unref(msg);
|
|
|
+ return SDL_FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (SDL_DBus_CallWithBasicReply(dbus.session_conn, msg, DBUS_TYPE_OBJECT_PATH, &reply)) {
|
|
|
+ inhibit_handle = SDL_strdup(reply);
|
|
|
+ retval = SDL_TRUE;
|
|
|
+ }
|
|
|
+
|
|
|
+ dbus.message_unref(msg);
|
|
|
+ return retval;
|
|
|
+ } else {
|
|
|
+ if (!SDL_DBus_CallVoidMethod(bus_name, inhibit_handle, "org.freedesktop.portal.Request", "Close", DBUS_TYPE_INVALID)) {
|
|
|
+ return SDL_FALSE;
|
|
|
+ }
|
|
|
+ SDL_free(inhibit_handle);
|
|
|
+ inhibit_handle = NULL;
|
|
|
+ }
|
|
|
} else {
|
|
|
- const char *node = "org.freedesktop.ScreenSaver";
|
|
|
+ const char *bus_name = "org.freedesktop.ScreenSaver";
|
|
|
const char *path = "/org/freedesktop/ScreenSaver";
|
|
|
const char *interface = "org.freedesktop.ScreenSaver";
|
|
|
|
|
@@ -387,17 +479,17 @@ SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
|
|
|
app = "My SDL application";
|
|
|
}
|
|
|
if (!reason || !reason[0]) {
|
|
|
- reason = "Playing a game";
|
|
|
+ reason = default_inhibit_reason;
|
|
|
}
|
|
|
|
|
|
- if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
|
|
|
+ if (!SDL_DBus_CallMethod(bus_name, path, interface, "Inhibit",
|
|
|
DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
|
|
|
DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
|
|
|
return SDL_FALSE;
|
|
|
}
|
|
|
return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
|
|
|
} else {
|
|
|
- if (!SDL_DBus_CallVoidMethod(node, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
|
|
|
+ if (!SDL_DBus_CallVoidMethod(bus_name, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
|
|
|
return SDL_FALSE;
|
|
|
}
|
|
|
screensaver_cookie = 0;
|