Bug 1398539: Inhibit screensaver with XScreenSaverSuspend r=karlt
authorLee Bousfield <ljbousfield@gmail.com>
Wed, 13 Sep 2017 18:28:51 -0600
changeset 443548 baff3e8129149cd9667ffd9b827ee16006892b0c
parent 443547 bbe8f621038333bea5eb4f6cbf157d1030166700
child 443549 1de3d5f589b3529f24d69aaa76662d1022ca80d9
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1398539
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1398539: Inhibit screensaver with XScreenSaverSuspend r=karlt 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;