Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1331)

Unified Diff: content/browser/power_save_blocker_linux.cc

Issue 10545076: Implement PowerSaveBlocker2 for Linux. Much simpler than the original! (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/power_save_blocker_linux.cc
===================================================================
--- content/browser/power_save_blocker_linux.cc (revision 141149)
+++ content/browser/power_save_blocker_linux.cc (working copy)
@@ -504,3 +504,258 @@
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DBusPowerSaveBlocker::GetInstance()->ApplyBlock(type);
}
+
+// TODO(mdm): remove from the beginning of the file up to (and including) this
+// line to switch to the new implementation.
+#define PowerSaveBlocker PowerSaveBlocker2
satorux1 2012/06/08 14:59:41 This looks ugly. Why do you need to keep the old i
Mike Mammarella 2012/06/08 18:33:36 We don't, strictly speaking. We had to do this for
+
+namespace content {
+
+class PowerSaveBlocker::Delegate
+ : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
+ public:
+ // Picks an appropriate DBus API to use based on the desktop environment.
+ Delegate(PowerSaveBlockerType type, const std::string& reason);
+
+ void ApplyBlock();
+ void RemoveBlock();
satorux1 2012/06/08 14:59:41 function comments are missing.
Mike Mammarella 2012/06/08 18:33:36 I actually had them in a previous patch set, but I
satorux1 2012/06/08 19:31:50 From function name alone, it's hard to tell what A
Mike Mammarella 2012/06/08 19:50:17 OK, I added comments. (The last patch set had them
+
+ private:
+ enum DBusAPI {
+ kNoAPI, // Disable. No supported API available.
+ kGnomeAPI, // Use the GNOME API. (Supports more features.)
+ kFreeDesktopAPI, // Use the FreeDesktop API, for KDE4 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 {
+ kInhibitLogOut = 1,
+ kInhibitSwitchUser = 2,
+ kInhibitSuspendSession = 4,
+ kInhibitMarkSessionAsIdle = 8
+ };
+
+ static const char kGnomeAPIServiceName[];
+ static const char kGnomeAPIInterfaceName[];
+ static const char kGnomeAPIObjectPath[];
+ static const char kFreeDesktopAPIServiceName[];
+ static const char kFreeDesktopAPIInterfaceName[];
+ static const char kFreeDesktopAPIObjectPath[];
satorux1 2012/06/08 14:59:41 nit: would be simpler to define these constants in
Mike Mammarella 2012/06/08 18:33:36 Done.
+
+ friend class base::RefCountedThreadSafe<Delegate>;
+ ~Delegate() {}
+
+ // If DPMS is not enabled, then we don't want to try to disable power saving,
satorux1 2012/06/08 14:59:41 what does DPMS stand for? Please add some comment
Mike Mammarella 2012/06/08 18:33:36 Improved the comment. It's not particularly releva
+ // 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();
+
+ // Returns an appropriate DBus API to use based on the desktop environment.
satorux1 2012/06/08 14:59:41 nit: DBus -> D-Bus
Mike Mammarella 2012/06/08 18:33:36 Done.
+ static DBusAPI SelectAPI();
+
+ const PowerSaveBlockerType type_;
+ const std::string reason_;
+ const DBusAPI api_;
+
+ scoped_refptr<dbus::Bus> bus_;
+
+ // The cookie that identifies our inhibit request,
+ // or 0 if there is no active inhibit request.
+ uint32 inhibit_cookie_;
+
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+};
+
+const char PowerSaveBlocker::Delegate::kGnomeAPIServiceName[] =
+ "org.gnome.SessionManager";
+const char PowerSaveBlocker::Delegate::kGnomeAPIInterfaceName[] =
+ "org.gnome.SessionManager";
+const char PowerSaveBlocker::Delegate::kGnomeAPIObjectPath[] =
+ "/org/gnome/SessionManager";
+
+const char PowerSaveBlocker::Delegate::kFreeDesktopAPIServiceName[] =
+ "org.freedesktop.PowerManagement";
+const char PowerSaveBlocker::Delegate::kFreeDesktopAPIInterfaceName[] =
+ "org.freedesktop.PowerManagement.Inhibit";
+const char PowerSaveBlocker::Delegate::kFreeDesktopAPIObjectPath[] =
+ "/org/freedesktop/PowerManagement/Inhibit";
+
+PowerSaveBlocker::Delegate::Delegate(PowerSaveBlockerType type,
+ const std::string& reason)
+ : type_(type), reason_(reason), api_(SelectAPI()) {
+ // We're on the client's thread here, so we don't allocate the dbus::Bus
+ // object yet. We'll do it below in ApplyBlock(), on the file thread.
+}
+
+void PowerSaveBlocker::Delegate::ApplyBlock() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(!bus_.get()); // ApplyBlock() should only be called once.
+ if (api_ == kNoAPI)
+ return;
+
+ 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;
+ // We must provide a valid-looking interface. We'll change it below.
satorux1 2012/06/08 14:59:41 This looks lie a hack. Rather than replacing it la
Mike Mammarella 2012/06/08 18:33:36 I considered that but thought this seemed a little
satorux1 2012/06/08 19:31:50 I think using a dummy place holder does not look g
Mike Mammarella 2012/06/08 19:50:17 Done. Personally I'm not a fan of the way this cas
+ dbus::MethodCall method_call("org.chromium.Placeholder", "Inhibit");
+ dbus::MessageWriter message_writer(&method_call);
+
+ switch (api_) {
+ case kNoAPI:
+ NOTREACHED(); // We return early above.
+ return;
+ case kGnomeAPI:
+ object_proxy = bus_->GetObjectProxy(
+ kGnomeAPIServiceName,
+ dbus::ObjectPath(kGnomeAPIObjectPath));
+ method_call.SetInterface(kGnomeAPIInterfaceName);
+ // 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(
+ CommandLine::ForCurrentProcess()->GetProgram().value());
+ message_writer.AppendUint32(0); // should be toplevel_xid
+ message_writer.AppendString(reason_.c_str());
satorux1 2012/06/08 14:59:41 no need to use .c_str()
Mike Mammarella 2012/06/08 18:33:36 Done.
+ {
+ uint32 flags = 0;
+ switch (type_) {
+ case kPowerSaveBlockPreventDisplaySleep:
+ flags |= kInhibitMarkSessionAsIdle;
+ flags |= kInhibitSuspendSession;
+ break;
+ case kPowerSaveBlockPreventAppSuspension:
+ flags |= kInhibitSuspendSession;
+ break;
+ }
+ message_writer.AppendUint32(flags);
+ }
+ break;
+ case kFreeDesktopAPI:
+ object_proxy = bus_->GetObjectProxy(
+ kFreeDesktopAPIServiceName,
+ dbus::ObjectPath(kFreeDesktopAPIObjectPath));
+ method_call.SetInterface(kFreeDesktopAPIInterfaceName);
+ // The arguments of the method are:
+ // app_id: The application identifier
+ // reason: The reason for the inhibit
+ message_writer.AppendString(
+ CommandLine::ForCurrentProcess()->GetProgram().value());
+ message_writer.AppendString(reason_.c_str());
+ break;
+ }
+
+ // We could do this method call asynchronously, but if we did, we'd need to
+ // handle the case where we want to cancel the block before we get a reply.
+ // We're on the FILE thread so it should be OK to block briefly here.
+ scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+ if (response.get()) {
+ // 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.get());
+ if (!message_reader.PopUint32(&inhibit_cookie_))
+ LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
+ } else {
+ LOG(ERROR) << "No response to Inhibit() request!";
+ }
+}
+
+void PowerSaveBlocker::Delegate::RemoveBlock() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (api_ == kNoAPI)
+ return;
+ DCHECK(bus_.get()); // RemoveBlock() should only be called once.
+
+ scoped_refptr<dbus::ObjectProxy> object_proxy;
+ // We must provide a valid-looking interface. We'll change it below.
satorux1 2012/06/08 14:59:41 see my comment above.
+ dbus::MethodCall method_call("org.chromium.Placeholder", "Uninhibit");
+ dbus::MessageWriter message_writer(&method_call);
+
+ switch (api_) {
+ case kNoAPI:
+ NOTREACHED(); // We return early above.
+ return;
+ case kGnomeAPI:
+ object_proxy = bus_->GetObjectProxy(
+ kGnomeAPIServiceName,
+ dbus::ObjectPath(kGnomeAPIObjectPath));
+ method_call.SetInterface(kGnomeAPIInterfaceName);
+ break;
+ case kFreeDesktopAPI:
+ object_proxy = bus_->GetObjectProxy(
+ kFreeDesktopAPIServiceName,
+ dbus::ObjectPath(kFreeDesktopAPIObjectPath));
+ method_call.SetInterface(kFreeDesktopAPIInterfaceName);
+ break;
+ }
+
+ message_writer.AppendUint32(inhibit_cookie_);
+ scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+ if (!response.get())
+ 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_ = NULL;
+}
+
+// static
+bool PowerSaveBlocker::Delegate::DPMSEnabled() {
+ Display* display = base::MessagePumpForUI::GetDefaultXDisplay();
+ BOOL enabled = false;
+ int dummy;
+ if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) {
+ CARD16 state;
+ DPMSInfo(display, &state, &enabled);
+ }
+ return enabled;
+}
+
+// static
+PowerSaveBlocker::Delegate::DBusAPI PowerSaveBlocker::Delegate::SelectAPI() {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ switch (base::nix::GetDesktopEnvironment(env.get())) {
+ case base::nix::DESKTOP_ENVIRONMENT_GNOME:
+ if (DPMSEnabled())
+ return kGnomeAPI;
+ break;
+ case base::nix::DESKTOP_ENVIRONMENT_XFCE:
+ case base::nix::DESKTOP_ENVIRONMENT_KDE4:
+ if (DPMSEnabled())
+ return kFreeDesktopAPI;
+ break;
+ case base::nix::DESKTOP_ENVIRONMENT_KDE3:
+ case base::nix::DESKTOP_ENVIRONMENT_OTHER:
+ // Not supported.
+ break;
+ }
+ return kNoAPI;
+}
+
+PowerSaveBlocker::PowerSaveBlocker(
+ PowerSaveBlockerType type, const std::string& reason)
+ : delegate_(new Delegate(type, reason)) {
+ // We use the FILE thread to service the DBus connection, since we need a
+ // thread that allows I/O operations. The same thread must be used in the
+ // destructor below, but other than that we could use any thread.
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
satorux1 2012/06/08 14:59:41 FILE thread is now deprecated. Please use BrowserT
Mike Mammarella 2012/06/08 18:33:36 Hmm. As the comment indicates, I need the same thr
satorux1 2012/06/08 19:31:50 Why do they need to run on the same thread? As lon
Mike Mammarella 2012/06/08 19:50:17 They need to be the same because the D-Bus library
satorux1 2012/06/08 20:00:14 Oh, I that explains. You might want to put it as a
Mike Mammarella 2012/06/08 20:28:46 Done.
+ base::Bind(&Delegate::ApplyBlock, delegate_));
+}
+
+PowerSaveBlocker::~PowerSaveBlocker() {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&Delegate::RemoveBlock, delegate_));
+}
+
+} // namespace content
« content/browser/power_save_blocker.h ('K') | « content/browser/power_save_blocker.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698