You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.4 KiB
C++
114 lines
3.4 KiB
C++
// SPDX-FileCopyrightText: 2026 Reion Wong <reionwong@gmail.com>
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
#include "cutefish/display/screen.h"
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
namespace cutefish::display {
|
|
|
|
Screen::Screen(std::string serviceName)
|
|
: m_client(std::move(serviceName))
|
|
{
|
|
m_countdown.setInterval(250ms);
|
|
m_countdown.onTimeout = [this] { stateChanged.emit(); };
|
|
m_subscriptions.push_back(m_client.availabilityChanged.connect([this] { stateChanged.emit(); }));
|
|
m_subscriptions.push_back(m_client.stateChanged.connect([this] { updateState(); }));
|
|
m_subscriptions.push_back(m_outputModel.dirtyChanged.connect([this] {
|
|
stateChanged.emit();
|
|
if (dirty())
|
|
apply();
|
|
}));
|
|
m_subscriptions.push_back(m_client.operationFinished.connect([this](DisplayClient::Operation operation) {
|
|
m_busy = false;
|
|
m_error = operation.succeeded && !operation.degraded ? std::string() : operation.message;
|
|
m_outputModel.setState(m_client.state());
|
|
stateChanged.emit();
|
|
}));
|
|
m_outputModel.setState(m_client.state());
|
|
updateState();
|
|
}
|
|
|
|
Screen::~Screen() = default;
|
|
|
|
bool Screen::canApply() const
|
|
{
|
|
return available() && !m_busy && dirty() && !pendingConfirmation();
|
|
}
|
|
|
|
int Screen::confirmationSeconds() const
|
|
{
|
|
if (!pendingConfirmation())
|
|
return 0;
|
|
const int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
std::chrono::system_clock::now().time_since_epoch())
|
|
.count();
|
|
return int(std::max<int64_t>(0, (int64_t(m_client.state().previewDeadlineMs) - now + 999) / 1000));
|
|
}
|
|
|
|
void Screen::updateState()
|
|
{
|
|
const DisplayClient::State& state = m_client.state();
|
|
if (m_client.loaded() && !m_client.available()) {
|
|
m_busy = false;
|
|
m_error = "The display service is unavailable.";
|
|
}
|
|
const bool topologyChanged = !m_instanceId.empty()
|
|
&& (m_instanceId != state.instanceId
|
|
|| m_topologyGeneration != state.topologyGeneration);
|
|
if (!m_outputModel.dirty() || topologyChanged || m_busy || pendingConfirmation())
|
|
m_outputModel.setState(state);
|
|
if (topologyChanged)
|
|
m_error = "Displays changed. The previous draft was discarded.";
|
|
m_instanceId = state.instanceId;
|
|
m_topologyGeneration = state.topologyGeneration;
|
|
if (pendingConfirmation()) {
|
|
if (!m_countdown.isActive())
|
|
m_countdown.start();
|
|
} else {
|
|
m_countdown.stop();
|
|
}
|
|
stateChanged.emit();
|
|
}
|
|
|
|
void Screen::apply()
|
|
{
|
|
if (!canApply())
|
|
return;
|
|
m_busy = true;
|
|
m_error.clear();
|
|
stateChanged.emit();
|
|
if (!m_client.apply(m_outputModel.requests(), m_outputModel.primary(), m_outputModel.placements(),
|
|
m_outputModel.mirrorGroups(), m_outputModel.needsConfirmation())) {
|
|
m_busy = false;
|
|
m_error = "The display service is unavailable.";
|
|
stateChanged.emit();
|
|
}
|
|
}
|
|
|
|
void Screen::discard()
|
|
{
|
|
if (!m_busy) {
|
|
m_outputModel.discard();
|
|
m_error.clear();
|
|
stateChanged.emit();
|
|
}
|
|
}
|
|
|
|
void Screen::keep()
|
|
{
|
|
if (pendingConfirmation())
|
|
m_client.confirm(m_client.state().previewToken);
|
|
}
|
|
|
|
void Screen::revert()
|
|
{
|
|
if (pendingConfirmation())
|
|
m_client.revert(m_client.state().previewToken);
|
|
}
|
|
|
|
} // namespace cutefish::display
|