File indexing completed on 2024-04-21 16:17:15

0001 /*
0002 *  Copyright 2019  Michail Vourlakos <mvourlakos@gmail.com>
0003 *
0004 *  This file is part of Latte-Dock
0005 *
0006 *  Latte-Dock is free software; you can redistribute it and/or
0007 *  modify it under the terms of the GNU General Public License as
0008 *  published by the Free Software Foundation; either version 2 of
0009 *  the License, or (at your option) any later version.
0010 *
0011 *  Latte-Dock is distributed in the hope that it will be useful,
0012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 *  GNU General Public License for more details.
0015 *
0016 *  You should have received a copy of the GNU General Public License
0017 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018 */
0019 
0020 #include "containmentinterface.h"
0021 
0022 // local
0023 #include "view.h"
0024 #include "../lattecorona.h"
0025 #include "../settings/universalsettings.h"
0026 
0027 // Qt
0028 #include <QDebug>
0029 
0030 // Plasma
0031 #include <Plasma/Applet>
0032 #include <Plasma/Containment>
0033 
0034 // KDE
0035 #include <KLocalizedString>
0036 #include <KPluginMetaData>
0037 
0038 namespace Latte {
0039 namespace ViewPart {
0040 
0041 ContainmentInterface::ContainmentInterface(Latte::View *parent)
0042     : QObject(parent),
0043       m_view(parent)
0044 {
0045     m_corona = qobject_cast<Latte::Corona *>(m_view->corona());
0046 }
0047 
0048 ContainmentInterface::~ContainmentInterface()
0049 {
0050 }
0051 
0052 void ContainmentInterface::identifyMainItem()
0053 {
0054     if (m_mainItem) {
0055         return;
0056     }
0057 
0058     if (QQuickItem *graphicItem = m_view->containment()->property("_plasma_graphicObject").value<QQuickItem *>()) {
0059         const auto &childItems = graphicItem->childItems();
0060 
0061         for (QQuickItem *item : childItems) {
0062             if (item->objectName() == "containmentViewLayout" ) {
0063                 m_mainItem = item;
0064                 identifyMethods();
0065                 return;
0066             }
0067         }
0068     }
0069 }
0070 
0071 void ContainmentInterface::identifyMethods()
0072 {
0073     int aeIndex = m_mainItem->metaObject()->indexOfMethod("activateEntryAtIndex(QVariant)");
0074     int niIndex = m_mainItem->metaObject()->indexOfMethod("newInstanceForEntryAtIndex(QVariant)");
0075     int sbIndex = m_mainItem->metaObject()->indexOfMethod("setShowAppletShortcutBadges(QVariant,QVariant,QVariant,QVariant)");
0076     int afiIndex = m_mainItem->metaObject()->indexOfMethod("appletIdForIndex(QVariant)");
0077 
0078     m_activateEntryMethod = m_mainItem->metaObject()->method(aeIndex);
0079     m_appletIdForIndexMethod = m_mainItem->metaObject()->method(afiIndex);
0080     m_newInstanceMethod = m_mainItem->metaObject()->method(niIndex);
0081     m_showShortcutsMethod = m_mainItem->metaObject()->method(sbIndex);
0082 }
0083 
0084 bool ContainmentInterface::applicationLauncherHasGlobalShortcut() const
0085 {
0086     if (!containsApplicationLauncher()) {
0087         return false;
0088     }
0089 
0090     int launcherAppletId = applicationLauncherId();
0091 
0092     const auto applets = m_view->containment()->applets();
0093 
0094     for (auto applet : applets) {
0095         if (applet->id() == launcherAppletId) {
0096             return !applet->globalShortcut().isEmpty();
0097         }
0098     }
0099 
0100     return false;
0101 }
0102 
0103 bool ContainmentInterface::applicationLauncherInPopup() const
0104 {
0105     if (!containsApplicationLauncher()) {
0106         return false;
0107     }
0108 
0109     int launcherAppletId = applicationLauncherId();
0110     QString launcherPluginId;
0111 
0112     const auto applets = m_view->containment()->applets();
0113 
0114     for (auto applet : applets) {
0115         if (applet->id() == launcherAppletId) {
0116             launcherPluginId = applet->kPackage().metadata().pluginId();
0117         }
0118     }
0119 
0120     return launcherPluginId != "org.kde.plasma.kickerdash";
0121 }
0122 
0123 bool ContainmentInterface::containsApplicationLauncher() const
0124 {
0125     return (applicationLauncherId() >= 0);
0126 }
0127 
0128 bool ContainmentInterface::isCapableToShowShortcutBadges()
0129 {
0130     identifyMainItem();
0131 
0132     if (!m_view->latteTasksArePresent() && m_view->tasksPresent()) {
0133         return false;
0134     }
0135 
0136     return m_showShortcutsMethod.isValid();
0137 }
0138 
0139 int ContainmentInterface::applicationLauncherId() const
0140 {
0141     const auto applets = m_view->containment()->applets();
0142 
0143     auto launcherId{-1};
0144 
0145     for (auto applet : applets) {
0146         const auto provides = applet->kPackage().metadata().value(QStringLiteral("X-Plasma-Provides"));
0147 
0148         if (provides.contains(QLatin1String("org.kde.plasma.launchermenu"))) {
0149             if (!applet->globalShortcut().isEmpty()) {
0150                 return applet->id();
0151             } else if (launcherId == -1) {
0152                 launcherId = applet->id();
0153             }
0154         }
0155     }
0156 
0157     return launcherId;
0158 }
0159 
0160 bool ContainmentInterface::updateBadgeForLatteTask(const QString identifier, const QString value)
0161 {
0162     if (!m_view->latteTasksArePresent()) {
0163         return false;
0164     }
0165 
0166     const auto &applets = m_view->containment()->applets();
0167 
0168     for (auto *applet : applets) {
0169         KPluginMetaData meta = applet->kPackage().metadata();
0170 
0171         if (meta.pluginId() == "org.kde.latte.plasmoid") {
0172 
0173             if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value<QQuickItem *>()) {
0174                 const auto &childItems = appletInterface->childItems();
0175 
0176                 if (childItems.isEmpty()) {
0177                     continue;
0178                 }
0179 
0180                 for (QQuickItem *item : childItems) {
0181                     if (auto *metaObject = item->metaObject()) {
0182                         // not using QMetaObject::invokeMethod to avoid warnings when calling
0183                         // this on applets that don't have it or other child items since this
0184                         // is pretty much trial and error.
0185                         // Also, "var" arguments are treated as QVariant in QMetaObject
0186 
0187                         int methodIndex = metaObject->indexOfMethod("updateBadge(QVariant,QVariant)");
0188 
0189                         if (methodIndex == -1) {
0190                             continue;
0191                         }
0192 
0193                         QMetaMethod method = metaObject->method(methodIndex);
0194 
0195                         if (method.invoke(item, Q_ARG(QVariant, identifier), Q_ARG(QVariant, value))) {
0196                             return true;
0197                         }
0198                     }
0199                 }
0200             }
0201         }
0202     }
0203 
0204     return false;
0205 }
0206 
0207 bool ContainmentInterface::activatePlasmaTask(const int index)
0208 {
0209     bool containsPlasmaTaskManager{m_view->tasksPresent() && !m_view->latteTasksArePresent()};
0210 
0211     if (!containsPlasmaTaskManager) {
0212         return false;
0213     }
0214 
0215     const auto &applets = m_view->containment()->applets();
0216 
0217     for (auto *applet : applets) {
0218         const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides"));
0219 
0220         if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) {
0221             if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value<QQuickItem *>()) {
0222                 const auto &childItems = appletInterface->childItems();
0223 
0224                 if (childItems.isEmpty()) {
0225                     continue;
0226                 }
0227 
0228                 KPluginMetaData meta = applet->kPackage().metadata();
0229 
0230                 for (QQuickItem *item : childItems) {
0231                     if (auto *metaObject = item->metaObject()) {
0232                         int methodIndex{metaObject->indexOfMethod("activateTaskAtIndex(QVariant)")};
0233 
0234                         if (methodIndex == -1) {
0235                             continue;
0236                         }
0237 
0238                         QMetaMethod method = metaObject->method(methodIndex);
0239 
0240                         if (method.invoke(item, Q_ARG(QVariant, index - 1))) {
0241                             showShortcutBadges(false, true);
0242 
0243                             return true;
0244                         }
0245                     }
0246                 }
0247             }
0248         }
0249     }
0250 
0251     return false;
0252 }
0253 
0254 bool ContainmentInterface::newInstanceForPlasmaTask(const int index)
0255 {
0256     bool containsPlasmaTaskManager{m_view->tasksPresent() && !m_view->latteTasksArePresent()};
0257 
0258     if (!containsPlasmaTaskManager) {
0259         return false;
0260     }
0261 
0262     const auto &applets = m_view->containment()->applets();
0263 
0264     for (auto *applet : applets) {
0265         const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides"));
0266 
0267         if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) {
0268             if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value<QQuickItem *>()) {
0269                 const auto &childItems = appletInterface->childItems();
0270 
0271                 if (childItems.isEmpty()) {
0272                     continue;
0273                 }
0274 
0275                 KPluginMetaData meta = applet->kPackage().metadata();
0276 
0277                 for (QQuickItem *item : childItems) {
0278                     if (auto *metaObject = item->metaObject()) {
0279                         int methodIndex{metaObject->indexOfMethod("ewInstanceForTaskAtIndex(QVariant)")};
0280 
0281                         if (methodIndex == -1) {
0282                             continue;
0283                         }
0284 
0285                         QMetaMethod method = metaObject->method(methodIndex);
0286 
0287                         if (method.invoke(item, Q_ARG(QVariant, index - 1))) {
0288                             showShortcutBadges(false, true);
0289 
0290                             return true;
0291                         }
0292                     }
0293                 }
0294             }
0295         }
0296     }
0297 
0298     return false;
0299 }
0300 
0301 bool ContainmentInterface::activateEntry(const int index)
0302 {
0303     identifyMainItem();
0304 
0305     if (!m_activateEntryMethod.isValid()) {
0306         return false;
0307     }
0308 
0309     return m_activateEntryMethod.invoke(m_mainItem, Q_ARG(QVariant, index));
0310 }
0311 
0312 bool ContainmentInterface::newInstanceForEntry(const int index)
0313 {
0314     identifyMainItem();
0315 
0316     if (!m_newInstanceMethod.isValid()) {
0317         return false;
0318     }
0319 
0320     return m_newInstanceMethod.invoke(m_mainItem, Q_ARG(QVariant, index));
0321 }
0322 
0323 bool ContainmentInterface::hideShortcutBadges()
0324 {
0325     identifyMainItem();
0326 
0327     if (!m_showShortcutsMethod.isValid()) {
0328         return false;
0329     }
0330 
0331     return m_showShortcutsMethod.invoke(m_mainItem, Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, -1));
0332 }
0333 
0334 bool ContainmentInterface::showOnlyMeta()
0335 {
0336     if (!m_corona->universalSettings()->kwin_metaForwardedToLatte()) {
0337         return false;
0338     }
0339 
0340     return showShortcutBadges(false, true);
0341 }
0342 
0343 bool ContainmentInterface::showShortcutBadges(const bool showLatteShortcuts, const bool showMeta)
0344 {
0345     identifyMainItem();
0346 
0347     if (!m_showShortcutsMethod.isValid()) {
0348         return false;
0349     }
0350 
0351     int appLauncherId = m_corona->universalSettings()->kwin_metaForwardedToLatte() && showMeta ? applicationLauncherId() : -1;
0352 
0353     return m_showShortcutsMethod.invoke(m_mainItem, Q_ARG(QVariant, showLatteShortcuts), Q_ARG(QVariant, true), Q_ARG(QVariant, showMeta), Q_ARG(QVariant, appLauncherId));
0354 }
0355 
0356 int ContainmentInterface::appletIdForIndex(const int index)
0357 {
0358     identifyMainItem();
0359 
0360     if (!m_appletIdForIndexMethod.isValid()) {
0361         return false;
0362     }
0363 
0364     QVariant appletId{-1};
0365 
0366     m_appletIdForIndexMethod.invoke(m_mainItem, Q_RETURN_ARG(QVariant, appletId), Q_ARG(QVariant, index));
0367 
0368     return appletId.toInt();
0369 }
0370 
0371 
0372 }
0373 }