123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "remoting/host/desktop_display_info_loader.h"
- #include <algorithm>
- #include <memory>
- #include "base/memory/raw_ptr.h"
- #include "base/numerics/safe_conversions.h"
- #include "remoting/base/logging.h"
- #include "ui/base/x/x11_display_util.h"
- #include "ui/base/x/x11_util.h"
- #include "ui/gfx/x/connection.h"
- #include "ui/gfx/x/event.h"
- #include "ui/gfx/x/future.h"
- #include "ui/gfx/x/randr.h"
- #include "ui/gfx/x/x11_window_event_manager.h"
- namespace remoting {
- namespace {
- // Monitors were added in XRANDR 1.5.
- constexpr int kMinRandrVersion = 105;
- constexpr int kDefaultScreenDpi = 96;
- constexpr double kMillimetersPerInch = 25.4;
- class DesktopDisplayInfoLoaderX11 : public DesktopDisplayInfoLoader,
- public x11::EventObserver {
- public:
- DesktopDisplayInfoLoaderX11() = default;
- ~DesktopDisplayInfoLoaderX11() override;
- // DesktopDisplayInfoLoader implementation.
- void Init() override;
- DesktopDisplayInfo GetCurrentDisplayInfo() override;
- // x11::EventObserver implementation.
- void OnEvent(const x11::Event& xevent) override;
- private:
- // Queries the X server and updates |monitors_|.
- void LoadMonitors();
- // XRANDR version as MAJOR * 100 + MINOR, or 0 if XRANDR is not present.
- int xrandr_version_ = 0;
- raw_ptr<x11::Connection> connection_ = nullptr;
- raw_ptr<x11::RandR> randr_ = nullptr;
- // Selector for root window events.
- std::unique_ptr<x11::XScopedEventSelector> root_window_events_;
- std::vector<x11::RandR::MonitorInfo> monitors_;
- };
- DesktopDisplayInfoLoaderX11::~DesktopDisplayInfoLoaderX11() {
- if (connection_) {
- connection_->RemoveEventObserver(this);
- }
- }
- void DesktopDisplayInfoLoaderX11::Init() {
- connection_ = x11::Connection::Get();
- connection_->AddEventObserver(this);
- randr_ = &connection_->randr();
- if (!randr_->present()) {
- HOST_LOG << "No XRANDR extension found.";
- return;
- }
- xrandr_version_ = ui::GetXrandrVersion();
- if (xrandr_version_ < kMinRandrVersion) {
- HOST_LOG << "XRANDR version (" << xrandr_version_ << ") is too old.";
- return;
- }
- root_window_events_ = std::make_unique<x11::XScopedEventSelector>(
- ui::GetX11RootWindow(), x11::EventMask::StructureNotify);
- auto randr_event_mask =
- x11::RandR::NotifyMask::ScreenChange | x11::RandR::NotifyMask::CrtcChange;
- randr_->SelectInput({ui::GetX11RootWindow(), randr_event_mask});
- LoadMonitors();
- }
- DesktopDisplayInfo DesktopDisplayInfoLoaderX11::GetCurrentDisplayInfo() {
- DesktopDisplayInfo result;
- for (const auto& monitor : monitors_) {
- DisplayGeometry info;
- // webrtc::ScreenCapturerX11 uses the |name| Atom as the monitor ID.
- info.id = static_cast<int32_t>(monitor.name);
- info.is_default = monitor.primary;
- info.x = monitor.x;
- info.y = monitor.y;
- info.width = monitor.width;
- info.height = monitor.height;
- info.dpi = kDefaultScreenDpi;
- info.bpp = 24;
- // Calculate DPI if possible, using width in millimeters.
- if (monitor.width_in_millimeters != 0) {
- double pixelsPerMillimeter =
- static_cast<double>(monitor.width) / monitor.width_in_millimeters;
- double pixelsPerInch = pixelsPerMillimeter * kMillimetersPerInch;
- info.dpi = base::ClampRound(pixelsPerInch);
- }
- result.AddDisplay(info);
- }
- return result;
- }
- void DesktopDisplayInfoLoaderX11::OnEvent(const x11::Event& xevent) {
- const auto* configure_notify = xevent.As<x11::ConfigureNotifyEvent>();
- const auto* screen_change = xevent.As<x11::RandR::ScreenChangeNotifyEvent>();
- const auto* notify = xevent.As<x11::RandR::NotifyEvent>();
- if (configure_notify) {
- HOST_LOG << "Got X11 ConfigureNotify event.";
- } else if (screen_change) {
- HOST_LOG << "Got RANDR ScreenChange event.";
- } else if (notify) {
- HOST_LOG << "Got RANDR Notify event.";
- } else {
- // Unhandled event received on root window, ignore.
- return;
- }
- LoadMonitors();
- }
- void DesktopDisplayInfoLoaderX11::LoadMonitors() {
- if (xrandr_version_ < kMinRandrVersion)
- return;
- auto reply = randr_->GetMonitors({ui::GetX11RootWindow()}).Sync();
- if (reply) {
- monitors_ = std::move(reply->monitors);
- } else {
- LOG(ERROR) << "RRGetMonitors request failed.";
- }
- }
- } // namespace
- // static
- std::unique_ptr<DesktopDisplayInfoLoader> DesktopDisplayInfoLoader::Create() {
- return std::make_unique<DesktopDisplayInfoLoaderX11>();
- }
- } // namespace remoting
|