diff options
Diffstat (limited to 'chromium/content/browser/power_save_blocker_x11.cc')
-rw-r--r-- | chromium/content/browser/power_save_blocker_x11.cc | 493 |
1 files changed, 0 insertions, 493 deletions
diff --git a/chromium/content/browser/power_save_blocker_x11.cc b/chromium/content/browser/power_save_blocker_x11.cc deleted file mode 100644 index e80265c5a77..00000000000 --- a/chromium/content/browser/power_save_blocker_x11.cc +++ /dev/null @@ -1,493 +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/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 "content/public/browser/browser_thread.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); - - // 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. - 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(); - - 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_; - - DISALLOW_COPY_AND_ASSIGN(Delegate); -}; - -PowerSaveBlockerImpl::Delegate::Delegate(PowerSaveBlockerType type, - const std::string& description, - bool freedesktop_only) - : type_(type), - description_(description), - freedesktop_only_(freedesktop_only), - api_(NO_API), - enqueue_apply_(false), - inhibit_cookie_(0) { - // 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; - BrowserThread::PostTask(BrowserThread::UI, 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()) { - BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, - base::Bind(&Delegate::RemoveBlock, this)); - } - - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&Delegate::XSSSuspendSet, false)); - } -} - -void PowerSaveBlockerImpl::Delegate::InitOnUIThread() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - 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. - BrowserThread::PostTask(BrowserThread::FILE, 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_CURRENTLY_ON(BrowserThread::FILE); - 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_CURRENTLY_ON(BrowserThread::FILE); - 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. - BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, - base::Bind(&Delegate::RemoveBlock, this)); - } -} - -void PowerSaveBlockerImpl::Delegate::RemoveBlock() { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - 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_CURRENTLY_ON(BrowserThread::FILE); - 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; -} - -// 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(); - BOOL enabled = false; - int dummy; - if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) { - CARD16 state; - DPMSInfo(display, &state, &enabled); - } - return enabled; -} - -// 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); - 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) - : delegate_(new Delegate(type, description, false /* freedesktop_only */)) { - delegate_->Init(); - - if (type == kPowerSaveBlockPreventDisplaySleep) { - freedesktop_suspend_delegate_ = - new Delegate(kPowerSaveBlockPreventAppSuspension, description, - true /* freedesktop_only */); - freedesktop_suspend_delegate_->Init(); - } -} - -PowerSaveBlockerImpl::~PowerSaveBlockerImpl() { - delegate_->CleanUp(); - if (freedesktop_suspend_delegate_) - freedesktop_suspend_delegate_->CleanUp(); -} - -} // namespace content |