Index: content/browser/power_save_blocker_linux.cc |
=================================================================== |
--- content/browser/power_save_blocker_linux.cc (revision 133819) |
+++ content/browser/power_save_blocker_linux.cc (working copy) |
@@ -4,6 +4,13 @@ |
#include "content/browser/power_save_blocker.h" |
+#include <X11/Xlib.h> |
+#include <X11/extensions/dpms.h> |
+// Xlib #defines Status, but we can't have that for some of our headers. |
+#ifdef Status |
+#undef Status |
+#endif |
+ |
#include "base/basictypes.h" |
#include "base/bind.h" |
#include "base/callback.h" |
@@ -15,6 +22,11 @@ |
#include "base/memory/scoped_ptr.h" |
#include "base/memory/singleton.h" |
#include "base/message_loop_proxy.h" |
+#if defined(TOOLKIT_GTK) |
+#include "base/message_pump_gtk.h" |
+#else |
+#include "base/message_pump_x.h" |
+#endif |
#include "base/nix/xdg_util.h" |
#include "content/public/browser/browser_thread.h" |
#include "dbus/bus.h" |
@@ -26,40 +38,36 @@ |
namespace { |
-// This class is used to inhibit Power Management on Linux systems |
-// using D-Bus interfaces. Mainly, there are two interfaces that |
-// make this possible. |
-// org.freedesktop.PowerManagement[.Inhibit] is considered to be |
-// the desktop-agnostic solution. However, it is only used by |
-// KDE4 and XFCE. |
-// org.gnome.SessionManager is the Power Management interface |
-// available on Gnome desktops. |
-// Given that there is no generic solution to this problem, |
-// this class delegates the task of calling specific D-Bus APIs, |
-// to a DBusPowerSaveBlock::Delegate object. |
-// This class is a Singleton and the delegate will be instantiated |
-// internally, when the singleton instance is created, based on |
-// the desktop environment in which the application is running. |
-// When the class is instantiated, if it runs under a supported |
-// desktop environment it creates the Bus object and the |
-// delegate. Otherwise, no object is created and the ApplyBlock |
-// method will not do anything. |
+// This class is used to inhibit Power Management on Linux systems using D-Bus |
+// interfaces. Mainly, there are two interfaces that make this possible. |
+// org.freedesktop.PowerManagement[.Inhibit] is considered to be the |
+// desktop-agnostic solution. However, it is only used by KDE4 and XFCE. |
+// |
+// org.gnome.SessionManager is the Power Management interface available on GNOME |
+// desktops. Given that there is no generic solution to this problem, this class |
+// delegates the task of calling specific D-Bus APIs, to a |
+// DBusPowerSaveBlock::Delegate object. |
+// |
+// This class is a Singleton and the delegate will be instantiated internally, |
+// when the singleton instance is created, based on the desktop environment in |
+// which the application is running. When the class is instantiated, if it runs |
+// under a supported desktop environment it creates the Bus object and the |
+// delegate. Otherwise, no object is created and the ApplyBlock method will not |
+// do anything. |
class DBusPowerSaveBlocker { |
public: |
// String passed to D-Bus APIs as the reason for which |
// the power management features are temporarily disabled. |
static const char kPowerSaveReason[]; |
- // This delegate interface represents a concrete |
- // implementation for a specific D-Bus interface. |
- // It is responsible for obtaining specific object proxies, |
+ // This delegate interface represents a concrete implementation for a specific |
+ // D-Bus interface. It is responsible for obtaining specific object proxies, |
// making D-Bus method calls and handling D-Bus responses. |
- // When a new DBusPowerBlocker is created, only a specific |
- // implementation of the delegate is instantiated. See the |
- // DBusPowerSaveBlocker constructor for more details. |
- // This is ref_counted to make sure that the callbacks |
- // stay alive even after the DBusPowerSaveBlocker object |
- // is deleted. |
+ // |
+ // When a new DBusPowerBlocker is created, only a specific implementation of |
+ // the delegate is instantiated. See the DBusPowerSaveBlocker constructor for |
+ // more details. This is ref_counted to make sure that the callbacks stay |
+ // alive even after the DBusPowerSaveBlocker object is deleted. |
class Delegate : public base::RefCountedThreadSafe<Delegate> { |
public: |
Delegate() {} |
@@ -72,10 +80,9 @@ |
// Returns a pointer to the sole instance of this class |
static DBusPowerSaveBlocker* GetInstance(); |
- // Forwards a power save block request to the concrete implementation |
- // of the Delegate interface. |
- // If |delegate_| is NULL, the application runs under an unsupported |
- // desktop environment. In this case, the method doesn't do anything. |
+ // Forwards a power save block request to the concrete implementation of the |
+ // Delegate interface. If |delegate_| is NULL, the application runs under an |
+ // unsupported desktop environment. In this case, the method does nothing. |
void ApplyBlock(PowerSaveBlocker::PowerSaveBlockerType type) { |
if (delegate_) |
delegate_->ApplyBlock(type); |
@@ -88,6 +95,11 @@ |
DBusPowerSaveBlocker(); |
virtual ~DBusPowerSaveBlocker(); |
+ // If DPMS 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). |
+ static bool DPMSEnabled(); |
+ |
// The D-Bus connection. |
scoped_refptr<dbus::Bus> bus_; |
@@ -99,15 +111,15 @@ |
DISALLOW_COPY_AND_ASSIGN(DBusPowerSaveBlocker); |
}; |
-// Delegate implementation for KDE4. |
-// It uses the org.freedesktop.PowerManagement interface. |
-// Works on XFCE4, too. |
+// Delegate implementation for KDE4. It uses the |
+// org.freedesktop.PowerManagement interface. It works on XFCE4, too. |
class KDEPowerSaveBlocker : public DBusPowerSaveBlocker::Delegate { |
public: |
KDEPowerSaveBlocker() |
: inhibit_cookie_(0), |
pending_inhibit_call_(false), |
- postponed_uninhibit_call_(false) {} |
+ postponed_uninhibit_call_(false) { |
+ } |
~KDEPowerSaveBlocker() {} |
virtual void ApplyBlock( |
@@ -253,22 +265,23 @@ |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
DCHECK(postponed_uninhibit_calls_ <= pending_inhibit_calls_); |
- // If we have a pending inhibit call, we add a postponed uninhibit |
- // request, such that it will be canceled as soon as the response arrives. |
- // We want to cancel the current inhibit request whether |type| is |
+ // If we have a pending inhibit call, we add a postponed uninhibit request, |
+ // such that it will be canceled as soon as the response arrives. We want to |
+ // cancel the current inhibit request whether |type| is |
// kPowerSaveBlockPreventNone or not. If |type| represents an inhibit |
- // request, we are dealing with the same case as below, just that the |
- // reply to the previous inhibit request did not arrive yet, so we have |
- // to wait for the cookie in order to cancel it. |
- // Meanwhile, we can still make the new request. |
- // We also have to check that |
- // postponed_uninhibit_calls_ < pending_inhibit_calls_. |
- // If this is not the case, then all the pending requests were already |
- // canceled and we should not increment the number of postponed uninhibit |
- // requests; otherwise we will cancel unwanted future inhibits, |
- // that will be made after this call. |
- // NOTE: The implementation is based on the fact that we receive |
- // the D-Bus replies in the same order in which the requests are made. |
+ // request, we are dealing with the same case as below, just that the reply |
+ // to the previous inhibit request did not arrive yet, so we have to wait |
+ // for the cookie in order to cancel it. Meanwhile, we can still make the |
+ // new request. |
+ // |
+ // We also have to check that postponed_uninhibit_calls_ < |
+ // pending_inhibit_calls_. If this is not the case, then all the pending |
+ // requests were already canceled and we should not increment the number of |
+ // postponed uninhibit requests; otherwise we will cancel unwanted future |
+ // inhibits, that will be made after this call. |
+ // |
+ // NOTE: The implementation is based on the fact that we receive the D-Bus |
+ // replies in the same order in which the requests are made. |
if (pending_inhibit_calls_ > 0 && |
postponed_uninhibit_calls_ < pending_inhibit_calls_) { |
++postponed_uninhibit_calls_; |
@@ -345,7 +358,7 @@ |
++pending_inhibit_calls_; |
break; |
case PowerSaveBlocker::kPowerSaveBlockPreventStateCount: |
- // This is an invalid argument; |
+ // This is an invalid argument. |
NOTREACHED(); |
break; |
} |
@@ -415,11 +428,13 @@ |
scoped_ptr<base::Environment> env(base::Environment::Create()); |
switch (base::nix::GetDesktopEnvironment(env.get())) { |
case base::nix::DESKTOP_ENVIRONMENT_GNOME: |
- delegate_ = new GnomePowerSaveBlocker(); |
+ if (DPMSEnabled()) |
+ delegate_ = new GnomePowerSaveBlocker(); |
break; |
case base::nix::DESKTOP_ENVIRONMENT_XFCE: |
case base::nix::DESKTOP_ENVIRONMENT_KDE4: |
- delegate_ = new KDEPowerSaveBlocker(); |
+ if (DPMSEnabled()) |
+ delegate_ = new KDEPowerSaveBlocker(); |
break; |
case base::nix::DESKTOP_ENVIRONMENT_KDE3: |
case base::nix::DESKTOP_ENVIRONMENT_OTHER: |
@@ -456,6 +471,22 @@ |
} |
// static |
+bool DBusPowerSaveBlocker::DPMSEnabled() { |
+#if defined(TOOLKIT_GTK) |
+ Display* display = base::MessagePumpGtk::GetDefaultXDisplay(); |
+#else |
+ Display* display = base::MessagePumpX::GetDefaultXDisplay(); |
+#endif |
+ BOOL enabled = false; |
+ int dummy; |
+ if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) { |
+ CARD16 state; |
+ DPMSInfo(display, &state, &enabled); |
+ } |
+ return enabled; |
+} |
+ |
+// static |
DBusPowerSaveBlocker* DBusPowerSaveBlocker::GetInstance() { |
return Singleton<DBusPowerSaveBlocker>::get(); |
} |