This source file includes following definitions.
- inhibit_cookie_
- Init
- CleanUp
- InitOnUIThread
- ApplyBlock
- RemoveBlock
- DPMSEnabled
- SelectAPI
#include "content/browser/power_save_blocker_impl.h"
#include <X11/Xlib.h>
#include <X11/extensions/dpms.h>
#ifdef Status
#undef Status
#endif
#include "base/basictypes.h"
#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/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/message_loop/message_loop_proxy.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"
#if defined(TOOLKIT_GTK)
#include "base/message_loop/message_pump_gtk.h"
#else
#include "base/message_loop/message_pump_x11.h"
#endif
namespace {
enum DBusAPI {
NO_API,
GNOME_API,
FREEDESKTOP_API,
};
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 kFreeDesktopAPIServiceName[] = "org.freedesktop.PowerManagement";
const char kFreeDesktopAPIInterfaceName[] =
"org.freedesktop.PowerManagement.Inhibit";
const char kFreeDesktopAPIObjectPath[] =
"/org/freedesktop/PowerManagement/Inhibit";
}
namespace content {
class PowerSaveBlockerImpl::Delegate
: public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
public:
Delegate(PowerSaveBlockerType type, const std::string& reason);
void Init();
void CleanUp();
private:
friend class base::RefCountedThreadSafe<Delegate>;
~Delegate() {}
void InitOnUIThread();
void ApplyBlock(DBusAPI api);
void RemoveBlock(DBusAPI api);
static bool DPMSEnabled();
static DBusAPI SelectAPI();
const PowerSaveBlockerType type_;
const std::string reason_;
DBusAPI api_;
bool enqueue_apply_;
base::Lock lock_;
scoped_refptr<dbus::Bus> bus_;
uint32 inhibit_cookie_;
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
PowerSaveBlockerImpl::Delegate::Delegate(PowerSaveBlockerType type,
const std::string& reason)
: type_(type),
reason_(reason),
api_(NO_API),
enqueue_apply_(false),
inhibit_cookie_(0) {
}
void PowerSaveBlockerImpl::Delegate::Init() {
base::AutoLock lock(lock_);
DCHECK(!enqueue_apply_);
enqueue_apply_ = true;
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&Delegate::InitOnUIThread, this));
}
void PowerSaveBlockerImpl::Delegate::CleanUp() {
base::AutoLock lock(lock_);
if (enqueue_apply_) {
enqueue_apply_ = false;
} else if (api_ != NO_API) {
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&Delegate::RemoveBlock, this, api_));
}
}
void PowerSaveBlockerImpl::Delegate::InitOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::AutoLock lock(lock_);
api_ = SelectAPI();
if (enqueue_apply_ && api_ != NO_API) {
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&Delegate::ApplyBlock, this, api_));
}
enqueue_apply_ = false;
}
void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DCHECK(!bus_.get());
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;
scoped_ptr<dbus::MethodCall> method_call;
scoped_ptr<dbus::MessageWriter> message_writer;
switch (api) {
case NO_API:
NOTREACHED();
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()));
message_writer->AppendString(
CommandLine::ForCurrentProcess()->GetProgram().value());
message_writer->AppendUint32(0);
message_writer->AppendString(reason_);
{
uint32 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:
object_proxy = bus_->GetObjectProxy(
kFreeDesktopAPIServiceName,
dbus::ObjectPath(kFreeDesktopAPIObjectPath));
method_call.reset(
new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "Inhibit"));
message_writer.reset(new dbus::MessageWriter(method_call.get()));
message_writer->AppendString(
CommandLine::ForCurrentProcess()->GetProgram().value());
message_writer->AppendString(reason_);
break;
}
scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (response) {
dbus::MessageReader message_reader(response.get());
if (!message_reader.PopUint32(&inhibit_cookie_))
LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
} else {
LOG(ERROR) << "No response to Inhibit() request!";
}
}
void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DCHECK(bus_.get());
scoped_refptr<dbus::ObjectProxy> object_proxy;
scoped_ptr<dbus::MethodCall> method_call;
switch (api) {
case NO_API:
NOTREACHED();
return;
case GNOME_API:
object_proxy = bus_->GetObjectProxy(
kGnomeAPIServiceName,
dbus::ObjectPath(kGnomeAPIObjectPath));
method_call.reset(
new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit"));
break;
case FREEDESKTOP_API:
object_proxy = bus_->GetObjectProxy(
kFreeDesktopAPIServiceName,
dbus::ObjectPath(kFreeDesktopAPIObjectPath));
method_call.reset(
new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "UnInhibit"));
break;
}
dbus::MessageWriter message_writer(method_call.get());
message_writer.AppendUint32(inhibit_cookie_);
scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response)
LOG(ERROR) << "No response to Uninhibit() request!";
inhibit_cookie_ = 0;
bus_->ShutdownAndBlock();
bus_ = NULL;
}
bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() {
XDisplay* display = base::MessagePumpForUI::GetDefaultXDisplay();
BOOL enabled = false;
int dummy;
if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) {
CARD16 state;
DPMSInfo(display, &state, &enabled);
}
return enabled;
}
DBusAPI PowerSaveBlockerImpl::Delegate::SelectAPI() {
scoped_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:
if (DPMSEnabled())
return FREEDESKTOP_API;
break;
case base::nix::DESKTOP_ENVIRONMENT_KDE3:
case base::nix::DESKTOP_ENVIRONMENT_OTHER:
break;
}
return NO_API;
}
PowerSaveBlockerImpl::PowerSaveBlockerImpl(
PowerSaveBlockerType type, const std::string& reason)
: delegate_(new Delegate(type, reason)) {
delegate_->Init();
}
PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
delegate_->CleanUp();
}
}