diff --git a/backends/kwayland/waylandbackend.h b/backends/kwayland/waylandbackend.h --- a/backends/kwayland/waylandbackend.h +++ b/backends/kwayland/waylandbackend.h @@ -17,16 +17,15 @@ * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************************/ - -#ifndef KWAYLAND_BACKEND_H -#define KWAYLAND_BACKEND_H +#pragma once #include "abstractbackend.h" #include namespace KScreen { + class WaylandConfig; class WaylandBackend : public KScreen::AbstractBackend @@ -45,17 +44,13 @@ bool isValid() const override; QByteArray edid(int outputId) const override; - void updateConfig(KScreen::ConfigPtr &config); - private: bool m_isValid; KScreen::ConfigPtr m_config; WaylandConfig *m_internalConfig; void emitConfigChanged(const KScreen::ConfigPtr &cfg); }; -} // namespace +} Q_DECLARE_LOGGING_CATEGORY(KSCREEN_WAYLAND) - -#endif //KWAYLAND_BACKEND_H diff --git a/backends/kwayland/waylandbackend.cpp b/backends/kwayland/waylandbackend.cpp --- a/backends/kwayland/waylandbackend.cpp +++ b/backends/kwayland/waylandbackend.cpp @@ -17,8 +17,8 @@ * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************************/ - #include "waylandbackend.h" + #include "waylandconfig.h" #include "waylandoutput.h" @@ -40,8 +40,10 @@ , m_internalConfig(new WaylandConfig(this)) { qCDebug(KSCREEN_WAYLAND) << "Loading Wayland backend."; + m_internalConfig = new WaylandConfig(this); m_config = m_internalConfig->toKScreenConfig(); + connect(m_internalConfig, &WaylandConfig::configChanged, this, &WaylandBackend::emitConfigChanged); } @@ -88,9 +90,3 @@ { return m_isValid; } - -void WaylandBackend::updateConfig(ConfigPtr &config) -{ - Q_ASSERT(config != nullptr); - m_internalConfig->updateKScreenConfig(config); -} diff --git a/backends/kwayland/waylandconfig.h b/backends/kwayland/waylandconfig.h --- a/backends/kwayland/waylandconfig.h +++ b/backends/kwayland/waylandconfig.h @@ -15,29 +15,28 @@ * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************************/ - -#ifndef KSCREEN_WAYLAND_CONFIG_H -#define KSCREEN_WAYLAND_CONFIG_H +#pragma once #include "abstractbackend.h" #include "config.h" #include #include -#include -#include -#include #include +#include +#include #include +#include - -namespace KWayland { - namespace Client { - class ConnectionThread; - class EventQueue; - class Registry; - class OutputManagement; - } +namespace KWayland +{ +namespace Client +{ +class ConnectionThread; +class EventQueue; +class Registry; +class OutputManagement; +} } namespace KScreen @@ -68,9 +67,8 @@ ~WaylandConfig() override; KScreen::ConfigPtr toKScreenConfig(); - void updateKScreenConfig(KScreen::ConfigPtr &config) const; - QMap outputMap() const; + QMap outputMap() const; void addOutput(quint32 name, quint32 version); void removeOutput(quint32 name); @@ -82,12 +80,12 @@ void initialized(); void gone(); -private Q_SLOTS: +private: void setupRegistry(); void checkInitialized(); void disconnected(); -private: + void updateKScreenConfig(KScreen::ConfigPtr &config) const; void initConnection(); void blockSignals(); void unblockSignals(); @@ -113,9 +111,6 @@ KScreen::ConfigPtr m_kscreenConfig; KScreen::ConfigPtr m_kscreenPendingConfig; WaylandScreen *m_screen; - }; -} // namespace - -#endif // KSCREEN_WAYLAND_CONFIG_H +} diff --git a/backends/kwayland/waylandconfig.cpp b/backends/kwayland/waylandconfig.cpp --- a/backends/kwayland/waylandconfig.cpp +++ b/backends/kwayland/waylandconfig.cpp @@ -16,31 +16,26 @@ * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************************/ - #include "waylandconfig.h" + +#include "waylandbackend.h" #include "waylandoutput.h" #include "waylandscreen.h" -#include "waylandbackend.h" -// KWayland +#include +#include + #include #include #include #include #include #include - -// Qt #include -#include -#include - - using namespace KScreen; - WaylandConfig::WaylandConfig(QObject *parent) : QObject(parent) , m_outputManagement(nullptr) @@ -52,14 +47,17 @@ , m_screen(new WaylandScreen(this)) { connect(this, &WaylandConfig::initialized, &m_syncLoop, &QEventLoop::quit); + QTimer::singleShot(1000, this, [this] { if (m_syncLoop.isRunning()) { - qCWarning(KSCREEN_WAYLAND) << "Connection to Wayland server at socket:" << m_connection->socketName() << "timed out."; + qCWarning(KSCREEN_WAYLAND) << "Connection to Wayland server at socket:" + << m_connection->socketName() << "timed out."; m_syncLoop.quit(); m_thread->quit(); m_thread->wait(); } }); + initConnection(); m_syncLoop.exec(); } @@ -74,16 +72,17 @@ void WaylandConfig::initConnection() { m_thread = new QThread(this); - //m_queue = new KWayland::Client::EventQueue(this); m_connection = new KWayland::Client::ConnectionThread; connect(m_connection, &KWayland::Client::ConnectionThread::connected, this, &WaylandConfig::setupRegistry, Qt::QueuedConnection); connect(m_connection, &KWayland::Client::ConnectionThread::connectionDied, this, &WaylandConfig::disconnected, Qt::QueuedConnection); + connect(m_connection, &KWayland::Client::ConnectionThread::failed, this, [this] { - qCWarning(KSCREEN_WAYLAND) << "Failed to connect to Wayland server at socket:" << m_connection->socketName(); + qCWarning(KSCREEN_WAYLAND) << "Failed to connect to Wayland server at socket:" + << m_connection->socketName(); m_syncLoop.quit(); m_thread->quit(); m_thread->wait(); @@ -172,30 +171,33 @@ { ++m_newOutputId; quint32 new_id = m_newOutputId; + m_outputIds[name] = new_id; if (m_outputMap.contains(new_id)) { return; } + if (!m_initializingOutputs.contains(name)) { m_initializingOutputs << name; } auto op = new KWayland::Client::OutputDevice(this); + WaylandOutput *waylandoutput = new WaylandOutput(new_id, this); waylandoutput->bindOutputDevice(m_registry, op, name, version); // finalize: when the output is done, we put it in the known outputs map, // remove if from the list of initializing outputs, and emit configChanged() connect(waylandoutput, &WaylandOutput::complete, this, [this, waylandoutput, name]{ - m_outputMap.insert(waylandoutput->id(), waylandoutput); m_initializingOutputs.removeAll(name); checkInitialized(); if (!m_blockSignals && m_initializingOutputs.empty()) { m_screen->setOutputs(m_outputMap.values()); Q_EMIT configChanged(toKScreenConfig()); } + connect(waylandoutput, &WaylandOutput::changed, this, [this]() { if (!m_blockSignals) { Q_EMIT configChanged(toKScreenConfig()); @@ -227,9 +229,11 @@ void WaylandConfig::removeOutput(quint32 name) { const int kscreen_id = m_outputIds[name]; + auto output = m_outputMap.take(kscreen_id); m_screen->setOutputs(m_outputMap.values()); delete output; + if (!m_blockSignals) { Q_EMIT configChanged(toKScreenConfig()); } @@ -245,15 +249,15 @@ //Removing removed outputs const KScreen::OutputList outputs = config->outputs(); - Q_FOREACH (const KScreen::OutputPtr &output, outputs) { + for (const auto &output : outputs) { if (!m_outputMap.contains(output->id())) { config->removeOutput(output->id()); } } // Add KScreen::Outputs that aren't in the list yet, handle primaryOutput KScreen::OutputList kscreenOutputs = config->outputs(); - Q_FOREACH (const auto &output, m_outputMap) { + for (const auto &output : m_outputMap) { KScreen::OutputPtr kscreenOutput = kscreenOutputs[output->id()]; if (!kscreenOutput) { kscreenOutput = output->toKScreenOutput(); @@ -263,7 +267,6 @@ kscreenOutput->setPrimary(true); } else if (m_outputMap.count() > 1) { // primaryScreen concept doesn't exist in kwayland, so we don't set one - //qCWarning(KSCREEN_WAYLAND) << "Multiple outputs, but no way to figure out the primary one. :/"; } output->updateKScreenOutput(kscreenOutput); } @@ -288,16 +291,16 @@ { using namespace KWayland::Client; // Create a new configuration object - auto wlOutputConfiguration = m_outputManagement->createConfiguration(); + auto wlConfig = m_outputManagement->createConfiguration(); bool changed = false; if (m_blockSignals) { /* Last apply still pending, remember new changes and apply afterwards */ m_kscreenPendingConfig = newConfig; return; } - Q_FOREACH (auto output, newConfig->outputs()) { + for (const auto &output : newConfig->outputs()) { auto o_old = m_outputMap[output->id()]; auto device = o_old->outputDevice(); Q_ASSERT(o_old != nullptr); @@ -307,35 +310,37 @@ if (old_enabled != output->isEnabled()) { changed = true; auto _enablement = output->isEnabled() ? OutputDevice::Enablement::Enabled : OutputDevice::Enablement::Disabled; - wlOutputConfiguration->setEnabled(o_old->outputDevice(), _enablement); + wlConfig->setEnabled(o_old->outputDevice(), _enablement); } // position if (device->globalPosition() != output->pos()) { changed = true; - wlOutputConfiguration->setPosition(o_old->outputDevice(), output->pos()); + wlConfig->setPosition(o_old->outputDevice(), output->pos()); } + // scale if (!qFuzzyCompare(device->scaleF(), output->scale())) { changed = true; - wlOutputConfiguration->setScaleF(o_old->outputDevice(), output->scale()); + wlConfig->setScaleF(o_old->outputDevice(), output->scale()); } // rotation auto r_current = o_old->toKScreenRotation(device->transform()); auto r_new = output->rotation(); if (r_current != r_new) { changed = true; - wlOutputConfiguration->setTransform(device, o_old->toKWaylandTransform(r_new)); + wlConfig->setTransform(device, o_old->toKWaylandTransform(r_new)); } // mode int w_currentmodeid = device->currentMode().id; QString l_newmodeid = output->currentModeId(); + int w_newmodeid = o_old->toKWaylandModeId(l_newmodeid); if (w_newmodeid != w_currentmodeid) { changed = true; - wlOutputConfiguration->setMode(device, w_newmodeid); + wlConfig->setMode(device, w_newmodeid); } } @@ -346,19 +351,20 @@ // We now block changes in order to compress events while the compositor is doing its thing // once it's done or failed, we'll trigger configChanged() only once, and not per individual // property change. - connect(wlOutputConfiguration, &OutputConfiguration::applied, this, [this, wlOutputConfiguration] { - wlOutputConfiguration->deleteLater(); + connect(wlConfig, &OutputConfiguration::applied, this, [this, wlConfig] { + wlConfig->deleteLater(); unblockSignals(); Q_EMIT configChanged(toKScreenConfig()); tryPendingConfig(); }); - connect(wlOutputConfiguration, &OutputConfiguration::failed, this, [this, wlOutputConfiguration] { - wlOutputConfiguration->deleteLater(); + connect(wlConfig, &OutputConfiguration::failed, this, [this, wlConfig] { + wlConfig->deleteLater(); unblockSignals(); Q_EMIT configChanged(toKScreenConfig()); tryPendingConfig(); }); + + // Now block signals and ask the compositor to apply the changes. blockSignals(); - // Now ask the compositor to apply the changes - wlOutputConfiguration->apply(); + wlConfig->apply(); } diff --git a/backends/kwayland/waylandoutput.h b/backends/kwayland/waylandoutput.h --- a/backends/kwayland/waylandoutput.h +++ b/backends/kwayland/waylandoutput.h @@ -15,24 +15,19 @@ * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************************/ +#pragma once -#ifndef KSCREEN_WAYLAND_OUTPUT_H -#define KSCREEN_WAYLAND_OUTPUT_H +#include "waylandconfig.h" -// libkscreen #include "abstractbackend.h" -#include "config.h" #include "output.h" -// Own -#include "waylandconfig.h" - -#include -#include -#include #include #include +#include +#include +#include namespace KScreen { @@ -42,23 +37,24 @@ Q_OBJECT public: - ~WaylandOutput() override; + ~WaylandOutput() override = default; KScreen::OutputPtr toKScreenOutput(); void updateKScreenOutput(KScreen::OutputPtr &output); quint32 id() const; - + QString name() const; bool enabled() const; KWayland::Client::OutputDevice* outputDevice() const; - void bindOutputDevice(KWayland::Client::Registry *registry, KWayland::Client::OutputDevice *op, quint32 name, quint32 version); - - QString name() const; + void bindOutputDevice(KWayland::Client::Registry *registry, + KWayland::Client::OutputDevice *op, quint32 name, quint32 version); // translation methods - KScreen::Output::Rotation toKScreenRotation(const KWayland::Client::OutputDevice::Transform transform) const; - KWayland::Client::OutputDevice::Transform toKWaylandTransform(const KScreen::Output::Rotation rotation) const; + KScreen::Output::Rotation toKScreenRotation( + const KWayland::Client::OutputDevice::Transform transform) const; + KWayland::Client::OutputDevice::Transform toKWaylandTransform( + const KScreen::Output::Rotation rotation) const; QString toKScreenModeId(int kwaylandmodeid) const; int toKWaylandModeId(const QString &kscreenmodeid) const; @@ -72,19 +68,18 @@ private: friend WaylandConfig; explicit WaylandOutput(quint32 id, WaylandConfig *parent = nullptr); + void showOutput(); QString modeName(const KWayland::Client::OutputDevice::Mode &m) const; quint32 m_id; - KWayland::Client::OutputDevice* m_output; - KWayland::Client::Registry* m_registry; + KWayland::Client::OutputDevice *m_output; + KWayland::Client::Registry *m_registry; - QMap m_rotationMap; - QMap m_modeIdMap; // left-hand-side: KScreen::Mode, right-hand-side: kwayland's mode.id + // left-hand-side: KScreen::Mode, right-hand-side: KWayland's mode.id + QMap m_modeIdMap; }; -} // namespace +} KSCREEN_EXPORT QDebug operator<<(QDebug dbg, const KScreen::WaylandOutput *output); - -#endif diff --git a/backends/kwayland/waylandoutput.cpp b/backends/kwayland/waylandoutput.cpp --- a/backends/kwayland/waylandoutput.cpp +++ b/backends/kwayland/waylandoutput.cpp @@ -15,47 +15,47 @@ * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************************/ - #include "waylandoutput.h" #include "waylandbackend.h" #include "waylandconfig.h" #include "../utils.h" #include #include -#include -#include - - using namespace KScreen; +namespace Wl = KWayland::Client; + +const QMap +s_rotationMap = { + {Wl::OutputDevice::Transform::Normal, Output::None}, + {Wl::OutputDevice::Transform::Rotated90, Output::Right}, + {Wl::OutputDevice::Transform::Rotated180, Output::Inverted}, + {Wl::OutputDevice::Transform::Rotated270, Output::Left}, + {Wl::OutputDevice::Transform::Flipped, Output::None}, + {Wl::OutputDevice::Transform::Flipped90, Output::Right}, + {Wl::OutputDevice::Transform::Flipped180, Output::Inverted}, + {Wl::OutputDevice::Transform::Flipped270, Output::Left} +}; WaylandOutput::WaylandOutput(quint32 id, WaylandConfig *parent) : QObject(parent) , m_id(id) , m_output(nullptr) { - m_rotationMap = { - {KWayland::Client::OutputDevice::Transform::Normal, KScreen::Output::None}, - {KWayland::Client::OutputDevice::Transform::Rotated90, KScreen::Output::Right}, - {KWayland::Client::OutputDevice::Transform::Rotated180, KScreen::Output::Inverted}, - {KWayland::Client::OutputDevice::Transform::Rotated270, KScreen::Output::Left}, - {KWayland::Client::OutputDevice::Transform::Flipped, KScreen::Output::None}, - {KWayland::Client::OutputDevice::Transform::Flipped90, KScreen::Output::Right}, - {KWayland::Client::OutputDevice::Transform::Flipped180, KScreen::Output::Inverted}, - {KWayland::Client::OutputDevice::Transform::Flipped270, KScreen::Output::Left} - }; } -KScreen::Output::Rotation WaylandOutput::toKScreenRotation(const KWayland::Client::OutputDevice::Transform transform) const +Output::Rotation +WaylandOutput::toKScreenRotation(const Wl::OutputDevice::Transform transform) const { - auto it = m_rotationMap.constFind(transform); + auto it = s_rotationMap.constFind(transform); return it.value(); } -KWayland::Client::OutputDevice::Transform WaylandOutput::toKWaylandTransform(const KScreen::Output::Rotation rotation) const +Wl::OutputDevice::Transform +WaylandOutput::toKWaylandTransform(const Output::Rotation rotation) const { - return m_rotationMap.key(rotation); + return s_rotationMap.key(rotation); } QString WaylandOutput::toKScreenModeId(int kwaylandmodeid) const @@ -76,10 +76,6 @@ return m_modeIdMap.value(kscreenmodeid, -1); } -WaylandOutput::~WaylandOutput() -{ -} - quint32 WaylandOutput::id() const { Q_ASSERT(m_output); @@ -91,92 +87,98 @@ return m_output != nullptr; } -KWayland::Client::OutputDevice* WaylandOutput::outputDevice() const +Wl::OutputDevice* WaylandOutput::outputDevice() const { return m_output; } -void WaylandOutput::bindOutputDevice(KWayland::Client::Registry* registry, KWayland::Client::OutputDevice* op, quint32 name, quint32 version) +void WaylandOutput::bindOutputDevice(Wl::Registry* registry, Wl::OutputDevice* op, + quint32 name, quint32 version) { if (m_output == op) { return; } m_output = op; - connect(m_output, &KWayland::Client::OutputDevice::done, this, [this]() { + connect(m_output, &Wl::OutputDevice::done, this, [this]() { Q_EMIT complete(); - connect(m_output, &KWayland::Client::OutputDevice::changed, - this, &WaylandOutput::changed); - + connect(m_output, &Wl::OutputDevice::changed, this, &WaylandOutput::changed); }); m_output->setup(registry->bindOutputDevice(name, version)); } -KScreen::OutputPtr WaylandOutput::toKScreenOutput() +OutputPtr WaylandOutput::toKScreenOutput() { - KScreen::OutputPtr output(new KScreen::Output()); + OutputPtr output(new Output()); output->setId(m_id); updateKScreenOutput(output); return output; } -void WaylandOutput::updateKScreenOutput(KScreen::OutputPtr &output) +void WaylandOutput::updateKScreenOutput(OutputPtr &output) { // Initialize primary output output->setId(m_id); - output->setEnabled(m_output->enabled() == KWayland::Client::OutputDevice::Enablement::Enabled); + output->setEnabled(m_output->enabled() == Wl::OutputDevice::Enablement::Enabled); output->setConnected(true); output->setPrimary(true); // FIXME: wayland doesn't have the concept of a primary display output->setName(name()); - // Physical size output->setSizeMm(m_output->physicalSize()); output->setPos(m_output->globalPosition()); - output->setRotation(m_rotationMap[m_output->transform()]); - KScreen::ModeList modeList; + output->setRotation(s_rotationMap[m_output->transform()]); + + ModeList modeList; QStringList preferredModeIds; m_modeIdMap.clear(); QString currentModeId = QStringLiteral("-1"); - Q_FOREACH (const KWayland::Client::OutputDevice::Mode &m, m_output->modes()) { - KScreen::ModePtr mode(new KScreen::Mode()); - const QString modename = modeName(m); - QString modeid = QString::number(m.id); - if (modeid.isEmpty()) { - qCDebug(KSCREEN_WAYLAND) << "Could not create mode id from" << m.id << ", using" << modename << "instead."; - modeid = modename; + + for (const Wl::OutputDevice::Mode &wlMode : m_output->modes()) { + ModePtr mode(new Mode()); + const QString name = modeName(wlMode); + + QString modeId = QString::number(wlMode.id); + if (modeId.isEmpty()) { + qCDebug(KSCREEN_WAYLAND) << "Could not create mode id from" + << wlMode.id << ", using" << name << "instead."; + modeId = name; } - if (m_modeIdMap.contains(modeid)) { - qCWarning(KSCREEN_WAYLAND) << "Mode id already in use:" << modeid; + + if (m_modeIdMap.contains(modeId)) { + qCWarning(KSCREEN_WAYLAND) << "Mode id already in use:" << modeId; } + mode->setId(modeId); - mode->setId(modeid); // KWayland gives the refresh rate as int in mHz - mode->setRefreshRate(m.refreshRate / 1000.0); - mode->setSize(m.size); - mode->setName(modename); - if (m.flags.testFlag(KWayland::Client::OutputDevice::Mode::Flag::Current)) { - currentModeId = modeid; + mode->setRefreshRate(wlMode.refreshRate / 1000.0); + mode->setSize(wlMode.size); + mode->setName(name); + + if (wlMode.flags.testFlag(Wl::OutputDevice::Mode::Flag::Current)) { + currentModeId = modeId; } - if (m.flags.testFlag(KWayland::Client::OutputDevice::Mode::Flag::Preferred)) { - preferredModeIds << modeid; + if (wlMode.flags.testFlag(Wl::OutputDevice::Mode::Flag::Preferred)) { + preferredModeIds << modeId; } + // Update the kscreen => kwayland mode id translation map - m_modeIdMap.insert(modeid, m.id); + m_modeIdMap.insert(modeId, wlMode.id); // Add to the modelist which gets set on the output - modeList[modeid] = mode; + modeList[modeId] = mode; } + if (currentModeId == QLatin1String("-1")) { qCWarning(KSCREEN_WAYLAND) << "Could not find the current mode id" << modeList; } - output->setCurrentModeId(currentModeId); + output->setCurrentModeId(currentModeId); output->setPreferredModes(preferredModeIds); output->setModes(modeList); output->setScale(m_output->scale()); output->setType(Utils::guessOutputType(m_output->model(), m_output->model())); } -QString WaylandOutput::modeName(const KWayland::Client::OutputDevice::Mode &m) const +QString WaylandOutput::modeName(const Wl::OutputDevice::Mode &m) const { return QString::number(m.size.width()) + QLatin1Char('x') + QString::number(m.size.height()) + QLatin1Char('@') +