x11_screensaver.cc 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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
  3. // found in the LICENSE file.
  4. #include "ui/base/x/x11_screensaver.h"
  5. #include <memory>
  6. #include "base/command_line.h"
  7. #include "base/no_destructor.h"
  8. #include "base/notreached.h"
  9. #include "ui/base/x/x11_util.h"
  10. #include "ui/gfx/switches.h"
  11. #include "ui/gfx/x/connection.h"
  12. #include "ui/gfx/x/event.h"
  13. #include "ui/gfx/x/property_cache.h"
  14. #include "ui/gfx/x/screensaver.h"
  15. #include "ui/gfx/x/x11_atom_cache.h"
  16. #include "ui/gfx/x/xproto_util.h"
  17. namespace ui {
  18. namespace {
  19. bool IsMitScreensaverActive(x11::ScreenSaver::State state) {
  20. switch (state) {
  21. case x11::ScreenSaver::State::Off:
  22. case x11::ScreenSaver::State::Disabled:
  23. return false;
  24. case x11::ScreenSaver::State::On:
  25. case x11::ScreenSaver::State::Cycle:
  26. return true;
  27. }
  28. NOTREACHED();
  29. return false;
  30. }
  31. class ScreensaverStatusWatcher : public x11::EventObserver {
  32. public:
  33. ScreensaverStatusWatcher() {
  34. auto* connection = x11::Connection::Get();
  35. x_screensaver_status_ = std::make_unique<x11::PropertyCache>(
  36. connection, connection->default_root(),
  37. std::vector<x11::Atom>{x11::GetAtom("_SCREENSAVER_STATUS")});
  38. // Let the server know the client version before making any requests.
  39. connection->screensaver().QueryVersion(
  40. {x11::ScreenSaver::major_version, x11::ScreenSaver::minor_version});
  41. connection->AddEventObserver(this);
  42. connection->screensaver().SelectInput(connection->default_root(),
  43. x11::ScreenSaver::Event::NotifyMask);
  44. auto reply =
  45. connection->screensaver().QueryInfo(connection->default_root()).Sync();
  46. if (reply) {
  47. mit_screensaver_active_ = IsMitScreensaverActive(
  48. static_cast<x11::ScreenSaver::State>(reply->state));
  49. }
  50. }
  51. ScreensaverStatusWatcher(const ScreensaverStatusWatcher&) = delete;
  52. ScreensaverStatusWatcher& operator=(const ScreensaverStatusWatcher&) = delete;
  53. ~ScreensaverStatusWatcher() override = default;
  54. bool ScreensaverActive() {
  55. if (mit_screensaver_active_)
  56. return true;
  57. // Ironically, xscreensaver does not use the MIT-SCREENSAVER extension,
  58. // so add a special check for xscreensaver.
  59. auto* status = x_screensaver_status_->GetAs<x11::Atom>(
  60. x11::GetAtom("_SCREENSAVER_STATUS"));
  61. return status && *status == x11::GetAtom("LOCK");
  62. }
  63. private:
  64. void OnEvent(const x11::Event& event) override {
  65. if (auto* notify = event.As<x11::ScreenSaver::NotifyEvent>())
  66. mit_screensaver_active_ = IsMitScreensaverActive(notify->state);
  67. }
  68. std::unique_ptr<x11::PropertyCache> x_screensaver_status_;
  69. bool mit_screensaver_active_ = false;
  70. };
  71. } // namespace
  72. bool IsXScreensaverActive() {
  73. // Avoid calling into potentially missing X11 APIs in headless mode.
  74. if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
  75. return false;
  76. static base::NoDestructor<ScreensaverStatusWatcher> watcher;
  77. return watcher->ScreensaverActive();
  78. }
  79. } // namespace ui