/* SPDX-FileCopyrightText: 2020 Michail Vourlakos SPDX-License-Identifier: GPL-2.0-or-later */ #include "screengeometries.h" //!local #include "../../lattecorona.h" #include "../../screenpool.h" #include "../../view/view.h" #include "../../layout/genericlayout.h" #include "../../layouts/manager.h" #include "../../settings/universalsettings.h" // Qt #include #include #define LATTESERVICE "org.kde.lattedock" #define PLASMASERVICE "org.kde.plasmashell" #define PLASMASTRUTNAMESPACE "org.kde.PlasmaShell.StrutManager" #define PUBLISHINTERVAL 1000 namespace Latte { namespace PlasmaExtended { ScreenGeometries::ScreenGeometries(Latte::Corona *parent) : QObject(parent), m_corona(parent), m_plasmaServiceWatcher(new QDBusServiceWatcher(this)) { qDBusRegisterMetaType>(); m_startupInitTimer.setInterval(2500); m_startupInitTimer.setSingleShot(true); connect(&m_startupInitTimer, &QTimer::timeout, this, &ScreenGeometries::init); m_publishTimer.setInterval(PUBLISHINTERVAL); m_publishTimer.setSingleShot(true); connect(&m_publishTimer, &QTimer::timeout, this, &ScreenGeometries::updateGeometries); m_startupInitTimer.start(); m_plasmaServiceWatcher->setConnection(QDBusConnection::sessionBus()); m_plasmaServiceWatcher->setWatchedServices(QStringList({PLASMASERVICE})); connect(m_plasmaServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString & serviceName) { if (serviceName == PLASMASERVICE && !m_plasmaInterfaceAvailable) { init(); } }); } ScreenGeometries::~ScreenGeometries() { qDebug() << "Plasma Extended Screen Geometries :: Deleted..."; } void ScreenGeometries::init() { qDebug() << " PLASMA STRUTS MANAGER :: checking availability...."; bool serviceavailable{false}; if (QDBusConnection::sessionBus().interface()) { serviceavailable = QDBusConnection::sessionBus().interface()->isServiceRegistered(PLASMASERVICE).value(); qDebug() << "PLASMA STRUTS MANAGER :: interface availability :: " << QDBusConnection::sessionBus().interface()->isServiceRegistered(PLASMASERVICE).value(); } connect(m_corona->universalSettings(), &Latte::UniversalSettings::isAvailableGeometryBroadcastedToPlasmaChanged, this, &ScreenGeometries::onBroadcastToPlasmaChanged); if (serviceavailable) { m_plasmaInterfaceAvailable = true; qDebug() << " PLASMA STRUTS MANAGER :: is available..."; connect(m_corona, &Latte::Corona::availableScreenRectChangedFrom, this, &ScreenGeometries::availableScreenGeometryChangedFrom); connect(m_corona, &Latte::Corona::availableScreenRegionChangedFrom, this, &ScreenGeometries::availableScreenGeometryChangedFrom); connect(m_corona->layoutsManager()->synchronizer(), &Latte::Layouts::Synchronizer::centralLayoutsChanged, this, [&]() { m_publishTimer.start(); }); connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() { if (m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma()) { m_publishTimer.start(); } }); if (m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma()) { m_publishTimer.start(); } } } bool ScreenGeometries::screenIsActive(const QString &screenName) const { for (QScreen *screen : qGuiApp->screens()) { if (screen->name() == screenName) { return true; } } return false; } void ScreenGeometries::onBroadcastToPlasmaChanged() { if (m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma()) { m_publishTimer.start(); } else { clearGeometries(); } } void ScreenGeometries::setPlasmaAvailableScreenRect(const QString &screenName, const QRect &rect) { QDBusMessage message = QDBusMessage::createMethodCall(PLASMASERVICE, "/StrutManager", PLASMASTRUTNAMESPACE, "setAvailableScreenRect"); QVariantList args; args << LATTESERVICE << screenName << rect; message.setArguments(args); QDBusConnection::sessionBus().call(message, QDBus::NoBlock); } void ScreenGeometries::setPlasmaAvailableScreenRegion(const QString &screenName, const QRegion ®ion) { QDBusMessage message = QDBusMessage::createMethodCall(PLASMASERVICE, "/StrutManager", PLASMASTRUTNAMESPACE, "setAvailableScreenRegion"); QVariant regionvariant; QList rects; if (!region.isNull()) { //! transorm QRegion to QList in order to be sent through dbus foreach (const QRect &rect, region) { rects << rect; } } else { rects << QRect(); } regionvariant = QVariant::fromValue(rects); QVariantList args; args << LATTESERVICE << screenName << regionvariant; message.setArguments(args); QDBusConnection::sessionBus().call(message, QDBus::NoBlock); } void ScreenGeometries::clearGeometries() { if (!m_plasmaInterfaceAvailable) { return; } for (QScreen *screen : qGuiApp->screens()) { QString scrName = screen->name(); int scrId = m_corona->screenPool()->id(screen->name()); if (m_corona->screenPool()->hasScreenId(scrId)) { setPlasmaAvailableScreenRect(scrName, QRect()); setPlasmaAvailableScreenRegion(scrName, QRegion()); } } m_lastAvailableRect.clear(); m_lastAvailableRegion.clear(); } void ScreenGeometries::updateGeometries() { if (!m_plasmaInterfaceAvailable || !m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma()) { return; } QStringList availableScreenNames; qDebug() << " PLASMA SCREEN GEOMETRIES, LAST AVAILABLE SCREEN RECTS :: " << m_lastAvailableRect; QStringList clearedScreenNames; //! check for available geometries changes for (QScreen *screen : qGuiApp->screens()) { QString scrName = screen->name(); int scrId = m_corona->screenPool()->id(screen->name()); qDebug() << " PLASMA SCREEN GEOMETRIES, SCREEN :: " << scrId << " - " << scrName; if (m_corona->screenPool()->hasScreenId(scrId)) { QRect availableRect = m_corona->availableScreenRectWithCriteria(scrId, QString(), m_ignoreModes, QList(), true, true); QRegion availableRegion = m_corona->availableScreenRegionWithCriteria(scrId, QString(), m_ignoreModes, QList(), true, true); bool clearedScreen = (availableRect == screen->geometry()); if (!clearedScreen) { //! Disable checks because of the workaround concerning plasma desktop behavior if (!m_lastAvailableRect.contains(scrName) || m_lastAvailableRect[scrName] != availableRect) { m_lastAvailableRect[scrName] = availableRect; setPlasmaAvailableScreenRect(scrName, availableRect); qDebug() << " PLASMA SCREEN GEOMETRIES, AVAILABLE RECT :: " << screen->name() << " : " << availableRect; } if (!m_lastAvailableRegion.contains(scrName) || m_lastAvailableRegion[scrName] != availableRegion) { m_lastAvailableRegion[scrName] = availableRegion; setPlasmaAvailableScreenRegion(scrName, availableRegion); qDebug() << " PLASMA SCREEN GEOMETRIES, AVAILABLE REGION :: " << screen->name() << " : " << availableRegion; } } else { clearedScreenNames << scrName; } } availableScreenNames << scrName; } //! check for inactive screens that were published previously for (QString &lastScrName : m_lastScreenNames) { bool scractive = screenIsActive(lastScrName); if (!scractive || clearedScreenNames.contains(lastScrName)) { //! screen became inactive and its geometries could be unpublished setPlasmaAvailableScreenRect(lastScrName, QRect()); setPlasmaAvailableScreenRegion(lastScrName, QRegion()); m_lastAvailableRect.remove(lastScrName); m_lastAvailableRegion.remove(lastScrName); } if (!scractive) { qDebug() << " PLASMA SCREEN GEOMETRIES, INACTIVE SCREEN :: " << lastScrName; } else if (clearedScreenNames.contains(lastScrName)) { qDebug() << " PLASMA SCREEN GEOMETRIES, CLEARED SCREEN :: " << lastScrName; } } m_lastScreenNames = availableScreenNames; } void ScreenGeometries::availableScreenGeometryChangedFrom(Latte::View *origin) { if (m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma() && origin && origin->layout() && origin->layout()->isCurrent()) { m_publishTimer.start(); } } } }