Bug 1398539: Inhibit screensaver with XScreenSaverSuspend
MozReview-Commit-ID: LhhpaDaPdaO
--- 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;