[go: nahoru, domu]

Linux/X11: Inhibit screen saver using X11

When no supported desktop environment (e.g. KDE or Gnome) is running,
inhibit the screen saver using the X11 Screen Saver Extension.

Currently, Chromium only supports a newer FreeDesktop API for
inhibiting the screen saver which is not available on bare X11.

BUG=246060

Review URL: https://codereview.chromium.org/1616733005

Cr-Commit-Position: refs/heads/master@{#384746}
diff --git a/AUTHORS b/AUTHORS
index 0225d9b6..89caae9 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -439,6 +439,8 @@
 Nedeljko Babic <nedeljko.babic@imgtec.com>
 Nikhil Bansal <n.bansal@samsung.com>
 Nikita Ofitserov <himikof@gmail.com>
+Nils Schneider <nils@nilsschneider.net>
+Nils Schneider <nils.schneider@gmail.com>
 Ningxin Hu <ningxin.hu@intel.com>
 Nitish Mehrotra <nitish.m@samsung.com>
 Noj Vek <nojvek@gmail.com>
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 7188165..b0b38b6 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -297,6 +297,9 @@
 
   if (use_x11) {
     configs += [ "//build/config/linux:x11" ]
+    if (!is_chromeos) {
+      configs += [ "//build/config/linux:xscrnsaver" ]
+    }
     deps += [ "//ui/gfx/x" ]
   }
 
diff --git a/content/browser/power_save_blocker_x11.cc b/content/browser/power_save_blocker_x11.cc
index 97eefef..babc814 100644
--- a/content/browser/power_save_blocker_x11.cc
+++ b/content/browser/power_save_blocker_x11.cc
@@ -7,6 +7,7 @@
 #include <X11/Xlib.h>
 #include <stdint.h>
 #include <X11/extensions/dpms.h>
+#include <X11/extensions/scrnsaver.h>
 // Xlib #defines Status, but we can't have that for some of our headers.
 #ifdef Status
 #undef Status
@@ -108,12 +109,22 @@
   void ApplyBlockFinished(dbus::Response* response);
   void RemoveBlockFinished(dbus::Response* response);
 
+  // Wrapper for XScreenSaverSuspend. Checks whether the X11 Screen Saver
+  // Extension is available first. If it isn't, this is a no-op.
+  // Must be called on the UI thread.
+  static void XSSSuspendSet(bool suspend);
+
   // If DPMS (the power saving system in X11) is not enabled, then we don't want
   // to try to disable power saving, since on some desktop environments that may
   // enable DPMS with very poor default settings (e.g. turning off the display
   // after only 1 second). Must be called on the UI thread.
   static bool DPMSEnabled();
 
+  // If no other method is available (i.e. not running under a Desktop
+  // Environment) check whether the X11 Screen Saver Extension can be used
+  // to disable the screen saver. Must be called on the UI thread.
+  static bool XSSAvailable();
+
   // Returns an appropriate D-Bus API to use based on the desktop environment.
   // Must be called on the UI thread, as it may call DPMSEnabled() above.
   static DBusAPI SelectAPI();
@@ -180,9 +191,14 @@
     // initializing on the UI thread, then just cancel it. We don't need to
     // remove the block because we haven't even applied it yet.
     enqueue_apply_ = false;
-  } else if (ShouldBlock()) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                            base::Bind(&Delegate::RemoveBlock, this));
+  } else {
+    if (ShouldBlock()) {
+      BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                              base::Bind(&Delegate::RemoveBlock, this));
+    }
+
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(&Delegate::XSSSuspendSet, false));
   }
 }
 
@@ -190,12 +206,17 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::AutoLock lock(lock_);
   api_ = SelectAPI();
-  if (enqueue_apply_ && ShouldBlock()) {
-    // The thread we use here becomes the origin and D-Bus thread for the D-Bus
-    // library, so we need to use the same thread above for RemoveBlock(). It
-    // must be a thread that allows I/O operations, so we use the FILE thread.
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                            base::Bind(&Delegate::ApplyBlock, this));
+
+  if (enqueue_apply_) {
+    if (ShouldBlock()) {
+      // The thread we use here becomes the origin and D-Bus thread for the
+      // D-Bus library, so we need to use the same thread above for
+      // RemoveBlock(). It must be a thread that allows I/O operations, so we
+      // use the FILE thread.
+      BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                              base::Bind(&Delegate::ApplyBlock, this));
+    }
+    XSSSuspendSet(true);
   }
   enqueue_apply_ = false;
 }
@@ -384,6 +405,17 @@
 }
 
 // static
+void PowerSaveBlockerImpl::Delegate::XSSSuspendSet(bool suspend) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  if (!XSSAvailable())
+    return;
+
+  XDisplay* display = gfx::GetXDisplay();
+  XScreenSaverSuspend(display, suspend);
+}
+
+// static
 bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   XDisplay* display = gfx::GetXDisplay();
@@ -397,6 +429,23 @@
 }
 
 // static
+bool PowerSaveBlockerImpl::Delegate::XSSAvailable() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  XDisplay* display = gfx::GetXDisplay();
+  int dummy;
+  int major;
+  int minor;
+
+  if (!XScreenSaverQueryExtension(display, &dummy, &dummy))
+    return false;
+
+  if (!XScreenSaverQueryVersion(display, &major, &minor))
+    return false;
+
+  return major > 1 || (major == 1 && minor >= 1);
+}
+
+// static
 DBusAPI PowerSaveBlockerImpl::Delegate::SelectAPI() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   scoped_ptr<base::Environment> env(base::Environment::Create());
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index cbb7986..5761e08 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -2021,6 +2021,7 @@
         '../build/linux/system.gyp:atk',
         '../build/linux/system.gyp:gconf',
         '../build/linux/system.gyp:glib',
+        '../build/linux/system.gyp:xscrnsaver',
       ],
       'variables': {
         'clang_warning_flags': [