Bug 1398539: Inhibit screensaver with XScreenSaverSuspend draft
authorLee Bousfield <ljbousfield@gmail.com>
Wed, 13 Sep 2017 18:28:51 -0600
changeset 693384 b31f3e9d92c7e7c18ad00c056aeb8598344a2a4a
parent 693376 179dae92e4d794e7f45ad080ff01908c80691f31
child 739008 6e909476da3dc692abcf9ec4fccd9dd95bf6ab0f
push id87774
push userbmo:ljbousfield@gmail.com
push dateMon, 06 Nov 2017 02:45:54 +0000
bugs1398539
milestone58.0a1
Bug 1398539: Inhibit screensaver with XScreenSaverSuspend MozReview-Commit-ID: LhhpaDaPdaO
widget/gtk/WakeLockListener.cpp
--- a/widget/gtk/WakeLockListener.cpp
+++ b/widget/gtk/WakeLockListener.cpp
@@ -7,16 +7,20 @@
 
 #ifdef MOZ_ENABLE_DBUS
 
 #include "WakeLockListener.h"
 
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#if defined(MOZ_X11)
+#include "prlink.h"
+#endif
+
 #define FREEDESKTOP_SCREENSAVER_TARGET    "org.freedesktop.ScreenSaver"
 #define FREEDESKTOP_SCREENSAVER_OBJECT    "/ScreenSaver"
 #define FREEDESKTOP_SCREENSAVER_INTERFACE "org.freedesktop.ScreenSaver"
 
 #define SESSION_MANAGER_TARGET            "org.gnome.SessionManager"
 #define SESSION_MANAGER_OBJECT            "/org/gnome/SessionManager"
 #define SESSION_MANAGER_INTERFACE         "org.gnome.SessionManager"
 
@@ -27,16 +31,19 @@ using namespace mozilla;
 NS_IMPL_ISUPPORTS(WakeLockListener, nsIDOMMozWakeLockListener)
 
 StaticRefPtr<WakeLockListener> WakeLockListener::sSingleton;
 
 
 enum DesktopEnvironment {
   FreeDesktop,
   GNOME,
+#if defined(MOZ_X11)
+  XScreenSaver,
+#endif
   Unsupported,
 };
 
 class WakeLockTopic
 {
 public:
   WakeLockTopic(const nsAString& aTopic, DBusConnection* aConnection)
     : mTopic(NS_ConvertUTF16toUTF8(aTopic))
@@ -54,16 +61,21 @@ public:
 private:
   bool SendInhibit();
   bool SendUninhibit();
 
   bool SendFreeDesktopInhibitMessage();
   bool SendGNOMEInhibitMessage();
   bool SendMessage(DBusMessage* aMessage);
 
+#if defined(MOZ_X11)
+  static bool CheckXScreenSaverSupport();
+  static bool InhibitXScreenSaver(bool inhibit);
+#endif
+
   static void ReceiveInhibitReply(DBusPendingCall* aPending, void* aUserData);
   void InhibitFailed();
   void InhibitSucceeded(uint32_t aInhibitRequest);
 
   nsCString mTopic;
   RefPtr<DBusConnection> mConnection;
 
   DesktopEnvironment mDesktopEnvironment;
@@ -138,29 +150,98 @@ WakeLockTopic::SendGNOMEInhibitMessage()
                            DBUS_TYPE_STRING, &topic,
                            DBUS_TYPE_UINT32, &flags,
                            DBUS_TYPE_INVALID);
 
   return SendMessage(message);
 }
 
 
+#if defined(MOZ_X11)
+
+typedef Bool (*_XScreenSaverQueryExtension_fn)(Display* dpy, int* event_base,
+                                               int* error_base);
+typedef Bool (*_XScreenSaverQueryVersion_fn)(Display* dpy, int* major,
+                                             int* minor);
+typedef void (*_XScreenSaverSuspend_fn)(Display* dpy, Bool suspend);
+
+static PRLibrary* sXssLib = nullptr;
+static _XScreenSaverQueryExtension_fn _XSSQueryExtension = nullptr;
+static _XScreenSaverQueryVersion_fn _XSSQueryVersion = nullptr;
+static _XScreenSaverSuspend_fn _XSSSuspend = nullptr;
+
+/* static */ bool
+WakeLockTopic::CheckXScreenSaverSupport()
+{
+  if (!sXssLib) {
+    sXssLib = PR_LoadLibrary("libXss.so.1");
+    if (!sXssLib) {
+      return false;
+    }
+  }
+
+  _XSSQueryExtension = (_XScreenSaverQueryExtension_fn)
+      PR_FindFunctionSymbol(sXssLib, "XScreenSaverQueryExtension");
+  _XSSQueryVersion = (_XScreenSaverQueryVersion_fn)
+      PR_FindFunctionSymbol(sXssLib, "XScreenSaverQueryVersion");
+  _XSSSuspend = (_XScreenSaverSuspend_fn)
+      PR_FindFunctionSymbol(sXssLib, "XScreenSaverSuspend");
+  if (!_XSSQueryExtension || !_XSSQueryVersion || !_XSSSuspend) {
+    return false;
+  }
+
+  GdkDisplay* gDisplay = gdk_display_get_default();
+  if (!GDK_IS_X11_DISPLAY(gDisplay)) return false;
+  Display* display = GDK_DISPLAY_XDISPLAY(gDisplay);
+
+  int throwaway;
+  if (!_XSSQueryExtension(display, &throwaway, &throwaway)) return false;
+
+  int major, minor;
+  if (!_XSSQueryVersion(display, &major, &minor)) return false;
+  // Needs to be compatible with version 1.1
+  if (major != 1) return false;
+  if (minor < 1) return false;
+
+  return true;
+}
+
+/* static */ bool
+WakeLockTopic::InhibitXScreenSaver(bool inhibit)
+{
+  // Should only be called if CheckXScreenSaverSupport returns true.
+  // There's a couple of safety checks here nonetheless.
+  if (!_XSSSuspend) return false;
+  GdkDisplay* gDisplay = gdk_display_get_default();
+  if (!GDK_IS_X11_DISPLAY(gDisplay)) return false;
+  Display* display = GDK_DISPLAY_XDISPLAY(gDisplay);
+  _XSSSuspend(display, inhibit);
+  return true;
+}
+
+#endif
+
+
 bool
 WakeLockTopic::SendInhibit()
 {
   bool sendOk = false;
 
   switch (mDesktopEnvironment)
   {
   case FreeDesktop:
     sendOk = SendFreeDesktopInhibitMessage();
     break;
   case GNOME:
     sendOk = SendGNOMEInhibitMessage();
     break;
+#if defined(MOZ_X11)
+  case XScreenSaver:
+    return InhibitXScreenSaver(true);
+#endif
   case Unsupported:
     return false;
   }
 
   if (sendOk) {
     mWaitingForReply = true;
   }
 
@@ -180,16 +261,21 @@ WakeLockTopic::SendUninhibit()
                                    "UnInhibit"));
   } else if (mDesktopEnvironment == GNOME) {
     message = already_AddRefed<DBusMessage>(
       dbus_message_new_method_call(SESSION_MANAGER_TARGET,
                                    SESSION_MANAGER_OBJECT,
                                    SESSION_MANAGER_INTERFACE,
                                    "Uninhibit"));
   }
+#if defined(MOZ_X11)
+  else if (mDesktopEnvironment == XScreenSaver) {
+    return InhibitXScreenSaver(false);
+  }
+#endif
 
   if (!message) {
     return false;
   }
 
   dbus_message_append_args(message,
                            DBUS_TYPE_UINT32, &mInhibitRequest,
                            DBUS_TYPE_INVALID);
@@ -244,18 +330,21 @@ WakeLockTopic::UninhibitScreensaver()
 
 void
 WakeLockTopic::InhibitFailed()
 {
   mWaitingForReply = false;
 
   if (mDesktopEnvironment == FreeDesktop) {
     mDesktopEnvironment = GNOME;
+#if defined(MOZ_X11)
+  } else if (mDesktopEnvironment == GNOME && CheckXScreenSaverSupport()) {
+    mDesktopEnvironment = XScreenSaver;
+#endif
   } else {
-    NS_ASSERTION(mDesktopEnvironment == GNOME, "Unknown desktop environment");
     mDesktopEnvironment = Unsupported;
     mShouldInhibit = false;
   }
 
   if (!mShouldInhibit) {
     // We were interrupted by UninhibitScreensaver() before we could find the
     // correct desktop environment.
     return;