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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/browser/power_save_blocker.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/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
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 } 497 }
498 498
499 } // namespace 499 } // namespace
500 500
501 // Called only from UI thread. 501 // Called only from UI thread.
502 // static 502 // static
503 void PowerSaveBlocker::ApplyBlock(PowerSaveBlockerType type) { 503 void PowerSaveBlocker::ApplyBlock(PowerSaveBlockerType type) {
504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
505 DBusPowerSaveBlocker::GetInstance()->ApplyBlock(type); 505 DBusPowerSaveBlocker::GetInstance()->ApplyBlock(type);
506 } 506 }
507
508 // TODO(mdm): remove from the beginning of the file up to (and including) this
509 // line to switch to the new implementation.
510 #define PowerSaveBlocker PowerSaveBlocker2
511
512 namespace {
513
514 enum DBusAPI {
515 kNoAPI, // Disable. No supported API available.
sky 2012/06/08 20:44:41 enum style in chrome is ALL_CAPS.
Mike Mammarella 2012/06/08 20:52:34 Ah yes, I always forget this difference between th
516 kGnomeAPI, // Use the GNOME API. (Supports more features.)
517 kFreeDesktopAPI, // Use the FreeDesktop API, for KDE4 and XFCE.
518 };
519
520 // Inhibit flags defined in the org.gnome.SessionManager interface.
521 // Can be OR'd together and passed as argument to the Inhibit() method
522 // to specify which power management features we want to suspend.
523 enum GnomeAPIInhibitFlags {
524 kInhibitLogOut = 1,
525 kInhibitSwitchUser = 2,
526 kInhibitSuspendSession = 4,
527 kInhibitMarkSessionAsIdle = 8
528 };
529
530 const char kGnomeAPIServiceName[] = "org.gnome.SessionManager";
531 const char kGnomeAPIInterfaceName[] = "org.gnome.SessionManager";
532 const char kGnomeAPIObjectPath[] = "/org/gnome/SessionManager";
533
534 const char kFreeDesktopAPIServiceName[] = "org.freedesktop.PowerManagement";
535 const char kFreeDesktopAPIInterfaceName[] =
536 "org.freedesktop.PowerManagement.Inhibit";
537 const char kFreeDesktopAPIObjectPath[] =
538 "/org/freedesktop/PowerManagement/Inhibit";
539
540 } // anonymous namespace
541
542 namespace content {
543
544 class PowerSaveBlocker::Delegate
545 : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
546 public:
547 // Picks an appropriate D-Bus API to use based on the desktop environment.
548 Delegate(PowerSaveBlockerType type, const std::string& reason);
549
550 // Apply or remove the power save block, respectively. These methods should be
551 // called once each, on the same thread, per instance. They block waiting for
552 // the action to complete (with a timeout); the thread must thus allow IO.
553 void ApplyBlock();
554 void RemoveBlock();
555
556 private:
557 friend class base::RefCountedThreadSafe<Delegate>;
558 ~Delegate() {}
559
560 // If DPMS (the power saving system in X11) is not enabled, then we don't want
561 // to try to disable power saving, since on some desktop environments that may
562 // enable DPMS with very poor default settings (e.g. turning off the display
563 // after only 1 second).
564 static bool DPMSEnabled();
565
566 // Returns an appropriate D-Bus API to use based on the desktop environment.
567 static DBusAPI SelectAPI();
568
569 const PowerSaveBlockerType type_;
570 const std::string reason_;
571 const DBusAPI api_;
572
573 scoped_refptr<dbus::Bus> bus_;
574
575 // The cookie that identifies our inhibit request,
576 // or 0 if there is no active inhibit request.
577 uint32 inhibit_cookie_;
578
579 DISALLOW_COPY_AND_ASSIGN(Delegate);
580 };
581
582 PowerSaveBlocker::Delegate::Delegate(PowerSaveBlockerType type,
583 const std::string& reason)
584 : type_(type), reason_(reason), api_(SelectAPI()) {
sky 2012/06/08 20:44:41 each on its own line, and initialize inhibit_cooki
Mike Mammarella 2012/06/08 20:52:34 Done. (Another difference in the style guides!)
585 // We're on the client's thread here, so we don't allocate the dbus::Bus
586 // object yet. We'll do it below in ApplyBlock(), on the FILE thread.
587 }
588
589 void PowerSaveBlocker::Delegate::ApplyBlock() {
590 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
591 DCHECK(!bus_.get()); // ApplyBlock() should only be called once.
592 if (api_ == kNoAPI)
593 return;
594
595 dbus::Bus::Options options;
596 options.bus_type = dbus::Bus::SESSION;
597 options.connection_type = dbus::Bus::PRIVATE;
598 bus_ = new dbus::Bus(options);
599
600 scoped_refptr<dbus::ObjectProxy> object_proxy;
601 scoped_ptr<dbus::MethodCall> method_call;
602 scoped_ptr<dbus::MessageWriter> message_writer;
603
604 switch (api_) {
605 case kNoAPI:
606 NOTREACHED(); // We return early above.
607 return;
608 case kGnomeAPI:
609 object_proxy = bus_->GetObjectProxy(
610 kGnomeAPIServiceName,
611 dbus::ObjectPath(kGnomeAPIObjectPath));
612 method_call.reset(
613 new dbus::MethodCall(kGnomeAPIInterfaceName, "Inhibit"));
614 message_writer.reset(new dbus::MessageWriter(method_call.get()));
615 // The arguments of the method are:
616 // app_id: The application identifier
617 // toplevel_xid: The toplevel X window identifier
618 // reason: The reason for the inhibit
619 // flags: Flags that spefify what should be inhibited
620 message_writer->AppendString(
621 CommandLine::ForCurrentProcess()->GetProgram().value());
622 message_writer->AppendUint32(0); // should be toplevel_xid
623 message_writer->AppendString(reason_);
624 {
625 uint32 flags = 0;
626 switch (type_) {
627 case kPowerSaveBlockPreventDisplaySleep:
628 flags |= kInhibitMarkSessionAsIdle;
629 flags |= kInhibitSuspendSession;
630 break;
631 case kPowerSaveBlockPreventAppSuspension:
632 flags |= kInhibitSuspendSession;
633 break;
634 }
635 message_writer->AppendUint32(flags);
636 }
637 break;
638 case kFreeDesktopAPI:
639 object_proxy = bus_->GetObjectProxy(
640 kFreeDesktopAPIServiceName,
641 dbus::ObjectPath(kFreeDesktopAPIObjectPath));
642 method_call.reset(
643 new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "Inhibit"));
644 message_writer.reset(new dbus::MessageWriter(method_call.get()));
645 // The arguments of the method are:
646 // app_id: The application identifier
647 // reason: The reason for the inhibit
648 message_writer->AppendString(
649 CommandLine::ForCurrentProcess()->GetProgram().value());
650 message_writer->AppendString(reason_);
651 break;
652 }
653
654 // We could do this method call asynchronously, but if we did, we'd need to
655 // handle the case where we want to cancel the block before we get a reply.
656 // We're on the FILE thread so it should be OK to block briefly here.
657 scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
658 method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
659 if (response.get()) {
660 // The method returns an inhibit_cookie, used to uniquely identify
661 // this request. It should be used as an argument to Uninhibit()
662 // in order to remove the request.
663 dbus::MessageReader message_reader(response.get());
664 if (!message_reader.PopUint32(&inhibit_cookie_))
665 LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
666 } else {
667 LOG(ERROR) << "No response to Inhibit() request!";
668 }
669 }
670
671 void PowerSaveBlocker::Delegate::RemoveBlock() {
672 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
673 if (api_ == kNoAPI)
674 return;
675 DCHECK(bus_.get()); // RemoveBlock() should only be called once.
676
677 scoped_refptr<dbus::ObjectProxy> object_proxy;
678 scoped_ptr<dbus::MethodCall> method_call;
679
680 switch (api_) {
681 case kNoAPI:
682 NOTREACHED(); // We return early above.
683 return;
684 case kGnomeAPI:
685 object_proxy = bus_->GetObjectProxy(
686 kGnomeAPIServiceName,
687 dbus::ObjectPath(kGnomeAPIObjectPath));
688 method_call.reset(
689 new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit"));
690 break;
691 case kFreeDesktopAPI:
692 object_proxy = bus_->GetObjectProxy(
693 kFreeDesktopAPIServiceName,
694 dbus::ObjectPath(kFreeDesktopAPIObjectPath));
695 method_call.reset(
696 new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "Uninhibit"));
697 break;
698 }
699
700 dbus::MessageWriter message_writer(method_call.get());
701 message_writer.AppendUint32(inhibit_cookie_);
702 scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
703 method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
704 if (!response.get())
705 LOG(ERROR) << "No response to Uninhibit() request!";
706 // We don't care about checking the result. We assume it works; we can't
707 // really do anything about it anyway if it fails.
708 inhibit_cookie_ = 0;
709
710 bus_->ShutdownAndBlock();
711 bus_ = NULL;
712 }
713
714 // static
715 bool PowerSaveBlocker::Delegate::DPMSEnabled() {
716 Display* display = base::MessagePumpForUI::GetDefaultXDisplay();
717 BOOL enabled = false;
718 int dummy;
719 if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) {
720 CARD16 state;
721 DPMSInfo(display, &state, &enabled);
722 }
723 return enabled;
724 }
725
726 // static
727 DBusAPI PowerSaveBlocker::Delegate::SelectAPI() {
728 scoped_ptr<base::Environment> env(base::Environment::Create());
729 switch (base::nix::GetDesktopEnvironment(env.get())) {
730 case base::nix::DESKTOP_ENVIRONMENT_GNOME:
731 if (DPMSEnabled())
732 return kGnomeAPI;
733 break;
734 case base::nix::DESKTOP_ENVIRONMENT_XFCE:
735 case base::nix::DESKTOP_ENVIRONMENT_KDE4:
736 if (DPMSEnabled())
737 return kFreeDesktopAPI;
738 break;
739 case base::nix::DESKTOP_ENVIRONMENT_KDE3:
740 case base::nix::DESKTOP_ENVIRONMENT_OTHER:
741 // Not supported.
742 break;
743 }
744 return kNoAPI;
745 }
746
747 PowerSaveBlocker::PowerSaveBlocker(
748 PowerSaveBlockerType type, const std::string& reason)
749 : delegate_(new Delegate(type, reason)) {
750 // The thread we use here becomes the origin and D-Bus thread for the D-Bus
751 // library, so we need to use the same thread below in the destructor. It must
752 // be a thread that allows I/O operations.
753 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
754 base::Bind(&Delegate::ApplyBlock, delegate_));
755 }
756
757 PowerSaveBlocker::~PowerSaveBlocker() {
758 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
759 base::Bind(&Delegate::RemoveBlock, delegate_));
760 }
761
762 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/power_save_blocker.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698