Commit c2723071 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

wayland: Move Wayland-specific code out of AbstractWaylandOutput

Currently, output properties are looked up either on the wl_output
object or the output device object. This puts a hard dependency on the
wayland server in the platforms.

This change intends to fix some flaws in the current output
abstractions, and allow creating/destroying wayland-specific globals as
we wish.

With the work done in this patch, the need for the AbstractWaylandOutput
class is unclear, and it might be a good idea to merge it with the base
AbstractOutput class.
parent 3d231b3c
......@@ -136,6 +136,8 @@ set(kwin_SRCS
was_user_interaction_x11_filter.cpp
wayland_server.cpp
waylandclient.cpp
waylandoutput.cpp
waylandoutputdevice.cpp
waylandshellintegration.cpp
window_property_notify_x11_filter.cpp
windowitem.cpp
......
......@@ -8,42 +8,36 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "abstract_wayland_output.h"
#include "screens.h"
#include "wayland_server.h"
// KWayland
#include <KWaylandServer/display.h>
#include <KWaylandServer/outputchangeset.h>
#include <KWaylandServer/xdgoutput_v1_interface.h>
// KF5
#include <KLocalizedString>
#include <QMatrix4x4>
#include <cmath>
namespace KWin
{
static AbstractWaylandOutput::Transform outputDeviceTransformToKWinTransform(KWaylandServer::OutputDeviceInterface::Transform transform)
{
return static_cast<AbstractWaylandOutput::Transform>(transform);
}
AbstractWaylandOutput::AbstractWaylandOutput(QObject *parent)
: AbstractOutput(parent)
{
m_waylandOutput = new KWaylandServer::OutputInterface(waylandServer()->display(), this);
m_waylandOutputDevice = new KWaylandServer::OutputDeviceInterface(waylandServer()->display(), this);
m_xdgOutputV1 = waylandServer()->xdgOutputManagerV1()->createXdgOutput(m_waylandOutput, this);
connect(m_waylandOutput, &KWaylandServer::OutputInterface::dpmsModeRequested, this,
[this] (KWaylandServer::OutputInterface::DpmsMode mode) {
updateDpms(mode);
});
}
connect(m_waylandOutput, &KWaylandServer::OutputInterface::globalPositionChanged, this, &AbstractWaylandOutput::geometryChanged);
connect(m_waylandOutput, &KWaylandServer::OutputInterface::pixelSizeChanged, this, &AbstractWaylandOutput::geometryChanged);
connect(m_waylandOutput, &KWaylandServer::OutputInterface::scaleChanged, this, &AbstractWaylandOutput::geometryChanged);
AbstractWaylandOutput::Capabilities AbstractWaylandOutput::capabilities() const
{
return m_capabilities;
}
AbstractWaylandOutput::~AbstractWaylandOutput()
void AbstractWaylandOutput::setCapabilityInternal(Capability capability, bool on)
{
m_capabilities.setFlag(capability, on);
}
QString AbstractWaylandOutput::name() const
......@@ -53,7 +47,7 @@ QString AbstractWaylandOutput::name() const
QString AbstractWaylandOutput::uuid() const
{
return m_waylandOutputDevice->uuid();
return m_uuid;
}
QRect AbstractWaylandOutput::geometry() const
......@@ -63,122 +57,74 @@ QRect AbstractWaylandOutput::geometry() const
QSize AbstractWaylandOutput::physicalSize() const
{
return orientateSize(m_waylandOutputDevice->physicalSize());
return orientateSize(m_physicalSize);
}
int AbstractWaylandOutput::refreshRate() const
{
return m_waylandOutputDevice->refreshRate();
return m_refreshRate;
}
QPoint AbstractWaylandOutput::globalPos() const
{
return m_waylandOutputDevice->globalPosition();
return m_position;
}
void AbstractWaylandOutput::setGlobalPos(const QPoint &pos)
{
m_waylandOutputDevice->setGlobalPosition(pos);
m_waylandOutput->setGlobalPosition(pos);
m_xdgOutputV1->setLogicalPosition(pos);
m_waylandOutput->done();
m_xdgOutputV1->done();
if (m_position != pos) {
m_position = pos;
emit geometryChanged();
}
}
QString AbstractWaylandOutput::manufacturer() const
{
return m_waylandOutputDevice->manufacturer();
return m_manufacturer;
}
QString AbstractWaylandOutput::model() const
{
return m_waylandOutputDevice->model();
return m_model;
}
QString AbstractWaylandOutput::serialNumber() const
{
return m_waylandOutputDevice->serialNumber();
return m_serialNumber;
}
QSize AbstractWaylandOutput::modeSize() const
{
return m_waylandOutputDevice->pixelSize();
return m_modeSize;
}
QSize AbstractWaylandOutput::pixelSize() const
{
return orientateSize(m_waylandOutputDevice->pixelSize());
return orientateSize(m_modeSize);
}
qreal AbstractWaylandOutput::scale() const
QByteArray AbstractWaylandOutput::edid() const
{
return m_waylandOutputDevice->scaleF();
}
void AbstractWaylandOutput::setScale(qreal scale)
{
m_waylandOutputDevice->setScaleF(scale);
// this is the scale that clients will ideally use for their buffers
// this has to be an int which is fine
// I don't know whether we want to round or ceil
// or maybe even set this to 3 when we're scaling to 1.5
// don't treat this like it's chosen deliberately
m_waylandOutput->setScale(std::ceil(scale));
m_xdgOutputV1->setLogicalSize(pixelSize() / scale);
m_waylandOutput->done();
m_xdgOutputV1->done();
}
using DeviceInterface = KWaylandServer::OutputDeviceInterface;
KWaylandServer::OutputInterface::Transform toOutputTransform(DeviceInterface::Transform transform)
{
using Transform = DeviceInterface::Transform;
using OutputTransform = KWaylandServer::OutputInterface::Transform;
switch (transform) {
case Transform::Rotated90:
return OutputTransform::Rotated90;
case Transform::Rotated180:
return OutputTransform::Rotated180;
case Transform::Rotated270:
return OutputTransform::Rotated270;
case Transform::Flipped:
return OutputTransform::Flipped;
case Transform::Flipped90:
return OutputTransform::Flipped90;
case Transform::Flipped180:
return OutputTransform::Flipped180;
case Transform::Flipped270:
return OutputTransform::Flipped270;
default:
return OutputTransform::Normal;
}
return m_edid;
}
void AbstractWaylandOutput::setTransform(DeviceInterface::Transform transform)
QVector<AbstractWaylandOutput::Mode> AbstractWaylandOutput::modes() const
{
m_waylandOutputDevice->setTransform(transform);
m_waylandOutput->setTransform(toOutputTransform(transform));
m_xdgOutputV1->setLogicalSize(pixelSize() / scale());
m_waylandOutput->done();
m_xdgOutputV1->done();
return m_modes;
}
inline
AbstractWaylandOutput::Transform toTransform(DeviceInterface::Transform deviceTransform)
qreal AbstractWaylandOutput::scale() const
{
return static_cast<AbstractWaylandOutput::Transform>(deviceTransform);
return m_scale;
}
inline
DeviceInterface::Transform toDeviceTransform(AbstractWaylandOutput::Transform transform)
void AbstractWaylandOutput::setScale(qreal scale)
{
return static_cast<DeviceInterface::Transform>(transform);
if (m_scale != scale) {
m_scale = scale;
emit scaleChanged();
emit geometryChanged();
}
}
void AbstractWaylandOutput::applyChanges(const KWaylandServer::OutputChangeSet *changeSet)
......@@ -190,14 +136,14 @@ void AbstractWaylandOutput::applyChanges(const KWaylandServer::OutputChangeSet *
// Enablement changes are handled by platform.
if (changeSet->modeChanged()) {
qCDebug(KWIN_CORE) << "Setting new mode:" << changeSet->mode();
m_waylandOutputDevice->setCurrentMode(changeSet->mode());
updateMode(changeSet->mode());
emitModeChanged = true;
}
if (changeSet->transformChanged()) {
qCDebug(KWIN_CORE) << "Server setting transform: " << (int)(changeSet->transform());
setTransform(changeSet->transform());
updateTransform(toTransform(changeSet->transform()));
auto transform = outputDeviceTransformToKWinTransform(changeSet->transform());
setTransformInternal(transform);
updateTransform(transform);
emitModeChanged = true;
}
if (changeSet->positionChanged()) {
......@@ -224,114 +170,91 @@ void AbstractWaylandOutput::applyChanges(const KWaylandServer::OutputChangeSet *
bool AbstractWaylandOutput::isEnabled() const
{
return m_waylandOutputDevice->enabled() == DeviceInterface::Enablement::Enabled;
return m_isEnabled;
}
void AbstractWaylandOutput::setEnabled(bool enable)
{
if (enable == isEnabled()) {
return;
}
if (enable) {
m_waylandOutputDevice->setEnabled(DeviceInterface::Enablement::Enabled);
m_waylandOutput->create();
updateEnablement(true);
} else {
m_waylandOutputDevice->setEnabled(DeviceInterface::Enablement::Disabled);
m_waylandOutput->destroy();
// xdg-output is destroyed in KWayland on wl_output going away.
updateEnablement(false);
if (m_isEnabled != enable) {
m_isEnabled = enable;
updateEnablement(enable);
emit enabledChanged();
}
emit enabledChanged();
}
QString AbstractWaylandOutput::description() const
{
return QStringLiteral("%1 %2").arg(m_waylandOutputDevice->manufacturer()).arg(
m_waylandOutputDevice->model());
return m_manufacturer + ' ' + m_model;
}
void AbstractWaylandOutput::setWaylandMode(const QSize &size, int refreshRate)
void AbstractWaylandOutput::setCurrentModeInternal(const QSize &size, int refreshRate)
{
m_waylandOutput->setCurrentMode(size, refreshRate);
m_waylandOutputDevice->setCurrentMode(size, refreshRate);
m_xdgOutputV1->setLogicalSize(pixelSize() / scale());
m_waylandOutput->done();
m_xdgOutputV1->done();
if (m_modeSize != size || m_refreshRate != refreshRate) {
m_modeSize = size;
m_refreshRate = refreshRate;
emit geometryChanged();
}
}
void AbstractWaylandOutput::initInterfaces(const QString &model, const QString &manufacturer,
const QString &uuid, const QSize &physicalSize,
const QVector<DeviceInterface::Mode> &modes,
const QByteArray &edid)
void AbstractWaylandOutput::initialize(const QString &model, const QString &manufacturer,
const QString &uuid, const QSize &physicalSize,
const QVector<Mode> &modes, const QByteArray &edid)
{
m_waylandOutputDevice->setUuid(uuid);
if (manufacturer.isEmpty()) {
m_waylandOutputDevice->setManufacturer(i18n("unknown"));
} else {
m_waylandOutputDevice->setManufacturer(manufacturer);
}
m_waylandOutputDevice->setEdid(edid);
m_waylandOutputDevice->setModel(model);
m_waylandOutputDevice->setPhysicalSize(physicalSize);
m_waylandOutput->setManufacturer(m_waylandOutputDevice->manufacturer());
m_waylandOutput->setModel(m_waylandOutputDevice->model());
m_waylandOutput->setPhysicalSize(m_waylandOutputDevice->physicalSize());
int i = 0;
for (auto mode : modes) {
qCDebug(KWIN_CORE).nospace() << "Adding mode " << ++i << ": " << mode.size << " [" << mode.refreshRate << "]";
m_waylandOutputDevice->addMode(mode);
m_manufacturer = manufacturer.isEmpty() ? i18n("unknown") : manufacturer;
m_model = model;
m_physicalSize = physicalSize;
m_uuid = uuid;
m_edid = edid;
m_modes = modes;
KWaylandServer::OutputInterface::ModeFlags flags;
if (mode.flags & DeviceInterface::ModeFlag::Current) {
flags |= KWaylandServer::OutputInterface::ModeFlag::Current;
for (const Mode &mode : modes) {
if (mode.flags & ModeFlag::Current) {
m_modeSize = mode.size;
m_refreshRate = mode.refreshRate;
break;
}
if (mode.flags & DeviceInterface::ModeFlag::Preferred) {
flags |= KWaylandServer::OutputInterface::ModeFlag::Preferred;
}
m_waylandOutput->addMode(mode.size, flags, mode.refreshRate);
}
// start off enabled
m_xdgOutputV1->setName(name());
m_xdgOutputV1->setDescription(description());
m_xdgOutputV1->setLogicalSize(pixelSize() / scale());
m_waylandOutput->create();
m_waylandOutput->done();
m_xdgOutputV1->done();
}
QSize AbstractWaylandOutput::orientateSize(const QSize &size) const
{
using Transform = DeviceInterface::Transform;
const Transform transform = m_waylandOutputDevice->transform();
if (transform == Transform::Rotated90 || transform == Transform::Rotated270 ||
transform == Transform::Flipped90 || transform == Transform::Flipped270) {
if (m_transform == Transform::Rotated90 || m_transform == Transform::Rotated270 ||
m_transform == Transform::Flipped90 || m_transform == Transform::Flipped270) {
return size.transposed();
}
return size;
}
void AbstractWaylandOutput::setTransform(Transform transform)
void AbstractWaylandOutput::setTransformInternal(Transform transform)
{
const auto deviceTransform = toDeviceTransform(transform);
if (deviceTransform == m_waylandOutputDevice->transform()) {
return;
if (m_transform != transform) {
m_transform = transform;
emit transformChanged();
emit modeChanged();
}
setTransform(deviceTransform);
emit modeChanged();
}
AbstractWaylandOutput::Transform AbstractWaylandOutput::transform() const
{
return static_cast<Transform>(m_waylandOutputDevice->transform());
return m_transform;
}
void AbstractWaylandOutput::setDpmsModeInternal(DpmsMode dpmsMode)
{
if (m_dpmsMode != dpmsMode) {
m_dpmsMode = dpmsMode;
emit dpmsModeChanged();
}
}
void AbstractWaylandOutput::setDpmsMode(DpmsMode mode)
{
Q_UNUSED(mode)
}
AbstractWaylandOutput::DpmsMode AbstractWaylandOutput::dpmsMode() const
{
return m_dpmsMode;
}
QMatrix4x4 AbstractWaylandOutput::logicalToNativeMatrix(const QRect &rect, qreal scale, Transform transform)
......
......@@ -14,22 +14,11 @@
#include <kwin_export.h>
#include <QObject>
#include <QPoint>
#include <QPointer>
#include <QRect>
#include <QSize>
#include <QVector>
#include <KWaylandServer/output_interface.h>
#include <KWaylandServer/outputdevice_interface.h>
#include <QTimer>
namespace KWaylandServer
{
class OutputInterface;
class OutputDeviceInterface;
class OutputChangeSet;
class OutputManagementInterface;
class XdgOutputV1Interface;
}
namespace KWin
......@@ -53,8 +42,33 @@ public:
Flipped270
};
enum class ModeFlag : uint {
Current = 0x1,
Preferred = 0x2,
};
Q_DECLARE_FLAGS(ModeFlags, ModeFlag)
struct Mode
{
QSize size;
int refreshRate;
ModeFlags flags;
int id;
};
enum class DpmsMode {
On,
Standby,
Suspend,
Off,
};
enum class Capability : uint {
Dpms = 0x1,
};
Q_DECLARE_FLAGS(Capabilities, Capability)
explicit AbstractWaylandOutput(QObject *parent = nullptr);
~AbstractWaylandOutput() override;
QString name() const override;
QString uuid() const override;
......@@ -93,14 +107,15 @@ public:
void applyChanges(const KWaylandServer::OutputChangeSet *changeSet) override;
QPointer<KWaylandServer::OutputInterface> waylandOutput() const {
return m_waylandOutput;
}
bool isEnabled() const override;
void setEnabled(bool enable) override;
QString description() const;
Capabilities capabilities() const;
QByteArray edid() const;
QVector<Mode> modes() const;
DpmsMode dpmsMode() const;
virtual void setDpmsMode(DpmsMode mode);
/**
* Returns a matrix that can translate into the display's coordinates system
......@@ -115,12 +130,14 @@ public:
Q_SIGNALS:
void modeChanged();
void outputChange(const QRegion &damagedRegion);
void scaleChanged();
void transformChanged();
void dpmsModeChanged();
protected:
void initInterfaces(const QString &model, const QString &manufacturer,
const QString &uuid, const QSize &physicalSize,
const QVector<KWaylandServer::OutputDeviceInterface::Mode> &modes,
const QByteArray &edid);
void initialize(const QString &model, const QString &manufacturer,
const QString &uuid, const QSize &physicalSize,
const QVector<Mode> &modes, const QByteArray &edid);
QPoint globalPos() const;
......@@ -133,16 +150,10 @@ protected:
void setInternal(bool set) {
m_internal = set;
}
void setDpmsSupported(bool set) {
m_waylandOutput->setDpmsSupported(set);
}
virtual void updateEnablement(bool enable) {
Q_UNUSED(enable);
}
virtual void updateDpms(KWaylandServer::OutputInterface::DpmsMode mode) {
Q_UNUSED(mode);
}
virtual void updateMode(int modeIndex) {
Q_UNUSED(modeIndex);
}
......@@ -150,24 +161,36 @@ protected:
Q_UNUSED(transform);
}
void setWaylandMode(const QSize &size, int refreshRate);
void setTransform(Transform transform);
void setCurrentModeInternal(const QSize &size, int refreshRate);
void setTransformInternal(Transform transform);
void setDpmsModeInternal(DpmsMode dpmsMode);
void setCapabilityInternal(Capability capability, bool on = true);
QSize orientateSize(const QSize &size) const;
private:
void setTransform(KWaylandServer::OutputDeviceInterface::Transform transform);
KWaylandServer::OutputInterface *m_waylandOutput;
KWaylandServer::XdgOutputV1Interface *m_xdgOutputV1;
KWaylandServer::OutputDeviceInterface *m_waylandOutputDevice;
KWaylandServer::OutputInterface::DpmsMode m_dpms = KWaylandServer::OutputInterface::DpmsMode::On;
QString m_name;
bool m_internal = false;
QString m_manufacturer;
QString m_model;
QString m_serialNumber;
QString m_uuid;
QSize m_modeSize;
QSize m_physicalSize;
QPoint m_position;
qreal m_scale = 1;
Capabilities m_capabilities;
Transform m_transform = Transform::Normal;
QByteArray m_edid;
QVector<Mode> m_modes;
DpmsMode m_dpmsMode = DpmsMode::On;
int m_refreshRate = -1;
int m_recorders = 0;
bool m_isEnabled = true;
bool m_internal = false;
};
}
Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::AbstractWaylandOutput::Capabilities)
#endif // KWIN_OUTPUT_H
......@@ -115,7 +115,7 @@ void DrmBackend::turnOutputsOn()
{
m_dpmsFilter.reset();
for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) {
(*it)->updateDpms(KWaylandServer::OutputInterface::DpmsMode::On);
(*it)->setDpmsMode(AbstractWaylandOutput::DpmsMode::On);
}
}
......@@ -376,7 +376,7 @@ void DrmBackend::readOutputsConfiguration()
(*it)->setGlobalPos(outputConfig.readEntry<QPoint>("Position", pos));
if (outputConfig.hasKey("Scale"))
(*it)->setScale(outputConfig.readEntry("Scale", 1.0));
(*it)->setTransform(stringToTransform(outputConfig.readEntry("Transform", "normal")));
(*it)->setTransformInternal(stringToTransform(outputConfig.readEntry("Transform", "normal")));
pos.setX(pos.x() + (*it)->geometry().width());
if (outputConfig.hasKey("Mode")) {
QString mode = outputConfig.readEntry("Mode");
......
......@@ -18,9 +18,6 @@
#include "renderloop.h"
#include "screens.h"
#include "session.h"
#include "wayland_server.h"
// KWayland
#include <KWaylandServer/output_interface.h>
// Qt
#include <QMatrix4x4>
#include <QCryptographicHash>
......@@ -196,7 +193,7 @@ bool DrmOutput::init(drmModeConnector *connector)
}
setInternal(m_conn->isInternal());
setDpmsSupported(true);
setCapabilityInternal(DrmOutput::Capability::Dpms);
initOutputDevice(connector);
if (!m_gpu->atomicModeSetting() && !m_crtc->blank(this)) {
......@@ -204,7 +201,7 @@ bool DrmOutput::init(drmModeConnector *connector)
return false;
}
updateDpms(KWaylandServer::OutputInterface::DpmsMode::On);
setDpmsMode(DpmsMode::On);
return true;
}