| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/power_save_blocker.h" | 5 #include "content/public/browser/power_save_blocker.h" |
| 6 | 6 |
| 7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
| 8 #include <X11/extensions/dpms.h> | 8 #include <X11/extensions/dpms.h> |
| 9 // Xlib #defines Status, but we can't have that for some of our headers. | 9 // Xlib #defines Status, but we can't have that for some of our headers. |
| 10 #ifdef Status | 10 #ifdef Status |
| 11 #undef Status | 11 #undef Status |
| 12 #endif | 12 #endif |
| 13 | 13 |
| 14 #include "base/basictypes.h" | 14 #include "base/basictypes.h" |
| 15 #include "base/bind.h" | 15 #include "base/bind.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 28 #include "base/message_pump_aurax11.h" | 28 #include "base/message_pump_aurax11.h" |
| 29 #endif | 29 #endif |
| 30 #include "base/nix/xdg_util.h" | 30 #include "base/nix/xdg_util.h" |
| 31 #include "base/synchronization/lock.h" | 31 #include "base/synchronization/lock.h" |
| 32 #include "content/public/browser/browser_thread.h" | 32 #include "content/public/browser/browser_thread.h" |
| 33 #include "dbus/bus.h" | 33 #include "dbus/bus.h" |
| 34 #include "dbus/message.h" | 34 #include "dbus/message.h" |
| 35 #include "dbus/object_path.h" | 35 #include "dbus/object_path.h" |
| 36 #include "dbus/object_proxy.h" | 36 #include "dbus/object_proxy.h" |
| 37 | 37 |
| 38 namespace content { |
| 39 |
| 38 namespace { | 40 namespace { |
| 39 | 41 |
| 40 enum DBusAPI { | 42 enum DBusAPI { |
| 41 NO_API, // Disable. No supported API available. | 43 NO_API, // Disable. No supported API available. |
| 42 GNOME_API, // Use the GNOME API. (Supports more features.) | 44 GNOME_API, // Use the GNOME API. (Supports more features.) |
| 43 FREEDESKTOP_API, // Use the FreeDesktop API, for KDE4 and XFCE. | 45 FREEDESKTOP_API, // Use the FreeDesktop API, for KDE4 and XFCE. |
| 44 }; | 46 }; |
| 45 | 47 |
| 46 // Inhibit flags defined in the org.gnome.SessionManager interface. | 48 // Inhibit flags defined in the org.gnome.SessionManager interface. |
| 47 // Can be OR'd together and passed as argument to the Inhibit() method | 49 // Can be OR'd together and passed as argument to the Inhibit() method |
| 48 // to specify which power management features we want to suspend. | 50 // to specify which power management features we want to suspend. |
| 49 enum GnomeAPIInhibitFlags { | 51 enum GnomeAPIInhibitFlags { |
| 50 INHIBIT_LOGOUT = 1, | 52 INHIBIT_LOGOUT = 1, |
| 51 INHIBIT_SWITCH_USER = 2, | 53 INHIBIT_SWITCH_USER = 2, |
| 52 INHIBIT_SUSPEND_SESSION = 4, | 54 INHIBIT_SUSPEND_SESSION = 4, |
| 53 INHIBIT_MARK_SESSION_IDLE = 8 | 55 INHIBIT_MARK_SESSION_IDLE = 8 |
| 54 }; | 56 }; |
| 55 | 57 |
| 56 const char kGnomeAPIServiceName[] = "org.gnome.SessionManager"; | 58 const char kGnomeAPIServiceName[] = "org.gnome.SessionManager"; |
| 57 const char kGnomeAPIInterfaceName[] = "org.gnome.SessionManager"; | 59 const char kGnomeAPIInterfaceName[] = "org.gnome.SessionManager"; |
| 58 const char kGnomeAPIObjectPath[] = "/org/gnome/SessionManager"; | 60 const char kGnomeAPIObjectPath[] = "/org/gnome/SessionManager"; |
| 59 | 61 |
| 60 const char kFreeDesktopAPIServiceName[] = "org.freedesktop.PowerManagement"; | 62 const char kFreeDesktopAPIServiceName[] = "org.freedesktop.PowerManagement"; |
| 61 const char kFreeDesktopAPIInterfaceName[] = | 63 const char kFreeDesktopAPIInterfaceName[] = |
| 62 "org.freedesktop.PowerManagement.Inhibit"; | 64 "org.freedesktop.PowerManagement.Inhibit"; |
| 63 const char kFreeDesktopAPIObjectPath[] = | 65 const char kFreeDesktopAPIObjectPath[] = |
| 64 "/org/freedesktop/PowerManagement/Inhibit"; | 66 "/org/freedesktop/PowerManagement/Inhibit"; |
| 65 | 67 |
| 66 } // anonymous namespace | 68 class PowerSaveBlockerLinux : public PowerSaveBlocker { |
| 69 public: |
| 70 PowerSaveBlockerLinux(PowerSaveBlockerType type, const std::string& reason); |
| 71 virtual ~PowerSaveBlockerLinux(); |
| 67 | 72 |
| 68 namespace content { | 73 private: |
| 74 class Delegate; |
| 69 | 75 |
| 70 class PowerSaveBlocker::Delegate | 76 // A second object with different lifetime than the RAII container. |
| 71 : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> { | 77 scoped_refptr<Delegate> delegate_; |
| 78 |
| 79 DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerLinux); |
| 80 }; |
| 81 |
| 82 class PowerSaveBlockerLinux::Delegate |
| 83 : public base::RefCountedThreadSafe<PowerSaveBlockerLinux::Delegate> { |
| 72 public: | 84 public: |
| 73 // Picks an appropriate D-Bus API to use based on the desktop environment. | 85 // Picks an appropriate D-Bus API to use based on the desktop environment. |
| 74 Delegate(PowerSaveBlockerType type, const std::string& reason); | 86 Delegate(PowerSaveBlockerType type, const std::string& reason); |
| 75 | 87 |
| 76 // Post a task to initialize the delegate on the UI thread, which will itself | 88 // Post a task to initialize the delegate on the UI thread, which will itself |
| 77 // then post a task to apply the power save block on the FILE thread. | 89 // then post a task to apply the power save block on the FILE thread. |
| 78 void Init(); | 90 void Init(); |
| 79 | 91 |
| 80 // Post a task to remove the power save block on the FILE thread, unless it | 92 // Post a task to remove the power save block on the FILE thread, unless it |
| 81 // hasn't yet been applied, in which case we just prevent it from applying. | 93 // hasn't yet been applied, in which case we just prevent it from applying. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 | 133 |
| 122 scoped_refptr<dbus::Bus> bus_; | 134 scoped_refptr<dbus::Bus> bus_; |
| 123 | 135 |
| 124 // The cookie that identifies our inhibit request, | 136 // The cookie that identifies our inhibit request, |
| 125 // or 0 if there is no active inhibit request. | 137 // or 0 if there is no active inhibit request. |
| 126 uint32 inhibit_cookie_; | 138 uint32 inhibit_cookie_; |
| 127 | 139 |
| 128 DISALLOW_COPY_AND_ASSIGN(Delegate); | 140 DISALLOW_COPY_AND_ASSIGN(Delegate); |
| 129 }; | 141 }; |
| 130 | 142 |
| 131 PowerSaveBlocker::Delegate::Delegate(PowerSaveBlockerType type, | 143 PowerSaveBlockerLinux::Delegate::Delegate(PowerSaveBlockerType type, |
| 132 const std::string& reason) | 144 const std::string& reason) |
| 133 : type_(type), | 145 : type_(type), |
| 134 reason_(reason), | 146 reason_(reason), |
| 135 api_(NO_API), | 147 api_(NO_API), |
| 136 enqueue_apply_(false), | 148 enqueue_apply_(false), |
| 137 inhibit_cookie_(0) { | 149 inhibit_cookie_(0) { |
| 138 // We're on the client's thread here, so we don't allocate the dbus::Bus | 150 // We're on the client's thread here, so we don't allocate the dbus::Bus |
| 139 // object yet. We'll do it later in ApplyBlock(), on the FILE thread. | 151 // object yet. We'll do it later in ApplyBlock(), on the FILE thread. |
| 140 } | 152 } |
| 141 | 153 |
| 142 void PowerSaveBlocker::Delegate::Init() { | 154 void PowerSaveBlockerLinux::Delegate::Init() { |
| 143 base::AutoLock lock(lock_); | 155 base::AutoLock lock(lock_); |
| 144 DCHECK(!enqueue_apply_); | 156 DCHECK(!enqueue_apply_); |
| 145 enqueue_apply_ = true; | 157 enqueue_apply_ = true; |
| 146 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 158 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 147 base::Bind(&Delegate::InitOnUIThread, this)); | 159 base::Bind(&Delegate::InitOnUIThread, this)); |
| 148 } | 160 } |
| 149 | 161 |
| 150 void PowerSaveBlocker::Delegate::CleanUp() { | 162 void PowerSaveBlockerLinux::Delegate::CleanUp() { |
| 151 base::AutoLock lock(lock_); | 163 base::AutoLock lock(lock_); |
| 152 if (enqueue_apply_) { | 164 if (enqueue_apply_) { |
| 153 // If a call to ApplyBlock() has not yet been enqueued because we are still | 165 // If a call to ApplyBlock() has not yet been enqueued because we are still |
| 154 // initializing on the UI thread, then just cancel it. We don't need to | 166 // initializing on the UI thread, then just cancel it. We don't need to |
| 155 // remove the block because we haven't even applied it yet. | 167 // remove the block because we haven't even applied it yet. |
| 156 enqueue_apply_ = false; | 168 enqueue_apply_ = false; |
| 157 } else if (api_ != NO_API) { | 169 } else if (api_ != NO_API) { |
| 158 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 170 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 159 base::Bind(&Delegate::RemoveBlock, this, api_)); | 171 base::Bind(&Delegate::RemoveBlock, this, api_)); |
| 160 } | 172 } |
| 161 } | 173 } |
| 162 | 174 |
| 163 void PowerSaveBlocker::Delegate::InitOnUIThread() { | 175 void PowerSaveBlockerLinux::Delegate::InitOnUIThread() { |
| 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 165 base::AutoLock lock(lock_); | 177 base::AutoLock lock(lock_); |
| 166 api_ = SelectAPI(); | 178 api_ = SelectAPI(); |
| 167 if (enqueue_apply_ && api_ != NO_API) { | 179 if (enqueue_apply_ && api_ != NO_API) { |
| 168 // The thread we use here becomes the origin and D-Bus thread for the D-Bus | 180 // The thread we use here becomes the origin and D-Bus thread for the D-Bus |
| 169 // library, so we need to use the same thread above for RemoveBlock(). It | 181 // library, so we need to use the same thread above for RemoveBlock(). It |
| 170 // must be a thread that allows I/O operations, so we use the FILE thread. | 182 // must be a thread that allows I/O operations, so we use the FILE thread. |
| 171 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 183 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 172 base::Bind(&Delegate::ApplyBlock, this, api_)); | 184 base::Bind(&Delegate::ApplyBlock, this, api_)); |
| 173 } | 185 } |
| 174 enqueue_apply_ = false; | 186 enqueue_apply_ = false; |
| 175 } | 187 } |
| 176 | 188 |
| 177 void PowerSaveBlocker::Delegate::ApplyBlock(DBusAPI api) { | 189 void PowerSaveBlockerLinux::Delegate::ApplyBlock(DBusAPI api) { |
| 178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 179 DCHECK(!bus_.get()); // ApplyBlock() should only be called once. | 191 DCHECK(!bus_.get()); // ApplyBlock() should only be called once. |
| 180 | 192 |
| 181 dbus::Bus::Options options; | 193 dbus::Bus::Options options; |
| 182 options.bus_type = dbus::Bus::SESSION; | 194 options.bus_type = dbus::Bus::SESSION; |
| 183 options.connection_type = dbus::Bus::PRIVATE; | 195 options.connection_type = dbus::Bus::PRIVATE; |
| 184 bus_ = new dbus::Bus(options); | 196 bus_ = new dbus::Bus(options); |
| 185 | 197 |
| 186 scoped_refptr<dbus::ObjectProxy> object_proxy; | 198 scoped_refptr<dbus::ObjectProxy> object_proxy; |
| 187 scoped_ptr<dbus::MethodCall> method_call; | 199 scoped_ptr<dbus::MethodCall> method_call; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 // this request. It should be used as an argument to Uninhibit() | 259 // this request. It should be used as an argument to Uninhibit() |
| 248 // in order to remove the request. | 260 // in order to remove the request. |
| 249 dbus::MessageReader message_reader(response.get()); | 261 dbus::MessageReader message_reader(response.get()); |
| 250 if (!message_reader.PopUint32(&inhibit_cookie_)) | 262 if (!message_reader.PopUint32(&inhibit_cookie_)) |
| 251 LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString(); | 263 LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString(); |
| 252 } else { | 264 } else { |
| 253 LOG(ERROR) << "No response to Inhibit() request!"; | 265 LOG(ERROR) << "No response to Inhibit() request!"; |
| 254 } | 266 } |
| 255 } | 267 } |
| 256 | 268 |
| 257 void PowerSaveBlocker::Delegate::RemoveBlock(DBusAPI api) { | 269 void PowerSaveBlockerLinux::Delegate::RemoveBlock(DBusAPI api) { |
| 258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 259 DCHECK(bus_.get()); // RemoveBlock() should only be called once. | 271 DCHECK(bus_.get()); // RemoveBlock() should only be called once. |
| 260 | 272 |
| 261 scoped_refptr<dbus::ObjectProxy> object_proxy; | 273 scoped_refptr<dbus::ObjectProxy> object_proxy; |
| 262 scoped_ptr<dbus::MethodCall> method_call; | 274 scoped_ptr<dbus::MethodCall> method_call; |
| 263 | 275 |
| 264 switch (api) { | 276 switch (api) { |
| 265 case NO_API: | 277 case NO_API: |
| 266 NOTREACHED(); // We should never call this method with this value. | 278 NOTREACHED(); // We should never call this method with this value. |
| 267 return; | 279 return; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 289 LOG(ERROR) << "No response to Uninhibit() request!"; | 301 LOG(ERROR) << "No response to Uninhibit() request!"; |
| 290 // We don't care about checking the result. We assume it works; we can't | 302 // We don't care about checking the result. We assume it works; we can't |
| 291 // really do anything about it anyway if it fails. | 303 // really do anything about it anyway if it fails. |
| 292 inhibit_cookie_ = 0; | 304 inhibit_cookie_ = 0; |
| 293 | 305 |
| 294 bus_->ShutdownAndBlock(); | 306 bus_->ShutdownAndBlock(); |
| 295 bus_ = NULL; | 307 bus_ = NULL; |
| 296 } | 308 } |
| 297 | 309 |
| 298 // static | 310 // static |
| 299 bool PowerSaveBlocker::Delegate::DPMSEnabled() { | 311 bool PowerSaveBlockerLinux::Delegate::DPMSEnabled() { |
| 300 Display* display = base::MessagePumpForUI::GetDefaultXDisplay(); | 312 Display* display = base::MessagePumpForUI::GetDefaultXDisplay(); |
| 301 BOOL enabled = false; | 313 BOOL enabled = false; |
| 302 int dummy; | 314 int dummy; |
| 303 if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) { | 315 if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) { |
| 304 CARD16 state; | 316 CARD16 state; |
| 305 DPMSInfo(display, &state, &enabled); | 317 DPMSInfo(display, &state, &enabled); |
| 306 } | 318 } |
| 307 return enabled; | 319 return enabled; |
| 308 } | 320 } |
| 309 | 321 |
| 310 // static | 322 // static |
| 311 DBusAPI PowerSaveBlocker::Delegate::SelectAPI() { | 323 DBusAPI PowerSaveBlockerLinux::Delegate::SelectAPI() { |
| 312 scoped_ptr<base::Environment> env(base::Environment::Create()); | 324 scoped_ptr<base::Environment> env(base::Environment::Create()); |
| 313 switch (base::nix::GetDesktopEnvironment(env.get())) { | 325 switch (base::nix::GetDesktopEnvironment(env.get())) { |
| 314 case base::nix::DESKTOP_ENVIRONMENT_GNOME: | 326 case base::nix::DESKTOP_ENVIRONMENT_GNOME: |
| 315 case base::nix::DESKTOP_ENVIRONMENT_UNITY: | 327 case base::nix::DESKTOP_ENVIRONMENT_UNITY: |
| 316 if (DPMSEnabled()) | 328 if (DPMSEnabled()) |
| 317 return GNOME_API; | 329 return GNOME_API; |
| 318 break; | 330 break; |
| 319 case base::nix::DESKTOP_ENVIRONMENT_XFCE: | 331 case base::nix::DESKTOP_ENVIRONMENT_XFCE: |
| 320 case base::nix::DESKTOP_ENVIRONMENT_KDE4: | 332 case base::nix::DESKTOP_ENVIRONMENT_KDE4: |
| 321 if (DPMSEnabled()) | 333 if (DPMSEnabled()) |
| 322 return FREEDESKTOP_API; | 334 return FREEDESKTOP_API; |
| 323 break; | 335 break; |
| 324 case base::nix::DESKTOP_ENVIRONMENT_KDE3: | 336 case base::nix::DESKTOP_ENVIRONMENT_KDE3: |
| 325 case base::nix::DESKTOP_ENVIRONMENT_OTHER: | 337 case base::nix::DESKTOP_ENVIRONMENT_OTHER: |
| 326 // Not supported. | 338 // Not supported. |
| 327 break; | 339 break; |
| 328 } | 340 } |
| 329 return NO_API; | 341 return NO_API; |
| 330 } | 342 } |
| 331 | 343 |
| 332 PowerSaveBlocker::PowerSaveBlocker( | 344 PowerSaveBlockerLinux::PowerSaveBlockerLinux( |
| 333 PowerSaveBlockerType type, const std::string& reason) | 345 PowerSaveBlockerType type, const std::string& reason) |
| 334 : delegate_(new Delegate(type, reason)) { | 346 : delegate_(new Delegate(type, reason)) { |
| 335 delegate_->Init(); | 347 delegate_->Init(); |
| 336 } | 348 } |
| 337 | 349 |
| 338 PowerSaveBlocker::~PowerSaveBlocker() { | 350 PowerSaveBlockerLinux::~PowerSaveBlockerLinux() { |
| 339 delegate_->CleanUp(); | 351 delegate_->CleanUp(); |
| 340 } | 352 } |
| 341 | 353 |
| 354 } // namespace |
| 355 |
| 356 // static |
| 357 scoped_ptr<PowerSaveBlocker> PowerSaveBlocker::Create( |
| 358 PowerSaveBlockerType type, |
| 359 const std::string& reason) { |
| 360 return scoped_ptr<PowerSaveBlocker>(new PowerSaveBlockerLinux(type, reason)); |
| 361 } |
| 362 |
| 342 } // namespace content | 363 } // namespace content |
| OLD | NEW |