Index: content/browser/power_save_blocker_x11.cc |
diff --git a/content/browser/power_save_blocker_x11.cc b/content/browser/power_save_blocker_x11.cc |
deleted file mode 100644 |
index a177e392ce1466f2469fe0f76908cd1c09959d7d..0000000000000000000000000000000000000000 |
--- a/content/browser/power_save_blocker_x11.cc |
+++ /dev/null |
@@ -1,508 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include <X11/Xlib.h> |
-#include <X11/extensions/dpms.h> |
-#include <X11/extensions/scrnsaver.h> |
-#include <stdint.h> |
- |
-#include <memory> |
- |
-#include "content/browser/power_save_blocker_impl.h" |
-// Xlib #defines Status, but we can't have that for some of our headers. |
-#ifdef Status |
-#undef Status |
-#endif |
- |
-#include "base/bind.h" |
-#include "base/callback.h" |
-#include "base/command_line.h" |
-#include "base/environment.h" |
-#include "base/files/file_path.h" |
-#include "base/location.h" |
-#include "base/logging.h" |
-#include "base/macros.h" |
-#include "base/memory/ref_counted.h" |
-#include "base/memory/singleton.h" |
-#include "base/nix/xdg_util.h" |
-#include "base/synchronization/lock.h" |
-#include "dbus/bus.h" |
-#include "dbus/message.h" |
-#include "dbus/object_path.h" |
-#include "dbus/object_proxy.h" |
-#include "ui/gfx/x/x11_types.h" |
- |
-namespace { |
- |
-enum DBusAPI { |
- NO_API, // Disable. No supported API available. |
- GNOME_API, // Use the GNOME API. (Supports more features.) |
- FREEDESKTOP_API, // Use the FreeDesktop API, for KDE4, KDE5, and XFCE. |
-}; |
- |
-// Inhibit flags defined in the org.gnome.SessionManager interface. |
-// Can be OR'd together and passed as argument to the Inhibit() method |
-// to specify which power management features we want to suspend. |
-enum GnomeAPIInhibitFlags { |
- INHIBIT_LOGOUT = 1, |
- INHIBIT_SWITCH_USER = 2, |
- INHIBIT_SUSPEND_SESSION = 4, |
- INHIBIT_MARK_SESSION_IDLE = 8 |
-}; |
- |
-const char kGnomeAPIServiceName[] = "org.gnome.SessionManager"; |
-const char kGnomeAPIInterfaceName[] = "org.gnome.SessionManager"; |
-const char kGnomeAPIObjectPath[] = "/org/gnome/SessionManager"; |
- |
-const char kFreeDesktopAPIPowerServiceName[] = |
- "org.freedesktop.PowerManagement"; |
-const char kFreeDesktopAPIPowerInterfaceName[] = |
- "org.freedesktop.PowerManagement.Inhibit"; |
-const char kFreeDesktopAPIPowerObjectPath[] = |
- "/org/freedesktop/PowerManagement/Inhibit"; |
- |
-const char kFreeDesktopAPIScreenServiceName[] = "org.freedesktop.ScreenSaver"; |
-const char kFreeDesktopAPIScreenInterfaceName[] = "org.freedesktop.ScreenSaver"; |
-const char kFreeDesktopAPIScreenObjectPath[] = "/org/freedesktop/ScreenSaver"; |
- |
-} // namespace |
- |
-namespace content { |
- |
-class PowerSaveBlockerImpl::Delegate |
- : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> { |
- public: |
- // Picks an appropriate D-Bus API to use based on the desktop environment. |
- Delegate(PowerSaveBlockerType type, |
- const std::string& description, |
- bool freedesktop_only, |
- scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner); |
- |
- // Post a task to initialize the delegate on the UI thread, which will itself |
- // then post a task to apply the power save block on the FILE thread. |
- void Init(); |
- |
- // Post a task to remove the power save block on the FILE thread, unless it |
- // hasn't yet been applied, in which case we just prevent it from applying. |
- void CleanUp(); |
- |
- private: |
- friend class base::RefCountedThreadSafe<Delegate>; |
- ~Delegate() {} |
- |
- // Selects an appropriate D-Bus API to use for this object. Must be called on |
- // the UI thread. Checks enqueue_apply_ once an API has been selected, and |
- // enqueues a call back to ApplyBlock() if it is true. See the comments for |
- // enqueue_apply_ below. |
- void InitOnUIThread(); |
- |
- // Returns true if ApplyBlock() / RemoveBlock() should be called. |
- bool ShouldBlock() const; |
- |
- // Apply or remove the power save block, respectively. These methods should be |
- // called once each, on the same thread, per instance. They block waiting for |
- // the action to complete (with a timeout); the thread must thus allow I/O. |
- void ApplyBlock(); |
- void RemoveBlock(); |
- |
- // Asynchronous callback functions for ApplyBlock and RemoveBlock. |
- // Functions do not receive ownership of |response|. |
- 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. |
- 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. |
- 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. |
- 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. |
- DBusAPI SelectAPI(); |
- |
- const PowerSaveBlockerType type_; |
- const std::string description_; |
- const bool freedesktop_only_; |
- |
- // Initially, we post a message to the UI thread to select an API. When it |
- // finishes, it will post a message to the FILE thread to perform the actual |
- // application of the block, unless enqueue_apply_ is false. We set it to |
- // false when we post that message, or when RemoveBlock() is called before |
- // ApplyBlock() has run. Both api_ and enqueue_apply_ are guarded by lock_. |
- DBusAPI api_; |
- bool enqueue_apply_; |
- base::Lock lock_; |
- |
- // Indicates that a D-Bus power save blocking request is in flight. |
- bool block_inflight_; |
- // Used to detect erronous redundant calls to RemoveBlock(). |
- bool unblock_inflight_; |
- // Indicates that RemoveBlock() is called before ApplyBlock() has finished. |
- // If it's true, then the RemoveBlock() call will be processed immediately |
- // after ApplyBlock() has finished. |
- bool enqueue_unblock_; |
- |
- scoped_refptr<dbus::Bus> bus_; |
- |
- // The cookie that identifies our inhibit request, |
- // or 0 if there is no active inhibit request. |
- uint32_t inhibit_cookie_; |
- |
- scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; |
- scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner_; |
- |
- DISALLOW_COPY_AND_ASSIGN(Delegate); |
-}; |
- |
-PowerSaveBlockerImpl::Delegate::Delegate( |
- PowerSaveBlockerType type, |
- const std::string& description, |
- bool freedesktop_only, |
- scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner) |
- : type_(type), |
- description_(description), |
- freedesktop_only_(freedesktop_only), |
- api_(NO_API), |
- enqueue_apply_(false), |
- inhibit_cookie_(0), |
- ui_task_runner_(ui_task_runner), |
- blocking_task_runner_(blocking_task_runner) { |
- // We're on the client's thread here, so we don't allocate the dbus::Bus |
- // object yet. We'll do it later in ApplyBlock(), on the FILE thread. |
-} |
- |
-void PowerSaveBlockerImpl::Delegate::Init() { |
- base::AutoLock lock(lock_); |
- DCHECK(!enqueue_apply_); |
- enqueue_apply_ = true; |
- block_inflight_ = false; |
- unblock_inflight_ = false; |
- enqueue_unblock_ = false; |
- ui_task_runner_->PostTask(FROM_HERE, |
- base::Bind(&Delegate::InitOnUIThread, this)); |
-} |
- |
-void PowerSaveBlockerImpl::Delegate::CleanUp() { |
- base::AutoLock lock(lock_); |
- if (enqueue_apply_) { |
- // If a call to ApplyBlock() has not yet been enqueued because we are still |
- // 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()) { |
- blocking_task_runner_->PostTask(FROM_HERE, |
- base::Bind(&Delegate::RemoveBlock, this)); |
- } |
- |
- ui_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&Delegate::XSSSuspendSet, this, false)); |
- } |
-} |
- |
-void PowerSaveBlockerImpl::Delegate::InitOnUIThread() { |
- DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
- base::AutoLock lock(lock_); |
- api_ = SelectAPI(); |
- |
- 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. |
- blocking_task_runner_->PostTask(FROM_HERE, |
- base::Bind(&Delegate::ApplyBlock, this)); |
- } |
- XSSSuspendSet(true); |
- } |
- enqueue_apply_ = false; |
-} |
- |
-bool PowerSaveBlockerImpl::Delegate::ShouldBlock() const { |
- return freedesktop_only_ ? api_ == FREEDESKTOP_API : api_ != NO_API; |
-} |
- |
-void PowerSaveBlockerImpl::Delegate::ApplyBlock() { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(!bus_); // ApplyBlock() should only be called once. |
- DCHECK(!block_inflight_); |
- |
- dbus::Bus::Options options; |
- options.bus_type = dbus::Bus::SESSION; |
- options.connection_type = dbus::Bus::PRIVATE; |
- bus_ = new dbus::Bus(options); |
- |
- scoped_refptr<dbus::ObjectProxy> object_proxy; |
- std::unique_ptr<dbus::MethodCall> method_call; |
- std::unique_ptr<dbus::MessageWriter> message_writer; |
- |
- switch (api_) { |
- case NO_API: |
- NOTREACHED(); // We should never call this method with this value. |
- return; |
- case GNOME_API: |
- object_proxy = bus_->GetObjectProxy( |
- kGnomeAPIServiceName, |
- dbus::ObjectPath(kGnomeAPIObjectPath)); |
- method_call.reset( |
- new dbus::MethodCall(kGnomeAPIInterfaceName, "Inhibit")); |
- message_writer.reset(new dbus::MessageWriter(method_call.get())); |
- // The arguments of the method are: |
- // app_id: The application identifier |
- // toplevel_xid: The toplevel X window identifier |
- // reason: The reason for the inhibit |
- // flags: Flags that spefify what should be inhibited |
- message_writer->AppendString( |
- base::CommandLine::ForCurrentProcess()->GetProgram().value()); |
- message_writer->AppendUint32(0); // should be toplevel_xid |
- message_writer->AppendString(description_); |
- { |
- uint32_t flags = 0; |
- switch (type_) { |
- case kPowerSaveBlockPreventDisplaySleep: |
- flags |= INHIBIT_MARK_SESSION_IDLE; |
- flags |= INHIBIT_SUSPEND_SESSION; |
- break; |
- case kPowerSaveBlockPreventAppSuspension: |
- flags |= INHIBIT_SUSPEND_SESSION; |
- break; |
- } |
- message_writer->AppendUint32(flags); |
- } |
- break; |
- case FREEDESKTOP_API: |
- switch (type_) { |
- case kPowerSaveBlockPreventDisplaySleep: |
- object_proxy = bus_->GetObjectProxy( |
- kFreeDesktopAPIScreenServiceName, |
- dbus::ObjectPath(kFreeDesktopAPIScreenObjectPath)); |
- method_call.reset(new dbus::MethodCall( |
- kFreeDesktopAPIScreenInterfaceName, "Inhibit")); |
- break; |
- case kPowerSaveBlockPreventAppSuspension: |
- object_proxy = bus_->GetObjectProxy( |
- kFreeDesktopAPIPowerServiceName, |
- dbus::ObjectPath(kFreeDesktopAPIPowerObjectPath)); |
- method_call.reset(new dbus::MethodCall( |
- kFreeDesktopAPIPowerInterfaceName, "Inhibit")); |
- break; |
- } |
- message_writer.reset(new dbus::MessageWriter(method_call.get())); |
- // The arguments of the method are: |
- // app_id: The application identifier |
- // reason: The reason for the inhibit |
- message_writer->AppendString( |
- base::CommandLine::ForCurrentProcess()->GetProgram().value()); |
- message_writer->AppendString(description_); |
- break; |
- } |
- |
- block_inflight_ = true; |
- object_proxy->CallMethod( |
- method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
- base::Bind(&PowerSaveBlockerImpl::Delegate::ApplyBlockFinished, this)); |
-} |
- |
-void PowerSaveBlockerImpl::Delegate::ApplyBlockFinished( |
- dbus::Response* response) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(bus_); |
- DCHECK(block_inflight_); |
- block_inflight_ = false; |
- |
- if (response) { |
- // The method returns an inhibit_cookie, used to uniquely identify |
- // this request. It should be used as an argument to Uninhibit() |
- // in order to remove the request. |
- dbus::MessageReader message_reader(response); |
- if (!message_reader.PopUint32(&inhibit_cookie_)) |
- LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString(); |
- } else { |
- LOG(ERROR) << "No response to Inhibit() request!"; |
- } |
- |
- if (enqueue_unblock_) { |
- enqueue_unblock_ = false; |
- // RemoveBlock() was called while the Inhibit operation was in flight, |
- // so go ahead and remove the block now. |
- blocking_task_runner_->PostTask(FROM_HERE, |
- base::Bind(&Delegate::RemoveBlock, this)); |
- } |
-} |
- |
-void PowerSaveBlockerImpl::Delegate::RemoveBlock() { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(bus_); // RemoveBlock() should only be called once. |
- DCHECK(!unblock_inflight_); |
- |
- if (block_inflight_) { |
- DCHECK(!enqueue_unblock_); |
- // Can't call RemoveBlock until ApplyBlock's async operation has |
- // finished. Enqueue it for execution once ApplyBlock is done. |
- enqueue_unblock_ = true; |
- return; |
- } |
- |
- scoped_refptr<dbus::ObjectProxy> object_proxy; |
- std::unique_ptr<dbus::MethodCall> method_call; |
- |
- switch (api_) { |
- case NO_API: |
- NOTREACHED(); // We should never call this method with this value. |
- return; |
- case GNOME_API: |
- object_proxy = bus_->GetObjectProxy( |
- kGnomeAPIServiceName, |
- dbus::ObjectPath(kGnomeAPIObjectPath)); |
- method_call.reset( |
- new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit")); |
- break; |
- case FREEDESKTOP_API: |
- switch (type_) { |
- case kPowerSaveBlockPreventDisplaySleep: |
- object_proxy = bus_->GetObjectProxy( |
- kFreeDesktopAPIScreenServiceName, |
- dbus::ObjectPath(kFreeDesktopAPIScreenObjectPath)); |
- method_call.reset(new dbus::MethodCall( |
- kFreeDesktopAPIScreenInterfaceName, "UnInhibit")); |
- break; |
- case kPowerSaveBlockPreventAppSuspension: |
- object_proxy = bus_->GetObjectProxy( |
- kFreeDesktopAPIPowerServiceName, |
- dbus::ObjectPath(kFreeDesktopAPIPowerObjectPath)); |
- method_call.reset(new dbus::MethodCall( |
- kFreeDesktopAPIPowerInterfaceName, "UnInhibit")); |
- break; |
- } |
- break; |
- } |
- |
- dbus::MessageWriter message_writer(method_call.get()); |
- message_writer.AppendUint32(inhibit_cookie_); |
- unblock_inflight_ = true; |
- object_proxy->CallMethod( |
- method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
- base::Bind(&PowerSaveBlockerImpl::Delegate::RemoveBlockFinished, this)); |
-} |
- |
-void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished( |
- dbus::Response* response) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(bus_); |
- unblock_inflight_ = false; |
- |
- if (!response) |
- LOG(ERROR) << "No response to Uninhibit() request!"; |
- // We don't care about checking the result. We assume it works; we can't |
- // really do anything about it anyway if it fails. |
- inhibit_cookie_ = 0; |
- |
- bus_->ShutdownAndBlock(); |
- bus_ = nullptr; |
-} |
- |
-void PowerSaveBlockerImpl::Delegate::XSSSuspendSet(bool suspend) { |
- DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
- |
- if (!XSSAvailable()) |
- return; |
- |
- XDisplay* display = gfx::GetXDisplay(); |
- XScreenSaverSuspend(display, suspend); |
-} |
- |
-bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() { |
- DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
- XDisplay* display = gfx::GetXDisplay(); |
- BOOL enabled = false; |
- int dummy; |
- if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) { |
- CARD16 state; |
- DPMSInfo(display, &state, &enabled); |
- } |
- return enabled; |
-} |
- |
-bool PowerSaveBlockerImpl::Delegate::XSSAvailable() { |
- DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
- 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); |
-} |
- |
-DBusAPI PowerSaveBlockerImpl::Delegate::SelectAPI() { |
- DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
- std::unique_ptr<base::Environment> env(base::Environment::Create()); |
- switch (base::nix::GetDesktopEnvironment(env.get())) { |
- case base::nix::DESKTOP_ENVIRONMENT_GNOME: |
- case base::nix::DESKTOP_ENVIRONMENT_UNITY: |
- if (DPMSEnabled()) |
- return GNOME_API; |
- break; |
- case base::nix::DESKTOP_ENVIRONMENT_XFCE: |
- case base::nix::DESKTOP_ENVIRONMENT_KDE4: |
- case base::nix::DESKTOP_ENVIRONMENT_KDE5: |
- if (DPMSEnabled()) |
- return FREEDESKTOP_API; |
- break; |
- case base::nix::DESKTOP_ENVIRONMENT_KDE3: |
- case base::nix::DESKTOP_ENVIRONMENT_OTHER: |
- // Not supported. |
- break; |
- } |
- return NO_API; |
-} |
- |
-PowerSaveBlockerImpl::PowerSaveBlockerImpl( |
- PowerSaveBlockerType type, |
- Reason reason, |
- const std::string& description, |
- scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner) |
- : delegate_(new Delegate(type, |
- description, |
- false /* freedesktop_only */, |
- ui_task_runner, |
- blocking_task_runner)), |
- ui_task_runner_(ui_task_runner), |
- blocking_task_runner_(blocking_task_runner) { |
- delegate_->Init(); |
- |
- if (type == kPowerSaveBlockPreventDisplaySleep) { |
- freedesktop_suspend_delegate_ = new Delegate( |
- kPowerSaveBlockPreventAppSuspension, description, |
- true /* freedesktop_only */, ui_task_runner, blocking_task_runner); |
- freedesktop_suspend_delegate_->Init(); |
- } |
-} |
- |
-PowerSaveBlockerImpl::~PowerSaveBlockerImpl() { |
- delegate_->CleanUp(); |
- if (freedesktop_suspend_delegate_) |
- freedesktop_suspend_delegate_->CleanUp(); |
-} |
- |
-} // namespace content |