Libplasma

applet.cpp
1/*
2 SPDX-FileCopyrightText: 2005 Aaron Seigo <aseigo@kde.org>
3 SPDX-FileCopyrightText: 2007 Riccardo Iaconelli <riccardo@kde.org>
4 SPDX-FileCopyrightText: 2008 Ménard Alexis <darktears31@gmail.com>
5 SPDX-FileCopyrightText: 2009 Chani Armitage <chani@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "applet.h"
11#include "private/applet_p.h"
12
13#include "config-plasma.h"
14
15#include <QDebug>
16#include <QFile>
17#include <QJSEngine>
18#include <QList>
19#include <QMetaEnum>
20
21#include <KAuthorized>
22#include <KConfigLoader>
23#include <KConfigPropertyMap>
24#include <KGlobalAccel>
25#include <KLocalizedString>
26#include <KPackage/Package>
27
28#include "containment.h"
29#include "corona.h"
30#include "plasma.h"
31#include "pluginloader.h"
32
33#include "debug_p.h"
34#include "private/containment_p.h"
35
36#include <cmath>
37#include <limits>
38
39namespace Plasma
40{
41Applet::Applet(QObject *parentObject, const KPluginMetaData &data, const QVariantList &args)
42 : QObject(parentObject)
43 , d(new AppletPrivate(data, args.count() > 1 ? args[1].toInt() : 0, this))
44{
45 if (!args.isEmpty()) {
46 const QVariant first = args.first();
47 if (first.canConvert<KPackage::Package>()) {
48 d->package = first.value<KPackage::Package>();
49 }
50 }
51 d->icon = d->appletDescription.iconName();
52
53 if (args.contains(QVariant::fromValue(QStringLiteral("org.kde.plasma:force-create")))) {
54 setProperty("org.kde.plasma:force-create", true);
55 }
56
57 // WARNING: do not access config() OR globalConfig() in this method!
58 // that requires a scene, which is not available at this point
59 d->init(args.mid(2));
60}
61
62Applet::~Applet()
63{
64 for (QAction *a : d->actions.values()) {
65 disconnect(a, nullptr, this, nullptr);
66 }
67 for (QAction *a : d->contextualActions) {
68 disconnect(a, nullptr, this, nullptr);
69 }
70
71 // let people know that i will die
72 Q_EMIT appletDeleted(this);
73
74 if (d->transient) {
75 d->resetConfigurationObject();
76 }
77
78 // ConfigLoader is deleted when AppletPrivate closes not Applet
79 // It saves on closure and emits a signal.
80 // disconnect early to avoid a crash. See 411221
81 if (d->configLoader) {
82 disconnect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
83 }
84 delete d;
85}
86
87void Applet::init()
88{
89 // Don't implement anything here, it will be overridden by subclasses
90}
91
92uint Applet::id() const
93{
94 return d->appletId;
95}
96
97QVariantList Applet::startupArguments() const
98{
99 return d->startupArguments;
100}
101
102void Applet::save(KConfigGroup &g) const
103{
104 if (d->transient || !d->appletDescription.isValid()) {
105 return;
106 }
107
108 KConfigGroup group = g;
109 if (!group.isValid()) {
110 group = *d->mainConfigGroup();
111 }
112
113 // qCDebug(LOG_PLASMA) << "saving" << pluginName() << "to" << group.name();
114 // we call the dptr member directly for locked since isImmutable()
115 // also checks kiosk and parent containers
116 group.writeEntry("immutability", (int)d->immutability);
117 group.writeEntry("plugin", d->appletDescription.pluginId());
118
119 if (!d->started) {
120 return;
121 }
122
123 KConfigGroup appletConfigGroup(&group, QStringLiteral("Configuration"));
124 saveState(appletConfigGroup);
125
126 if (d->configLoader) {
127 // we're saving so we know its changed, we don't need or want the configChanged
128 // signal bubbling up at this point due to that
129 disconnect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
130 d->configLoader->save();
131 connect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
132 }
133}
134
135void Applet::restore(KConfigGroup &group)
136{
137 setImmutability((Types::ImmutabilityType)group.readEntry("immutability", (int)Types::Mutable));
138
139 KConfigGroup shortcutConfig(&group, QStringLiteral("Shortcuts"));
140 QString shortcutText = shortcutConfig.readEntryUntranslated("global", QString());
141 if (!shortcutText.isEmpty()) {
142 setGlobalShortcut(QKeySequence(shortcutText));
143 /*
144 #ifndef NDEBUG
145 // qCDebug(LOG_PLASMA) << "got global shortcut for" << name() << "of" << QKeySequence(shortcutText);
146 #endif
147 #ifndef NDEBUG
148 // qCDebug(LOG_PLASMA) << "set to" << d->activationAction->objectName()
149 #endif
150 << d->activationAction->globalShortcut().primary();
151 */
152 }
153
154 // User background hints
155 // TODO support flags in the config
156 QByteArray hintsString = config().readEntry("UserBackgroundHints", QString()).toUtf8();
158 bool ok;
159 int value = hintEnum.keyToValue(hintsString.constData(), &ok);
160 if (ok) {
161 d->userBackgroundHints = Plasma::Types::BackgroundHints(value);
162 d->userBackgroundHintsInitialized = true;
163 Q_EMIT userBackgroundHintsChanged();
164 if (d->backgroundHints & Plasma::Types::ConfigurableBackground) {
165 Q_EMIT effectiveBackgroundHintsChanged();
166 }
167 }
168}
170void Applet::setLaunchErrorMessage(const QString &message)
171{
172 if (message == d->launchErrorMessage) {
173 return;
174 }
175
176 d->failed = true;
177 d->launchErrorMessage = message;
178}
180void Applet::saveState(KConfigGroup &group) const
181{
182 if (group.config()->name() != config().config()->name()) {
183 // we're being saved to a different file!
184 // let's just copy the current values in our configuration over
185 KConfigGroup c = config();
186 c.copyTo(&group);
187 }
188}
190KConfigGroup Applet::config() const
191{
192 if (d->transient) {
193 return KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("PlasmaTransientsConfig"));
194 }
195
196 if (isContainment()) {
197 return *(d->mainConfigGroup());
198 }
199
200 return KConfigGroup(d->mainConfigGroup(), QStringLiteral("Configuration"));
201}
203KConfigGroup Applet::globalConfig() const
204{
205 KConfigGroup globalAppletConfig;
206 QString group = isContainment() ? QStringLiteral("ContainmentGlobals") : QStringLiteral("AppletGlobals");
207
208 Containment *cont = containment();
209 Corona *corona = nullptr;
210 if (cont) {
211 corona = cont->corona();
212 }
213 if (corona) {
214 KSharedConfig::Ptr coronaConfig = corona->config();
215 globalAppletConfig = KConfigGroup(coronaConfig, group);
216 } else {
217 globalAppletConfig = KConfigGroup(KSharedConfig::openConfig(), group);
218 }
219
220 return KConfigGroup(&globalAppletConfig, d->globalName());
221}
223void Applet::destroy()
224{
225 if (immutability() != Types::Mutable || d->transient || !d->started) {
226 return; // don't double delete
227 }
228
229 d->setDestroyed(true);
230 // FIXME: an animation on leave if !isContainment() would be good again .. which should be handled by the containment class
231 d->cleanUpAndDelete();
232}
234bool Applet::destroyed() const
235{
236 return d->transient;
237}
239KConfigLoader *Applet::configScheme() const
240{
241 if (!d->configLoader) {
242 const QString xmlPath = d->package.isValid() ? d->package.filePath("mainconfigxml") : QString();
243 KConfigGroup cfg = config();
244 if (xmlPath.isEmpty()) {
245 d->configLoader = new KConfigLoader(cfg, nullptr);
246 } else {
247 QFile file(xmlPath);
248 d->configLoader = new KConfigLoader(cfg, &file);
249 QObject::connect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
250 }
251 }
252
253 return d->configLoader;
254}
255
256KConfigPropertyMap *Applet::configuration()
257{
258 if (!d->configPropertyMap) {
259 d->configPropertyMap = new KConfigPropertyMap(configScheme(), this);
260 connect(d->configPropertyMap, &KConfigPropertyMap::valueChanged, this, [this]() {
261 d->scheduleModificationNotification();
262 });
263 }
264 return d->configPropertyMap;
265}
267void Applet::updateConstraints(Constraints constraints)
268{
269 d->scheduleConstraintsUpdate(constraints);
270}
271
272void Applet::constraintsEvent(Constraints constraints)
273{
274 // NOTE: do NOT put any code in here that reacts to constraints updates
275 // as it will not get called for any applet that reimplements constraintsEvent
276 // without calling the Applet:: version as well, which it shouldn't need to.
277 // INSTEAD put such code into flushPendingConstraintsEvents
278 Q_UNUSED(constraints)
279 // qCDebug(LOG_PLASMA) << constraints << "constraints are FormFactor: " << formFactor()
280 // << ", Location: " << location();
281}
283QString Applet::title() const
284{
285 if (!d->customTitle.isEmpty()) {
286 return d->customTitle;
287 }
288
289 if (d->appletDescription.isValid()) {
290 return d->appletDescription.name();
291 }
292
293 return i18n("Unknown");
294}
296void Applet::setTitle(const QString &title)
297{
298 if (title == d->customTitle) {
299 return;
300 }
301
302 d->customTitle = title;
303 Q_EMIT titleChanged(title);
304}
306QString Applet::icon() const
307{
308 return d->icon;
309}
311void Applet::setIcon(const QString &icon)
312{
313 if (icon == d->icon) {
314 return;
315 }
316
317 d->icon = icon;
318 Q_EMIT iconChanged(icon);
319}
321bool Applet::isBusy() const
322{
323 return d->busy;
324}
326void Applet::setBusy(bool busy)
327{
328 if (busy == d->busy) {
329 return;
330 }
331
332 d->busy = busy;
333 Q_EMIT busyChanged(busy);
334}
336Plasma::Types::BackgroundHints Applet::backgroundHints() const
337{
338 return d->backgroundHints;
339}
341void Applet::setBackgroundHints(Plasma::Types::BackgroundHints hint)
342{
343 if (d->backgroundHints == hint) {
344 return;
345 }
346
347 Plasma::Types::BackgroundHints oldeffectiveHints = effectiveBackgroundHints();
348
349 d->backgroundHints = hint;
350 Q_EMIT backgroundHintsChanged();
351
352 if (oldeffectiveHints != effectiveBackgroundHints()) {
353 Q_EMIT effectiveBackgroundHintsChanged();
354 }
355}
357Plasma::Types::BackgroundHints Applet::effectiveBackgroundHints() const
358{
359 if (d->userBackgroundHintsInitialized && (d->backgroundHints & Plasma::Types::ConfigurableBackground)) {
360 return d->userBackgroundHints;
361 } else {
362 return d->backgroundHints;
363 }
364}
366Plasma::Types::BackgroundHints Applet::userBackgroundHints() const
367{
368 return d->userBackgroundHints;
369}
371void Applet::setUserBackgroundHints(Plasma::Types::BackgroundHints hint)
372{
373 if (d->userBackgroundHints == hint && d->userBackgroundHintsInitialized) {
374 return;
375 }
376
377 d->userBackgroundHints = hint;
378 d->userBackgroundHintsInitialized = true;
380 config().writeEntry("UserBackgroundHints", hintEnum.valueToKey(d->userBackgroundHints));
381 if (containment() && containment()->corona()) {
382 containment()->corona()->requestConfigSync();
383 }
384
385 Q_EMIT userBackgroundHintsChanged();
386
387 if (d->backgroundHints & Plasma::Types::ConfigurableBackground) {
388 Q_EMIT effectiveBackgroundHintsChanged();
389 }
390}
392KPluginMetaData Applet::pluginMetaData() const
393{
394 return d->appletDescription;
395}
397QString Applet::pluginName() const
398{
399 return d->appletDescription.isValid() ? d->appletDescription.pluginId() : QString();
400}
402Types::ImmutabilityType Applet::immutability() const
403{
404 // if this object is itself system immutable, then just return that; it's the most
405 // restrictive setting possible and will override anything that might be happening above it
406 // in the Corona->Containment->Applet hierarchy
407 if (d->transient || (d->mainConfig && d->mainConfig->isImmutable())) {
408 return Types::SystemImmutable;
409 }
410
411 // Returning the more strict immutability between the applet immutability, Containment and Corona
412 Types::ImmutabilityType upperImmutability = Types::Mutable;
413
414 if (isContainment()) {
415 Corona *cor = static_cast<Containment *>(const_cast<Applet *>(this))->corona();
416 if (cor) {
417 upperImmutability = cor->immutability();
418 }
419 } else {
420 const Containment *cont = containment();
421 if (cont) {
422 if (cont->corona()) {
423 upperImmutability = cont->corona()->immutability();
424 } else {
425 upperImmutability = cont->immutability();
426 }
427 }
428 }
429
430 if (upperImmutability != Types::Mutable) {
431 // it's either system or user immutable, and we already check for local system immutability,
432 // so upperImmutability is guaranteed to be as or more severe as this object's immutability
433 return upperImmutability;
434 } else {
435 return d->immutability;
436 }
437}
439void Applet::setImmutability(const Types::ImmutabilityType immutable)
440{
441 if (d->immutability == immutable || immutable == Types::SystemImmutable) {
442 // we do not store system immutability in d->immutability since that gets saved
443 // out to the config file; instead, we check with
444 // the config group itself for this information at all times. this differs from
445 // corona, where SystemImmutability is stored in d->immutability.
446 return;
447 }
448
449 d->immutability = immutable;
450 updateConstraints(ImmutableConstraint);
451}
453bool Applet::immutable() const
454{
455 return immutability() != Types::Mutable;
456}
458QString Applet::launchErrorMessage() const
459{
460 return d->launchErrorMessage;
461}
463bool Applet::failedToLaunch() const
464{
465 return d->failed;
466}
468bool Applet::configurationRequired() const
469{
470 return d->needsConfig;
471}
473QString Applet::configurationRequiredReason() const
474{
475 return d->configurationRequiredReason;
476}
478void Applet::setConfigurationRequired(bool needsConfig, const QString &reason)
479{
480 if (d->needsConfig == needsConfig && reason == d->configurationRequiredReason) {
481 return;
482 }
483
484 d->needsConfig = needsConfig;
485 d->configurationRequiredReason = reason;
486
487 Q_EMIT configurationRequiredChanged(needsConfig, reason);
488}
490void Applet::setConstraintHints(ConstraintHints constraintHints)
491{
492 if (d->constraintHints == constraintHints) {
493 return;
494 }
495
496 d->constraintHints = constraintHints;
497 Q_EMIT constraintHintsChanged(constraintHints);
498}
500Applet::ConstraintHints Applet::constraintHints() const
501{
502 return d->constraintHints;
503}
505bool Applet::isUserConfiguring() const
506{
507 return d->userConfiguring;
508}
510void Applet::setUserConfiguring(bool configuring)
511{
512 if (configuring == d->userConfiguring) {
513 return;
514 }
515
516 d->userConfiguring = configuring;
517 Q_EMIT userConfiguringChanged(configuring);
518}
520Types::ItemStatus Applet::status() const
521{
522 return d->itemStatus;
523}
525void Applet::setStatus(const Types::ItemStatus status)
526{
527 if (status == d->itemStatus) {
528 return;
529 }
530 d->itemStatus = status;
531 Q_EMIT statusChanged(status);
532}
534void Applet::flushPendingConstraintsEvents()
535{
536 if (d->pendingConstraints == NoConstraint) {
537 return;
538 }
539
540 if (d->constraintsTimer.isActive()) {
541 d->constraintsTimer.stop();
542 }
543
544 // qCDebug(LOG_PLASMA) << "flushing constraints: " << d->pendingConstraints << "!!!!!!!!!!!!!!!!!!!!!!!!!!!";
545 Constraints c = d->pendingConstraints;
546 d->pendingConstraints = NoConstraint;
547
548 if (c & UiReadyConstraint) {
549 d->setUiReady();
550 }
551
552 if (c & StartupCompletedConstraint) {
553 // common actions
554 bool unlocked = immutability() == Types::Mutable;
555 QAction *closeApplet = d->actions.value(QStringLiteral("remove"));
556 if (closeApplet) {
557 closeApplet->setEnabled(unlocked);
558 closeApplet->setVisible(unlocked);
559 connect(closeApplet, SIGNAL(triggered(bool)), this, SLOT(askDestroy()), Qt::UniqueConnection);
560 }
561
562 QAction *configAction = d->actions.value(QStringLiteral("configure"));
563 if (configAction) {
564 if (d->hasConfigurationInterface) {
565 bool canConfig = unlocked || KAuthorized::authorize(QStringLiteral("plasma/allow_configure_when_locked"));
566 configAction->setVisible(canConfig);
567 configAction->setEnabled(canConfig);
568 }
569 }
570 }
571
572 if (c & ImmutableConstraint) {
573 bool unlocked = immutability() == Types::Mutable;
574 QAction *action = d->actions.value(QStringLiteral("remove"));
575 if (action) {
576 action->setVisible(unlocked);
577 action->setEnabled(unlocked);
578 }
579
580 action = d->actions.value(QStringLiteral("configure"));
581 if (action && d->hasConfigurationInterface) {
582 bool canConfig = unlocked || KAuthorized::authorize(QStringLiteral("plasma/allow_configure_when_locked"));
583 action->setVisible(canConfig);
584 action->setEnabled(canConfig);
585 }
586
587 // an immutable constraint will always happen at startup
588 // make sure don't emit a change signal for nothing
589 if (d->oldImmutability != immutability()) {
590 Q_EMIT immutabilityChanged(immutability());
591 }
592 d->oldImmutability = immutability();
593 }
594
595 // now take care of constraints in special subclass: Containment
596 Containment *containment = qobject_cast<Plasma::Containment *>(this);
597 if (containment) {
598 containment->d->containmentConstraintsEvent(c);
599 }
600
601 // pass the constraint on to the actual subclass
602 constraintsEvent(c);
603
604 if (c & StartupCompletedConstraint) {
605 // start up is done, we can now go do a mod timer
606 if (d->modificationsTimer) {
607 if (d->modificationsTimer->isActive()) {
608 d->modificationsTimer->stop();
609 }
610 } else {
611 d->modificationsTimer = new QBasicTimer;
612 }
613 }
614
615 if (c & FormFactorConstraint) {
616 Q_EMIT formFactorChanged(formFactor());
617 }
618
619 if (c & LocationConstraint) {
620 Q_EMIT locationChanged(location());
621 }
622}
623
624QList<QAction *> Applet::contextualActions()
625{
626 return d->contextualActions;
627}
628
629QQmlListProperty<QAction> Applet::qmlContextualActions()
630{
631 return QQmlListProperty<QAction>(this,
632 nullptr,
633 AppletPrivate::contextualActions_append,
634 AppletPrivate::contextualActions_count,
635 AppletPrivate::contextualActions_at,
636 AppletPrivate::contextualActions_clear,
637 AppletPrivate::contextualActions_replace,
638 AppletPrivate::contextualActions_removeLast);
639}
641void Applet::setInternalAction(const QString &name, QAction *action)
642{
643 if (name.isEmpty()) {
644 return;
645 }
646
647 action->setObjectName(name);
648 QAction *oldAction = d->actions.value(name);
649 if (oldAction && QJSEngine::objectOwnership(oldAction) == QJSEngine::CppOwnership) {
650 delete oldAction;
651 }
652
653 d->actions[name] = action;
654
655 QObject::connect(action, &QObject::destroyed, this, [this, name]() {
656 d->actions.remove(name);
657 Q_EMIT internalActionsChanged(d->actions.values());
658 });
659
660 Q_EMIT internalActionsChanged(d->actions.values());
661}
663QAction *Applet::internalAction(const QString &name) const
664{
665 return d->actions.value(name);
666}
668void Applet::removeInternalAction(const QString &name)
669{
670 QAction *action = d->actions.value(name);
671
672 if (action && QJSEngine::objectOwnership(action) == QJSEngine::CppOwnership) {
673 disconnect(action, &QObject::destroyed, this, nullptr); // Avoid emitting signal again
674 delete action;
675 }
676
677 d->actions.remove(name);
678
679 Q_EMIT internalActionsChanged(d->actions.values());
680}
682QList<QAction *> Applet::internalActions() const
683{
684 return d->actions.values();
685}
687Types::FormFactor Applet::formFactor() const
688{
689 Containment *c = containment();
690 QObject *pw = qobject_cast<QObject *>(parent());
691 Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(pw);
692 // assumption: this loop is usually is -really- short or doesn't run at all
693 while (!parentApplet && pw && pw->parent()) {
694 pw = pw->parent();
695 parentApplet = qobject_cast<Plasma::Applet *>(pw);
696 }
697
698 return c ? c->d->formFactor : Plasma::Types::Planar;
699}
701Types::ContainmentDisplayHints Applet::containmentDisplayHints() const
702{
703 Containment *c = containment();
704
705 return c ? c->d->containmentDisplayHints : Plasma::Types::NoContainmentDisplayHint;
706}
708Containment *Applet::containment() const
709{
710 Containment *c = qobject_cast<Containment *>(const_cast<Applet *>(this));
711 if (c && c->isContainment()) {
712 return c;
713 } else {
714 c = nullptr;
715 }
716
717 QObject *parent = this->parent();
718
719 while (parent) {
720 Containment *possibleC = qobject_cast<Containment *>(parent);
721
722 if (possibleC && possibleC->isContainment()) {
723 c = possibleC;
724 break;
725 }
726 parent = parent->parent();
727 }
728
729 return c;
730}
732void Applet::setGlobalShortcut(const QKeySequence &shortcut)
733{
734 if (!d->activationAction) {
735 d->activationAction = new QAction(this);
736 d->activationAction->setText(i18n("Activate %1 Widget", title()));
737 d->activationAction->setObjectName(QStringLiteral("activate widget %1").arg(id())); // NO I18N
738 connect(d->activationAction, &QAction::triggered, this, &Applet::activated);
739 connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, [this](QAction *action, const QKeySequence &shortcut) {
740 if (action == d->activationAction) {
741 d->activationAction->setShortcut(shortcut);
742 d->globalShortcutChanged();
743 }
744 });
745 } else if (d->activationAction->shortcut() == shortcut) {
746 return;
747 }
748
749 d->activationAction->setShortcut(shortcut);
750 d->globalShortcutEnabled = true;
751 QList<QKeySequence> seqs{shortcut};
752 KGlobalAccel::self()->setShortcut(d->activationAction, seqs, KGlobalAccel::NoAutoloading);
753 d->globalShortcutChanged();
754
755 Q_EMIT globalShortcutChanged(shortcut);
756}
758QKeySequence Applet::globalShortcut() const
759{
760 if (d->activationAction) {
761 QList<QKeySequence> shortcuts = KGlobalAccel::self()->shortcut(d->activationAction);
762 if (!shortcuts.isEmpty()) {
763 return shortcuts.first();
764 }
765 }
766
767 return QKeySequence();
768}
770Types::Location Applet::location() const
771{
772 Containment *c = containment();
773 return c ? c->d->location : Plasma::Types::Desktop;
774}
776bool Applet::hasConfigurationInterface() const
777{
778 return d->hasConfigurationInterface;
779}
781void Applet::setHasConfigurationInterface(bool hasInterface)
782{
783 if (hasInterface == d->hasConfigurationInterface) {
784 return;
785 }
786
787 QAction *configAction = d->actions.value(QStringLiteral("configure"));
788 if (configAction) {
789 bool enable = hasInterface;
790 if (enable) {
791 const bool unlocked = immutability() == Types::Mutable;
792 enable = unlocked || KAuthorized::authorize(QStringLiteral("plasma/allow_configure_when_locked"));
793 }
794 configAction->setEnabled(enable);
795 }
796
797 d->hasConfigurationInterface = hasInterface;
798 Q_EMIT hasConfigurationInterfaceChanged(hasInterface);
799}
801void Applet::configChanged()
802{
803 if (d->configLoader) {
804 d->configLoader->load();
805 }
806}
807
808QUrl Applet::fileUrl(const QByteArray &key, const QString &filename) const
809{
810 if (d->package.isValid()) {
811 return d->package.fileUrl(key, filename);
812 }
813 return QUrl();
814}
815
816QUrl Applet::mainScript() const
817{
818 if (d->package.isValid()) {
819 return d->package.fileUrl("mainscript");
820 }
821 return QUrl();
822}
823
824QUrl Applet::configModel() const
825{
826 if (d->package.isValid()) {
827 return d->package.fileUrl("configmodel");
828 }
829
830 return QUrl();
831}
832
833bool Applet::sourceValid() const
834{
835 return d->package.isValid();
836}
838void Applet::timerEvent(QTimerEvent *event)
839{
840 if (d->transient) {
841 d->constraintsTimer.stop();
842 if (d->modificationsTimer) {
843 d->modificationsTimer->stop();
844 }
845 return;
846 }
847
848 if (event->timerId() == d->constraintsTimer.timerId()) {
849 d->constraintsTimer.stop();
850
851 // Don't flushPendingConstraints if we're just starting up
852 // flushPendingConstraints will be called by Corona
853 if (!(d->pendingConstraints & StartupCompletedConstraint)) {
854 flushPendingConstraintsEvents();
855 }
856 } else if (d->modificationsTimer && event->timerId() == d->modificationsTimer->timerId()) {
857 d->modificationsTimer->stop();
858 // invalid group, will result in save using the default group
859 KConfigGroup cg;
860
861 save(cg);
862 Q_EMIT configNeedsSaving();
863 }
864}
866bool Applet::isContainment() const
867{
868 // HACK: this is a special case for the systray
869 // containment in an applet that is not a containment
870 Applet *pa = qobject_cast<Applet *>(parent());
871 if (pa && !pa->isContainment()) {
872 return true;
873 }
874 // normal "acting as a containment" condition
875 return qobject_cast<const Containment *>(this) && qobject_cast<Corona *>(parent());
876}
878QString Applet::translationDomain() const
879{
880 const QString rootPath = d->appletDescription.value(u"X-Plasma-RootPath");
881 if (!rootPath.isEmpty()) {
882 return QLatin1String("plasma_applet_") + rootPath;
883 } else {
884 return QLatin1String("plasma_applet_") + d->appletDescription.pluginId();
885 }
886}
887
888} // Plasma namespace
889
890#include "moc_applet.cpp"
static Q_INVOKABLE bool authorize(const QString &action)
QString readEntryUntranslated(const char *key, const QString &aDefault=QString()) const
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
bool isValid() const
KConfig * config()
QString readEntry(const char *key, const char *aDefault=nullptr) const
void copyTo(KConfigBase *other, WriteConfigFlags pFlags=Normal) const
QString name() const
static KGlobalAccel * self()
bool setShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
QList< QKeySequence > shortcut(const QAction *action) const
void globalShortcutChanged(QAction *action, const QKeySequence &seq)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
The base Applet class.
Definition applet.h:64
bool isContainment
True if this applet is a Containment and is acting as one, such as a desktop or a panel.
Definition applet.h:200
Applet(QObject *parentObject, const KPluginMetaData &data, const QVariantList &args)
This constructor can be used with the KCoreAddons plugin loading system.
Definition applet.cpp:41
The base class for plugins that provide backgrounds and applet grouping containers.
Definition containment.h:47
A bookkeeping Scene for Plasma::Applets.
Definition corona.h:28
KSharedConfig::Ptr config() const
Returns the config file used to store the configuration for this Corona.
Definition corona.cpp:230
Types::ImmutabilityType immutability() const
Definition corona.cpp:282
ImmutabilityType
Defines the immutability of items like applets, corona and containments they can be free to modify,...
Definition plasma.h:99
ItemStatus
Status of an applet.
Definition plasma.h:112
BackgroundHints
Description on how draw a background for the applet.
Definition plasma.h:127
Location
The Location enumeration describes where on screen an element, such as an Applet or its managing cont...
Definition plasma.h:81
@ Desktop
On the planar desktop layer, extending across the full screen from edge to edge.
Definition plasma.h:84
FormFactor
The FormFactor enumeration describes how a Plasma::Applet should arrange itself.
Definition plasma.h:40
@ Planar
The applet lives in a plane and has two degrees of freedom to grow.
Definition plasma.h:41
Q_SCRIPTABLE CaptureState status()
QString i18n(const char *text, const TYPE &arg...)
Namespace for everything in libplasma.
void setEnabled(bool)
void triggered(bool checked)
void setVisible(bool)
const char * constData() const const
ObjectOwnership objectOwnership(QObject *object)
T & first()
bool isEmpty() const const
QMetaEnum fromType()
int keyToValue(const char *key, bool *ok) const const
const char * valueToKey(int value) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
QObject * parent() const const
void setObjectName(QAnyStringView name)
void valueChanged(const QString &key, const QVariant &value)
bool isEmpty() const const
UniqueConnection
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:34:35 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.