File indexing completed on 2024-03-24 05:33:49

0001 /*
0002     SPDX-FileCopyrightText: 2020 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "screengeometries.h"
0007 
0008 //!local
0009 #include "../../lattecorona.h"
0010 #include "../../screenpool.h"
0011 #include "../../view/view.h"
0012 #include "../../layout/genericlayout.h"
0013 #include "../../layouts/manager.h"
0014 #include "../../settings/universalsettings.h"
0015 
0016 // Qt
0017 #include <QDebug>
0018 #include <QtDBus>
0019 
0020 
0021 #define LATTESERVICE "org.kde.lattedock"
0022 #define PLASMASERVICE "org.kde.plasmashell"
0023 #define PLASMASTRUTNAMESPACE "org.kde.PlasmaShell.StrutManager"
0024 
0025 #define PUBLISHINTERVAL 1000
0026 
0027 namespace Latte {
0028 namespace PlasmaExtended {
0029 
0030 ScreenGeometries::ScreenGeometries(Latte::Corona *parent)
0031     : QObject(parent),
0032       m_corona(parent),
0033       m_plasmaServiceWatcher(new QDBusServiceWatcher(this))
0034 {
0035     qDBusRegisterMetaType<QList<QRect>>();
0036 
0037     m_startupInitTimer.setInterval(2500);
0038     m_startupInitTimer.setSingleShot(true);
0039     connect(&m_startupInitTimer, &QTimer::timeout, this, &ScreenGeometries::init);
0040 
0041     m_publishTimer.setInterval(PUBLISHINTERVAL);
0042     m_publishTimer.setSingleShot(true);
0043     connect(&m_publishTimer, &QTimer::timeout, this, &ScreenGeometries::updateGeometries);
0044 
0045     m_startupInitTimer.start();
0046 
0047     m_plasmaServiceWatcher->setConnection(QDBusConnection::sessionBus());
0048     m_plasmaServiceWatcher->setWatchedServices(QStringList({PLASMASERVICE}));
0049     connect(m_plasmaServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString & serviceName) {
0050         if (serviceName == PLASMASERVICE && !m_plasmaInterfaceAvailable) {
0051             init();
0052         }
0053     });
0054 }
0055 
0056 ScreenGeometries::~ScreenGeometries()
0057 {
0058     qDebug() << "Plasma Extended Screen Geometries :: Deleted...";
0059 }
0060 
0061 void ScreenGeometries::init()
0062 {
0063     qDebug() << " PLASMA STRUTS MANAGER :: checking availability....";
0064     bool serviceavailable{false};
0065 
0066     if (QDBusConnection::sessionBus().interface()) {
0067         serviceavailable = QDBusConnection::sessionBus().interface()->isServiceRegistered(PLASMASERVICE).value();
0068         qDebug() << "PLASMA STRUTS MANAGER :: interface availability :: " << QDBusConnection::sessionBus().interface()->isServiceRegistered(PLASMASERVICE).value();
0069     }
0070 
0071     connect(m_corona->universalSettings(), &Latte::UniversalSettings::isAvailableGeometryBroadcastedToPlasmaChanged, this, &ScreenGeometries::onBroadcastToPlasmaChanged);
0072 
0073     if (serviceavailable) {
0074         m_plasmaInterfaceAvailable = true;
0075 
0076         qDebug() << " PLASMA STRUTS MANAGER :: is available...";
0077 
0078         connect(m_corona, &Latte::Corona::availableScreenRectChangedFrom, this, &ScreenGeometries::availableScreenGeometryChangedFrom);
0079         connect(m_corona, &Latte::Corona::availableScreenRegionChangedFrom, this, &ScreenGeometries::availableScreenGeometryChangedFrom);
0080 
0081         connect(m_corona->layoutsManager()->synchronizer(), &Latte::Layouts::Synchronizer::centralLayoutsChanged, this, [&]() {
0082             m_publishTimer.start();
0083         });
0084 
0085         connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() {
0086             if (m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma()) {
0087                 m_publishTimer.start();
0088             }
0089         });
0090 
0091         if (m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma()) {
0092             m_publishTimer.start();
0093         }
0094     }
0095 }
0096 
0097 bool ScreenGeometries::screenIsActive(const QString &screenName) const
0098 {
0099     for (QScreen *screen : qGuiApp->screens()) {
0100         if (screen->name() == screenName) {
0101             return true;
0102         }
0103     }
0104 
0105     return false;
0106 }
0107 
0108 void ScreenGeometries::onBroadcastToPlasmaChanged()
0109 {
0110     if (m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma()) {
0111         m_publishTimer.start();
0112     } else {
0113         clearGeometries();
0114     }
0115 }
0116 
0117 void ScreenGeometries::setPlasmaAvailableScreenRect(const QString &screenName, const QRect &rect)
0118 {
0119     QDBusMessage message = QDBusMessage::createMethodCall(PLASMASERVICE,
0120                                                           "/StrutManager",
0121                                                           PLASMASTRUTNAMESPACE,
0122                                                           "setAvailableScreenRect");
0123     QVariantList args;
0124 
0125     args << LATTESERVICE
0126          << screenName
0127          << rect;
0128 
0129     message.setArguments(args);
0130     QDBusConnection::sessionBus().call(message, QDBus::NoBlock);
0131 }
0132 
0133 void ScreenGeometries::setPlasmaAvailableScreenRegion(const QString &screenName, const QRegion &region)
0134 {
0135     QDBusMessage message = QDBusMessage::createMethodCall(PLASMASERVICE,
0136                                                           "/StrutManager",
0137                                                           PLASMASTRUTNAMESPACE,
0138                                                           "setAvailableScreenRegion");
0139 
0140     QVariant regionvariant;
0141 
0142     QList<QRect> rects;
0143     if (!region.isNull()) {
0144         //! transorm QRegion to QList<QRect> in order to be sent through dbus
0145         foreach (const QRect &rect, region) {
0146             rects << rect;
0147         }
0148     } else {
0149         rects << QRect();
0150     }
0151     regionvariant = QVariant::fromValue(rects);
0152 
0153     QVariantList args;
0154 
0155     args << LATTESERVICE
0156          << screenName
0157          << regionvariant;
0158 
0159     message.setArguments(args);
0160     QDBusConnection::sessionBus().call(message, QDBus::NoBlock);
0161 }
0162 
0163 void ScreenGeometries::clearGeometries()
0164 {
0165     if (!m_plasmaInterfaceAvailable) {
0166         return;
0167     }
0168 
0169     for (QScreen *screen : qGuiApp->screens()) {
0170         QString scrName = screen->name();
0171         int scrId = m_corona->screenPool()->id(screen->name());
0172 
0173         if (m_corona->screenPool()->hasScreenId(scrId)) {
0174             setPlasmaAvailableScreenRect(scrName, QRect());
0175             setPlasmaAvailableScreenRegion(scrName, QRegion());
0176         }
0177     }
0178 
0179     m_lastAvailableRect.clear();
0180     m_lastAvailableRegion.clear();
0181 }
0182 
0183 void ScreenGeometries::updateGeometries()
0184 {
0185     if (!m_plasmaInterfaceAvailable || !m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma()) {
0186         return;
0187     }
0188 
0189     QStringList availableScreenNames;
0190 
0191     qDebug() << " PLASMA SCREEN GEOMETRIES, LAST AVAILABLE SCREEN RECTS :: " << m_lastAvailableRect;
0192 
0193     QStringList clearedScreenNames;
0194 
0195     //! check for available geometries changes
0196     for (QScreen *screen : qGuiApp->screens()) {
0197         QString scrName = screen->name();
0198         int scrId = m_corona->screenPool()->id(screen->name());
0199 
0200         qDebug() << " PLASMA SCREEN GEOMETRIES, SCREEN :: " << scrId << " - " << scrName;
0201 
0202         if (m_corona->screenPool()->hasScreenId(scrId)) {
0203             QRect availableRect = m_corona->availableScreenRectWithCriteria(scrId,
0204                                                                             QString(),
0205                                                                             m_ignoreModes,
0206                                                                             QList<Plasma::Types::Location>(),
0207                                                                             true,
0208                                                                             true);
0209 
0210             QRegion availableRegion = m_corona->availableScreenRegionWithCriteria(scrId,
0211                                                                                   QString(),
0212                                                                                   m_ignoreModes,
0213                                                                                   QList<Plasma::Types::Location>(),
0214                                                                                   true,
0215                                                                                   true);
0216 
0217             bool clearedScreen = (availableRect == screen->geometry());
0218 
0219             if (!clearedScreen) {
0220                 //! Disable checks because of the workaround concerning plasma desktop behavior
0221                 if (!m_lastAvailableRect.contains(scrName) || m_lastAvailableRect[scrName] != availableRect) {
0222                     m_lastAvailableRect[scrName] = availableRect;
0223                     setPlasmaAvailableScreenRect(scrName, availableRect);
0224                     qDebug() << " PLASMA SCREEN GEOMETRIES, AVAILABLE RECT :: " << screen->name() << " : " << availableRect;
0225                 }
0226 
0227                 if (!m_lastAvailableRegion.contains(scrName) || m_lastAvailableRegion[scrName] != availableRegion) {
0228                     m_lastAvailableRegion[scrName] = availableRegion;
0229                     setPlasmaAvailableScreenRegion(scrName, availableRegion);
0230                     qDebug() << " PLASMA SCREEN GEOMETRIES, AVAILABLE REGION :: " << screen->name() << " : " << availableRegion;
0231                 }
0232             } else {
0233                 clearedScreenNames << scrName;
0234             }
0235         }
0236 
0237         availableScreenNames << scrName;
0238     }
0239 
0240     //! check for inactive screens that were published previously
0241     for (QString &lastScrName : m_lastScreenNames) {
0242         bool scractive = screenIsActive(lastScrName);
0243 
0244         if (!scractive || clearedScreenNames.contains(lastScrName)) {
0245             //! screen became inactive and its geometries could be unpublished
0246             setPlasmaAvailableScreenRect(lastScrName, QRect());
0247             setPlasmaAvailableScreenRegion(lastScrName, QRegion());
0248 
0249             m_lastAvailableRect.remove(lastScrName);
0250             m_lastAvailableRegion.remove(lastScrName);
0251         }
0252 
0253         if (!scractive) {
0254             qDebug() << " PLASMA SCREEN GEOMETRIES, INACTIVE SCREEN :: " << lastScrName;
0255         } else if (clearedScreenNames.contains(lastScrName)) {
0256             qDebug() << " PLASMA SCREEN GEOMETRIES, CLEARED SCREEN :: " << lastScrName;
0257         }
0258     }
0259 
0260     m_lastScreenNames = availableScreenNames;
0261 }
0262 
0263 void ScreenGeometries::availableScreenGeometryChangedFrom(Latte::View *origin)
0264 {
0265     if (m_corona->universalSettings()->isAvailableGeometryBroadcastedToPlasma() &&  origin && origin->layout() && origin->layout()->isCurrent()) {
0266         m_publishTimer.start();
0267     }
0268 }
0269 
0270 }
0271 }