Commit 4ca76b3e59ba4128e23910e09c853f001da1e26b

Bastien Nocera 2014-03-02T14:59:06

Add support for the freedesktop.org Idle Inhibition specification, as per: http://people.freedesktop.org/~hadess/idle-inhibition-spec/ This makes screensaver inhibition work with GNOME 3 and other desktop environments that implement the specification. https://bugzilla.libsdl.org/show_bug.cgi?id=2169

diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index bf0b139..ad3c59d 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -1029,7 +1029,19 @@ X11_SuspendScreenSaver(_THIS)
     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
     int dummy;
     int major_version, minor_version;
+#endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
 
+#if SDL_USE_LIBDBUS
+    if (SDL_dbus_screensaver_inhibit(_this)) {
+        return;
+    }
+
+    if (_this->suspend_screensaver) {
+        SDL_dbus_screensaver_tickle(_this);
+    }
+#endif
+
+#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
     if (SDL_X11_HAVE_XSS) {
         /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
         if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
@@ -1043,12 +1055,6 @@ X11_SuspendScreenSaver(_THIS)
         X11_XResetScreenSaver(data->display);
     }
 #endif
-
-#if SDL_USE_LIBDBUS
-    if (_this->suspend_screensaver) {
-        SDL_dbus_screensaver_tickle(_this);
-    }
-#endif
 }
 
 #endif /* SDL_VIDEO_DRIVER_X11 */
diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
index 63cfa98..ca9faee 100644
--- a/src/video/x11/SDL_x11video.c
+++ b/src/video/x11/SDL_x11video.c
@@ -45,6 +45,7 @@
 #include "SDL_loadso.h"
 static const char *dbus_library = "libdbus-1.so.3";
 static void *dbus_handle = NULL;
+static unsigned int screensaver_cookie = 0;
 
 /* !!! FIXME: this is kinda ugly. */
 static SDL_bool
@@ -63,10 +64,13 @@ load_dbus_sym(const char *fn, void **addr)
 static DBusConnection *(*DBUS_dbus_bus_get_private)(DBusBusType, DBusError *) = NULL;
 static void (*DBUS_dbus_connection_set_exit_on_disconnect)(DBusConnection *, dbus_bool_t) = NULL;
 static dbus_bool_t (*DBUS_dbus_connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *) = NULL;
+static DBusMessage *(*DBUS_dbus_connection_send_with_reply_and_block)(DBusConnection *, DBusMessage *, int, DBusError *) = NULL;
 static void (*DBUS_dbus_connection_close)(DBusConnection *) = NULL;
 static void (*DBUS_dbus_connection_unref)(DBusConnection *) = NULL;
 static void (*DBUS_dbus_connection_flush)(DBusConnection *) = NULL;
 static DBusMessage *(*DBUS_dbus_message_new_method_call)(const char *, const char *, const char *, const char *) = NULL;
+static dbus_bool_t (*DBUS_dbus_message_append_args)(DBusMessage *, int, ...) = NULL;
+static dbus_bool_t (*DBUS_dbus_message_get_args)(DBusMessage *, DBusError *, int, ...) = NULL;
 static void (*DBUS_dbus_message_unref)(DBusMessage *) = NULL;
 static void (*DBUS_dbus_error_init)(DBusError *) = NULL;
 static dbus_bool_t (*DBUS_dbus_error_is_set)(const DBusError *) = NULL;
@@ -82,9 +86,12 @@ load_dbus_syms(void)
     SDL_DBUS_SYM(dbus_bus_get_private);
     SDL_DBUS_SYM(dbus_connection_set_exit_on_disconnect);
     SDL_DBUS_SYM(dbus_connection_send);
+    SDL_DBUS_SYM(dbus_connection_send_with_reply_and_block);
     SDL_DBUS_SYM(dbus_connection_close);
     SDL_DBUS_SYM(dbus_connection_unref);
     SDL_DBUS_SYM(dbus_connection_flush);
+    SDL_DBUS_SYM(dbus_message_append_args);
+    SDL_DBUS_SYM(dbus_message_get_args);
     SDL_DBUS_SYM(dbus_message_new_method_call);
     SDL_DBUS_SYM(dbus_message_unref);
     SDL_DBUS_SYM(dbus_error_init);
@@ -174,6 +181,76 @@ SDL_dbus_screensaver_tickle(_THIS)
         }
     }
 }
+
+SDL_bool
+SDL_dbus_screensaver_inhibit(_THIS)
+{
+    const SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
+    DBusConnection *conn = data->dbus;
+
+    if (conn == NULL)
+        return SDL_FALSE;
+
+    if (_this->suspend_screensaver &&
+        screensaver_cookie != 0)
+        return SDL_TRUE;
+    if (!_this->suspend_screensaver &&
+        screensaver_cookie == 0)
+        return SDL_TRUE;
+
+    if (_this->suspend_screensaver) {
+        const char *app = "My SDL application";
+        const char *reason = "Playing a game";
+
+        DBusMessage *msg = DBUS_dbus_message_new_method_call("org.freedesktop.ScreenSaver",
+                                                             "/org/freedesktop/ScreenSaver",
+                                                             "org.freedesktop.ScreenSaver",
+                                                             "Inhibit");
+        if (msg != NULL) {
+            DBUS_dbus_message_append_args (msg,
+                                           DBUS_TYPE_STRING, &app,
+                                           DBUS_TYPE_STRING, &reason,
+                                           DBUS_TYPE_INVALID);
+        }
+
+        if (msg != NULL) {
+            DBusMessage *reply;
+
+            reply = DBUS_dbus_connection_send_with_reply_and_block(conn, msg, 300, NULL);
+            if (reply) {
+                if (!DBUS_dbus_message_get_args(reply, NULL,
+                                                DBUS_TYPE_UINT32, &screensaver_cookie,
+                                                DBUS_TYPE_INVALID))
+                    screensaver_cookie = 0;
+                DBUS_dbus_message_unref(reply);
+            }
+
+            DBUS_dbus_message_unref(msg);
+        }
+
+        if (screensaver_cookie == 0) {
+            return SDL_FALSE;
+        }
+        return SDL_TRUE;
+    } else {
+        DBusMessage *msg = DBUS_dbus_message_new_method_call("org.freedesktop.ScreenSaver",
+                                                             "/org/freedesktop/ScreenSaver",
+                                                             "org.freedesktop.ScreenSaver",
+                                                             "UnInhibit");
+        DBUS_dbus_message_append_args (msg,
+                                       DBUS_TYPE_UINT32, &screensaver_cookie,
+                                       DBUS_TYPE_INVALID);
+        if (msg != NULL) {
+            if (DBUS_dbus_connection_send(conn, msg, NULL)) {
+                DBUS_dbus_connection_flush(conn);
+            }
+            DBUS_dbus_message_unref(msg);
+        }
+
+        screensaver_cookie = 0;
+        return SDL_TRUE;
+    }
+}
 #endif
 
 /* Initialization/Query functions */
diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h
index 927e38b..8ab88f7 100644
--- a/src/video/x11/SDL_x11video.h
+++ b/src/video/x11/SDL_x11video.h
@@ -121,6 +121,7 @@ typedef struct SDL_VideoData
 
 extern SDL_bool X11_UseDirectColorVisuals(void);
 
+SDL_bool SDL_dbus_screensaver_inhibit(_THIS);
 void SDL_dbus_screensaver_tickle(_THIS);
 
 #endif /* _SDL_x11video_h */