File indexing completed on 2023-10-01 04:11:42
0001 /* 0002 SPDX-FileCopyrightText: 2005 Aaron Seigo <aseigo@kde.org> 0003 SPDX-FileCopyrightText: 2007 Riccardo Iaconelli <riccardo@kde.org> 0004 SPDX-FileCopyrightText: 2008 Ménard Alexis <darktears31@gmail.com> 0005 SPDX-FileCopyrightText: 2009 Chani Armitage <chani@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "applet.h" 0011 #include "private/applet_p.h" 0012 0013 #include "config-plasma.h" 0014 0015 #include <QAbstractButton> 0016 #include <QDebug> 0017 #include <QFile> 0018 #include <QList> 0019 #include <QMessageBox> 0020 #include <QMetaEnum> 0021 0022 #include <KActionCollection> 0023 #include <KAuthorized> 0024 #include <KColorScheme> 0025 #include <KConfigLoader> 0026 #include <KDesktopFile> 0027 #include <KGlobalAccel> 0028 #include <KLocalizedString> 0029 #include <KPackage/Package> 0030 #include <KService> 0031 0032 #include "containment.h" 0033 #include "corona.h" 0034 #include "package.h" 0035 #include "plasma.h" 0036 #include "pluginloader.h" 0037 #include "scripting/appletscript.h" 0038 0039 #include "debug_p.h" 0040 #include "private/associatedapplicationmanager_p.h" 0041 #include "private/containment_p.h" 0042 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0043 #include "private/package_p.h" 0044 #endif 0045 0046 #include <cmath> 0047 #include <limits> 0048 0049 namespace Plasma 0050 { 0051 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86) 0052 static KPluginMetaData appletMetadataForDirectory(const QString &path) 0053 { 0054 return QFile::exists(path + QLatin1String("/metadata.json")) 0055 ? KPluginMetaData(path + QLatin1String("/metadata.json")) 0056 : KPluginMetaData::fromDesktopFile(path + QLatin1String("/metadata.desktop"), {QStringLiteral("plasma-applet.desktop")}); 0057 } 0058 0059 Applet::Applet(const KPluginMetaData &info, QObject *parent, uint appletId) 0060 : QObject(parent) 0061 , d(new AppletPrivate(info, appletId, this)) 0062 { 0063 qCDebug(LOG_PLASMA) << " From KPluginMetaData, valid? " << info.isValid(); 0064 // WARNING: do not access config() OR globalConfig() in this method! 0065 // that requires a scene, which is not available at this point 0066 d->init(); 0067 d->setupPackage(); 0068 } 0069 0070 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 28) 0071 Applet::Applet(const KPluginInfo &info, QObject *parent, uint appletId) 0072 : Applet(info.toMetaData(), parent, appletId) 0073 { 0074 } 0075 #endif 0076 0077 Applet::Applet(QObject *parent, const QString &serviceID, uint appletId) 0078 : QObject(parent) 0079 , d(new AppletPrivate(KPluginMetaData(serviceID), appletId, this)) 0080 { 0081 // WARNING: do not access config() OR globalConfig() in this method! 0082 // that requires a scene, which is not available at this point 0083 d->init(); 0084 d->setupPackage(); 0085 } 0086 0087 Applet::Applet(QObject *parentObject, const QVariantList &args) 0088 : QObject(nullptr) 0089 , d(new AppletPrivate(KPluginMetaData(), args.count() > 2 ? args[2].toInt() : 0, this)) 0090 { 0091 setParent(parentObject); 0092 if (!args.isEmpty()) { 0093 const QVariant first = args.first(); 0094 if (first.canConvert<KPackage::Package>()) { 0095 d->package = first.value<KPackage::Package>(); 0096 } 0097 } 0098 if (args.count() > 1) { 0099 const QVariant second = args[1]; 0100 if (second.canConvert<QString>()) { 0101 d->appletDescription = KPluginMetaData(second.toString()); 0102 } else if (second.canConvert<QVariantMap>()) { 0103 auto metadata = second.toMap().value(QStringLiteral("MetaData")).toMap(); 0104 d->appletDescription = KPluginMetaData(QJsonObject::fromVariantMap(metadata), {}); 0105 } 0106 } 0107 d->icon = d->appletDescription.iconName(); 0108 0109 if (args.contains(QVariant::fromValue(QStringLiteral("org.kde.plasma:force-create")))) { 0110 setProperty("org.kde.plasma:force-create", true); 0111 } 0112 0113 // WARNING: do not access config() OR globalConfig() in this method! 0114 // that requires a scene, which is not available at this point 0115 d->init(QString(), args.mid(3)); 0116 d->setupPackage(); 0117 } 0118 0119 Applet::Applet(const QString &packagePath, uint appletId) 0120 : QObject(nullptr) 0121 , d(new AppletPrivate(appletMetadataForDirectory(packagePath), appletId, this)) 0122 { 0123 d->init(packagePath); 0124 d->setupPackage(); 0125 } 0126 #endif 0127 0128 Applet::Applet(QObject *parentObject, const KPluginMetaData &data, const QVariantList &args) 0129 : QObject(nullptr) 0130 , d(new AppletPrivate(data, args.count() > 2 ? args[2].toInt() : 0, this)) 0131 { 0132 setParent(parentObject); 0133 if (!args.isEmpty()) { 0134 const QVariant first = args.first(); 0135 if (first.canConvert<KPackage::Package>()) { 0136 d->package = first.value<KPackage::Package>(); 0137 } 0138 } 0139 d->icon = d->appletDescription.iconName(); 0140 0141 if (args.contains(QVariant::fromValue(QStringLiteral("org.kde.plasma:force-create")))) { 0142 setProperty("org.kde.plasma:force-create", true); 0143 } 0144 0145 // WARNING: do not access config() OR globalConfig() in this method! 0146 // that requires a scene, which is not available at this point 0147 d->init(QString(), args.mid(3)); 0148 d->setupPackage(); 0149 } 0150 0151 Applet::~Applet() 0152 { 0153 if (d->transient) { 0154 d->resetConfigurationObject(); 0155 } 0156 // let people know that i will die 0157 Q_EMIT appletDeleted(this); 0158 0159 // ConfigLoader is deleted when AppletPrivate closes not Applet 0160 // It saves on closure and emits a signal. 0161 // disconnect early to avoid a crash. See 411221 0162 if (d->configLoader) { 0163 disconnect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged())); 0164 } 0165 delete d; 0166 } 0167 0168 void Applet::init() 0169 { 0170 // Don't implement anything here, it will be overridden by subclasses 0171 } 0172 0173 uint Applet::id() const 0174 { 0175 return d->appletId; 0176 } 0177 0178 void Applet::save(KConfigGroup &g) const 0179 { 0180 if (d->transient || !d->appletDescription.isValid()) { 0181 return; 0182 } 0183 0184 KConfigGroup group = g; 0185 if (!group.isValid()) { 0186 group = *d->mainConfigGroup(); 0187 } 0188 0189 // qCDebug(LOG_PLASMA) << "saving" << pluginName() << "to" << group.name(); 0190 // we call the dptr member directly for locked since isImmutable() 0191 // also checks kiosk and parent containers 0192 group.writeEntry("immutability", (int)d->immutability); 0193 group.writeEntry("plugin", d->appletDescription.pluginId()); 0194 0195 if (!d->started) { 0196 return; 0197 } 0198 0199 KConfigGroup appletConfigGroup(&group, "Configuration"); 0200 saveState(appletConfigGroup); 0201 0202 if (d->configLoader) { 0203 // we're saving so we know its changed, we don't need or want the configChanged 0204 // signal bubbling up at this point due to that 0205 disconnect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged())); 0206 d->configLoader->save(); 0207 connect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged())); 0208 } 0209 } 0210 0211 void Applet::restore(KConfigGroup &group) 0212 { 0213 setImmutability((Types::ImmutabilityType)group.readEntry("immutability", (int)Types::Mutable)); 0214 0215 KConfigGroup shortcutConfig(&group, "Shortcuts"); 0216 QString shortcutText = shortcutConfig.readEntryUntranslated("global", QString()); 0217 if (!shortcutText.isEmpty()) { 0218 setGlobalShortcut(QKeySequence(shortcutText)); 0219 /* 0220 #ifndef NDEBUG 0221 // qCDebug(LOG_PLASMA) << "got global shortcut for" << name() << "of" << QKeySequence(shortcutText); 0222 #endif 0223 #ifndef NDEBUG 0224 // qCDebug(LOG_PLASMA) << "set to" << d->activationAction->objectName() 0225 #endif 0226 << d->activationAction->globalShortcut().primary(); 0227 */ 0228 } 0229 0230 // User background hints 0231 // TODO support flags in the config 0232 QByteArray hintsString = config().readEntry("UserBackgroundHints", QString()).toUtf8(); 0233 QMetaEnum hintEnum = QMetaEnum::fromType<Plasma::Types::BackgroundHints>(); 0234 bool ok; 0235 int value = hintEnum.keyToValue(hintsString.constData(), &ok); 0236 if (ok) { 0237 d->userBackgroundHints = Plasma::Types::BackgroundHints(value); 0238 d->userBackgroundHintsInitialized = true; 0239 Q_EMIT userBackgroundHintsChanged(); 0240 if (d->backgroundHints & Plasma::Types::ConfigurableBackground) { 0241 Q_EMIT effectiveBackgroundHintsChanged(); 0242 } 0243 } 0244 } 0245 0246 void Applet::setLaunchErrorMessage(const QString &message) 0247 { 0248 if (message == d->launchErrorMessage) { 0249 return; 0250 } 0251 0252 d->failed = true; 0253 d->launchErrorMessage = message; 0254 } 0255 0256 void Applet::saveState(KConfigGroup &group) const 0257 { 0258 if (d->script) { 0259 Q_EMIT d->script->saveState(group); 0260 } 0261 0262 if (group.config()->name() != config().config()->name()) { 0263 // we're being saved to a different file! 0264 // let's just copy the current values in our configuration over 0265 KConfigGroup c = config(); 0266 c.copyTo(&group); 0267 } 0268 } 0269 0270 KConfigGroup Applet::config() const 0271 { 0272 if (d->transient) { 0273 return KConfigGroup(KSharedConfig::openConfig(), "PlasmaTransientsConfig"); 0274 } 0275 0276 if (isContainment()) { 0277 return *(d->mainConfigGroup()); 0278 } 0279 0280 return KConfigGroup(d->mainConfigGroup(), "Configuration"); 0281 } 0282 0283 KConfigGroup Applet::globalConfig() const 0284 { 0285 KConfigGroup globalAppletConfig; 0286 QString group = isContainment() ? QStringLiteral("ContainmentGlobals") : QStringLiteral("AppletGlobals"); 0287 0288 Containment *cont = containment(); 0289 Corona *corona = nullptr; 0290 if (cont) { 0291 corona = cont->corona(); 0292 } 0293 if (corona) { 0294 KSharedConfig::Ptr coronaConfig = corona->config(); 0295 globalAppletConfig = KConfigGroup(coronaConfig, group); 0296 } else { 0297 globalAppletConfig = KConfigGroup(KSharedConfig::openConfig(), group); 0298 } 0299 0300 return KConfigGroup(&globalAppletConfig, d->globalName()); 0301 } 0302 0303 void Applet::destroy() 0304 { 0305 if (immutability() != Types::Mutable || d->transient || !d->started) { 0306 return; // don't double delete 0307 } 0308 0309 d->setDestroyed(true); 0310 // FIXME: an animation on leave if !isContainment() would be good again .. which should be handled by the containment class 0311 d->cleanUpAndDelete(); 0312 } 0313 0314 bool Applet::destroyed() const 0315 { 0316 return d->transient; 0317 } 0318 0319 KConfigLoader *Applet::configScheme() const 0320 { 0321 if (!d->configLoader) { 0322 const QString xmlPath = d->package.isValid() ? d->package.filePath("mainconfigxml") : QString(); 0323 KConfigGroup cfg = config(); 0324 if (xmlPath.isEmpty()) { 0325 d->configLoader = new KConfigLoader(cfg, nullptr); 0326 } else { 0327 QFile file(xmlPath); 0328 d->configLoader = new KConfigLoader(cfg, &file); 0329 QObject::connect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged())); 0330 } 0331 } 0332 0333 return d->configLoader; 0334 } 0335 0336 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 6) 0337 Package Applet::package() const 0338 { 0339 Package p; 0340 p.d->internalPackage = new KPackage::Package(d->package); 0341 return p; 0342 } 0343 #endif 0344 0345 KPackage::Package Applet::kPackage() const 0346 { 0347 return d->package; 0348 } 0349 0350 void Applet::updateConstraints(Plasma::Types::Constraints constraints) 0351 { 0352 d->scheduleConstraintsUpdate(constraints); 0353 } 0354 0355 void Applet::constraintsEvent(Plasma::Types::Constraints constraints) 0356 { 0357 // NOTE: do NOT put any code in here that reacts to constraints updates 0358 // as it will not get called for any applet that reimplements constraintsEvent 0359 // without calling the Applet:: version as well, which it shouldn't need to. 0360 // INSTEAD put such code into flushPendingConstraintsEvents 0361 Q_UNUSED(constraints) 0362 // qCDebug(LOG_PLASMA) << constraints << "constraints are FormFactor: " << formFactor() 0363 // << ", Location: " << location(); 0364 if (d->script) { 0365 d->script->constraintsEvent(constraints); 0366 } 0367 } 0368 0369 QString Applet::title() const 0370 { 0371 if (!d->customTitle.isEmpty()) { 0372 return d->customTitle; 0373 } 0374 0375 if (d->appletDescription.isValid()) { 0376 return d->appletDescription.name(); 0377 } 0378 0379 return i18n("Unknown"); 0380 } 0381 0382 void Applet::setTitle(const QString &title) 0383 { 0384 if (title == d->customTitle) { 0385 return; 0386 } 0387 0388 d->customTitle = title; 0389 Q_EMIT titleChanged(title); 0390 } 0391 0392 QString Applet::icon() const 0393 { 0394 return d->icon; 0395 } 0396 0397 void Applet::setIcon(const QString &icon) 0398 { 0399 if (icon == d->icon) { 0400 return; 0401 } 0402 0403 d->icon = icon; 0404 Q_EMIT iconChanged(icon); 0405 } 0406 0407 bool Applet::isBusy() const 0408 { 0409 return d->busy; 0410 } 0411 0412 void Applet::setBusy(bool busy) 0413 { 0414 if (busy == d->busy) { 0415 return; 0416 } 0417 0418 d->busy = busy; 0419 Q_EMIT busyChanged(busy); 0420 } 0421 0422 Plasma::Types::BackgroundHints Applet::backgroundHints() const 0423 { 0424 return d->backgroundHints; 0425 } 0426 0427 void Applet::setBackgroundHints(Plasma::Types::BackgroundHints hint) 0428 { 0429 if (d->backgroundHints == hint) { 0430 return; 0431 } 0432 0433 Plasma::Types::BackgroundHints oldeffectiveHints = effectiveBackgroundHints(); 0434 0435 d->backgroundHints = hint; 0436 Q_EMIT backgroundHintsChanged(); 0437 0438 if (oldeffectiveHints != effectiveBackgroundHints()) { 0439 Q_EMIT effectiveBackgroundHintsChanged(); 0440 } 0441 } 0442 0443 Plasma::Types::BackgroundHints Applet::effectiveBackgroundHints() const 0444 { 0445 if (d->userBackgroundHintsInitialized && (d->backgroundHints & Plasma::Types::ConfigurableBackground)) { 0446 return d->userBackgroundHints; 0447 } else { 0448 return d->backgroundHints; 0449 } 0450 } 0451 0452 Plasma::Types::BackgroundHints Applet::userBackgroundHints() const 0453 { 0454 return d->userBackgroundHints; 0455 } 0456 0457 void Applet::setUserBackgroundHints(Plasma::Types::BackgroundHints hint) 0458 { 0459 if (d->userBackgroundHints == hint && d->userBackgroundHintsInitialized) { 0460 return; 0461 } 0462 0463 d->userBackgroundHints = hint; 0464 d->userBackgroundHintsInitialized = true; 0465 QMetaEnum hintEnum = QMetaEnum::fromType<Plasma::Types::BackgroundHints>(); 0466 config().writeEntry("UserBackgroundHints", hintEnum.valueToKey(d->userBackgroundHints)); 0467 if (containment() && containment()->corona()) { 0468 containment()->corona()->requestConfigSync(); 0469 } 0470 0471 Q_EMIT userBackgroundHintsChanged(); 0472 0473 if (d->backgroundHints & Plasma::Types::ConfigurableBackground) { 0474 Q_EMIT effectiveBackgroundHintsChanged(); 0475 } 0476 } 0477 0478 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 28) 0479 KPluginInfo Applet::pluginInfo() const 0480 { 0481 return KPluginInfo(d->appletDescription); 0482 } 0483 #endif 0484 0485 KPluginMetaData Applet::pluginMetaData() const 0486 { 0487 return d->appletDescription; 0488 } 0489 0490 Types::ImmutabilityType Applet::immutability() const 0491 { 0492 // if this object is itself system immutable, then just return that; it's the most 0493 // restrictive setting possible and will override anything that might be happening above it 0494 // in the Corona->Containment->Applet hierarchy 0495 if (d->transient || (d->mainConfig && d->mainConfig->isImmutable())) { 0496 return Types::SystemImmutable; 0497 } 0498 0499 // Returning the more strict immutability between the applet immutability, Containment and Corona 0500 Types::ImmutabilityType upperImmutability = Types::Mutable; 0501 0502 if (isContainment()) { 0503 Corona *cor = static_cast<Containment *>(const_cast<Applet *>(this))->corona(); 0504 if (cor) { 0505 upperImmutability = cor->immutability(); 0506 } 0507 } else { 0508 const Containment *cont = containment(); 0509 if (cont) { 0510 if (cont->corona()) { 0511 upperImmutability = cont->corona()->immutability(); 0512 } else { 0513 upperImmutability = cont->immutability(); 0514 } 0515 } 0516 } 0517 0518 if (upperImmutability != Types::Mutable) { 0519 // it's either system or user immutable, and we already check for local system immutability, 0520 // so upperImmutability is guaranteed to be as or more severe as this object's immutability 0521 return upperImmutability; 0522 } else { 0523 return d->immutability; 0524 } 0525 } 0526 0527 void Applet::setImmutability(const Types::ImmutabilityType immutable) 0528 { 0529 if (d->immutability == immutable || immutable == Types::SystemImmutable) { 0530 // we do not store system immutability in d->immutability since that gets saved 0531 // out to the config file; instead, we check with 0532 // the config group itself for this information at all times. this differs from 0533 // corona, where SystemImmutability is stored in d->immutability. 0534 return; 0535 } 0536 0537 d->immutability = immutable; 0538 updateConstraints(Types::ImmutableConstraint); 0539 } 0540 0541 QString Applet::launchErrorMessage() const 0542 { 0543 return d->launchErrorMessage; 0544 } 0545 0546 bool Applet::failedToLaunch() const 0547 { 0548 return d->failed; 0549 } 0550 0551 bool Applet::configurationRequired() const 0552 { 0553 return d->needsConfig; 0554 } 0555 0556 QString Applet::configurationRequiredReason() const 0557 { 0558 return d->configurationRequiredReason; 0559 } 0560 0561 void Applet::setConfigurationRequired(bool needsConfig, const QString &reason) 0562 { 0563 if (d->needsConfig == needsConfig && reason == d->configurationRequiredReason) { 0564 return; 0565 } 0566 0567 d->needsConfig = needsConfig; 0568 d->configurationRequiredReason = reason; 0569 0570 Q_EMIT configurationRequiredChanged(needsConfig, reason); 0571 } 0572 0573 bool Applet::isUserConfiguring() const 0574 { 0575 return d->userConfiguring; 0576 } 0577 0578 void Applet::setUserConfiguring(bool configuring) 0579 { 0580 if (configuring == d->userConfiguring) { 0581 return; 0582 } 0583 0584 d->userConfiguring = configuring; 0585 Q_EMIT userConfiguringChanged(configuring); 0586 } 0587 0588 Types::ItemStatus Applet::status() const 0589 { 0590 return d->itemStatus; 0591 } 0592 0593 void Applet::setStatus(const Types::ItemStatus status) 0594 { 0595 if (status == d->itemStatus) { 0596 return; 0597 } 0598 d->itemStatus = status; 0599 Q_EMIT statusChanged(status); 0600 } 0601 0602 void Applet::flushPendingConstraintsEvents() 0603 { 0604 if (d->pendingConstraints == Types::NoConstraint) { 0605 return; 0606 } 0607 0608 if (d->constraintsTimer.isActive()) { 0609 d->constraintsTimer.stop(); 0610 } 0611 0612 // qCDebug(LOG_PLASMA) << "flushing constraints: " << d->pendingConstraints << "!!!!!!!!!!!!!!!!!!!!!!!!!!!"; 0613 Plasma::Types::Constraints c = d->pendingConstraints; 0614 d->pendingConstraints = Types::NoConstraint; 0615 0616 if (c & Plasma::Types::UiReadyConstraint) { 0617 d->setUiReady(); 0618 } 0619 0620 if (c & Plasma::Types::StartupCompletedConstraint) { 0621 // common actions 0622 bool unlocked = immutability() == Types::Mutable; 0623 QAction *closeApplet = d->actions->action(QStringLiteral("remove")); 0624 if (closeApplet) { 0625 closeApplet->setEnabled(unlocked); 0626 closeApplet->setVisible(unlocked); 0627 connect(closeApplet, SIGNAL(triggered(bool)), this, SLOT(askDestroy()), Qt::UniqueConnection); 0628 } 0629 0630 QAction *configAction = d->actions->action(QStringLiteral("configure")); 0631 if (configAction) { 0632 if (d->hasConfigurationInterface) { 0633 bool canConfig = unlocked || KAuthorized::authorize(QStringLiteral("plasma/allow_configure_when_locked")); 0634 configAction->setVisible(canConfig); 0635 configAction->setEnabled(canConfig); 0636 } 0637 } 0638 0639 QAction *runAssociatedApplication = d->actions->action(QStringLiteral("run associated application")); 0640 if (runAssociatedApplication) { 0641 connect(runAssociatedApplication, &QAction::triggered, this, &Applet::runAssociatedApplication, Qt::UniqueConnection); 0642 } 0643 0644 d->updateShortcuts(); 0645 } 0646 0647 if (c & Plasma::Types::ImmutableConstraint) { 0648 bool unlocked = immutability() == Types::Mutable; 0649 QAction *action = d->actions->action(QStringLiteral("remove")); 0650 if (action) { 0651 action->setVisible(unlocked); 0652 action->setEnabled(unlocked); 0653 } 0654 0655 action = d->actions->action(QStringLiteral("configure")); 0656 if (action && d->hasConfigurationInterface) { 0657 bool canConfig = unlocked || KAuthorized::authorize(QStringLiteral("plasma/allow_configure_when_locked")); 0658 action->setVisible(canConfig); 0659 action->setEnabled(canConfig); 0660 } 0661 0662 // an immutable constraint will always happen at startup 0663 // make sure don't emit a change signal for nothing 0664 if (d->oldImmutability != immutability()) { 0665 Q_EMIT immutabilityChanged(immutability()); 0666 } 0667 d->oldImmutability = immutability(); 0668 } 0669 0670 // now take care of constraints in special subclass: Containment 0671 Containment *containment = qobject_cast<Plasma::Containment *>(this); 0672 if (containment) { 0673 containment->d->containmentConstraintsEvent(c); 0674 } 0675 0676 // pass the constraint on to the actual subclass 0677 constraintsEvent(c); 0678 0679 if (c & Types::StartupCompletedConstraint) { 0680 // start up is done, we can now go do a mod timer 0681 if (d->modificationsTimer) { 0682 if (d->modificationsTimer->isActive()) { 0683 d->modificationsTimer->stop(); 0684 } 0685 } else { 0686 d->modificationsTimer = new QBasicTimer; 0687 } 0688 } 0689 0690 if (c & Plasma::Types::FormFactorConstraint) { 0691 Q_EMIT formFactorChanged(formFactor()); 0692 } 0693 0694 if (c & Plasma::Types::LocationConstraint) { 0695 Q_EMIT locationChanged(location()); 0696 } 0697 } 0698 0699 QList<QAction *> Applet::contextualActions() 0700 { 0701 // qCDebug(LOG_PLASMA) << "empty context actions"; 0702 return d->script ? d->script->contextualActions() : QList<QAction *>(); 0703 } 0704 0705 KActionCollection *Applet::actions() const 0706 { 0707 return d->actions; 0708 } 0709 0710 Types::FormFactor Applet::formFactor() const 0711 { 0712 Containment *c = containment(); 0713 QObject *pw = qobject_cast<QObject *>(parent()); 0714 Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(pw); 0715 // assumption: this loop is usually is -really- short or doesn't run at all 0716 while (!parentApplet && pw && pw->parent()) { 0717 pw = pw->parent(); 0718 parentApplet = qobject_cast<Plasma::Applet *>(pw); 0719 } 0720 0721 return c ? c->d->formFactor : Plasma::Types::Planar; 0722 } 0723 0724 Types::ContainmentDisplayHints Applet::containmentDisplayHints() const 0725 { 0726 Containment *c = containment(); 0727 0728 return c ? c->d->containmentDisplayHints : Plasma::Types::NoContainmentDisplayHint; 0729 } 0730 0731 Containment *Applet::containment() const 0732 { 0733 Containment *c = qobject_cast<Containment *>(const_cast<Applet *>(this)); 0734 if (c && c->isContainment()) { 0735 return c; 0736 } else { 0737 c = nullptr; 0738 } 0739 0740 QObject *parent = this->parent(); 0741 0742 while (parent) { 0743 Containment *possibleC = qobject_cast<Containment *>(parent); 0744 0745 if (possibleC && possibleC->isContainment()) { 0746 c = possibleC; 0747 break; 0748 } 0749 parent = parent->parent(); 0750 } 0751 0752 return c; 0753 } 0754 0755 void Applet::setGlobalShortcut(const QKeySequence &shortcut) 0756 { 0757 if (!d->activationAction) { 0758 d->activationAction = new QAction(this); 0759 d->activationAction->setText(i18n("Activate %1 Widget", title())); 0760 d->activationAction->setObjectName(QStringLiteral("activate widget %1").arg(id())); // NO I18N 0761 connect(d->activationAction, &QAction::triggered, this, &Applet::activated); 0762 connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, [this](QAction *action, const QKeySequence &shortcut) { 0763 if (action == d->activationAction) { 0764 d->activationAction->setShortcut(shortcut); 0765 d->globalShortcutChanged(); 0766 } 0767 }); 0768 } else if (d->activationAction->shortcut() == shortcut) { 0769 return; 0770 } 0771 0772 d->activationAction->setShortcut(shortcut); 0773 d->globalShortcutEnabled = true; 0774 QList<QKeySequence> seqs{shortcut}; 0775 KGlobalAccel::self()->setShortcut(d->activationAction, seqs, KGlobalAccel::NoAutoloading); 0776 d->globalShortcutChanged(); 0777 } 0778 0779 QKeySequence Applet::globalShortcut() const 0780 { 0781 if (d->activationAction) { 0782 QList<QKeySequence> shortcuts = KGlobalAccel::self()->shortcut(d->activationAction); 0783 if (!shortcuts.isEmpty()) { 0784 return shortcuts.first(); 0785 } 0786 } 0787 0788 return QKeySequence(); 0789 } 0790 0791 Types::Location Applet::location() const 0792 { 0793 Containment *c = containment(); 0794 return c ? c->d->location : Plasma::Types::Desktop; 0795 } 0796 0797 bool Applet::hasConfigurationInterface() const 0798 { 0799 return d->hasConfigurationInterface; 0800 } 0801 0802 void Applet::setHasConfigurationInterface(bool hasInterface) 0803 { 0804 if (hasInterface == d->hasConfigurationInterface) { 0805 return; 0806 } 0807 0808 QAction *configAction = d->actions->action(QStringLiteral("configure")); 0809 if (configAction) { 0810 bool enable = hasInterface; 0811 if (enable) { 0812 const bool unlocked = immutability() == Types::Mutable; 0813 enable = unlocked || KAuthorized::authorize(QStringLiteral("plasma/allow_configure_when_locked")); 0814 } 0815 configAction->setEnabled(enable); 0816 } 0817 0818 d->hasConfigurationInterface = hasInterface; 0819 } 0820 0821 void Applet::configChanged() 0822 { 0823 if (d->script) { 0824 if (d->configLoader) { 0825 d->configLoader->load(); 0826 } 0827 d->script->configChanged(); 0828 } 0829 } 0830 0831 void Applet::setAssociatedApplication(const QString &string) 0832 { 0833 AssociatedApplicationManager::self()->setApplication(this, string); 0834 0835 QAction *runAssociatedApplication = d->actions->action(QStringLiteral("run associated application")); 0836 if (runAssociatedApplication) { 0837 bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this); 0838 runAssociatedApplication->setVisible(valid); 0839 runAssociatedApplication->setEnabled(valid); 0840 } 0841 } 0842 0843 void Applet::setAssociatedApplicationUrls(const QList<QUrl> &urls) 0844 { 0845 AssociatedApplicationManager::self()->setUrls(this, urls); 0846 0847 QAction *runAssociatedApplication = d->actions->action(QStringLiteral("run associated application")); 0848 if (runAssociatedApplication) { 0849 bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this); 0850 runAssociatedApplication->setVisible(valid); 0851 runAssociatedApplication->setEnabled(valid); 0852 } 0853 } 0854 0855 QString Applet::associatedApplication() const 0856 { 0857 return AssociatedApplicationManager::self()->application(this); 0858 } 0859 0860 QList<QUrl> Applet::associatedApplicationUrls() const 0861 { 0862 return AssociatedApplicationManager::self()->urls(this); 0863 } 0864 0865 void Applet::runAssociatedApplication() 0866 { 0867 AssociatedApplicationManager::self()->run(this); 0868 } 0869 0870 bool Applet::hasValidAssociatedApplication() const 0871 { 0872 return AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this); 0873 } 0874 0875 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 19) 0876 Applet *Applet::loadPlasmoid(const QString &path, uint appletId) 0877 { 0878 const KPluginMetaData md = appletMetadataForDirectory(path); 0879 if (md.isValid()) { 0880 QStringList types = md.serviceTypes(); 0881 0882 if (types.contains(QLatin1String("Plasma/Containment")) || md.rawData().contains(QStringLiteral("X-Plasma-ContainmentType"))) { 0883 return new Containment(md, appletId); 0884 } else { 0885 return new Applet(md, nullptr, appletId); 0886 } 0887 } 0888 0889 return nullptr; 0890 } 0891 #endif 0892 0893 QString Applet::filePath(const QByteArray &key, const QString &filename) const 0894 { 0895 if (d->package.isValid()) { 0896 return d->package.filePath(key, filename); 0897 } 0898 return QString(); 0899 } 0900 0901 void Applet::timerEvent(QTimerEvent *event) 0902 { 0903 if (d->transient) { 0904 d->constraintsTimer.stop(); 0905 if (d->modificationsTimer) { 0906 d->modificationsTimer->stop(); 0907 } 0908 return; 0909 } 0910 0911 if (event->timerId() == d->constraintsTimer.timerId()) { 0912 d->constraintsTimer.stop(); 0913 0914 // Don't flushPendingConstraints if we're just starting up 0915 // flushPendingConstraints will be called by Corona 0916 if (!(d->pendingConstraints & Plasma::Types::StartupCompletedConstraint)) { 0917 flushPendingConstraintsEvents(); 0918 } 0919 } else if (d->modificationsTimer && event->timerId() == d->modificationsTimer->timerId()) { 0920 d->modificationsTimer->stop(); 0921 // invalid group, will result in save using the default group 0922 KConfigGroup cg; 0923 0924 save(cg); 0925 Q_EMIT configNeedsSaving(); 0926 } 0927 } 0928 0929 bool Applet::isContainment() const 0930 { 0931 // HACK: this is a special case for the systray 0932 // containment in an applet that is not a containment 0933 Applet *pa = qobject_cast<Applet *>(parent()); 0934 if (pa && !pa->isContainment()) { 0935 return true; 0936 } 0937 // normal "acting as a containment" condition 0938 return qobject_cast<const Containment *>(this) && qobject_cast<Corona *>(parent()); 0939 } 0940 0941 } // Plasma namespace 0942 0943 #include "moc_applet.cpp"