File indexing completed on 2023-10-01 04:11:43
0001 /* 0002 SPDX-FileCopyrightText: 2007 Matt Broadstone <mbroadst@gmail.com> 0003 SPDX-FileCopyrightText: 2007-2011 Aaron Seigo <aseigo@kde.org> 0004 SPDX-FileCopyrightText: 2007 Riccardo Iaconelli <riccardo@kde.org> 0005 SPDX-FileCopyrightText: 2009 Chani Armitage <chani@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "corona.h" 0011 #include "private/corona_p.h" 0012 0013 #include <QDebug> 0014 #include <QGuiApplication> 0015 #include <QMimeData> 0016 #include <QPainter> 0017 #include <QScreen> 0018 #include <QTimer> 0019 0020 #include <KLocalizedString> 0021 0022 #include <cmath> 0023 0024 #include "containment.h" 0025 #include "debug_p.h" 0026 #include "pluginloader.h" 0027 #include "private/applet_p.h" 0028 #include "private/containment_p.h" 0029 #include "private/timetracker.h" 0030 0031 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0032 #include "packagestructure.h" 0033 #include "private/package_p.h" 0034 #endif 0035 0036 using namespace Plasma; 0037 0038 namespace Plasma 0039 { 0040 Corona::Corona(QObject *parent) 0041 : QObject(parent) 0042 , d(new CoronaPrivate(this)) 0043 { 0044 d->init(); 0045 0046 #ifndef NDEBUG 0047 if (qEnvironmentVariableIsSet("PLASMA_TRACK_STARTUP")) { 0048 new TimeTracker(this); 0049 } 0050 #endif 0051 } 0052 0053 Corona::~Corona() 0054 { 0055 KConfigGroup trans(KSharedConfig::openConfig(), "PlasmaTransientsConfig"); 0056 trans.deleteGroup(); 0057 0058 delete d; 0059 } 0060 0061 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 6) 0062 Plasma::Package Corona::package() const 0063 { 0064 return Package(d->package); 0065 } 0066 0067 void Corona::setPackage(const Plasma::Package &package) 0068 { 0069 setKPackage(*package.d->internalPackage); 0070 Q_EMIT packageChanged(package); 0071 } 0072 #endif 0073 0074 KPackage::Package Corona::kPackage() const 0075 { 0076 return d->package; 0077 } 0078 0079 void Corona::setKPackage(const KPackage::Package &package) 0080 { 0081 d->package = package; 0082 Q_EMIT kPackageChanged(package); 0083 } 0084 0085 void Corona::saveLayout(const QString &configName) const 0086 { 0087 KSharedConfigPtr c; 0088 0089 if (configName.isEmpty() || configName == d->configName) { 0090 c = config(); 0091 } else { 0092 c = KSharedConfig::openConfig(configName, KConfig::SimpleConfig); 0093 } 0094 0095 d->saveLayout(c); 0096 } 0097 0098 void Corona::exportLayout(KConfigGroup &config, QList<Containment *> containments) 0099 { 0100 const auto groupList = config.groupList(); 0101 for (const QString &group : groupList) { 0102 KConfigGroup cg(&config, group); 0103 cg.deleteGroup(); 0104 } 0105 0106 // temporarily unlock so that removal works 0107 Types::ImmutabilityType oldImm = immutability(); 0108 d->immutability = Types::Mutable; 0109 0110 KConfigGroup dest(&config, "Containments"); 0111 KConfigGroup dummy; 0112 for (Plasma::Containment *c : std::as_const(containments)) { 0113 c->save(dummy); 0114 c->config().reparent(&dest); 0115 0116 // ensure the containment is unlocked 0117 // this is done directly because we have to bypass any Types::SystemImmutable checks 0118 c->Applet::d->immutability = Types::Mutable; 0119 const auto lstApplet = c->applets(); 0120 for (Applet *a : lstApplet) { 0121 a->d->immutability = Types::Mutable; 0122 } 0123 0124 c->destroy(); 0125 } 0126 0127 // restore immutability 0128 d->immutability = oldImm; 0129 0130 config.sync(); 0131 } 0132 0133 void Corona::requestConfigSync() 0134 { 0135 // constant controlling how long between requesting a configuration sync 0136 // and one happening should occur. currently 10 seconds 0137 static const int CONFIG_SYNC_TIMEOUT = 10000; 0138 0139 // TODO: should we check into our immutability before doing this? 0140 0141 // NOTE: this is a pretty simplistic model: we simply save no more than CONFIG_SYNC_TIMEOUT 0142 // after the first time this is called. not much of a heuristic for save points, but 0143 // it should at least compress these activities a bit and provide a way for applet 0144 // authors to ween themselves from the sync() disease. A more interesting/dynamic 0145 // algorithm for determining when to actually sync() to disk might be better, though. 0146 if (!d->configSyncTimer->isActive()) { 0147 d->configSyncTimer->start(CONFIG_SYNC_TIMEOUT); 0148 } 0149 } 0150 0151 void Corona::requireConfigSync() 0152 { 0153 d->syncConfig(); 0154 } 0155 0156 void Corona::loadLayout(const QString &configName) 0157 { 0158 if (!configName.isEmpty() && configName != d->configName) { 0159 // if we have a new config name passed in, then use that as the config file for this Corona 0160 d->config = nullptr; 0161 d->configName = configName; 0162 } 0163 0164 KConfigGroup conf(config(), QString()); 0165 if (!config()->groupList().isEmpty()) { 0166 d->importLayout(conf, false); 0167 } else { 0168 loadDefaultLayout(); 0169 d->notifyContainmentsReady(); 0170 } 0171 0172 KConfigGroup cg(config(), "General"); 0173 setImmutability((Plasma::Types::ImmutabilityType)cg.readEntry("immutability", (int)Plasma::Types::Mutable)); 0174 } 0175 0176 QList<Plasma::Containment *> Corona::importLayout(const KConfigGroup &conf) 0177 { 0178 return d->importLayout(conf, true); 0179 } 0180 0181 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 46) 0182 Containment *Corona::containmentForScreen(int screen) const 0183 { 0184 for (Containment *containment : std::as_const(d->containments)) { 0185 if (containment->screen() == screen // 0186 && (containment->containmentType() == Plasma::Types::DesktopContainment // 0187 || containment->containmentType() == Plasma::Types::CustomContainment)) { 0188 return containment; 0189 } 0190 } 0191 0192 return nullptr; 0193 } 0194 0195 Containment *Corona::containmentForScreen(int screen, const QString &defaultPluginIfNonExistent, const QVariantList &defaultArgs) 0196 { 0197 return containmentForScreen(screen, QString(), defaultPluginIfNonExistent, defaultArgs); 0198 } 0199 #endif 0200 0201 Containment *Corona::containmentForScreen(int screen, const QString &activity, const QString &defaultPluginIfNonExistent, const QVariantList &defaultArgs) 0202 { 0203 Containment *containment = nullptr; 0204 0205 for (Containment *cont : std::as_const(d->containments)) { 0206 /* clang-format off */ 0207 if (cont->lastScreen() == screen 0208 && ((cont->activity().isEmpty() || activity.isEmpty()) || cont->activity() == activity) 0209 && (cont->containmentType() == Plasma::Types::DesktopContainment 0210 || cont->containmentType() == Plasma::Types::CustomContainment)) { /* clang-format on */ 0211 containment = cont; 0212 } 0213 } 0214 0215 if (!containment && !defaultPluginIfNonExistent.isEmpty()) { 0216 // screen requests are allowed to bypass immutability 0217 if (screen >= 0) { 0218 Plasma::Types::ImmutabilityType imm = d->immutability; 0219 d->immutability = Types::Mutable; 0220 containment = d->addContainment(defaultPluginIfNonExistent, defaultArgs, 0, screen, false); 0221 0222 d->immutability = imm; 0223 } 0224 } 0225 0226 if (containment) { 0227 containment->setActivity(activity); 0228 } 0229 return containment; 0230 } 0231 0232 QList<Containment *> Corona::containmentsForActivity(const QString &activity) 0233 { 0234 QList<Containment *> conts; 0235 0236 if (activity.isEmpty()) { 0237 return conts; 0238 } 0239 0240 std::copy_if(d->containments.begin(), d->containments.end(), std::back_inserter(conts), [activity](Containment *cont) { 0241 return cont->activity() == activity // 0242 && (cont->containmentType() == Plasma::Types::DesktopContainment // 0243 || cont->containmentType() == Plasma::Types::CustomContainment); 0244 }); 0245 0246 return conts; 0247 } 0248 0249 QList<Containment *> Corona::containmentsForScreen(int screen) 0250 { 0251 QList<Containment *> conts; 0252 0253 if (screen < 0) { 0254 return conts; 0255 } 0256 0257 std::copy_if(d->containments.begin(), d->containments.end(), std::back_inserter(conts), [screen](Containment *cont) { 0258 return cont->lastScreen() == screen // 0259 && (cont->containmentType() == Plasma::Types::DesktopContainment // 0260 || cont->containmentType() == Plasma::Types::CustomContainment); 0261 }); 0262 0263 return conts; 0264 } 0265 0266 QList<Containment *> Corona::containments() const 0267 { 0268 return d->containments; 0269 } 0270 0271 bool Corona::isStartupCompleted() const 0272 { 0273 return d->containmentsStarting <= 0; 0274 } 0275 0276 KSharedConfigPtr Corona::config() const 0277 { 0278 if (!d->config) { 0279 d->config = KSharedConfig::openConfig(d->configName, KConfig::SimpleConfig); 0280 } 0281 0282 return d->config; 0283 } 0284 0285 Containment *Corona::createContainment(const QString &name, const QVariantList &args) 0286 { 0287 if (d->immutability == Types::Mutable || args.contains(QVariant::fromValue(QStringLiteral("org.kde.plasma:force-create")))) { 0288 return d->addContainment(name, args, 0, -1, false); 0289 } 0290 0291 return nullptr; 0292 } 0293 0294 Containment *Corona::createContainmentDelayed(const QString &name, const QVariantList &args) 0295 { 0296 if (d->immutability == Types::Mutable) { 0297 return d->addContainment(name, args, 0, -1, true); 0298 } 0299 0300 return nullptr; 0301 } 0302 0303 int Corona::screenForContainment(const Containment *) const 0304 { 0305 return -1; 0306 } 0307 0308 int Corona::numScreens() const 0309 { 0310 return 1; 0311 } 0312 0313 QRegion Corona::availableScreenRegion(int id) const 0314 { 0315 return QRegion(screenGeometry(id)); 0316 } 0317 0318 QRect Corona::availableScreenRect(int id) const 0319 { 0320 return screenGeometry(id); 0321 } 0322 0323 void Corona::loadDefaultLayout() 0324 { 0325 // Default implementation does nothing 0326 } 0327 0328 Types::ImmutabilityType Corona::immutability() const 0329 { 0330 return d->immutability; 0331 } 0332 0333 void Corona::setImmutability(const Types::ImmutabilityType immutable) 0334 { 0335 if (d->immutability == immutable || d->immutability == Types::SystemImmutable) { 0336 return; 0337 } 0338 0339 #ifndef NDEBUG 0340 // qCDebug(LOG_PLASMA) << "setting immutability to" << immutable; 0341 #endif 0342 d->immutability = immutable; 0343 d->updateContainmentImmutability(); 0344 // tell non-containments that might care (like plasmaapp or a custom corona) 0345 Q_EMIT immutabilityChanged(immutable); 0346 0347 // update our actions 0348 QAction *action = d->actions.action(QStringLiteral("lock widgets")); 0349 if (action) { 0350 if (d->immutability == Types::SystemImmutable) { 0351 action->setEnabled(false); 0352 action->setVisible(false); 0353 } else { 0354 bool unlocked = d->immutability == Types::Mutable; 0355 action->setText(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets")); 0356 action->setIcon(QIcon::fromTheme(unlocked ? QStringLiteral("object-locked") : QStringLiteral("object-unlocked"))); 0357 action->setEnabled(true); 0358 action->setVisible(true); 0359 } 0360 } 0361 0362 action = d->actions.action(QStringLiteral("edit mode")); 0363 if (action) { 0364 switch (d->immutability) { 0365 case Types::UserImmutable: 0366 action->setEnabled(false); 0367 action->setVisible(true); 0368 break; 0369 case Types::SystemImmutable: 0370 action->setEnabled(false); 0371 action->setVisible(false); 0372 break; 0373 case Types::Mutable: 0374 default: 0375 action->setEnabled(true); 0376 action->setVisible(true); 0377 break; 0378 } 0379 } 0380 0381 if (d->immutability != Types::SystemImmutable) { 0382 KConfigGroup cg(config(), "General"); 0383 0384 // we call the dptr member directly for locked since isImmutable() 0385 // also checks kiosk and parent containers 0386 cg.writeEntry("immutability", (int)d->immutability); 0387 requestConfigSync(); 0388 } 0389 0390 if (d->immutability != Types::Mutable) { 0391 setEditMode(false); 0392 } 0393 } 0394 0395 void Corona::setEditMode(bool edit) 0396 { 0397 if (edit == d->editMode || (edit && d->immutability != Plasma::Types::Mutable)) { 0398 return; 0399 } 0400 0401 QAction *editAction = d->actions.action(QStringLiteral("edit mode")); 0402 if (editAction) { 0403 if (edit) { 0404 editAction->setText(i18n("Exit Edit Mode")); 0405 } else { 0406 editAction->setText(i18n("Enter Edit Mode")); 0407 } 0408 } 0409 0410 if (!edit) { 0411 requireConfigSync(); 0412 } 0413 0414 d->editMode = edit; 0415 Q_EMIT editModeChanged(edit); 0416 } 0417 0418 bool Corona::isEditMode() const 0419 { 0420 return d->editMode; 0421 } 0422 0423 QList<Plasma::Types::Location> Corona::freeEdges(int screen) const 0424 { 0425 QList<Plasma::Types::Location> freeEdges; 0426 /* clang-format off */ 0427 freeEdges << Plasma::Types::TopEdge 0428 << Plasma::Types::BottomEdge 0429 << Plasma::Types::LeftEdge 0430 << Plasma::Types::RightEdge; 0431 /* clang-format on */ 0432 0433 const auto containments = this->containments(); 0434 for (Containment *containment : containments) { 0435 if (containment->screen() == screen && freeEdges.contains(containment->location())) { 0436 freeEdges.removeAll(containment->location()); 0437 } 0438 } 0439 0440 return freeEdges; 0441 } 0442 0443 KActionCollection *Corona::actions() const 0444 { 0445 return &d->actions; 0446 } 0447 0448 CoronaPrivate::CoronaPrivate(Corona *corona) 0449 : q(corona) 0450 , immutability(Types::Mutable) 0451 , config(nullptr) 0452 , configSyncTimer(new QTimer(corona)) 0453 , actions(corona) 0454 , containmentsStarting(0) 0455 { 0456 // TODO: make Package path configurable 0457 0458 if (QCoreApplication::instance()) { 0459 configName = QCoreApplication::instance()->applicationName() + QStringLiteral("-appletsrc"); 0460 } else { 0461 configName = QStringLiteral("plasma-appletsrc"); 0462 } 0463 } 0464 0465 CoronaPrivate::~CoronaPrivate() 0466 { 0467 qDeleteAll(containments); 0468 } 0469 0470 void CoronaPrivate::init() 0471 { 0472 desktopDefaultsConfig = KConfigGroup(KSharedConfig::openConfig(package.filePath("defaults")), "Desktop"); 0473 0474 configSyncTimer->setSingleShot(true); 0475 QObject::connect(configSyncTimer, SIGNAL(timeout()), q, SLOT(syncConfig())); 0476 0477 // some common actions 0478 actions.setConfigGroup(QStringLiteral("Shortcuts")); 0479 0480 QAction *lockAction = actions.add<QAction>(QStringLiteral("lock widgets")); 0481 QObject::connect(lockAction, SIGNAL(triggered(bool)), q, SLOT(toggleImmutability())); 0482 lockAction->setText(i18n("Lock Widgets")); 0483 lockAction->setAutoRepeat(true); 0484 lockAction->setIcon(QIcon::fromTheme(QStringLiteral("object-locked"))); 0485 lockAction->setData(Plasma::Types::ControlAction); 0486 lockAction->setShortcutContext(Qt::ApplicationShortcut); 0487 0488 // fake containment/applet actions 0489 KActionCollection *containmentActions = AppletPrivate::defaultActions(q); // containment has to start with applet stuff 0490 ContainmentPrivate::addDefaultActions(containmentActions); // now it's really containment 0491 0492 QAction *editAction = actions.add<QAction>(QStringLiteral("edit mode")); 0493 QObject::connect(editAction, &QAction::triggered, q, [this]() { 0494 q->setEditMode(!q->isEditMode()); 0495 }); 0496 editAction->setText(i18n("Enter Edit Mode")); 0497 editAction->setAutoRepeat(true); 0498 editAction->setIcon(QIcon::fromTheme(QStringLiteral("document-edit"))); 0499 editAction->setData(Plasma::Types::ControlAction); 0500 editAction->setShortcut(QKeySequence(QStringLiteral("alt+d, e"))); 0501 editAction->setShortcutContext(Qt::ApplicationShortcut); 0502 } 0503 0504 void CoronaPrivate::toggleImmutability() 0505 { 0506 if (immutability == Types::Mutable) { 0507 q->setImmutability(Types::UserImmutable); 0508 } else { 0509 q->setImmutability(Types::Mutable); 0510 } 0511 } 0512 0513 void CoronaPrivate::saveLayout(KSharedConfigPtr cg) const 0514 { 0515 KConfigGroup containmentsGroup(cg, "Containments"); 0516 for (const Containment *containment : containments) { 0517 QString cid = QString::number(containment->id()); 0518 KConfigGroup containmentConfig(&containmentsGroup, cid); 0519 containment->save(containmentConfig); 0520 } 0521 } 0522 0523 void CoronaPrivate::updateContainmentImmutability() 0524 { 0525 for (Containment *c : std::as_const(containments)) { 0526 // we need to tell each containment that immutability has been altered 0527 c->updateConstraints(Types::ImmutableConstraint); 0528 } 0529 } 0530 0531 void CoronaPrivate::containmentDestroyed(QObject *obj) 0532 { 0533 // we do a static_cast here since it really isn't an Containment by this 0534 // point anymore since we are in the qobject dtor. we don't actually 0535 // try and do anything with it, we just need the value of the pointer 0536 // so this unsafe looking code is actually just fine. 0537 Containment *containment = static_cast<Plasma::Containment *>(obj); 0538 int index = containments.indexOf(containment); 0539 0540 if (index > -1) { 0541 containments.removeAt(index); 0542 q->requestConfigSync(); 0543 } 0544 } 0545 0546 void CoronaPrivate::syncConfig() 0547 { 0548 q->config()->sync(); 0549 Q_EMIT q->configSynced(); 0550 } 0551 0552 Containment *CoronaPrivate::addContainment(const QString &name, const QVariantList &args, uint id, int lastScreen, bool delayedInit) 0553 { 0554 QString pluginName = name; 0555 Containment *containment = nullptr; 0556 Applet *applet = nullptr; 0557 0558 // qCDebug(LOG_PLASMA) << "Loading" << name << args << id; 0559 0560 if (pluginName.isEmpty() || pluginName == QLatin1String("default")) { 0561 // default to the desktop containment 0562 pluginName = desktopDefaultsConfig.readEntry("Containment", "org.kde.desktopcontainment"); 0563 } 0564 0565 bool loadingNull = pluginName == QLatin1String("null"); 0566 if (!loadingNull) { 0567 applet = PluginLoader::self()->loadApplet(pluginName, id, args); 0568 containment = dynamic_cast<Containment *>(applet); 0569 if (containment) { 0570 containment->setParent(q); 0571 } 0572 } 0573 0574 if (!containment) { 0575 if (!loadingNull) { 0576 #ifndef NDEBUG 0577 // qCDebug(LOG_PLASMA) << "loading of containment" << name << "failed."; 0578 #endif 0579 } 0580 0581 // in case we got a non-Containment from Applet::loadApplet or 0582 // a null containment was requested 0583 if (applet) { 0584 // the applet probably doesn't know what's hit it, so let's pretend it can be 0585 // initialized to make assumptions in the applet's dtor safer 0586 applet->init(); 0587 delete applet; 0588 } 0589 applet = containment = new Containment(q, KPluginMetaData(), QVariantList{QVariant(), QVariant(), id}); 0590 if (lastScreen >= 0) { 0591 containment->d->lastScreen = lastScreen; 0592 } 0593 // if it's a dummy containment, just say its ui is ready, not blocking the corona 0594 applet->updateConstraints(Plasma::Types::UiReadyConstraint); 0595 0596 // we want to provide something and don't care about the failure to launch 0597 containment->setFormFactor(Plasma::Types::Planar); 0598 } 0599 0600 // if this is a new containment, we need to ensure that there are no stale 0601 // configuration data around 0602 if (id == 0) { 0603 KConfigGroup conf(q->config(), "Containments"); 0604 conf = KConfigGroup(&conf, QString::number(containment->id())); 0605 conf.deleteGroup(); 0606 } 0607 0608 // make sure the containments are sorted by id 0609 auto position = std::lower_bound(containments.begin(), containments.end(), containment, [](Plasma::Containment *c1, Plasma::Containment *c2) { 0610 return c1->id() < c2->id(); 0611 }); 0612 containments.insert(position, containment); 0613 0614 QObject::connect(containment, SIGNAL(destroyed(QObject *)), q, SLOT(containmentDestroyed(QObject *))); 0615 QObject::connect(containment, &Applet::configNeedsSaving, q, &Corona::requestConfigSync); 0616 QObject::connect(containment, &Containment::screenChanged, q, &Corona::screenOwnerChanged); 0617 0618 if (!delayedInit) { 0619 containment->init(); 0620 KConfigGroup cg = containment->config(); 0621 containment->restore(cg); 0622 containment->updateConstraints(Plasma::Types::StartupCompletedConstraint); 0623 containment->save(cg); 0624 q->requestConfigSync(); 0625 containment->flushPendingConstraintsEvents(); 0626 Q_EMIT q->containmentAdded(containment); 0627 // if id = 0 a new containment has been created, not restored 0628 if (id == 0) { 0629 Q_EMIT q->containmentCreated(containment); 0630 } 0631 } 0632 0633 return containment; 0634 } 0635 0636 QList<Plasma::Containment *> CoronaPrivate::importLayout(const KConfigGroup &conf, bool mergeConfig) 0637 { 0638 if (!conf.isValid()) { 0639 return QList<Containment *>(); 0640 } 0641 0642 QList<Plasma::Containment *> newContainments; 0643 QSet<uint> containmentsIds; 0644 0645 for (Containment *containment : std::as_const(containments)) { 0646 containmentsIds.insert(containment->id()); 0647 } 0648 0649 KConfigGroup containmentsGroup(&conf, "Containments"); 0650 QStringList groups = containmentsGroup.groupList(); 0651 std::sort(groups.begin(), groups.end()); 0652 0653 for (const QString &group : std::as_const(groups)) { 0654 KConfigGroup containmentConfig(&containmentsGroup, group); 0655 0656 if (containmentConfig.entryMap().isEmpty()) { 0657 continue; 0658 } else if (containmentConfig.readEntry(QStringLiteral("transient"), false)) { 0659 containmentConfig.deleteGroup(); 0660 continue; 0661 } 0662 0663 uint cid = group.toUInt(); 0664 if (containmentsIds.contains(cid)) { 0665 cid = ++AppletPrivate::s_maxAppletId; 0666 } else if (cid > AppletPrivate::s_maxAppletId) { 0667 AppletPrivate::s_maxAppletId = cid; 0668 } 0669 0670 if (mergeConfig) { 0671 KConfigGroup realConf(q->config(), "Containments"); 0672 realConf = KConfigGroup(&realConf, QString::number(cid)); 0673 // in case something was there before us 0674 realConf.deleteGroup(); 0675 containmentConfig.copyTo(&realConf); 0676 } 0677 0678 // qCDebug(LOG_PLASMA) << "got a containment in the config, trying to make a" << containmentConfig.readEntry("plugin", QString()) << "from" << group; 0679 #ifndef NDEBUG 0680 // qCDebug(LOG_PLASMA) << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Adding Containment" << containmentConfig.readEntry("plugin", 0681 // QString()); 0682 #endif 0683 Containment *c = addContainment(containmentConfig.readEntry("plugin", QString()), QVariantList(), cid, -1); 0684 if (!c) { 0685 continue; 0686 } 0687 0688 newContainments.append(c); 0689 containmentsIds.insert(c->id()); 0690 0691 #ifndef NDEBUG 0692 // qCDebug(LOG_PLASMA) << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Restored Containment" << c->pluginName(); 0693 #endif 0694 } 0695 0696 if (!mergeConfig) { 0697 notifyContainmentsReady(); 0698 } 0699 0700 return newContainments; 0701 } 0702 0703 void CoronaPrivate::notifyContainmentsReady() 0704 { 0705 containmentsStarting = 0; 0706 for (Containment *containment : std::as_const(containments)) { 0707 if (!containment->isUiReady() && containment->screen() >= 0) { 0708 ++containmentsStarting; 0709 QObject::connect(containment, &Plasma::Containment::uiReadyChanged, q, [this](bool ready) { 0710 containmentReady(ready); 0711 }); 0712 } 0713 } 0714 0715 if (containmentsStarting <= 0) { 0716 Q_EMIT q->startupCompleted(); 0717 } 0718 } 0719 0720 void CoronaPrivate::containmentReady(bool ready) 0721 { 0722 if (!ready) { 0723 return; 0724 } 0725 --containmentsStarting; 0726 if (containmentsStarting <= 0) { 0727 Q_EMIT q->startupCompleted(); 0728 } 0729 } 0730 0731 } // namespace Plasma 0732 0733 #include "moc_corona.cpp"