1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
|
// Copyright 2021 The Chromium Authors
// 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_monitor.h"
#include <memory>
#include <utility>
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "remoting/host/desktop_display_info.h"
#include "remoting/host/desktop_display_info_loader.h"
namespace remoting {
namespace {
// Polling interval for querying the OS for changes to the multi-monitor
// configuration. Before this class was written, the DesktopCapturerProxy would
// poll after each captured frame, which could occur up to 30x per second. The
// value chosen here is slower than this (to reduce the load on the OS), but
// still fast enough to be responsive to any changes.
constexpr base::TimeDelta kPollingInterval = base::Milliseconds(100);
} // namespace
DesktopDisplayInfoMonitor::DesktopDisplayInfoMonitor(
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
std::unique_ptr<DesktopDisplayInfoLoader> info_loader)
: ui_task_runner_(ui_task_runner),
desktop_display_info_loader_(std::move(info_loader)) {
// The loader must be initialized and used on the UI thread (though it can be
// created on any thread).
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DesktopDisplayInfoLoader::Init,
base::Unretained(desktop_display_info_loader_.get())));
}
DesktopDisplayInfoMonitor::~DesktopDisplayInfoMonitor() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
ui_task_runner_->DeleteSoon(FROM_HERE,
desktop_display_info_loader_.release());
}
void DesktopDisplayInfoMonitor::Start() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!timer_running_) {
timer_running_ = true;
timer_.Start(FROM_HERE, kPollingInterval, this,
&DesktopDisplayInfoMonitor::QueryDisplayInfoImpl);
}
}
void DesktopDisplayInfoMonitor::QueryDisplayInfo() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!timer_running_) {
QueryDisplayInfoImpl();
}
}
void DesktopDisplayInfoMonitor::AddCallback(
DesktopDisplayInfoMonitor::Callback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Adding callbacks is not supported after displays have been loaded.
DCHECK_EQ(desktop_display_info_.NumDisplays(), 0);
callback_list_.AddUnsafe(std::move(callback));
}
void DesktopDisplayInfoMonitor::QueryDisplayInfoImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!callback_list_.empty()) {
ui_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&DesktopDisplayInfoLoader::GetCurrentDisplayInfo,
base::Unretained(desktop_display_info_loader_.get())),
base::BindOnce(&DesktopDisplayInfoMonitor::OnDisplayInfoLoaded,
weak_factory_.GetWeakPtr()));
}
}
void DesktopDisplayInfoMonitor::OnDisplayInfoLoaded(DesktopDisplayInfo info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (callback_list_.empty() || desktop_display_info_ == info) {
return;
}
desktop_display_info_ = std::move(info);
callback_list_.Notify(desktop_display_info_);
}
} // namespace remoting
|