diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -453,6 +453,7 @@ decorations/decorationrenderer.cpp decorations/decorations_logging.cpp platform.cpp + output.cpp shell_client.cpp wayland_server.cpp wayland_cursor_theme.cpp diff --git a/autotests/integration/screen_changes_test.cpp b/autotests/integration/screen_changes_test.cpp --- a/autotests/integration/screen_changes_test.cpp +++ b/autotests/integration/screen_changes_test.cpp @@ -125,15 +125,15 @@ QCOMPARE(outputRemovedSpy.count(), 1); // let's create the output objects to ensure they are correct - QScopedPointer o1(registry.createOutput(outputAnnouncedSpy.first().first().value(), outputAnnouncedSpy.first().last().value())); + QScopedPointer o1(registry.createOutput(outputAnnouncedSpy.first().first().value(), outputAnnouncedSpy.first().last().value())); QVERIFY(o1->isValid()); - QSignalSpy o1ChangedSpy(o1.data(), &Output::changed); + QSignalSpy o1ChangedSpy(o1.data(), &KWayland::Client::Output::changed); QVERIFY(o1ChangedSpy.isValid()); QVERIFY(o1ChangedSpy.wait()); QCOMPARE(o1->geometry(), geometries.at(0)); - QScopedPointer o2(registry.createOutput(outputAnnouncedSpy.last().first().value(), outputAnnouncedSpy.last().last().value())); + QScopedPointer o2(registry.createOutput(outputAnnouncedSpy.last().first().value(), outputAnnouncedSpy.last().last().value())); QVERIFY(o2->isValid()); - QSignalSpy o2ChangedSpy(o2.data(), &Output::changed); + QSignalSpy o2ChangedSpy(o2.data(), &KWayland::Client::Output::changed); QVERIFY(o2ChangedSpy.isValid()); QVERIFY(o2ChangedSpy.wait()); QCOMPARE(o2->geometry(), geometries.at(1)); @@ -143,9 +143,9 @@ outputRemovedSpy.clear(); screensChangedSpy.clear(); - QSignalSpy o1RemovedSpy(o1.data(), &Output::removed); + QSignalSpy o1RemovedSpy(o1.data(), &KWayland::Client::Output::removed); QVERIFY(o1RemovedSpy.isValid()); - QSignalSpy o2RemovedSpy(o2.data(), &Output::removed); + QSignalSpy o2RemovedSpy(o2.data(), &KWayland::Client::Output::removed); QVERIFY(o2RemovedSpy.isValid()); const QVector geometries2{QRect(0, 0, 1280, 1024)}; diff --git a/output.h b/output.h new file mode 100644 --- /dev/null +++ b/output.h @@ -0,0 +1,138 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright 2018 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_OUTPUT_H +#define KWIN_OUTPUT_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace KWayland +{ +namespace Server +{ +class OutputInterface; +class OutputDeviceInterface; +class OutputChangeSet; +class OutputManagementInterface; +} +} + +namespace KWin +{ + +/** + * Generic output representation in a Wayland session + **/ +class KWIN_EXPORT Output : public QObject +{ + Q_OBJECT +public: + virtual ~Output() {} + + QString name() const; + bool isEnabled() const { + return !m_waylandOutput.isNull(); + } + + virtual QSize pixelSize() const = 0; + qreal scale() const { + return m_scale; + } + /* + * The geometry of this output in global compositor co-ordinates (i.e scaled) + */ + QRect geometry() const; + QSize physicalSize() const; + Qt::ScreenOrientation orientation() const { + return m_orientation; + } + + bool isInternal() const { + return m_internal; + } + + void setGlobalPos(const QPoint &pos); + void setScale(qreal scale); + + /** + * This sets the changes and tests them against the specific output + */ + void setChanges(KWayland::Server::OutputChangeSet *changeset); + virtual bool commitChanges() { return false; } + + QPointer waylandOutput() const { + return m_waylandOutput; + } + +protected: + QPointer changes() const { + return m_changeset; + } + + void setWaylandOutput(KWayland::Server::OutputInterface *set); + + QPointer waylandOutputDevice() const { + return m_waylandOutputDevice; + } + void setWaylandOutputDevice(KWayland::Server::OutputDeviceInterface *set); + + QPoint globalPos() const { + return m_globalPos; + } + + QSize rawPhysicalSize() const { + return m_physicalSize; + } + void setRawPhysicalSize(const QSize &set) { + m_physicalSize = set; + } + + void setOrientation(Qt::ScreenOrientation set) { + m_orientation = set; + } + bool internal() const { + return m_internal; + } + void setInternal(bool set) { + m_internal = set; + } + +private: + QPointer m_changeset; + QPointer m_waylandOutput; + QPointer m_waylandOutputDevice; + + QPoint m_globalPos; + qreal m_scale = 1; + QSize m_physicalSize; + Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; + bool m_internal = false; +}; + +} + +#endif // KWIN_OUTPUT_H diff --git a/output.cpp b/output.cpp new file mode 100644 --- /dev/null +++ b/output.cpp @@ -0,0 +1,92 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright 2018 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "output.h" + +// KWayland +#include +#include +#include +// KF5 +#include + +namespace KWin +{ + +QString Output::name() const +{ + if (!m_waylandOutput) { + return i18n("unknown"); + } + return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model()); +} + +QRect Output::geometry() const +{ + return QRect(m_globalPos, pixelSize() / scale()); +} + +QSize Output::physicalSize() const +{ + if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) { + return QSize(m_physicalSize.height(), m_physicalSize.width()); + } + return m_physicalSize; +} + +void Output::setGlobalPos(const QPoint &pos) +{ + m_globalPos = pos; + if (m_waylandOutput) { + m_waylandOutput->setGlobalPosition(pos); + } + if (m_waylandOutputDevice) { + m_waylandOutputDevice->setGlobalPosition(pos); + } +} + +void Output::setScale(qreal scale) +{ + m_scale = scale; + if (m_waylandOutput) { + m_waylandOutput->setScale(scale); + } + if (m_waylandOutputDevice) { + m_waylandOutputDevice->setScale(scale); + } +} + +void Output::setChanges(KWayland::Server::OutputChangeSet *changes) +{ + m_changeset = changes; + qCDebug(KWIN_CORE) << "set changes in Output"; + commitChanges(); +} + +void Output::setWaylandOutput(KWayland::Server::OutputInterface *set) +{ + m_waylandOutput = set; +} + +void Output::setWaylandOutputDevice(KWayland::Server::OutputDeviceInterface *set) +{ + m_waylandOutputDevice = set; +} + +} diff --git a/platform.h b/platform.h --- a/platform.h +++ b/platform.h @@ -45,6 +45,7 @@ struct GammaRamp; } +class Output; class Edge; class Compositor; class OverlayWindow; @@ -411,6 +412,15 @@ return false; } + // outputs with connections (org_kde_kwin_outputdevice) + QVector outputs() const { + return m_outputs; + } + // actively compositing outputs (wl_output) + QVector enabledOutputs() const { + return m_enabledOutputs; + } + /* * A string of information to include in kwin debug output * It should not be translated. @@ -500,6 +510,9 @@ **/ virtual void doShowCursor(); + QVector m_outputs; + QVector m_enabledOutputs; + private: void triggerCursorRepaint(); bool m_softWareCursor = false; diff --git a/platform.cpp b/platform.cpp --- a/platform.cpp +++ b/platform.cpp @@ -46,6 +46,7 @@ Platform::~Platform() { + qDeleteAll(m_outputs); if (m_eglDisplay != EGL_NO_DISPLAY) { eglTerminate(m_eglDisplay); } diff --git a/plugins/platforms/drm/drm_backend.h b/plugins/platforms/drm/drm_backend.h --- a/plugins/platforms/drm/drm_backend.h +++ b/plugins/platforms/drm/drm_backend.h @@ -93,12 +93,6 @@ int fd() const { return m_fd; } - QVector outputs() const { - return m_outputs; - } - QVector enabledOutputs() const { - return m_enabledOutputs; - } QVector planes() const { return m_planes; } @@ -173,10 +167,6 @@ QVector m_crtcs; // all connectors QVector m_connectors; - // active output pipelines (planes + crtc + encoder + connector) - QVector m_outputs; - // active and enabled pipelines (above + wl_output) - QVector m_enabledOutputs; bool m_deleteBufferAfterPageFlip; bool m_atomicModeSetting = false; diff --git a/plugins/platforms/drm/drm_backend.cpp b/plugins/platforms/drm/drm_backend.cpp --- a/plugins/platforms/drm/drm_backend.cpp +++ b/plugins/platforms/drm/drm_backend.cpp @@ -90,7 +90,10 @@ while (m_pageFlipsPending != 0) { QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); } + // we need to first remove all outputs qDeleteAll(m_outputs); + m_outputs.clear(); + qDeleteAll(m_planes); qDeleteAll(m_crtcs); qDeleteAll(m_connectors); @@ -130,7 +133,8 @@ { m_dpmsFilter.reset(); for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) { - (*it)->setDpms(DrmOutput::DpmsMode::On); + auto *o = qobject_cast(*it); + o->setDpms(DrmOutput::DpmsMode::On); } } @@ -141,7 +145,8 @@ return; } for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) { - if (!(*it)->isDpmsEnabled()) { + auto *o = qobject_cast(*it); + if (!o->isDpmsEnabled()) { // dpms still disabled, need to keep the filter return; } @@ -170,7 +175,7 @@ if (!usesSoftwareCursor()) { const QPoint cp = Cursor::pos() - softwareCursorHotspot(); for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - DrmOutput *o = *it; + auto *o = qobject_cast(*it); // only relevant in atomic mode o->m_modesetRequested = true; o->pageFlipped(); // TODO: Do we really need this? @@ -198,7 +203,7 @@ } // hide cursor and disable for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - DrmOutput *o = *it; + auto *o = qobject_cast(*it); o->hideCursor(); } m_active = false; @@ -373,7 +378,7 @@ return; } - QVector connectedOutputs; + QVector connectedOutputs; QVector pendingConnectors; // split up connected connectors in already or not yet assigned ones @@ -392,15 +397,15 @@ // check for outputs which got removed auto it = m_outputs.begin(); while (it != m_outputs.end()) { - if (connectedOutputs.contains(*it)) { + Output *o = *it; + if (connectedOutputs.contains(o)) { it++; continue; } - DrmOutput *removed = *it; it = m_outputs.erase(it); - m_enabledOutputs.removeOne(removed); - emit outputRemoved(removed); - delete removed; + m_enabledOutputs.removeOne(o); + emit outputRemoved(qobject_cast(o)); + delete o; } // now check new connections @@ -427,8 +432,8 @@ // check if crtc isn't used yet -- currently we don't allow multiple outputs on one crtc (cloned mode) auto it = std::find_if(connectedOutputs.constBegin(), connectedOutputs.constEnd(), - [crtc] (DrmOutput *o) { - return o->m_crtc == crtc; + [crtc] (Output *o) { + return qobject_cast(o)->m_crtc == crtc; } ); if (it != connectedOutputs.constEnd()) { @@ -476,7 +481,9 @@ } } } - std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_conn->id() < b->m_conn->id(); }); + std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (Output *a, Output *b) { + return qobject_cast(a)->m_conn->id() < qobject_cast(b)->m_conn->id(); + }); m_outputs = connectedOutputs; m_enabledOutputs = connectedOutputs; readOutputsConfiguration(); @@ -496,25 +503,27 @@ // default position goes from left to right QPoint pos(0, 0); for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { - qCDebug(KWIN_DRM) << "Reading output configuration for [" << uuid << "] ["<< (*it)->uuid() << "]"; - const auto outputConfig = configGroup.group((*it)->uuid()); - (*it)->setGlobalPos(outputConfig.readEntry("Position", pos)); + auto *o = qobject_cast(*it); + qCDebug(KWIN_DRM) << "Reading output configuration for [" << uuid << "] ["<< o->uuid() << "]"; + const auto outputConfig = configGroup.group(o->uuid()); + o->setGlobalPos(outputConfig.readEntry("Position", pos)); // TODO: add mode - (*it)->setScale(outputConfig.readEntry("Scale", 1.0)); - pos.setX(pos.x() + (*it)->geometry().width()); + o->setScale(outputConfig.readEntry("Scale", 1.0)); + pos.setX(pos.x() + o->geometry().width()); } } QByteArray DrmBackend::generateOutputConfigurationUuid() const { auto it = m_outputs.constBegin(); if (m_outputs.size() == 1) { // special case: one output - return (*it)->uuid(); + return qobject_cast(*it)->uuid(); } QCryptographicHash hash(QCryptographicHash::Md5); for (; it != m_outputs.constEnd(); ++it) { - hash.addData((*it)->uuid()); + auto *o = qobject_cast(*it); + hash.addData(o->uuid()); } return hash.result().toHex().left(10); } @@ -574,22 +583,22 @@ DrmOutput *DrmBackend::findOutput(quint32 connector) { - auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) { - return o->m_conn->id() == connector; + auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (Output *o) { + return qobject_cast(o)->m_conn->id() == connector; }); if (it != m_outputs.constEnd()) { - return *it; + return qobject_cast(*it); } return nullptr; } DrmOutput *DrmBackend::findOutput(const QByteArray &uuid) { - auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [uuid] (DrmOutput *o) { - return o->m_uuid == uuid; + auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [uuid] (Output *o) { + return qobject_cast(o)->m_uuid == uuid; }); if (it != m_outputs.constEnd()) { - return *it; + return qobject_cast(*it); } return nullptr; } @@ -623,10 +632,11 @@ return; } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { + auto *o = qobject_cast(*it); if (m_cursorEnabled) { - (*it)->showCursor(); + o->showCursor(); } else { - (*it)->hideCursor(); + o->hideCursor(); } } } @@ -653,7 +663,8 @@ { if (m_cursorEnabled) { for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->showCursor(); + auto *o = qobject_cast(*it); + o->showCursor(); } } markCursorAsRendered(); @@ -673,7 +684,8 @@ return; } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->updateCursor(); + auto *o = qobject_cast(*it); + o->updateCursor(); } setCursor(); @@ -691,7 +703,8 @@ return; } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->hideCursor(); + auto *o = qobject_cast(*it); + o->hideCursor(); } } @@ -701,7 +714,8 @@ return; } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->moveCursor(Cursor::pos()); + auto *o = qobject_cast(*it); + o->moveCursor(Cursor::pos()); } } @@ -747,7 +761,8 @@ } bool enabled = false; for (auto it = m_enabledOutputs.constBegin(); it != m_enabledOutputs.constEnd(); ++it) { - enabled = enabled || (*it)->isDpmsEnabled(); + auto *o = qobject_cast(*it); + enabled = enabled || o->isDpmsEnabled(); } setOutputsEnabled(enabled); } @@ -766,15 +781,17 @@ if (m_outputs.size() <= screen) { return 0; } - return m_outputs.at(screen)->m_crtc->getGammaRampSize(); + auto *o = qobject_cast(m_outputs.at(screen)); + return o->m_crtc->getGammaRampSize(); } bool DrmBackend::setGammaRamp(int screen, ColorCorrect::GammaRamp &gamma) { if (m_outputs.size() <= screen) { return false; } - return m_outputs.at(screen)->m_crtc->setGammaRamp(gamma); + auto *o = qobject_cast(m_outputs.at(screen)); + return o->m_crtc->setGammaRamp(gamma); } QString DrmBackend::supportInformation() const diff --git a/plugins/platforms/drm/drm_output.h b/plugins/platforms/drm/drm_output.h --- a/plugins/platforms/drm/drm_output.h +++ b/plugins/platforms/drm/drm_output.h @@ -20,30 +20,19 @@ #ifndef KWIN_DRM_OUTPUT_H #define KWIN_DRM_OUTPUT_H +#include "output.h" #include "drm_pointer.h" #include "drm_object.h" #include "drm_object_plane.h" #include #include -#include #include #include #include #include -namespace KWayland -{ -namespace Server -{ -class OutputInterface; -class OutputDeviceInterface; -class OutputChangeSet; -class OutputManagementInterface; -} -} - namespace KWin { @@ -54,7 +43,7 @@ class DrmConnector; class DrmCrtc; -class DrmOutput : public QObject +class KWIN_EXPORT DrmOutput : public Output { Q_OBJECT public: @@ -82,23 +71,11 @@ * The default is on */ void setEnabled(bool enabled); - bool isEnabled() const; - - /** - * This sets the changes and tests them against the DRM output - */ - void setChanges(KWayland::Server::OutputChangeSet *changeset); - bool commitChanges(); - QSize pixelSize() const; - qreal scale() const; + virtual bool commitChanges() override; - /* - * The geometry of this output in global compositor co-ordinates (i.e scaled) - */ - QRect geometry() const; + QSize pixelSize() const override; - QString name() const; int currentRefreshRate() const; // These values are defined by the kernel enum class DpmsMode { @@ -117,24 +94,10 @@ return m_uuid; } - QSize physicalSize() const; - bool initCursor(const QSize &cursorSize); bool supportsTransformations() const; - bool isInternal() const { - return m_internal; - } - - Qt::ScreenOrientation orientation() const { - return m_orientation; - } - - const QPointer getWaylandInterface() const { - return m_waylandOutput; - } - Q_SIGNALS: void dpmsChanged(); void modeChanged(); @@ -160,8 +123,6 @@ bool isCurrentMode(const drmModeModeInfo *mode) const; void initUuid(); - void setGlobalPos(const QPoint &pos); - void setScale(qreal scale); void initOutput(); bool initPrimaryPlane(); bool initCursorPlane(); @@ -178,14 +139,9 @@ DrmBackend *m_backend; DrmConnector *m_conn = nullptr; DrmCrtc *m_crtc = nullptr; - QPoint m_globalPos; - qreal m_scale = 1; bool m_lastGbm = false; drmModeModeInfo m_mode; Edid m_edid; - QPointer m_waylandOutput; - QPointer m_waylandOutputDevice; - QPointer m_changeset; KWin::ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> m_dpms; DpmsMode m_dpmsMode = DpmsMode::On; DpmsMode m_dpmsModePending = DpmsMode::On; @@ -198,8 +154,6 @@ bool m_pageFlipPending = false; bool m_dpmsAtomicOffPending = false; bool m_modesetRequested = true; - QSize m_physicalSize; - Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; struct { Qt::ScreenOrientation orientation; @@ -211,7 +165,6 @@ DrmDumbBuffer *m_cursor[2] = {nullptr, nullptr}; int m_cursorIndex = 0; bool m_hasNewCursor = false; - bool m_internal = false; }; } diff --git a/plugins/platforms/drm/drm_output.cpp b/plugins/platforms/drm/drm_output.cpp --- a/plugins/platforms/drm/drm_output.cpp +++ b/plugins/platforms/drm/drm_output.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include // KF5 @@ -57,7 +56,7 @@ { DrmOutput::DrmOutput(DrmBackend *backend) - : QObject() + : Output() , m_backend(backend) { } @@ -80,8 +79,8 @@ m_crtc->setOutput(nullptr); m_conn->setOutput(nullptr); - delete m_waylandOutput.data(); - delete m_waylandOutputDevice.data(); + delete waylandOutput().data(); + delete waylandOutputDevice().data(); delete m_cursor[0]; delete m_cursor[1]; } @@ -127,7 +126,7 @@ c->fill(Qt::transparent); QPainter p; p.begin(c); - if (m_orientation == Qt::InvertedLandscapeOrientation) { + if (orientation() == Qt::InvertedLandscapeOrientation) { QMatrix4x4 matrix; matrix.translate(cursorImage.width() / 2.0, cursorImage.height() / 2.0); matrix.rotate(180.0f, 0.0f, 0.0f, 1.0f); @@ -142,47 +141,31 @@ { QMatrix4x4 matrix; QMatrix4x4 hotspotMatrix; - if (m_orientation == Qt::InvertedLandscapeOrientation) { + if (orientation() == Qt::InvertedLandscapeOrientation) { matrix.translate(pixelSize().width() /2.0, pixelSize().height() / 2.0); matrix.rotate(180.0f, 0.0f, 0.0f, 1.0f); matrix.translate(-pixelSize().width() /2.0, -pixelSize().height() / 2.0); const auto cursorSize = m_backend->softwareCursor().size(); hotspotMatrix.translate(cursorSize.width()/2.0, cursorSize.height()/2.0); hotspotMatrix.rotate(180.0f, 0.0f, 0.0f, 1.0f); hotspotMatrix.translate(-cursorSize.width()/2.0, -cursorSize.height()/2.0); } - matrix.scale(m_scale); - matrix.translate(-m_globalPos.x(), -m_globalPos.y()); + matrix.scale(scale()); + auto outputGlobalPos = Output::globalPos(); + matrix.translate(-outputGlobalPos.x(), -outputGlobalPos.y()); const QPoint p = matrix.map(globalPos) - hotspotMatrix.map(m_backend->softwareCursorHotspot()); drmModeMoveCursor(m_backend->fd(), m_crtc->id(), p.x(), p.y()); } QSize DrmOutput::pixelSize() const { - if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) { + auto orient = orientation(); + if (orient == Qt::PortraitOrientation || orient == Qt::InvertedPortraitOrientation) { return QSize(m_mode.vdisplay, m_mode.hdisplay); } return QSize(m_mode.hdisplay, m_mode.vdisplay); } -QSize DrmOutput::physicalSize() const -{ - if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) { - return QSize(m_physicalSize.height(), m_physicalSize.width()); - } - return m_physicalSize; -} - -QRect DrmOutput::geometry() const -{ - return QRect(m_globalPos, pixelSize() / scale()); -} - -qreal DrmOutput::scale() const -{ - return m_scale; -} - void DrmOutput::setEnabled(bool enabled) { if (enabled == isEnabled()) { @@ -193,17 +176,12 @@ initOutput(); } else { setDpms(DpmsMode::Off); - delete m_waylandOutput.data(); + delete waylandOutput().data(); } - m_waylandOutputDevice->setEnabled(enabled ? + waylandOutputDevice()->setEnabled(enabled ? KWayland::Server::OutputDeviceInterface::Enablement::Enabled : KWayland::Server::OutputDeviceInterface::Enablement::Disabled); } -bool DrmOutput::isEnabled() const -{ - return !m_waylandOutput.isNull(); -} - static KWayland::Server::OutputInterface::DpmsMode toWaylandDpmsMode(DrmOutput::DpmsMode mode) { using namespace KWayland::Server; @@ -290,9 +268,10 @@ return false; } - m_internal = connector->connector_type == DRM_MODE_CONNECTOR_LVDS || connector->connector_type == DRM_MODE_CONNECTOR_eDP; + setInternal(connector->connector_type == DRM_MODE_CONNECTOR_LVDS || + connector->connector_type == DRM_MODE_CONNECTOR_eDP); - if (m_internal) { + if (internal()) { connect(kwinApp(), &Application::screensCreated, this, [this] { connect(screens()->orientationSensor(), &OrientationSensor::orientationChanged, this, &DrmOutput::automaticRotation); @@ -312,7 +291,7 @@ qCWarning(KWIN_DRM) << "Overwriting monitor physical size for" << m_edid.eisaId << "/" << m_edid.monitorName << "/" << m_edid.serialNumber << " from " << physicalSize << "to " << overwriteSize; physicalSize = overwriteSize; } - m_physicalSize = physicalSize; + setRawPhysicalSize(physicalSize); initOutputDevice(connector); @@ -332,62 +311,69 @@ void DrmOutput::initOutput() { - Q_ASSERT(m_waylandOutputDevice); - if (!m_waylandOutput.isNull()) { - delete m_waylandOutput.data(); - m_waylandOutput.clear(); + auto wlOutputDevice = waylandOutputDevice(); + Q_ASSERT(wlOutputDevice); + + auto wlOutput = waylandOutput(); + if (!wlOutput.isNull()) { + delete wlOutput.data(); + wlOutput.clear(); } - m_waylandOutput = waylandServer()->display()->createOutput(); + wlOutput = waylandServer()->display()->createOutput(); connect(this, &DrmOutput::modeChanged, this, [this] { - if (m_waylandOutput.isNull()) { + auto wlOutput = waylandOutput(); + if (wlOutput.isNull()) { return; } - m_waylandOutput->setCurrentMode(QSize(m_mode.hdisplay, m_mode.vdisplay), refreshRateForMode(&m_mode)); + wlOutput->setCurrentMode(QSize(m_mode.hdisplay, m_mode.vdisplay), + refreshRateForMode(&m_mode)); } ); - m_waylandOutput->setManufacturer(m_waylandOutputDevice->manufacturer()); - m_waylandOutput->setModel(m_waylandOutputDevice->model()); - m_waylandOutput->setPhysicalSize(m_physicalSize); + wlOutput->setManufacturer(wlOutputDevice->manufacturer()); + wlOutput->setModel(wlOutputDevice->model()); + wlOutput->setPhysicalSize(rawPhysicalSize()); // set dpms if (!m_dpms.isNull()) { - m_waylandOutput->setDpmsSupported(true); - m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsMode)); - connect(m_waylandOutput.data(), &KWayland::Server::OutputInterface::dpmsModeRequested, this, + wlOutput->setDpmsSupported(true); + wlOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsMode)); + connect(wlOutput.data(), &KWayland::Server::OutputInterface::dpmsModeRequested, this, [this] (KWayland::Server::OutputInterface::DpmsMode mode) { setDpms(fromWaylandDpmsMode(mode)); }, Qt::QueuedConnection ); } - for(const auto &mode: m_waylandOutputDevice->modes()) { + for(const auto &mode: wlOutputDevice->modes()) { KWayland::Server::OutputInterface::ModeFlags flags; if (mode.flags & KWayland::Server::OutputDeviceInterface::ModeFlag::Current) { flags |= KWayland::Server::OutputInterface::ModeFlag::Current; } if (mode.flags & KWayland::Server::OutputDeviceInterface::ModeFlag::Preferred) { flags |= KWayland::Server::OutputInterface::ModeFlag::Preferred; } - m_waylandOutput->addMode(mode.size, flags, mode.refreshRate); + wlOutput->addMode(mode.size, flags, mode.refreshRate); } - m_waylandOutput->create(); + wlOutput->create(); + setWaylandOutput(wlOutput.data()); } void DrmOutput::initOutputDevice(drmModeConnector *connector) { - if (!m_waylandOutputDevice.isNull()) { - delete m_waylandOutputDevice.data(); - m_waylandOutputDevice.clear(); + auto wlOutputDevice = waylandOutputDevice(); + if (!wlOutputDevice.isNull()) { + delete wlOutputDevice.data(); + wlOutputDevice.clear(); } - m_waylandOutputDevice = waylandServer()->display()->createOutputDevice(); - m_waylandOutputDevice->setUuid(m_uuid); + wlOutputDevice = waylandServer()->display()->createOutputDevice(); + wlOutputDevice->setUuid(m_uuid); if (!m_edid.eisaId.isEmpty()) { - m_waylandOutputDevice->setManufacturer(QString::fromLatin1(m_edid.eisaId)); + wlOutputDevice->setManufacturer(QString::fromLatin1(m_edid.eisaId)); } else { - m_waylandOutputDevice->setManufacturer(i18n("unknown")); + wlOutputDevice->setManufacturer(i18n("unknown")); } QString connectorName = s_connectorNames.value(connector->connector_type, QByteArrayLiteral("Unknown")); @@ -406,9 +392,9 @@ modelName = i18n("unknown"); } - m_waylandOutputDevice->setModel(connectorName + QStringLiteral("-") + QString::number(connector->connector_type_id) + QStringLiteral("-") + modelName); + wlOutputDevice->setModel(connectorName + QStringLiteral("-") + QString::number(connector->connector_type_id) + QStringLiteral("-") + modelName); - m_waylandOutputDevice->setPhysicalSize(m_physicalSize); + wlOutputDevice->setPhysicalSize(rawPhysicalSize()); // read in mode information for (int i = 0; i < connector->count_modes; ++i) { @@ -431,9 +417,10 @@ mode.flags = deviceflags; mode.refreshRate = refreshRate; qCDebug(KWIN_DRM) << "Adding mode: " << i << mode.size; - m_waylandOutputDevice->addMode(mode); + wlOutputDevice->addMode(mode); } - m_waylandOutputDevice->create(); + wlOutputDevice->create(); + setWaylandOutputDevice(wlOutputDevice.data()); } bool DrmOutput::isCurrentMode(const drmModeModeInfo *mode) const @@ -728,8 +715,9 @@ { qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to On."; - if (m_waylandOutput) { - m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); + auto wlOutput = waylandOutput(); + if (wlOutput) { + wlOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); } emit dpmsChanged(); @@ -746,154 +734,124 @@ { qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to Off."; - if (m_waylandOutput) { - m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); + auto wlOutput = waylandOutput(); + if (wlOutput) { + wlOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); } emit dpmsChanged(); m_backend->outputWentOff(); } -QString DrmOutput::name() const -{ - if (!m_waylandOutput) { - return i18n("unknown"); - } - return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model()); -} - int DrmOutput::currentRefreshRate() const { - if (!m_waylandOutput) { + auto wlOutput = waylandOutput(); + if (!wlOutput) { return 60000; } - return m_waylandOutput->refreshRate(); -} - -void DrmOutput::setGlobalPos(const QPoint &pos) -{ - m_globalPos = pos; - if (m_waylandOutput) { - m_waylandOutput->setGlobalPosition(pos); - } - if (m_waylandOutputDevice) { - m_waylandOutputDevice->setGlobalPosition(pos); - } -} - -void DrmOutput::setScale(qreal scale) -{ - m_scale = scale; - if (m_waylandOutput) { - m_waylandOutput->setScale(scale); - } - if (m_waylandOutputDevice) { - m_waylandOutputDevice->setScale(scale); - } -} - -void DrmOutput::setChanges(KWayland::Server::OutputChangeSet *changes) -{ - m_changeset = changes; - qCDebug(KWIN_DRM) << "set changes in DrmOutput"; - commitChanges(); + return wlOutput->refreshRate(); } bool DrmOutput::commitChanges() { - Q_ASSERT(!m_waylandOutputDevice.isNull()); + auto wlOutputDevice = waylandOutputDevice(); + Q_ASSERT(!wlOutputDevice.isNull()); - if (m_changeset.isNull()) { + auto changeset = changes(); + + if (changeset.isNull()) { qCDebug(KWIN_DRM) << "no changes"; // No changes to an output is an entirely valid thing return true; } //enabledChanged is handled by drmbackend - if (m_changeset->modeChanged()) { - qCDebug(KWIN_DRM) << "Setting new mode:" << m_changeset->mode(); - m_waylandOutputDevice->setCurrentMode(m_changeset->mode()); - updateMode(m_changeset->mode()); - } - if (m_changeset->transformChanged()) { - qCDebug(KWIN_DRM) << "Server setting transform: " << (int)(m_changeset->transform()); - transform(m_changeset->transform()); - } - if (m_changeset->positionChanged()) { - qCDebug(KWIN_DRM) << "Server setting position: " << m_changeset->position(); - setGlobalPos(m_changeset->position()); + if (changeset->modeChanged()) { + qCDebug(KWIN_DRM) << "Setting new mode:" << changeset->mode(); + wlOutputDevice->setCurrentMode(changeset->mode()); + updateMode(changeset->mode()); + } + if (changeset->transformChanged()) { + qCDebug(KWIN_DRM) << "Server setting transform: " << (int)(changeset->transform()); + transform(changeset->transform()); + } + if (changeset->positionChanged()) { + qCDebug(KWIN_DRM) << "Server setting position: " << changeset->position(); + setGlobalPos(changeset->position()); // may just work already! } - if (m_changeset->scaleChanged()) { - qCDebug(KWIN_DRM) << "Setting scale:" << m_changeset->scale(); - setScale(m_changeset->scale()); + if (changeset->scaleChanged()) { + qCDebug(KWIN_DRM) << "Setting scale:" << changeset->scale(); + setScale(changeset->scale()); } return true; } void DrmOutput::transform(KWayland::Server::OutputDeviceInterface::Transform transform) { - m_waylandOutputDevice->setTransform(transform); + waylandOutputDevice()->setTransform(transform); using KWayland::Server::OutputDeviceInterface; using KWayland::Server::OutputInterface; + auto wlOutput = waylandOutput(); + switch (transform) { case OutputDeviceInterface::Transform::Normal: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate0); } - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Normal); + if (wlOutput) { + wlOutput->setTransform(OutputInterface::Transform::Normal); } - m_orientation = Qt::PrimaryOrientation; + setOrientation(Qt::PrimaryOrientation); break; case OutputDeviceInterface::Transform::Rotated90: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate90); } - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Rotated90); + if (wlOutput) { + wlOutput->setTransform(OutputInterface::Transform::Rotated90); } - m_orientation = Qt::PortraitOrientation; + setOrientation(Qt::PortraitOrientation); break; case OutputDeviceInterface::Transform::Rotated180: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate180); } - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Rotated180); + if (wlOutput) { + wlOutput->setTransform(OutputInterface::Transform::Rotated180); } - m_orientation = Qt::InvertedLandscapeOrientation; + setOrientation(Qt::InvertedLandscapeOrientation); break; case OutputDeviceInterface::Transform::Rotated270: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate270); } - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Rotated270); + if (wlOutput) { + wlOutput->setTransform(OutputInterface::Transform::Rotated270); } - m_orientation = Qt::InvertedPortraitOrientation; + setOrientation(Qt::InvertedPortraitOrientation); break; case OutputDeviceInterface::Transform::Flipped: // TODO: what is this exactly? - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Flipped); + if (wlOutput) { + wlOutput->setTransform(OutputInterface::Transform::Flipped); } break; case OutputDeviceInterface::Transform::Flipped90: // TODO: what is this exactly? - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Flipped90); + if (wlOutput) { + wlOutput->setTransform(OutputInterface::Transform::Flipped90); } break; case OutputDeviceInterface::Transform::Flipped180: // TODO: what is this exactly? - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Flipped180); + if (wlOutput) { + wlOutput->setTransform(OutputInterface::Transform::Flipped180); } break; case OutputDeviceInterface::Transform::Flipped270: // TODO: what is this exactly? - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Flipped270); + if (wlOutput) { + wlOutput->setTransform(OutputInterface::Transform::Flipped270); } break; } @@ -1023,7 +981,7 @@ // go back to previous state if (m_lastWorkingState.valid) { m_mode = m_lastWorkingState.mode; - m_orientation = m_lastWorkingState.orientation; + setOrientation(m_lastWorkingState.orientation); setGlobalPos(m_lastWorkingState.globalPos); if (m_primaryPlane) { m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations); @@ -1047,8 +1005,8 @@ if (wasModeset) { // store current mode set as new good state m_lastWorkingState.mode = m_mode; - m_lastWorkingState.orientation = m_orientation; - m_lastWorkingState.globalPos = m_globalPos; + m_lastWorkingState.orientation = orientation(); + m_lastWorkingState.globalPos = globalPos(); if (m_primaryPlane) { m_lastWorkingState.planeTransformations = m_primaryPlane->transformation(); } diff --git a/plugins/platforms/drm/egl_gbm_backend.h b/plugins/platforms/drm/egl_gbm_backend.h --- a/plugins/platforms/drm/egl_gbm_backend.h +++ b/plugins/platforms/drm/egl_gbm_backend.h @@ -61,7 +61,7 @@ bool initBufferConfigs(); bool initRenderingContext(); void initRemotePresent(); - struct Output { + struct EglGbmOutput { DrmOutput *output = nullptr; DrmBuffer *buffer = nullptr; std::shared_ptr gbmSurface; @@ -72,13 +72,13 @@ */ QList damageHistory; }; - bool resetOutput(Output &output, DrmOutput *drmOutput); - bool makeContextCurrent(const Output &output); - void presentOnOutput(Output &output); - void cleanupOutput(const Output &output); + bool resetOutput(EglGbmOutput &output, DrmOutput *drmOutput); + bool makeContextCurrent(const EglGbmOutput &output); + void presentOnOutput(EglGbmOutput &output); + void cleanupOutput(const EglGbmOutput &output); void createOutput(DrmOutput *output); DrmBackend *m_backend; - QVector m_outputs; + QVector m_outputs; QScopedPointer m_remoteaccessManager; friend class EglGbmTexture; }; diff --git a/plugins/platforms/drm/egl_gbm_backend.cpp b/plugins/platforms/drm/egl_gbm_backend.cpp --- a/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/plugins/platforms/drm/egl_gbm_backend.cpp @@ -47,7 +47,7 @@ connect(m_backend, &DrmBackend::outputRemoved, this, [this] (DrmOutput *output) { auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [output] (const Output &o) { + [output] (const EglGbmOutput &o) { return o.output == output; } ); @@ -73,7 +73,7 @@ m_outputs.clear(); } -void EglGbmBackend::cleanupOutput(const Output &o) +void EglGbmBackend::cleanupOutput(const EglGbmOutput &o) { o.output->releaseGbm(); @@ -142,8 +142,8 @@ } const auto outputs = m_backend->outputs(); - for (DrmOutput *drmOutput: outputs) { - createOutput(drmOutput); + for (Output *drmOutput: outputs) { + createOutput(qobject_cast(drmOutput)); } if (m_outputs.isEmpty()) { qCCritical(KWIN_DRM) << "Create Window Surfaces failed"; @@ -165,7 +165,7 @@ m_remoteaccessManager.reset(new RemoteAccessManager); } -bool EglGbmBackend::resetOutput(Output &o, DrmOutput *drmOutput) +bool EglGbmBackend::resetOutput(EglGbmOutput &o, DrmOutput *drmOutput) { o.output = drmOutput; auto size = drmOutput->pixelSize(); @@ -196,7 +196,7 @@ void EglGbmBackend::createOutput(DrmOutput *drmOutput) { - Output o; + EglGbmOutput o; if (resetOutput(o, drmOutput)) { connect(drmOutput, &DrmOutput::modeChanged, this, [drmOutput, this] { @@ -215,7 +215,7 @@ } } -bool EglGbmBackend::makeContextCurrent(const Output &output) +bool EglGbmBackend::makeContextCurrent(const EglGbmOutput &output) { const EGLSurface surface = output.eglSurface; if (surface == EGL_NO_SURFACE) { @@ -303,7 +303,7 @@ } } -void EglGbmBackend::presentOnOutput(EglGbmBackend::Output &o) +void EglGbmBackend::presentOnOutput(EglGbmBackend::EglGbmOutput &o) { eglSwapBuffers(eglDisplay(), o.eglSurface); o.buffer = m_backend->createBuffer(o.gbmSurface); @@ -339,7 +339,7 @@ QRegion EglGbmBackend::prepareRenderingForScreen(int screenId) { - const Output &o = m_outputs.at(screenId); + const EglGbmOutput &o = m_outputs.at(screenId); makeContextCurrent(o); if (supportsBufferAge()) { QRegion region; @@ -365,7 +365,7 @@ void EglGbmBackend::endRenderingFrameForScreen(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) { - Output &o = m_outputs[screenId]; + EglGbmOutput &o = m_outputs[screenId]; if (damagedRegion.intersected(o.output->geometry()).isEmpty() && screenId == 0) { // If the damaged region of a window is fully occluded, the only diff --git a/plugins/platforms/drm/remoteaccess_manager.cpp b/plugins/platforms/drm/remoteaccess_manager.cpp --- a/plugins/platforms/drm/remoteaccess_manager.cpp +++ b/plugins/platforms/drm/remoteaccess_manager.cpp @@ -82,7 +82,7 @@ buf->setStride(gbm_bo_get_stride(bo)); buf->setFormat(gbm_bo_get_format(bo)); - m_interface->sendBufferReady(output->getWaylandInterface().data(), buf); + m_interface->sendBufferReady(output->waylandOutput().data(), buf); } } // KWin namespace diff --git a/plugins/platforms/drm/scene_qpainter_drm_backend.h b/plugins/platforms/drm/scene_qpainter_drm_backend.h --- a/plugins/platforms/drm/scene_qpainter_drm_backend.h +++ b/plugins/platforms/drm/scene_qpainter_drm_backend.h @@ -47,12 +47,12 @@ private: void initOutput(DrmOutput *output); - struct Output { + struct QPainterOutput { DrmDumbBuffer *buffer[2]; DrmOutput *output; int index = 0; }; - QVector m_outputs; + QVector m_outputs; DrmBackend *m_backend; }; } diff --git a/plugins/platforms/drm/scene_qpainter_drm_backend.cpp b/plugins/platforms/drm/scene_qpainter_drm_backend.cpp --- a/plugins/platforms/drm/scene_qpainter_drm_backend.cpp +++ b/plugins/platforms/drm/scene_qpainter_drm_backend.cpp @@ -32,13 +32,13 @@ { const auto outputs = m_backend->outputs(); for (auto output: outputs) { - initOutput(output); + initOutput(qobject_cast(output)); } connect(m_backend, &DrmBackend::outputAdded, this, &DrmQPainterBackend::initOutput); connect(m_backend, &DrmBackend::outputRemoved, this, [this] (DrmOutput *o) { auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [o] (const Output &output) { + [o] (const QPainterOutput &output) { return output.output == o; } ); @@ -62,7 +62,7 @@ void DrmQPainterBackend::initOutput(DrmOutput *output) { - Output o; + QPainterOutput o; auto initBuffer = [&o, output, this] (int index) { o.buffer[index] = m_backend->createBuffer(output->pixelSize()); o.buffer[index]->map(); @@ -102,7 +102,7 @@ QImage *DrmQPainterBackend::bufferForScreen(int screenId) { - const Output &o = m_outputs.at(screenId); + const QPainterOutput &o = m_outputs.at(screenId); return o.buffer[o.index]->image(); } @@ -126,7 +126,7 @@ return; } for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { - const Output &o = *it; + const QPainterOutput &o = *it; m_backend->present(o.buffer[o.index], o.output); } } diff --git a/plugins/platforms/drm/screens_drm.cpp b/plugins/platforms/drm/screens_drm.cpp --- a/plugins/platforms/drm/screens_drm.cpp +++ b/plugins/platforms/drm/screens_drm.cpp @@ -79,7 +79,8 @@ int minDistance = INT_MAX; const auto outputs = m_backend->enabledOutputs(); for (int i = 0; i < outputs.size(); ++i) { - const QRect &geo = outputs.at(i)->geometry(); + auto o = qobject_cast(outputs.at(i)); + const QRect &geo = o->geometry(); if (geo.contains(pos)) { return i; } @@ -110,16 +111,18 @@ if (screen >= outputs.size()) { return Screens::refreshRate(screen); } - return outputs.at(screen)->currentRefreshRate() / 1000.0f; + auto *o = qobject_cast(outputs.at(screen)); + return o->currentRefreshRate() / 1000.0f; } QSizeF DrmScreens::physicalSize(int screen) const { const auto outputs = m_backend->enabledOutputs(); if (screen >= outputs.size()) { return Screens::physicalSize(screen); } - return outputs.at(screen)->physicalSize(); + auto *o = qobject_cast(outputs.at(screen)); + return o->physicalSize(); } bool DrmScreens::isInternal(int screen) const @@ -137,16 +140,18 @@ if (screen >= outputs.size()) { return false; } - return outputs.at(screen)->supportsTransformations(); + auto *o = qobject_cast(outputs.at(screen)); + return o->supportsTransformations(); } Qt::ScreenOrientation DrmScreens::orientation(int screen) const { const auto outputs = m_backend->outputs(); if (screen >= outputs.size()) { return Qt::PrimaryOrientation; } - return outputs.at(screen)->orientation(); + auto *o = qobject_cast(outputs.at(screen)); + return o->orientation(); } }