You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

435 lines
8.7 KiB

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "output.h"
#include "outputconfiguration.h"
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
namespace KWin
{
QDebug operator<<(QDebug debug, const Output *output)
{
QDebugStateSaver saver(debug);
debug.nospace();
if (output) {
debug << output->metaObject()->className() << '(' << static_cast<const void *>(output);
debug << ", name=" << output->name();
debug << ", geometry=" << output->geometry();
debug << ", scale=" << output->scale();
if (debug.verbosity() > 2) {
debug << ", manufacturer=" << output->manufacturer();
debug << ", model=" << output->model();
debug << ", serialNumber=" << output->serialNumber();
}
debug << ')';
} else {
debug << "Output(0x0)";
}
return debug;
}
OutputMode::OutputMode(const QSize &size, uint32_t refreshRate, Flags flags)
: m_size(size)
, m_refreshRate(refreshRate)
, m_flags(flags)
{
}
QSize OutputMode::size() const
{
return m_size;
}
uint32_t OutputMode::refreshRate() const
{
return m_refreshRate;
}
OutputMode::Flags OutputMode::flags() const
{
return m_flags;
}
Output::Output(QObject *parent)
: QObject(parent)
{
}
Output::~Output()
{
}
void Output::ref()
{
m_refCount++;
}
void Output::unref()
{
Q_ASSERT(m_refCount > 0);
m_refCount--;
if (m_refCount == 0) {
delete this;
}
}
QString Output::name() const
{
return m_information.name;
}
QUuid Output::uuid() const
{
return m_uuid;
}
Output::Transform Output::transform() const
{
return m_state.transform;
}
QString Output::eisaId() const
{
return m_information.eisaId;
}
QString Output::manufacturer() const
{
return m_information.manufacturer;
}
QString Output::model() const
{
return m_information.model;
}
QString Output::serialNumber() const
{
return m_information.serialNumber;
}
bool Output::isInternal() const
{
return m_information.internal;
}
void Output::inhibitDirectScanout()
{
m_directScanoutCount++;
}
void Output::uninhibitDirectScanout()
{
m_directScanoutCount--;
}
bool Output::directScanoutInhibited() const
{
return m_directScanoutCount;
}
std::chrono::milliseconds Output::dimAnimationTime()
{
// See kscreen.kcfg
return std::chrono::milliseconds(KSharedConfig::openConfig()->group("Effect-Kscreen").readEntry("Duration", 250));
}
QRect Output::mapFromGlobal(const QRect &rect) const
{
return rect.translated(-geometry().topLeft());
}
QRectF Output::mapFromGlobal(const QRectF &rect) const
{
return rect.translated(-geometry().topLeft());
}
QRectF Output::mapToGlobal(const QRectF &rect) const
{
return rect.translated(geometry().topLeft());
}
Output::Capabilities Output::capabilities() const
{
return m_information.capabilities;
}
qreal Output::scale() const
{
return m_state.scale;
}
QRect Output::geometry() const
{
return QRect(m_state.position, pixelSize() / scale());
}
QRectF Output::fractionalGeometry() const
{
return QRectF(m_state.position, QSizeF(pixelSize()) / scale());
}
QSize Output::physicalSize() const
{
return orientateSize(m_information.physicalSize);
}
int Output::refreshRate() const
{
return m_state.currentMode ? m_state.currentMode->refreshRate() : 0;
}
QSize Output::modeSize() const
{
return m_state.currentMode ? m_state.currentMode->size() : QSize();
}
QSize Output::pixelSize() const
{
return orientateSize(modeSize());
}
QByteArray Output::edid() const
{
return m_information.edid;
}
QList<std::shared_ptr<OutputMode>> Output::modes() const
{
return m_state.modes;
}
std::shared_ptr<OutputMode> Output::currentMode() const
{
return m_state.currentMode;
}
Output::SubPixel Output::subPixel() const
{
return m_information.subPixel;
}
void Output::applyChanges(const OutputConfiguration &config)
{
auto props = config.constChangeSet(this);
Q_EMIT aboutToChange();
State next = m_state;
next.enabled = props->enabled;
next.transform = props->transform;
next.position = props->pos;
next.scale = props->scale;
next.rgbRange = props->rgbRange;
setState(next);
setVrrPolicy(props->vrrPolicy);
Q_EMIT changed();
}
bool Output::isEnabled() const
{
return m_state.enabled;
}
QString Output::description() const
{
return manufacturer() + ' ' + model();
}
static QUuid generateOutputId(const QString &eisaId, const QString &model,
const QString &serialNumber, const QString &name)
{
static const QUuid urlNs = QUuid("6ba7b811-9dad-11d1-80b4-00c04fd430c8"); // NameSpace_URL
static const QUuid kwinNs = QUuid::createUuidV5(urlNs, QStringLiteral("https://kwin.kde.org/o/"));
const QString payload = QStringList{name, eisaId, model, serialNumber}.join(':');
return QUuid::createUuidV5(kwinNs, payload);
}
void Output::setInformation(const Information &information)
{
m_information = information;
m_uuid = generateOutputId(eisaId(), model(), serialNumber(), name());
}
void Output::setState(const State &state)
{
const QRect oldGeometry = geometry();
const State oldState = m_state;
m_state = state;
if (oldGeometry != geometry()) {
Q_EMIT geometryChanged();
}
if (oldState.scale != state.scale) {
Q_EMIT scaleChanged();
}
if (oldState.modes != state.modes) {
Q_EMIT modesChanged();
}
if (oldState.currentMode != state.currentMode) {
Q_EMIT currentModeChanged();
}
if (oldState.transform != state.transform) {
Q_EMIT transformChanged();
}
if (oldState.overscan != state.overscan) {
Q_EMIT overscanChanged();
}
if (oldState.dpmsMode != state.dpmsMode) {
Q_EMIT dpmsModeChanged();
}
if (oldState.rgbRange != state.rgbRange) {
Q_EMIT rgbRangeChanged();
}
if (oldState.enabled != state.enabled) {
Q_EMIT enabledChanged();
}
}
QSize Output::orientateSize(const QSize &size) const
{
switch (m_state.transform) {
case Transform::Rotated90:
case Transform::Rotated270:
case Transform::Flipped90:
case Transform::Flipped270:
return size.transposed();
default:
return size;
}
}
void Output::setDpmsMode(DpmsMode mode)
{
}
Output::DpmsMode Output::dpmsMode() const
{
return m_state.dpmsMode;
}
QMatrix4x4 Output::logicalToNativeMatrix(const QRectF &rect, qreal scale, Transform transform)
{
QMatrix4x4 matrix;
matrix.scale(scale);
switch (transform) {
case Transform::Normal:
case Transform::Flipped:
break;
case Transform::Rotated90:
case Transform::Flipped90:
matrix.translate(0, rect.width());
matrix.rotate(-90, 0, 0, 1);
break;
case Transform::Rotated180:
case Transform::Flipped180:
matrix.translate(rect.width(), rect.height());
matrix.rotate(-180, 0, 0, 1);
break;
case Transform::Rotated270:
case Transform::Flipped270:
matrix.translate(rect.height(), 0);
matrix.rotate(-270, 0, 0, 1);
break;
}
switch (transform) {
case Transform::Flipped:
case Transform::Flipped90:
case Transform::Flipped180:
case Transform::Flipped270:
matrix.translate(rect.width(), 0);
matrix.scale(-1, 1);
break;
default:
break;
}
matrix.translate(-rect.x(), -rect.y());
return matrix;
}
uint32_t Output::overscan() const
{
return m_state.overscan;
}
void Output::setVrrPolicy(RenderLoop::VrrPolicy policy)
{
if (renderLoop()->vrrPolicy() != policy && (capabilities() & Capability::Vrr)) {
renderLoop()->setVrrPolicy(policy);
Q_EMIT vrrPolicyChanged();
}
}
RenderLoop::VrrPolicy Output::vrrPolicy() const
{
return renderLoop()->vrrPolicy();
}
bool Output::isPlaceholder() const
{
return m_information.placeholder;
}
bool Output::isNonDesktop() const
{
return m_information.nonDesktop;
}
Output::RgbRange Output::rgbRange() const
{
return m_state.rgbRange;
}
bool Output::setGammaRamp(const std::shared_ptr<ColorTransformation> &transformation)
{
return false;
}
bool Output::setCTM(const QMatrix3x3 &ctm)
{
return false;
}
ContentType Output::contentType() const
{
return m_contentType;
}
void Output::setContentType(ContentType contentType)
{
m_contentType = contentType;
}
Output::Transform Output::panelOrientation() const
{
return m_information.panelOrientation;
}
bool Output::setCursor(CursorSource *source)
{
return false;
}
bool Output::moveCursor(const QPointF &position)
{
return false;
}
} // namespace KWin