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.
This commit is contained in:
Vlad Zahorodnii 2021-04-04 17:11:13 +03:00
parent 3d231b3cb5
commit c27230719c
16 changed files with 603 additions and 317 deletions

View file

@ -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

View file

@ -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::~AbstractWaylandOutput()
AbstractWaylandOutput::Capabilities AbstractWaylandOutput::capabilities() const
{
return m_capabilities;
}
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,124 +57,76 @@ 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);
}
QByteArray AbstractWaylandOutput::edid() const
{
return m_edid;
}
QVector<AbstractWaylandOutput::Mode> AbstractWaylandOutput::modes() const
{
return m_modes;
}
qreal AbstractWaylandOutput::scale() const
{
return m_waylandOutputDevice->scaleF();
return m_scale;
}
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;
if (m_scale != scale) {
m_scale = scale;
emit scaleChanged();
emit geometryChanged();
}
}
void AbstractWaylandOutput::setTransform(DeviceInterface::Transform transform)
{
m_waylandOutputDevice->setTransform(transform);
m_waylandOutput->setTransform(toOutputTransform(transform));
m_xdgOutputV1->setLogicalSize(pixelSize() / scale());
m_waylandOutput->done();
m_xdgOutputV1->done();
}
inline
AbstractWaylandOutput::Transform toTransform(DeviceInterface::Transform deviceTransform)
{
return static_cast<AbstractWaylandOutput::Transform>(deviceTransform);
}
inline
DeviceInterface::Transform toDeviceTransform(AbstractWaylandOutput::Transform transform)
{
return static_cast<DeviceInterface::Transform>(transform);
}
void AbstractWaylandOutput::applyChanges(const KWaylandServer::OutputChangeSet *changeSet)
{
qCDebug(KWIN_CORE) << "Apply changes to the Wayland output.";
@ -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 (m_isEnabled != enable) {
m_isEnabled = enable;
updateEnablement(enable);
emit enabledChanged();
}
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);
}
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);
m_manufacturer = manufacturer.isEmpty() ? i18n("unknown") : manufacturer;
m_model = model;
m_physicalSize = physicalSize;
m_uuid = uuid;
m_edid = edid;
m_modes = modes;
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);
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)

View file

@ -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

View file

@ -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");

View file

@ -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;
}
@ -221,29 +218,29 @@ void DrmOutput::initUuid()
void DrmOutput::initOutputDevice(drmModeConnector *connector)
{
// read in mode information
QVector<KWaylandServer::OutputDeviceInterface::Mode> modes;
QVector<Mode> modes;
modes.reserve(connector->count_modes);
for (int i = 0; i < connector->count_modes; ++i) {
// TODO: in AMS here we could read and store for later every mode's blob_id
// would simplify isCurrentMode(..) and presentAtomically(..) in case of mode set
auto *m = &connector->modes[i];
KWaylandServer::OutputDeviceInterface::ModeFlags deviceflags;
Mode mode;
if (isCurrentMode(m)) {
deviceflags |= KWaylandServer::OutputDeviceInterface::ModeFlag::Current;
mode.flags |= ModeFlag::Current;
}
if (m->type & DRM_MODE_TYPE_PREFERRED) {
deviceflags |= KWaylandServer::OutputDeviceInterface::ModeFlag::Preferred;
mode.flags |= ModeFlag::Preferred;
}
KWaylandServer::OutputDeviceInterface::Mode mode;
mode.id = i;
mode.size = QSize(m->hdisplay, m->vdisplay);
mode.flags = deviceflags;
mode.refreshRate = refreshRateForMode(m);
modes << mode;
}
setName(m_conn->connectorName());
initInterfaces(m_conn->modelName(), m_conn->edid()->manufacturerString(), m_uuid, m_conn->physicalSize(), modes, m_conn->edid()->raw());
initialize(m_conn->modelName(), m_conn->edid()->manufacturerString(), m_uuid, m_conn->physicalSize(), modes, m_conn->edid()->raw());
}
bool DrmOutput::isCurrentMode(const drmModeModeInfo *mode) const
@ -331,59 +328,21 @@ void DrmOutput::atomicDisable()
}
}
static DrmOutput::DpmsMode fromWaylandDpmsMode(KWaylandServer::OutputInterface::DpmsMode wlMode)
{
using namespace KWaylandServer;
switch (wlMode) {
case OutputInterface::DpmsMode::On:
return DrmOutput::DpmsMode::On;
case OutputInterface::DpmsMode::Standby:
return DrmOutput::DpmsMode::Standby;
case OutputInterface::DpmsMode::Suspend:
return DrmOutput::DpmsMode::Suspend;
case OutputInterface::DpmsMode::Off:
return DrmOutput::DpmsMode::Off;
default:
Q_UNREACHABLE();
}
}
static KWaylandServer::OutputInterface::DpmsMode toWaylandDpmsMode(DrmOutput::DpmsMode mode)
{
using namespace KWaylandServer;
switch (mode) {
case DrmOutput::DpmsMode::On:
return OutputInterface::DpmsMode::On;
case DrmOutput::DpmsMode::Standby:
return OutputInterface::DpmsMode::Standby;
case DrmOutput::DpmsMode::Suspend:
return OutputInterface::DpmsMode::Suspend;
case DrmOutput::DpmsMode::Off:
return OutputInterface::DpmsMode::Off;
default:
Q_UNREACHABLE();
}
}
void DrmOutput::updateDpms(KWaylandServer::OutputInterface::DpmsMode mode)
void DrmOutput::setDpmsMode(DpmsMode mode)
{
if (!m_conn->dpms() || !isEnabled()) {
return;
}
const auto drmMode = fromWaylandDpmsMode(mode);
if (drmMode == m_dpmsModePending) {
qCDebug(KWIN_DRM) << "New DPMS mode equals old mode. DPMS unchanged.";
waylandOutput()->setDpmsMode(mode);
if (mode == m_dpmsModePending) {
return;
}
m_dpmsModePending = drmMode;
m_dpmsModePending = mode;
if (m_gpu->atomicModeSetting()) {
m_modesetRequested = true;
if (drmMode == DpmsMode::On) {
if (mode == DpmsMode::On) {
if (m_atomicOffPending) {
Q_ASSERT(m_pageFlipPending);
m_atomicOffPending = false;
@ -404,8 +363,6 @@ void DrmOutput::dpmsFinishOn()
{
qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to On.";
waylandOutput()->setDpmsMode(toWaylandDpmsMode(DpmsMode::On));
m_backend->checkOutputsAreOn();
m_crtc->blank(this);
m_renderLoop->uninhibit();
@ -419,19 +376,33 @@ void DrmOutput::dpmsFinishOff()
qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to Off.";
if (isEnabled()) {
waylandOutput()->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending));
m_backend->createDpmsFilter();
} else {
waylandOutput()->setDpmsMode(toWaylandDpmsMode(DpmsMode::Off));
}
m_renderLoop->inhibit();
}
static uint64_t kwinDpmsModeToDrmDpmsMode(AbstractWaylandOutput::DpmsMode dpmsMode)
{
switch (dpmsMode) {
case AbstractWaylandOutput::DpmsMode::On:
return DRM_MODE_DPMS_ON;
case AbstractWaylandOutput::DpmsMode::Standby:
return DRM_MODE_DPMS_STANDBY;
case AbstractWaylandOutput::DpmsMode::Suspend:
return DRM_MODE_DPMS_SUSPEND;
case AbstractWaylandOutput::DpmsMode::Off:
return DRM_MODE_DPMS_OFF;
default:
Q_UNREACHABLE();
}
}
bool DrmOutput::dpmsLegacyApply()
{
if (drmModeConnectorSetProperty(m_gpu->fd(), m_conn->id(),
m_conn->dpms()->propId(), uint64_t(m_dpmsModePending)) < 0) {
m_dpmsModePending = m_dpmsMode;
m_conn->dpms()->propId(),
kwinDpmsModeToDrmDpmsMode(m_dpmsModePending)) < 0) {
m_dpmsModePending = dpmsMode();
qCWarning(KWIN_DRM) << "Setting DPMS failed";
return false;
}
@ -440,7 +411,7 @@ bool DrmOutput::dpmsLegacyApply()
} else {
dpmsFinishOff();
}
m_dpmsMode = m_dpmsModePending;
setDpmsModeInternal(m_dpmsModePending);
return true;
}
@ -540,12 +511,12 @@ void DrmOutput::updateMode(int modeIndex)
}
m_mode = connector->modes[modeIndex];
m_modesetRequested = true;
setWaylandMode();
setCurrentModeInternal();
}
void DrmOutput::setWaylandMode()
void DrmOutput::setCurrentModeInternal()
{
AbstractWaylandOutput::setWaylandMode(QSize(m_mode.hdisplay, m_mode.vdisplay),
AbstractWaylandOutput::setCurrentModeInternal(QSize(m_mode.hdisplay, m_mode.vdisplay),
refreshRateForMode(&m_mode));
}
@ -641,7 +612,7 @@ bool DrmOutput::presentAtomically(const QSharedPointer<DrmBuffer> &buffer)
// go back to previous state
if (m_lastWorkingState.valid) {
m_mode = m_lastWorkingState.mode;
setTransform(m_lastWorkingState.transform);
setTransformInternal(m_lastWorkingState.transform);
setGlobalPos(m_lastWorkingState.globalPos);
if (m_primaryPlane) {
m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations);
@ -652,7 +623,7 @@ bool DrmOutput::presentAtomically(const QSharedPointer<DrmBuffer> &buffer)
updateCursor();
showCursor();
}
setWaylandMode();
setCurrentModeInternal();
emit screens()->changed();
}
return false;
@ -727,10 +698,10 @@ bool DrmOutput::doAtomicCommit(AtomicCommitMode mode)
drmModeAtomicFree(req);
}
if (m_dpmsMode != m_dpmsModePending) {
if (dpmsMode() != m_dpmsModePending) {
qCWarning(KWIN_DRM) << "Setting DPMS failed";
m_dpmsModePending = m_dpmsMode;
if (m_dpmsMode != DpmsMode::On) {
m_dpmsModePending = dpmsMode();
if (dpmsMode() != DpmsMode::On) {
dpmsFinishOff();
}
}
@ -807,7 +778,7 @@ bool DrmOutput::doAtomicCommit(AtomicCommitMode mode)
if (mode == AtomicCommitMode::Real && (flags & DRM_MODE_ATOMIC_ALLOW_MODESET)) {
qCDebug(KWIN_DRM) << "Atomic Modeset successful.";
m_modesetRequested = false;
m_dpmsMode = m_dpmsModePending;
setDpmsModeInternal(m_dpmsModePending);
}
drmModeAtomicFree(req);

View file

@ -54,22 +54,11 @@ public:
bool present(const QSharedPointer<DrmBuffer> &buffer);
void pageFlipped();
// These values are defined by the kernel
enum class DpmsMode {
On = DRM_MODE_DPMS_ON,
Standby = DRM_MODE_DPMS_STANDBY,
Suspend = DRM_MODE_DPMS_SUSPEND,
Off = DRM_MODE_DPMS_OFF
};
Q_ENUM(DpmsMode);
bool isDpmsEnabled() const {
// We care for current as well as pending mode in order to allow first present in AMS.
return m_dpmsModePending == DpmsMode::On;
}
DpmsMode dpmsMode() const {
return m_dpmsMode;
}
DpmsMode dpmsModePending() const {
return m_dpmsModePending;
}
@ -131,10 +120,10 @@ private:
void dpmsFinishOff();
bool atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable);
void updateDpms(KWaylandServer::OutputInterface::DpmsMode mode) override;
void setDpmsMode(DpmsMode mode) override;
void updateMode(int modeIndex) override;
void updateMode(uint32_t width, uint32_t height, uint32_t refreshRate);
void setWaylandMode();
void setCurrentModeInternal();
void updateTransform(Transform transform) override;
@ -147,7 +136,6 @@ private:
DrmCrtc *m_crtc = nullptr;
bool m_lastGbm = false;
drmModeModeInfo m_mode;
DpmsMode m_dpmsMode = DpmsMode::On;
DpmsMode m_dpmsModePending = DpmsMode::On;
QByteArray m_uuid;
RenderLoop *m_renderLoop;

View file

@ -65,12 +65,12 @@ void FramebufferOutput::init(const QSize &pixelSize, const QSize &physicalSize)
const int refreshRate = 60000; // TODO: get actual refresh rate of fb device?
m_renderLoop->setRefreshRate(refreshRate);
KWaylandServer::OutputDeviceInterface::Mode mode;
Mode mode;
mode.id = 0;
mode.size = pixelSize;
mode.flags = KWaylandServer::OutputDeviceInterface::ModeFlag::Current;
mode.flags = ModeFlag::Current;
mode.refreshRate = refreshRate;
initInterfaces("model_TODO", "manufacturer_TODO", "UUID_TODO", physicalSize, { mode }, {});
initialize("model_TODO", "manufacturer_TODO", "UUID_TODO", physicalSize, { mode }, {});
}
void FramebufferOutput::vblank(std::chrono::nanoseconds timestamp)

View file

@ -48,15 +48,15 @@ void VirtualOutput::init(const QPoint &logicalPosition, const QSize &pixelSize)
m_renderLoop->setRefreshRate(refreshRate);
m_vsyncMonitor->setRefreshRate(refreshRate);
KWaylandServer::OutputDeviceInterface::Mode mode;
Mode mode;
mode.id = 0;
mode.size = pixelSize;
mode.flags = KWaylandServer::OutputDeviceInterface::ModeFlag::Current;
mode.flags = ModeFlag::Current;
mode.refreshRate = refreshRate;
initInterfaces(QByteArray("model_").append(QByteArray::number(m_identifier)),
QByteArray("manufacturer_").append(QByteArray::number(m_identifier)),
QByteArray("UUID_").append(QByteArray::number(m_identifier)),
pixelSize, { mode }, QByteArray("EDID_").append(QByteArray::number(m_identifier)));
initialize(QByteArray("model_").append(QByteArray::number(m_identifier)),
QByteArray("manufacturer_").append(QByteArray::number(m_identifier)),
QByteArray("UUID_").append(QByteArray::number(m_identifier)),
pixelSize, { mode }, QByteArray("EDID_").append(QByteArray::number(m_identifier)));
setGeometry(QRect(logicalPosition, pixelSize));
}

View file

@ -57,12 +57,12 @@ void WaylandOutput::init(const QPoint &logicalPosition, const QSize &pixelSize)
const int refreshRate = 60000; // TODO: can we get refresh rate data from Wayland host?
m_renderLoop->setRefreshRate(refreshRate);
KWaylandServer::OutputDeviceInterface::Mode mode;
Mode mode;
mode.id = 0;
mode.size = pixelSize;
mode.flags = KWaylandServer::OutputDeviceInterface::ModeFlag::Current;
mode.flags = ModeFlag::Current;
mode.refreshRate = refreshRate;
initInterfaces("model_TODO", "manufacturer_TODO", "UUID_TODO", pixelSize, { mode }, {});
initialize("model_TODO", "manufacturer_TODO", "UUID_TODO", pixelSize, { mode }, {});
setGeometry(logicalPosition, pixelSize);
setScale(backend()->initialOutputScale());
}

View file

@ -61,16 +61,16 @@ void X11WindowedOutput::init(const QPoint &logicalPosition, const QSize &pixelSi
m_renderLoop->setRefreshRate(refreshRate);
m_vsyncMonitor->setRefreshRate(refreshRate);
KWaylandServer::OutputDeviceInterface::Mode mode;
Mode mode;
mode.id = 0;
mode.size = pixelSize;
mode.flags = KWaylandServer::OutputDeviceInterface::ModeFlag::Current;
mode.flags = ModeFlag::Current;
mode.refreshRate = refreshRate;
// Physicial size must be adjusted, such that QPA calculates correct sizes of
// internal elements.
const QSize physicalSize = pixelSize / 96.0 * 25.4 / m_backend->initialOutputScale();
initInterfaces("model_TODO", "manufacturer_TODO", "UUID_TODO", physicalSize, { mode }, {});
initialize("model_TODO", "manufacturer_TODO", "UUID_TODO", physicalSize, { mode }, {});
setGeometry(logicalPosition, pixelSize);
setScale(m_backend->initialOutputScale());

View file

@ -20,6 +20,8 @@
#include "xdgshellclient.h"
#include "service_utils.h"
#include "unmanaged.h"
#include "waylandoutput.h"
#include "waylandoutputdevice.h"
// Client
#include <KWayland/Client/connection_thread.h>
@ -313,16 +315,55 @@ void WaylandServer::registerXdgGenericClient(AbstractClient *client)
qCDebug(KWIN_CORE) << "Received invalid xdg client:" << client->surface();
}
void WaylandServer::initOutputs()
{
connect(kwinApp()->platform(), &Platform::outputAdded, this, &WaylandServer::handleOutputAdded);
connect(kwinApp()->platform(), &Platform::outputRemoved, this, &WaylandServer::handleOutputRemoved);
connect(kwinApp()->platform(), &Platform::outputEnabled, this, &WaylandServer::handleOutputEnabled);
connect(kwinApp()->platform(), &Platform::outputDisabled, this, &WaylandServer::handleOutputDisabled);
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->outputs();
for (AbstractOutput *output : outputs) {
handleOutputAdded(output);
}
const QVector<AbstractOutput *> enabledOutputs = kwinApp()->platform()->enabledOutputs();
for (AbstractOutput *output : enabledOutputs) {
handleOutputEnabled(output);
}
}
void WaylandServer::handleOutputAdded(AbstractOutput *output)
{
auto o = static_cast<AbstractWaylandOutput *>(output);
m_waylandOutputDevices.insert(o, new WaylandOutputDevice(o));
}
void WaylandServer::handleOutputRemoved(AbstractOutput *output)
{
delete m_waylandOutputDevices.take(static_cast<AbstractWaylandOutput *>(output));
}
void WaylandServer::handleOutputEnabled(AbstractOutput *output)
{
auto o = static_cast<AbstractWaylandOutput *>(output);
m_waylandOutputs.insert(o, new WaylandOutput(o));
}
void WaylandServer::handleOutputDisabled(AbstractOutput *output)
{
delete m_waylandOutputs.take(static_cast<AbstractWaylandOutput *>(output));
}
AbstractWaylandOutput *WaylandServer::findOutput(KWaylandServer::OutputInterface *outputIface) const
{
AbstractWaylandOutput *outputFound = nullptr;
const auto outputs = kwinApp()->platform()->enabledOutputs();
for (auto output : outputs) {
if (static_cast<AbstractWaylandOutput *>(output)->waylandOutput() == outputIface) {
outputFound = static_cast<AbstractWaylandOutput *>(output);
for (auto it = m_waylandOutputs.constBegin(); it != m_waylandOutputs.constEnd(); ++it) {
if ((*it)->waylandOutput() == outputIface) {
return it.key();
}
}
return outputFound;
return nullptr;
}
bool WaylandServer::start()
@ -572,6 +613,8 @@ void WaylandServer::initWorkspace()
} else {
emit initialized();
}
initOutputs();
}
void WaylandServer::initScreenLocker()

View file

@ -66,11 +66,14 @@ namespace KWin
{
class AbstractClient;
class AbstractOutput;
class Toplevel;
class XdgPopupClient;
class XdgSurfaceClient;
class XdgToplevelClient;
class AbstractWaylandOutput;
class WaylandOutput;
class WaylandOutputDevice;
class KWIN_EXPORT WaylandServer : public QObject
{
@ -261,10 +264,15 @@ private:
void shellClientShown(Toplevel *t);
void destroyInternalConnection();
void initScreenLocker();
void initOutputs();
void registerXdgGenericClient(AbstractClient *client);
void registerXdgToplevelClient(XdgToplevelClient *client);
void registerXdgPopupClient(XdgPopupClient *client);
void registerShellClient(AbstractClient *client);
void handleOutputAdded(AbstractOutput *output);
void handleOutputRemoved(AbstractOutput *output);
void handleOutputEnabled(AbstractOutput *output);
void handleOutputDisabled(AbstractOutput *output);
KWaylandServer::Display *m_display = nullptr;
KWaylandServer::CompositorInterface *m_compositor = nullptr;
KWaylandServer::SeatInterface *m_seat = nullptr;
@ -303,6 +311,8 @@ private:
QList<AbstractClient *> m_clients;
InitializationFlags m_initFlags;
QVector<KWaylandServer::PlasmaShellSurfaceInterface*> m_plasmaShellSurfaces;
QHash<AbstractWaylandOutput *, WaylandOutput *> m_waylandOutputs;
QHash<AbstractWaylandOutput *, WaylandOutputDevice *> m_waylandOutputDevices;
KWIN_SINGLETON(WaylandServer)
};

161
src/waylandoutput.cpp Normal file
View file

@ -0,0 +1,161 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "waylandoutput.h"
#include "wayland_server.h"
#include <cmath>
namespace KWin
{
static KWaylandServer::OutputInterface::Transform kwinTransformToOutputTransform(AbstractWaylandOutput::Transform transform)
{
switch (transform) {
case AbstractWaylandOutput::Transform::Normal:
return KWaylandServer::OutputInterface::Transform::Normal;
case AbstractWaylandOutput::Transform::Rotated90:
return KWaylandServer::OutputInterface::Transform::Rotated90;
case AbstractWaylandOutput::Transform::Rotated180:
return KWaylandServer::OutputInterface::Transform::Rotated180;
case AbstractWaylandOutput::Transform::Rotated270:
return KWaylandServer::OutputInterface::Transform::Rotated270;
case AbstractWaylandOutput::Transform::Flipped:
return KWaylandServer::OutputInterface::Transform::Flipped;
case AbstractWaylandOutput::Transform::Flipped90:
return KWaylandServer::OutputInterface::Transform::Flipped90;
case AbstractWaylandOutput::Transform::Flipped180:
return KWaylandServer::OutputInterface::Transform::Flipped180;
case AbstractWaylandOutput::Transform::Flipped270:
return KWaylandServer::OutputInterface::Transform::Flipped270;
default:
Q_UNREACHABLE();
}
}
static KWaylandServer::OutputInterface::DpmsMode kwinDpmsModeToOutputDpmsMode(AbstractWaylandOutput::DpmsMode dpmsMode)
{
switch (dpmsMode) {
case AbstractWaylandOutput::DpmsMode::Off:
return KWaylandServer::OutputInterface::DpmsMode::Off;
case AbstractWaylandOutput::DpmsMode::On:
return KWaylandServer::OutputInterface::DpmsMode::On;
case AbstractWaylandOutput::DpmsMode::Standby:
return KWaylandServer::OutputInterface::DpmsMode::Standby;
case AbstractWaylandOutput::DpmsMode::Suspend:
return KWaylandServer::OutputInterface::DpmsMode::Suspend;
default:
Q_UNREACHABLE();
}
}
static AbstractWaylandOutput::DpmsMode outputDpmsModeToKWinDpmsMode(KWaylandServer::OutputInterface::DpmsMode dpmsMode)
{
switch (dpmsMode) {
case KWaylandServer::OutputInterface::DpmsMode::Off:
return AbstractWaylandOutput::DpmsMode::Off;
case KWaylandServer::OutputInterface::DpmsMode::On:
return AbstractWaylandOutput::DpmsMode::On;
case KWaylandServer::OutputInterface::DpmsMode::Standby:
return AbstractWaylandOutput::DpmsMode::Standby;
case KWaylandServer::OutputInterface::DpmsMode::Suspend:
return AbstractWaylandOutput::DpmsMode::Suspend;
default:
Q_UNREACHABLE();
}
}
WaylandOutput::WaylandOutput(AbstractWaylandOutput *output, QObject *parent)
: QObject(parent)
, m_platformOutput(output)
, m_waylandOutput(new KWaylandServer::OutputInterface(waylandServer()->display(), this))
, m_xdgOutputV1(waylandServer()->xdgOutputManagerV1()->createXdgOutput(m_waylandOutput, this))
{
const QRect geometry = m_platformOutput->geometry();
m_waylandOutput->setTransform(kwinTransformToOutputTransform(output->transform()));
m_waylandOutput->setManufacturer(output->manufacturer());
m_waylandOutput->setModel(output->model());
m_waylandOutput->setPhysicalSize(output->physicalSize());
m_waylandOutput->setDpmsMode(kwinDpmsModeToOutputDpmsMode(output->dpmsMode()));
m_waylandOutput->setDpmsSupported(output->capabilities() & AbstractWaylandOutput::Capability::Dpms);
m_waylandOutput->setGlobalPosition(geometry.topLeft());
m_waylandOutput->setScale(std::ceil(output->scale()));
m_xdgOutputV1->setName(output->name());
m_xdgOutputV1->setDescription(output->description());
m_xdgOutputV1->setLogicalPosition(geometry.topLeft());
m_xdgOutputV1->setLogicalSize(geometry.size());
const auto modes = output->modes();
for (const AbstractWaylandOutput::Mode &mode : modes) {
KWaylandServer::OutputInterface::ModeFlags flags;
if (mode.flags & AbstractWaylandOutput::ModeFlag::Current) {
flags |= KWaylandServer::OutputInterface::ModeFlag::Current;
}
if (mode.flags & AbstractWaylandOutput::ModeFlag::Preferred) {
flags |= KWaylandServer::OutputInterface::ModeFlag::Preferred;
}
m_waylandOutput->addMode(mode.size, flags, mode.refreshRate);
}
m_waylandOutput->create();
m_waylandOutput->done();
m_xdgOutputV1->done();
// The dpms functionality is not part of the wl_output interface, but org_kde_kwin_dpms.
connect(output, &AbstractWaylandOutput::dpmsModeChanged,
this, &WaylandOutput::handleDpmsModeChanged);
connect(m_waylandOutput, &KWaylandServer::OutputInterface::dpmsModeRequested,
this, &WaylandOutput::handleDpmsModeRequested);
// The timer is used to compress output updates so the wayland clients are not spammed.
m_updateTimer.setSingleShot(true);
connect(&m_updateTimer, &QTimer::timeout, this, &WaylandOutput::update);
connect(output, &AbstractWaylandOutput::geometryChanged, this, &WaylandOutput::scheduleUpdate);
connect(output, &AbstractWaylandOutput::transformChanged, this, &WaylandOutput::scheduleUpdate);
connect(output, &AbstractWaylandOutput::scaleChanged, this, &WaylandOutput::scheduleUpdate);
}
KWaylandServer::OutputInterface *WaylandOutput::waylandOutput() const
{
return m_waylandOutput;
}
void WaylandOutput::scheduleUpdate()
{
m_updateTimer.start();
}
void WaylandOutput::update()
{
const QRect geometry = m_platformOutput->geometry();
m_waylandOutput->setGlobalPosition(geometry.topLeft());
m_waylandOutput->setScale(std::ceil(m_platformOutput->scale()));
m_waylandOutput->setTransform(kwinTransformToOutputTransform(m_platformOutput->transform()));
m_waylandOutput->setCurrentMode(m_platformOutput->modeSize(), m_platformOutput->refreshRate());
m_xdgOutputV1->setLogicalPosition(geometry.topLeft());
m_xdgOutputV1->setLogicalSize(geometry.size());
m_waylandOutput->done();
m_xdgOutputV1->done();
}
void WaylandOutput::handleDpmsModeChanged()
{
m_waylandOutput->setDpmsMode(kwinDpmsModeToOutputDpmsMode(m_platformOutput->dpmsMode()));
}
void WaylandOutput::handleDpmsModeRequested(KWaylandServer::OutputInterface::DpmsMode dpmsMode)
{
m_platformOutput->setDpmsMode(outputDpmsModeToKWinDpmsMode(dpmsMode));
}
} // namespace KWin

40
src/waylandoutput.h Normal file
View file

@ -0,0 +1,40 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "abstract_wayland_output.h"
#include <KWaylandServer/output_interface.h>
#include <KWaylandServer/xdgoutput_v1_interface.h>
namespace KWin
{
class WaylandOutput : public QObject
{
Q_OBJECT
public:
explicit WaylandOutput(AbstractWaylandOutput *output, QObject *parent = nullptr);
KWaylandServer::OutputInterface *waylandOutput() const;
private Q_SLOTS:
void handleDpmsModeChanged();
void handleDpmsModeRequested(KWaylandServer::OutputInterface::DpmsMode dpmsMode);
void update();
void scheduleUpdate();
private:
AbstractWaylandOutput *m_platformOutput;
QTimer m_updateTimer;
KWaylandServer::OutputInterface *m_waylandOutput;
KWaylandServer::XdgOutputV1Interface *m_xdgOutputV1;
};
} // namespace KWin

View file

@ -0,0 +1,90 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "waylandoutputdevice.h"
#include "wayland_server.h"
namespace KWin
{
static KWaylandServer::OutputDeviceInterface::Transform kwinTransformToOutputDeviceTransform(AbstractWaylandOutput::Transform transform)
{
return static_cast<KWaylandServer::OutputDeviceInterface::Transform>(transform);
}
WaylandOutputDevice::WaylandOutputDevice(AbstractWaylandOutput *output, QObject *parent)
: QObject(parent)
, m_platformOutput(output)
, m_outputDevice(new KWaylandServer::OutputDeviceInterface(waylandServer()->display(), this))
{
m_outputDevice->setManufacturer(output->manufacturer());
m_outputDevice->setEdid(output->edid());
m_outputDevice->setUuid(output->uuid());
m_outputDevice->setModel(output->model());
m_outputDevice->setPhysicalSize(output->physicalSize());
m_outputDevice->setGlobalPosition(output->geometry().topLeft());
m_outputDevice->setScaleF(output->scale());
m_outputDevice->setTransform(kwinTransformToOutputDeviceTransform(output->transform()));
const auto modes = output->modes();
for (const AbstractWaylandOutput::Mode &mode : modes) {
KWaylandServer::OutputDeviceInterface::Mode deviceMode;
deviceMode.size = mode.size;
deviceMode.refreshRate = mode.refreshRate;
deviceMode.id = mode.id;
if (mode.flags & AbstractWaylandOutput::ModeFlag::Current) {
deviceMode.flags |= KWaylandServer::OutputDeviceInterface::ModeFlag::Current;
}
if (mode.flags & AbstractWaylandOutput::ModeFlag::Preferred) {
deviceMode.flags |= KWaylandServer::OutputDeviceInterface::ModeFlag::Preferred;
}
m_outputDevice->addMode(deviceMode);
}
connect(output, &AbstractWaylandOutput::geometryChanged,
this, &WaylandOutputDevice::handleGeometryChanged);
connect(output, &AbstractWaylandOutput::scaleChanged,
this, &WaylandOutputDevice::handleScaleChanged);
connect(output, &AbstractWaylandOutput::enabledChanged,
this, &WaylandOutputDevice::handleEnabledChanged);
connect(output, &AbstractWaylandOutput::transformChanged,
this, &WaylandOutputDevice::handleTransformChanged);
connect(output, &AbstractWaylandOutput::modeChanged,
this, &WaylandOutputDevice::handleModeChanged);
}
void WaylandOutputDevice::handleGeometryChanged()
{
m_outputDevice->setGlobalPosition(m_platformOutput->geometry().topLeft());
}
void WaylandOutputDevice::handleScaleChanged()
{
m_outputDevice->setScaleF(m_platformOutput->scale());
}
void WaylandOutputDevice::handleEnabledChanged()
{
if (m_platformOutput->isEnabled()) {
m_outputDevice->setEnabled(KWaylandServer::OutputDeviceInterface::Enablement::Enabled);
} else {
m_outputDevice->setEnabled(KWaylandServer::OutputDeviceInterface::Enablement::Disabled);
}
}
void WaylandOutputDevice::handleTransformChanged()
{
m_outputDevice->setTransform(kwinTransformToOutputDeviceTransform(m_platformOutput->transform()));
}
void WaylandOutputDevice::handleModeChanged()
{
m_outputDevice->setCurrentMode(m_platformOutput->modeSize(), m_platformOutput->refreshRate());
}
} // namespace KWin

35
src/waylandoutputdevice.h Normal file
View file

@ -0,0 +1,35 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "abstract_wayland_output.h"
#include <KWaylandServer/outputdevice_interface.h>
namespace KWin
{
class WaylandOutputDevice : public QObject
{
Q_OBJECT
public:
explicit WaylandOutputDevice(AbstractWaylandOutput *output, QObject *parent = nullptr);
private Q_SLOTS:
void handleGeometryChanged();
void handleScaleChanged();
void handleEnabledChanged();
void handleTransformChanged();
void handleModeChanged();
private:
AbstractWaylandOutput *m_platformOutput;
KWaylandServer::OutputDeviceInterface *m_outputDevice;
};
} // namespace KWin