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

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
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
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
511
512 namespace content {
513
514 class PowerSaveBlocker::Delegate
515 : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
516 public:
517 // Picks an appropriate DBus API to use based on the desktop environment.
518 Delegate(PowerSaveBlockerType type, const std::string& reason);
519
520 void ApplyBlock();
521 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
522
523 private:
524 enum DBusAPI {
525 kNoAPI, // Disable. No supported API available.
526 kGnomeAPI, // Use the GNOME API. (Supports more features.)
527 kFreeDesktopAPI, // Use the FreeDesktop API, for KDE4 and XFCE.
528 };
529
530 // Inhibit flags defined in the org.gnome.SessionManager interface.
531 // Can be OR'd together and passed as argument to the Inhibit() method
532 // to specify which power management features we want to suspend.
533 enum GnomeAPIInhibitFlags {
534 kInhibitLogOut = 1,
535 kInhibitSwitchUser = 2,
536 kInhibitSuspendSession = 4,
537 kInhibitMarkSessionAsIdle = 8
538 };
539
540 static const char kGnomeAPIServiceName[];
541 static const char kGnomeAPIInterfaceName[];
542 static const char kGnomeAPIObjectPath[];
543 static const char kFreeDesktopAPIServiceName[];
544 static const char kFreeDesktopAPIInterfaceName[];
545 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.
546
547 friend class base::RefCountedThreadSafe<Delegate>;
548 ~Delegate() {}
549
550 // 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
551 // since on some desktop environments that may enable DPMS with very poor
552 // default settings (e.g. turning off the display after only 1 second).
553 static bool DPMSEnabled();
554
555 // 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.
556 static DBusAPI SelectAPI();
557
558 const PowerSaveBlockerType type_;
559 const std::string reason_;
560 const DBusAPI api_;
561
562 scoped_refptr<dbus::Bus> bus_;
563
564 // The cookie that identifies our inhibit request,
565 // or 0 if there is no active inhibit request.
566 uint32 inhibit_cookie_;
567
568 DISALLOW_COPY_AND_ASSIGN(Delegate);
569 };
570
571 const char PowerSaveBlocker::Delegate::kGnomeAPIServiceName[] =
572 "org.gnome.SessionManager";
573 const char PowerSaveBlocker::Delegate::kGnomeAPIInterfaceName[] =
574 "org.gnome.SessionManager";
575 const char PowerSaveBlocker::Delegate::kGnomeAPIObjectPath[] =
576 "/org/gnome/SessionManager";
577
578 const char PowerSaveBlocker::Delegate::kFreeDesktopAPIServiceName[] =
579 "org.freedesktop.PowerManagement";
580 const char PowerSaveBlocker::Delegate::kFreeDesktopAPIInterfaceName[] =
581 "org.freedesktop.PowerManagement.Inhibit";
582 const char PowerSaveBlocker::Delegate::kFreeDesktopAPIObjectPath[] =
583 "/org/freedesktop/PowerManagement/Inhibit";
584
585 PowerSaveBlocker::Delegate::Delegate(PowerSaveBlockerType type,
586 const std::string& reason)
587 : type_(type), reason_(reason), api_(SelectAPI()) {
588 // We're on the client's thread here, so we don't allocate the dbus::Bus
589 // object yet. We'll do it below in ApplyBlock(), on the file thread.
590 }
591
592 void PowerSaveBlocker::Delegate::ApplyBlock() {
593 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
594 DCHECK(!bus_.get()); // ApplyBlock() should only be called once.
595 if (api_ == kNoAPI)
596 return;
597
598 dbus::Bus::Options options;
599 options.bus_type = dbus::Bus::SESSION;
600 options.connection_type = dbus::Bus::PRIVATE;
601 bus_ = new dbus::Bus(options);
602
603 scoped_refptr<dbus::ObjectProxy> object_proxy;
604 // 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
605 dbus::MethodCall method_call("org.chromium.Placeholder", "Inhibit");
606 dbus::MessageWriter message_writer(&method_call);
607
608 switch (api_) {
609 case kNoAPI:
610 NOTREACHED(); // We return early above.
611 return;
612 case kGnomeAPI:
613 object_proxy = bus_->GetObjectProxy(
614 kGnomeAPIServiceName,
615 dbus::ObjectPath(kGnomeAPIObjectPath));
616 method_call.SetInterface(kGnomeAPIInterfaceName);
617 // The arguments of the method are:
618 // app_id: The application identifier
619 // toplevel_xid: The toplevel X window identifier
620 // reason: The reason for the inhibit
621 // flags: Flags that spefify what should be inhibited
622 message_writer.AppendString(
623 CommandLine::ForCurrentProcess()->GetProgram().value());
624 message_writer.AppendUint32(0); // should be toplevel_xid
625 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.
626 {
627 uint32 flags = 0;
628 switch (type_) {
629 case kPowerSaveBlockPreventDisplaySleep:
630 flags |= kInhibitMarkSessionAsIdle;
631 flags |= kInhibitSuspendSession;
632 break;
633 case kPowerSaveBlockPreventAppSuspension:
634 flags |= kInhibitSuspendSession;
635 break;
636 }
637 message_writer.AppendUint32(flags);
638 }
639 break;
640 case kFreeDesktopAPI:
641 object_proxy = bus_->GetObjectProxy(
642 kFreeDesktopAPIServiceName,
643 dbus::ObjectPath(kFreeDesktopAPIObjectPath));
644 method_call.SetInterface(kFreeDesktopAPIInterfaceName);
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_.c_str());
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, 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 // We must provide a valid-looking interface. We'll change it below.
satorux1 2012/06/08 14:59:41 see my comment above.
679 dbus::MethodCall method_call("org.chromium.Placeholder", "Uninhibit");
680 dbus::MessageWriter message_writer(&method_call);
681
682 switch (api_) {
683 case kNoAPI:
684 NOTREACHED(); // We return early above.
685 return;
686 case kGnomeAPI:
687 object_proxy = bus_->GetObjectProxy(
688 kGnomeAPIServiceName,
689 dbus::ObjectPath(kGnomeAPIObjectPath));
690 method_call.SetInterface(kGnomeAPIInterfaceName);
691 break;
692 case kFreeDesktopAPI:
693 object_proxy = bus_->GetObjectProxy(
694 kFreeDesktopAPIServiceName,
695 dbus::ObjectPath(kFreeDesktopAPIObjectPath));
696 method_call.SetInterface(kFreeDesktopAPIInterfaceName);
697 break;
698 }
699
700 message_writer.AppendUint32(inhibit_cookie_);
701 scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
702 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
703 if (!response.get())
704 LOG(ERROR) << "No response to Uninhibit() request!";
705 // We don't care about checking the result. We assume it works; we can't
706 // really do anything about it anyway if it fails.
707 inhibit_cookie_ = 0;
708
709 bus_->ShutdownAndBlock();
710 bus_ = NULL;
711 }
712
713 // static
714 bool PowerSaveBlocker::Delegate::DPMSEnabled() {
715 Display* display = base::MessagePumpForUI::GetDefaultXDisplay();
716 BOOL enabled = false;
717 int dummy;
718 if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) {
719 CARD16 state;
720 DPMSInfo(display, &state, &enabled);
721 }
722 return enabled;
723 }
724
725 // static
726 PowerSaveBlocker::Delegate::DBusAPI PowerSaveBlocker::Delegate::SelectAPI() {
727 scoped_ptr<base::Environment> env(base::Environment::Create());
728 switch (base::nix::GetDesktopEnvironment(env.get())) {
729 case base::nix::DESKTOP_ENVIRONMENT_GNOME:
730 if (DPMSEnabled())
731 return kGnomeAPI;
732 break;
733 case base::nix::DESKTOP_ENVIRONMENT_XFCE:
734 case base::nix::DESKTOP_ENVIRONMENT_KDE4:
735 if (DPMSEnabled())
736 return kFreeDesktopAPI;
737 break;
738 case base::nix::DESKTOP_ENVIRONMENT_KDE3:
739 case base::nix::DESKTOP_ENVIRONMENT_OTHER:
740 // Not supported.
741 break;
742 }
743 return kNoAPI;
744 }
745
746 PowerSaveBlocker::PowerSaveBlocker(
747 PowerSaveBlockerType type, const std::string& reason)
748 : delegate_(new Delegate(type, reason)) {
749 // We use the FILE thread to service the DBus connection, since we need a
750 // thread that allows I/O operations. The same thread must be used in the
751 // destructor below, but other than that we could use any thread.
752 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.
753 base::Bind(&Delegate::ApplyBlock, delegate_));
754 }
755
756 PowerSaveBlocker::~PowerSaveBlocker() {
757 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
758 base::Bind(&Delegate::RemoveBlock, delegate_));
759 }
760
761 } // namespace content
OLDNEW
« 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