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:
parent
3d231b3cb5
commit
c27230719c
16 changed files with 603 additions and 317 deletions
|
@ -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::~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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
161
src/waylandoutput.cpp
Normal 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
40
src/waylandoutput.h
Normal 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
|
90
src/waylandoutputdevice.cpp
Normal file
90
src/waylandoutputdevice.cpp
Normal 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
35
src/waylandoutputdevice.h
Normal 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
|
Loading…
Reference in a new issue