File indexing completed on 2025-02-16 05:04:48
0001 /* 0002 SPDX-FileCopyrightText: 2019 Michail Vourlakos <mvourlakos@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "genericlayout.h" 0008 0009 // local 0010 #include "abstractlayout.h" 0011 #include "../apptypes.h" 0012 #include "../lattecorona.h" 0013 #include "../screenpool.h" 0014 #include "../layouts/importer.h" 0015 #include "../layouts/manager.h" 0016 #include "../layouts/storage.h" 0017 #include "../layouts/synchronizer.h" 0018 #include "../shortcuts/shortcutstracker.h" 0019 #include "../templates/templatesmanager.h" 0020 #include "../view/clonedview.h" 0021 #include "../view/originalview.h" 0022 #include "../view/positioner.h" 0023 #include "../view/view.h" 0024 0025 // Qt 0026 #include <QDebug> 0027 #include <QScreen> 0028 0029 // Plasma 0030 #include <Plasma> 0031 #include <Plasma/Applet> 0032 #include <Plasma/Containment> 0033 0034 // KDE 0035 #include <KActionCollection> 0036 #include <KConfigGroup> 0037 0038 namespace Latte { 0039 namespace Layout { 0040 0041 GenericLayout::GenericLayout(QObject *parent, QString layoutFile, QString assignedName) 0042 : AbstractLayout (parent, layoutFile, assignedName) 0043 { 0044 } 0045 0046 GenericLayout::~GenericLayout() 0047 { 0048 } 0049 0050 Type GenericLayout::type() const 0051 { 0052 return Type::Generic; 0053 } 0054 0055 void GenericLayout::unloadContainments() 0056 { 0057 if (!m_corona) { 0058 return; 0059 } 0060 0061 qDebug() << "Layout - " + name() + " : [unloadContainments]" 0062 << "containments ::: " << m_containments.size() 0063 << " ,latteViews in memory ::: " << m_latteViews.size() 0064 << " ,hidden latteViews in memory ::: " << m_waitingLatteViews.size(); 0065 0066 for (const auto view : m_latteViews) { 0067 view->disconnectSensitiveSignals(); 0068 } 0069 0070 for (const auto view : m_waitingLatteViews) { 0071 view->disconnectSensitiveSignals(); 0072 } 0073 0074 m_unloadedContainmentsIds.clear(); 0075 0076 QList<Plasma::Containment *> subcontainments; 0077 0078 //!identify subcontainments and unload them first 0079 for (const auto containment : m_containments) { 0080 if (Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent())) { 0081 subcontainments.append(containment); 0082 } 0083 } 0084 0085 while (!subcontainments.isEmpty()) { 0086 Plasma::Containment *sub = subcontainments.at(0); 0087 m_unloadedContainmentsIds << QString::number(sub->id()); 0088 subcontainments.removeFirst(); 0089 m_containments.removeAll(sub); 0090 delete sub; 0091 } 0092 0093 while (!m_containments.isEmpty()) { 0094 Plasma::Containment *containment = m_containments.at(0); 0095 m_unloadedContainmentsIds << QString::number(containment->id()); 0096 m_containments.removeFirst(); 0097 delete containment; 0098 } 0099 } 0100 0101 void GenericLayout::unloadLatteViews() 0102 { 0103 if (!m_corona) { 0104 return; 0105 } 0106 0107 qDebug() << "Layout - " + name() + " : [unloadLatteViews]" 0108 << "containments ::: " << m_containments.size() 0109 << " ,latteViews in memory ::: " << m_latteViews.size() 0110 << " ,hidden latteViews in memory ::: " << m_waitingLatteViews.size(); 0111 0112 //!disconnect signals in order to avoid crashes when the layout is unloading 0113 disconnect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRectChanged); 0114 disconnect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRegionChanged); 0115 disconnect(this, &GenericLayout::activitiesChanged, this, &GenericLayout::updateLastUsedActivity); 0116 disconnect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, &GenericLayout::updateLastUsedActivity); 0117 0118 for (const auto view : m_latteViews) { 0119 view->disconnectSensitiveSignals(); 0120 } 0121 0122 for (const auto view : m_waitingLatteViews) { 0123 view->disconnectSensitiveSignals(); 0124 } 0125 0126 qDeleteAll(m_latteViews); 0127 qDeleteAll(m_waitingLatteViews); 0128 m_latteViews.clear(); 0129 m_waitingLatteViews.clear(); 0130 } 0131 0132 bool GenericLayout::blockAutomaticLatteViewCreation() const 0133 { 0134 return m_blockAutomaticLatteViewCreation; 0135 } 0136 0137 void GenericLayout::setBlockAutomaticLatteViewCreation(bool block) 0138 { 0139 if (m_blockAutomaticLatteViewCreation == block) { 0140 return; 0141 } 0142 0143 m_blockAutomaticLatteViewCreation = block; 0144 } 0145 0146 bool GenericLayout::isActive() const 0147 { 0148 return m_corona && m_hasInitializedContainments && (m_corona->layoutsManager()->synchronizer()->layout(m_layoutName) != nullptr); 0149 } 0150 0151 bool GenericLayout::isCurrent() 0152 { 0153 if (!m_corona) { 0154 return false; 0155 } 0156 0157 return m_corona->layoutsManager()->currentLayoutsNames().contains(name()); 0158 } 0159 0160 bool GenericLayout::hasCorona() const 0161 { 0162 return (m_corona!=nullptr); 0163 } 0164 0165 void GenericLayout::setCorona(Latte::Corona *corona) 0166 { 0167 m_corona = corona; 0168 } 0169 0170 QString GenericLayout::background() const 0171 { 0172 QString colorsPath = m_corona->kPackage().path() + "../../shells/org.kde.latte.shell/contents/images/canvas/"; 0173 0174 if (backgroundStyle() == Layout::PatternBackgroundStyle) { 0175 if (customBackground().isEmpty()) { 0176 0177 return colorsPath + "defaultcustomprint.jpg"; 0178 } else { 0179 return AbstractLayout::customBackground(); 0180 } 0181 } 0182 0183 return colorsPath + AbstractLayout::color() + "print.jpg"; 0184 } 0185 0186 QString GenericLayout::textColor() const 0187 { 0188 if (backgroundStyle() == Layout::PatternBackgroundStyle && customBackground().isEmpty() && customTextColor().isEmpty()) { 0189 return AbstractLayout::defaultCustomTextColor(); 0190 } 0191 0192 return AbstractLayout::textColor(); 0193 } 0194 0195 int GenericLayout::viewsCount(int screen) const 0196 { 0197 if (!m_corona) { 0198 return 0; 0199 } 0200 0201 QScreen *scr = m_corona->screenPool()->screenForId(screen); 0202 0203 int views{0}; 0204 0205 for (const auto view : m_latteViews) { 0206 if (view && view->screen() == scr && !view->containment()->destroyed()) { 0207 ++views; 0208 } 0209 } 0210 0211 return views; 0212 } 0213 0214 int GenericLayout::viewsCount(QScreen *screen) const 0215 { 0216 if (!m_corona) { 0217 return 0; 0218 } 0219 0220 int views{0}; 0221 0222 for (const auto view : m_latteViews) { 0223 if (view && view->screen() == screen && !view->containment()->destroyed()) { 0224 ++views; 0225 } 0226 } 0227 0228 return views; 0229 } 0230 0231 int GenericLayout::viewsCount() const 0232 { 0233 if (!m_corona) { 0234 return 0; 0235 } 0236 0237 int views{0}; 0238 0239 for (const auto view : m_latteViews) { 0240 if (view && view->containment() && !view->containment()->destroyed()) { 0241 ++views; 0242 } 0243 } 0244 0245 return views; 0246 } 0247 0248 QList<int> GenericLayout::qmlFreeEdges(int screen) const 0249 { 0250 if (!m_corona) { 0251 const QList<int> emptyEdges; 0252 return emptyEdges; 0253 } 0254 0255 const auto edges = freeEdges(screen); 0256 QList<int> edgesInt; 0257 0258 for (const Plasma::Types::Location &edge : edges) { 0259 edgesInt.append(static_cast<int>(edge)); 0260 } 0261 0262 return edgesInt; 0263 } 0264 0265 QList<Plasma::Types::Location> GenericLayout::freeEdges(QScreen *scr) const 0266 { 0267 using Plasma::Types; 0268 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge, 0269 Types::TopEdge, Types::RightEdge}; 0270 0271 if (!m_corona) { 0272 return edges; 0273 } 0274 0275 for (const auto view : m_latteViews) { 0276 if (view && view->positioner()->currentScreenName() == scr->name()) { 0277 edges.removeOne(view->location()); 0278 } 0279 } 0280 0281 return edges; 0282 } 0283 0284 QList<Plasma::Types::Location> GenericLayout::freeEdges(int screen) const 0285 { 0286 using Plasma::Types; 0287 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge, 0288 Types::TopEdge, Types::RightEdge}; 0289 0290 if (!m_corona) { 0291 return edges; 0292 } 0293 0294 QScreen *scr = m_corona->screenPool()->screenForId(screen); 0295 0296 for (const auto view : m_latteViews) { 0297 if (view && scr && view->positioner()->currentScreenName() == scr->name()) { 0298 edges.removeOne(view->location()); 0299 } 0300 } 0301 0302 return edges; 0303 } 0304 0305 int GenericLayout::viewsWithTasks() const 0306 { 0307 if (!m_corona) { 0308 return 0; 0309 } 0310 0311 int result = 0; 0312 0313 for (const auto view : m_latteViews) { 0314 if (view->extendedInterface()->hasLatteTasks() || view->extendedInterface()->hasPlasmaTasks()) { 0315 result++; 0316 } 0317 } 0318 0319 return result; 0320 } 0321 0322 QStringList GenericLayout::unloadedContainmentsIds() 0323 { 0324 return m_unloadedContainmentsIds; 0325 } 0326 0327 Latte::Corona *GenericLayout::corona() const 0328 { 0329 return m_corona; 0330 } 0331 0332 Types::ViewType GenericLayout::latteViewType(uint containmentId) const 0333 { 0334 for (const auto view : m_latteViews) { 0335 if (view->containment() && view->containment()->id() == containmentId) { 0336 return view->type(); 0337 } 0338 } 0339 0340 return Types::DockView; 0341 } 0342 0343 Latte::View *GenericLayout::highestPriorityView() 0344 { 0345 QList<Latte::View *> views = sortedLatteViews(); 0346 0347 return (views.count() > 0 ? views[0] : nullptr); 0348 } 0349 0350 Latte::View *GenericLayout::lastConfigViewFor() 0351 { 0352 return m_lastConfigViewFor; 0353 } 0354 0355 void GenericLayout::setLastConfigViewFor(Latte::View *view) 0356 { 0357 if (m_lastConfigViewFor == view) { 0358 return; 0359 } 0360 0361 m_lastConfigViewFor = view; 0362 0363 if (view) { 0364 emit lastConfigViewForChanged(view); 0365 } 0366 } 0367 0368 void GenericLayout::onLastConfigViewChangedFrom(Latte::View *view) 0369 { 0370 if (!m_latteViews.values().contains(view)) { 0371 setLastConfigViewFor(nullptr); 0372 } 0373 } 0374 0375 Latte::View *GenericLayout::viewForContainment(uint id) const 0376 { 0377 for(auto view : m_latteViews) { 0378 if (view && view->containment()->id() == id) { 0379 return view; 0380 } 0381 } 0382 0383 for(auto view : m_waitingLatteViews) { 0384 if (view && view->containment()->id() == id) { 0385 return view; 0386 } 0387 } 0388 0389 return nullptr; 0390 } 0391 0392 Plasma::Containment *GenericLayout::containmentForId(uint id) const 0393 { 0394 for(auto containment : m_containments) { 0395 if (containment->id() == id) { 0396 return containment; 0397 } 0398 } 0399 0400 return nullptr; 0401 } 0402 0403 bool GenericLayout::contains(Plasma::Containment *containment) const 0404 { 0405 return m_containments.contains(containment); 0406 } 0407 0408 int GenericLayout::screenForContainment(Plasma::Containment *containment) 0409 { 0410 if (!containment) { 0411 return -1; 0412 } 0413 0414 //! there is a pending update 0415 QString containmentid = QString::number(containment->id()); 0416 if (m_pendingContainmentUpdates.containsId(containmentid)) { 0417 if (m_corona && m_pendingContainmentUpdates[containmentid].onPrimary) { 0418 return m_corona->screenPool()->primaryScreenId(); 0419 } else { 0420 return m_pendingContainmentUpdates[containmentid].screen; 0421 } 0422 } 0423 0424 //! there is a view present 0425 Latte::View *view{nullptr}; 0426 0427 if (m_latteViews.contains(containment)) { 0428 view = m_latteViews[containment]; 0429 } else if (m_waitingLatteViews.contains(containment)) { 0430 view = m_waitingLatteViews[containment]; 0431 } 0432 0433 if (view && view->screen()) { 0434 return m_corona->screenPool()->id(view->screen()->name()); 0435 } 0436 0437 //! fallback scenario 0438 return containment->lastScreen(); 0439 } 0440 0441 bool GenericLayout::containsView(const int &containmentId) const 0442 { 0443 if (!isActive()) { 0444 return Layouts::Storage::self()->containsView(file(), containmentId); 0445 } 0446 0447 for(auto containment : m_containments) { 0448 if ((int)containment->id() == containmentId && Layouts::Storage::self()->isLatteContainment(containment)) { 0449 return true; 0450 } 0451 } 0452 0453 return false; 0454 } 0455 0456 Latte::View *GenericLayout::viewForContainment(Plasma::Containment *containment) const 0457 { 0458 if (m_containments.contains(containment) && m_latteViews.contains(containment)) { 0459 return m_latteViews[containment]; 0460 } 0461 0462 return nullptr; 0463 } 0464 0465 QList<Latte::View *> GenericLayout::latteViews() 0466 { 0467 return m_latteViews.values(); 0468 } 0469 0470 QList<Latte::View *> GenericLayout::onlyOriginalViews() 0471 { 0472 QList<Latte::View *> viewslist; 0473 0474 for (const auto v : m_latteViews) { 0475 if (v->isOriginal()) { 0476 viewslist << v; 0477 } 0478 } 0479 0480 return viewslist; 0481 } 0482 0483 QList<Latte::View *> GenericLayout::sortedLatteViews() 0484 { 0485 QScreen *primaryScreen = (m_corona ? m_corona->screenPool()->primaryScreen() : nullptr); 0486 return sortedLatteViews(latteViews(), primaryScreen); 0487 } 0488 0489 QList<Latte::View *> GenericLayout::sortedLatteViews(QList<Latte::View *> views, QScreen *primaryScreen) 0490 { 0491 QList<Latte::View *> sortedViews = views; 0492 0493 qDebug() << " -------- "; 0494 0495 for (int i = 0; i < sortedViews.count(); ++i) { 0496 qDebug() << i << ". " << sortedViews[i]->screen()->name() << " - " << sortedViews[i]->location(); 0497 } 0498 0499 //! sort the views based on screens and edges priorities 0500 //! views on primary screen have higher priority and 0501 //! for views in the same screen the priority goes to 0502 //! Bottom,Left,Top,Right 0503 for (int i = 0; i < sortedViews.size(); ++i) { 0504 for (int j = 0; j < sortedViews.size() - i - 1; ++j) { 0505 if (viewAtLowerScreenPriority(sortedViews[j], sortedViews[j + 1], primaryScreen) 0506 || (sortedViews[j]->screen() == sortedViews[j + 1]->screen() 0507 && viewAtLowerEdgePriority(sortedViews[j], sortedViews[j + 1]))) { 0508 Latte::View *temp = sortedViews[j + 1]; 0509 sortedViews[j + 1] = sortedViews[j]; 0510 sortedViews[j] = temp; 0511 } 0512 } 0513 } 0514 0515 Latte::View *highestPriorityView{nullptr}; 0516 0517 for (int i = 0; i < sortedViews.size(); ++i) { 0518 if (sortedViews[i]->isPreferredForShortcuts()) { 0519 highestPriorityView = sortedViews[i]; 0520 sortedViews.removeAt(i); 0521 break; 0522 } 0523 } 0524 0525 if (highestPriorityView) { 0526 sortedViews.prepend(highestPriorityView); 0527 } 0528 0529 qDebug() << " -------- sorted -----"; 0530 0531 for (int i = 0; i < sortedViews.count(); ++i) { 0532 qDebug() << i << ". " << sortedViews[i]->isPreferredForShortcuts() << " - " << sortedViews[i]->screen()->name() << " - " << sortedViews[i]->location(); 0533 } 0534 0535 return sortedViews; 0536 } 0537 0538 bool GenericLayout::viewAtLowerScreenPriority(Latte::View *test, Latte::View *base, QScreen *primaryScreen) 0539 { 0540 if (!base || ! test) { 0541 return true; 0542 } 0543 0544 if (base->screen() == test->screen()) { 0545 return false; 0546 } else if (base->screen() != primaryScreen && test->screen() == primaryScreen) { 0547 return false; 0548 } else if (base->screen() == primaryScreen && test->screen() != primaryScreen) { 0549 return true; 0550 } else { 0551 int basePriority = -1; 0552 int testPriority = -1; 0553 0554 for (int i = 0; i < qGuiApp->screens().count(); ++i) { 0555 if (base->screen() == qGuiApp->screens()[i]) { 0556 basePriority = i; 0557 } 0558 0559 if (test->screen() == qGuiApp->screens()[i]) { 0560 testPriority = i; 0561 } 0562 } 0563 0564 if (testPriority <= basePriority) { 0565 return true; 0566 } else { 0567 return false; 0568 } 0569 0570 } 0571 0572 qDebug() << "viewAtLowerScreenPriority : shouldn't had reached here..."; 0573 return false; 0574 } 0575 0576 bool GenericLayout::viewAtLowerEdgePriority(Latte::View *test, Latte::View *base) 0577 { 0578 if (!base || ! test) { 0579 return true; 0580 } 0581 0582 QList<Plasma::Types::Location> edges{Plasma::Types::RightEdge, Plasma::Types::TopEdge, 0583 Plasma::Types::LeftEdge, Plasma::Types::BottomEdge}; 0584 0585 int testPriority = -1; 0586 int basePriority = -1; 0587 0588 for (int i = 0; i < edges.count(); ++i) { 0589 if (edges[i] == base->location()) { 0590 basePriority = i; 0591 } 0592 0593 if (edges[i] == test->location()) { 0594 testPriority = i; 0595 } 0596 } 0597 0598 if (testPriority < basePriority) { 0599 return true; 0600 } else { 0601 return false; 0602 } 0603 } 0604 0605 bool GenericLayout::viewDataAtLowerScreenPriority(const Latte::Data::View &test, const Latte::Data::View &base) const 0606 { 0607 if (test.onPrimary && base.onPrimary) { 0608 return false; 0609 } else if (!base.onPrimary && test.onPrimary) { 0610 return false; 0611 } else if (base.onPrimary && !test.onPrimary) { 0612 return true; 0613 } else { 0614 return test.screen <= base.screen; 0615 } 0616 } 0617 0618 bool GenericLayout::viewDataAtLowerStatePriority(const Latte::Data::View &test, const Latte::Data::View &base) const 0619 { 0620 if (test.isActive == base.isActive) { 0621 return false; 0622 } else if (!base.isActive && test.isActive) { 0623 return false; 0624 } else if (base.isActive && !test.isActive) { 0625 return true; 0626 } 0627 0628 return false; 0629 } 0630 0631 bool GenericLayout::viewDataAtLowerEdgePriority(const Latte::Data::View &test, const Latte::Data::View &base) const 0632 { 0633 QList<Plasma::Types::Location> edges{Plasma::Types::RightEdge, Plasma::Types::TopEdge, 0634 Plasma::Types::LeftEdge, Plasma::Types::BottomEdge}; 0635 0636 int testPriority = -1; 0637 int basePriority = -1; 0638 0639 for (int i = 0; i < edges.count(); ++i) { 0640 if (edges[i] == base.edge) { 0641 basePriority = i; 0642 } 0643 0644 if (edges[i] == test.edge) { 0645 testPriority = i; 0646 } 0647 } 0648 0649 if (testPriority < basePriority) { 0650 return true; 0651 } else { 0652 return false; 0653 } 0654 } 0655 0656 QList<Latte::Data::View> GenericLayout::sortedViewsData(const QList<Latte::Data::View> &viewsData) 0657 { 0658 QList<Latte::Data::View> sortedData = viewsData; 0659 0660 //! sort the views based on screens and edges priorities 0661 //! views on primary screen have higher priority and 0662 //! for views in the same screen the priority goes to 0663 //! Bottom,Left,Top,Right 0664 for (int i = 0; i < sortedData.size(); ++i) { 0665 for (int j = 0; j < sortedData.size() - i - 1; ++j) { 0666 if (viewDataAtLowerStatePriority(sortedData[j], sortedData[j + 1]) 0667 || viewDataAtLowerScreenPriority(sortedData[j], sortedData[j + 1]) 0668 || (!viewDataAtLowerScreenPriority(sortedData[j], sortedData[j + 1]) 0669 && viewDataAtLowerEdgePriority(sortedData[j], sortedData[j + 1])) ) { 0670 Latte::Data::View temp = sortedData[j + 1]; 0671 sortedData[j + 1] = sortedData[j]; 0672 sortedData[j] = temp; 0673 } 0674 } 0675 } 0676 0677 return sortedData; 0678 } 0679 0680 0681 const QList<Plasma::Containment *> *GenericLayout::containments() const 0682 { 0683 return &m_containments; 0684 } 0685 0686 QList<Latte::View *> GenericLayout::viewsWithPlasmaShortcuts() 0687 { 0688 QList<Latte::View *> views; 0689 0690 if (!m_corona) { 0691 return views; 0692 } 0693 0694 QList<uint> appletsWithShortcuts = m_corona->globalShortcuts()->shortcutsTracker()->appletsWithPlasmaShortcuts(); 0695 0696 for (const auto &appletId : appletsWithShortcuts) { 0697 for (const auto view : m_latteViews) { 0698 bool found{false}; 0699 for (const auto applet : view->containment()->applets()) { 0700 if (appletId == applet->id()) { 0701 if (!views.contains(view)) { 0702 views.append(view); 0703 found = true; 0704 break; 0705 } 0706 } 0707 } 0708 0709 if (found) { 0710 break; 0711 } 0712 } 0713 } 0714 0715 return views; 0716 } 0717 0718 0719 //! Containments Actions 0720 void GenericLayout::addContainment(Plasma::Containment *containment) 0721 { 0722 if (!containment || m_containments.contains(containment)) { 0723 return; 0724 } 0725 0726 bool containmentInLayout{false}; 0727 0728 if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::SingleLayout) { 0729 m_containments.append(containment); 0730 containmentInLayout = true; 0731 } else if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) { 0732 QString layoutId = containment->config().readEntry("layoutId", QString()); 0733 0734 if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { 0735 m_containments.append(containment); 0736 containmentInLayout = true; 0737 } 0738 } 0739 0740 if (containmentInLayout) { 0741 if (!blockAutomaticLatteViewCreation()) { 0742 addView(containment); 0743 } else { 0744 qDebug() << "delaying LatteView creation for containment :: " << containment->id(); 0745 } 0746 0747 connect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed); 0748 } 0749 } 0750 0751 void GenericLayout::appletCreated(Plasma::Applet *applet) 0752 { 0753 //! In Multiple Layout the orphaned subcontainments must be assigned to layouts 0754 //! when the user adds them 0755 KConfigGroup appletSettings = applet->containment()->config().group("Applets").group(QString::number(applet->id())); 0756 0757 int subId = Layouts::Storage::self()->subContainmentId(appletSettings); 0758 0759 if (Layouts::Storage::isValid(subId)) { 0760 uint sId = (uint)subId; 0761 0762 for (const auto containment : m_corona->containments()) { 0763 if (containment->id() == sId) { 0764 containment->config().writeEntry("layoutId", m_layoutName); 0765 } 0766 0767 addContainment(containment); 0768 } 0769 } 0770 } 0771 0772 void GenericLayout::containmentDestroyed(QObject *cont) 0773 { 0774 if (!m_corona) { 0775 return; 0776 } 0777 0778 Plasma::Containment *containment = static_cast<Plasma::Containment *>(cont); 0779 0780 if (containment) { 0781 int containmentIndex = m_containments.indexOf(containment); 0782 0783 if (containmentIndex >= 0) { 0784 m_containments.removeAt(containmentIndex); 0785 } 0786 0787 qDebug() << "Layout " << name() << " :: containment destroyed!!!!"; 0788 auto view = m_latteViews.take(containment); 0789 0790 if (!view) { 0791 view = m_waitingLatteViews.take(containment); 0792 } 0793 0794 if (view) { 0795 view->disconnectSensitiveSignals(); 0796 view->positioner()->slideOutDuringExit(containment->location()); 0797 view->deleteLater(); 0798 0799 emit viewEdgeChanged(); 0800 emit viewsCountChanged(); 0801 } 0802 } 0803 } 0804 0805 void GenericLayout::destroyedChanged(bool destroyed) 0806 { 0807 if (!m_corona) { 0808 return; 0809 } 0810 0811 qDebug() << "dock containment destroyed changed!!!!"; 0812 Plasma::Containment *sender = qobject_cast<Plasma::Containment *>(QObject::sender()); 0813 0814 if (!sender) { 0815 return; 0816 } 0817 0818 Latte::View *view; 0819 0820 if (destroyed) { 0821 view = m_latteViews.take(static_cast<Plasma::Containment *>(sender)); 0822 m_waitingLatteViews[sender] = view; 0823 } else { 0824 view = m_waitingLatteViews.take(static_cast<Plasma::Containment *>(sender)); 0825 m_latteViews[sender] =view; 0826 } 0827 0828 if (view) { 0829 emit m_corona->availableScreenRectChangedFrom(view); 0830 emit m_corona->availableScreenRegionChangedFrom(view); 0831 emit viewEdgeChanged(); 0832 emit viewsCountChanged(); 0833 } 0834 } 0835 0836 void GenericLayout::renameLayout(QString newName) 0837 { 0838 if (!m_corona || m_corona->layoutsManager()->memoryUsage() != MemoryUsage::MultipleLayouts) { 0839 return; 0840 } 0841 0842 if (m_layoutFile != Layouts::Importer::layoutUserFilePath(newName)) { 0843 setFile(Layouts::Importer::layoutUserFilePath(newName)); 0844 } 0845 0846 setName(newName); 0847 0848 for (const auto containment : m_containments) { 0849 qDebug() << "Cont ID :: " << containment->id(); 0850 containment->config().writeEntry("layoutId", m_layoutName); 0851 } 0852 } 0853 0854 void GenericLayout::addView(Plasma::Containment *containment) 0855 { 0856 qDebug().noquote() << "Adding View: Called for layout:" << m_layoutName << "with m_containments.size() ::" << m_containments.size(); 0857 0858 if (!containment || !m_corona || !containment->kPackage().isValid()) { 0859 qWarning() << "Adding View: The requested containment plugin can not be located or loaded"; 0860 return; 0861 } 0862 0863 qDebug() << "Adding View:" << containment->id() << "- Step 1..."; 0864 0865 if (!Layouts::Storage::self()->isLatteContainment(containment)) { 0866 return; 0867 } 0868 0869 qDebug() << "Adding View:" << containment->id() << "- Step 2..."; 0870 0871 if (hasLatteView(containment)) { 0872 return; 0873 } 0874 0875 qDebug() << "Adding View:" << containment->id() << "- Step 3..."; 0876 0877 QScreen *nextScreen{m_corona->screenPool()->primaryScreen()}; 0878 Data::View viewdata = Layouts::Storage::self()->view(this, containment); 0879 viewdata.screen = Layouts::Storage::self()->expectedViewScreenId(m_corona, viewdata); 0880 0881 QString nextScreenName = m_corona->screenPool()->hasScreenId(viewdata.screen) ? m_corona->screenPool()->connector(viewdata.screen) : ""; 0882 0883 qDebug().noquote() << "Adding View:" << viewdata.id << "-" 0884 << "IsClonedFrom:" << viewdata.isClonedFrom 0885 << ", NextScreen:" << viewdata.screen << "-" << nextScreenName 0886 << ", OnPrimary:" << viewdata.onPrimary 0887 << ", Edge:" << viewdata.edge; 0888 0889 if (!viewdata.onPrimary && Layouts::Storage::isValid(viewdata.screen)) { 0890 bool foundNextExplicitScreen{false}; 0891 0892 if (m_corona->screenPool()->isScreenActive(viewdata.screen)) { 0893 foundNextExplicitScreen = true; 0894 nextScreen = m_corona->screenPool()->screenForId(viewdata.screen); 0895 } 0896 0897 if (!foundNextExplicitScreen) { 0898 qDebug().noquote() << "Adding View:" << viewdata.id << "- Rejected because Screen is not available :: " << nextScreenName; 0899 return; 0900 } 0901 } 0902 0903 //! it is used to set the correct flag during the creation 0904 //! of the window... This of course is also used during 0905 //! recreations of the window between different visibility modes 0906 auto mode = static_cast<Types::Visibility>(containment->config().readEntry("visibility", static_cast<int>(Types::DodgeActive))); 0907 bool byPassWM{false}; 0908 0909 if (mode == Types::AlwaysVisible 0910 || mode == Types::WindowsGoBelow 0911 || mode == Types::WindowsCanCover 0912 || mode == Types::WindowsAlwaysCover) { 0913 byPassWM = false; 0914 } else { 0915 byPassWM = containment->config().readEntry("byPassWM", false); 0916 } 0917 0918 Latte::View *latteView; 0919 0920 if (!viewdata.isCloned()) { 0921 latteView = new Latte::OriginalView(m_corona, nextScreen, byPassWM); 0922 } else { 0923 auto view = viewForContainment((uint)viewdata.isClonedFrom); 0924 0925 if (!containsView(viewdata.isClonedFrom) || !view) { 0926 qDebug().noquote() << "Adding View:" << viewdata.id << "- Clone did not find OriginalView and as such was stopped!!!"; 0927 return; 0928 } 0929 0930 auto originalview = qobject_cast<Latte::OriginalView *>(view); 0931 latteView = new Latte::ClonedView(m_corona, originalview, nextScreen, byPassWM); 0932 } 0933 0934 qDebug().noquote() << "Adding View:" << viewdata.id << "- Passed ALL checks !!!"; 0935 m_latteViews[containment] = latteView; 0936 0937 latteView->init(containment); 0938 latteView->setContainment(containment); 0939 latteView->setLayout(this); 0940 0941 //! Qt 5.9 creates a crash for this in wayland, that is why the check is used 0942 //! but on the other hand we need this for copy to work correctly and show 0943 //! the copied dock under X11 0944 //if (!KWindowSystem::isPlatformWayland()) { 0945 latteView->show(); 0946 //} 0947 0948 emit viewsCountChanged(); 0949 } 0950 0951 void GenericLayout::toggleHiddenState(QString viewName, QString screenName, Plasma::Types::Location edge) 0952 { 0953 if (!m_corona) { 0954 return; 0955 } 0956 0957 QString validScreenName = m_corona->screenPool()->primaryScreen()->name(); 0958 if (!screenName.isEmpty()) { 0959 validScreenName = screenName; 0960 } 0961 0962 int viewsOnEdge{0}; 0963 0964 for(const auto view : latteViews()) { 0965 if ((viewName.isEmpty() || (!viewName.isEmpty() && viewName == view->name())) 0966 && view->positioner()->currentScreenName() == validScreenName 0967 && (edge == Plasma::Types::Floating || ((edge != Plasma::Types::Floating) && view->location() == edge))) { 0968 viewsOnEdge++; 0969 } 0970 } 0971 0972 if (viewsOnEdge >= 1) { 0973 for(const auto view : latteViews()) { 0974 if ((viewName.isEmpty() || (!viewName.isEmpty() && viewName == view->name())) 0975 && view->positioner()->currentScreenName() == validScreenName 0976 && (edge == Plasma::Types::Floating || ((edge != Plasma::Types::Floating) && view->location() == edge))) { 0977 view->visibility()->toggleHiddenState(); 0978 } 0979 } 0980 } 0981 } 0982 0983 bool GenericLayout::initCorona() 0984 { 0985 if (!m_corona) { 0986 return false; 0987 } 0988 0989 connect(m_corona, &Plasma::Corona::containmentAdded, this, &GenericLayout::addContainment); 0990 0991 updateLastUsedActivity(); 0992 0993 //! signals 0994 connect(this, &GenericLayout::activitiesChanged, this, &GenericLayout::updateLastUsedActivity); 0995 connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, &GenericLayout::updateLastUsedActivity); 0996 connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, &GenericLayout::updateLastUsedActivity); 0997 0998 connect(this, &GenericLayout::lastConfigViewForChanged, m_corona->layoutsManager(), &Layouts::Manager::lastConfigViewChangedFrom); 0999 connect(m_corona->layoutsManager(), &Layouts::Manager::lastConfigViewChangedFrom, this, &GenericLayout::onLastConfigViewChangedFrom); 1000 1001 //!connect signals after adding the containment 1002 connect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRectChanged); 1003 connect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRegionChanged); 1004 1005 return true; 1006 } 1007 1008 bool GenericLayout::initContainments() 1009 { 1010 if (!m_corona || m_hasInitializedContainments) { 1011 return false; 1012 } 1013 1014 qDebug() << "Layout ::::: " << name() << " added containments ::: " << m_containments.size(); 1015 1016 for(int pass=1; pass<=2; ++pass) { 1017 for (const auto containment : m_corona->containments()) { 1018 //! in first pass we load subcontainments 1019 //! in second pass we load main dock and panel containments 1020 //! this way subcontainments will be always available to find when the layout is activating 1021 //! for example during startup that clones must be created and subcontainments should be taken into account 1022 if ((pass==1 && Layouts::Storage::self()->isLatteContainment(containment) 1023 || (pass==2 && !Layouts::Storage::self()->isLatteContainment(containment)))) { 1024 continue; 1025 } 1026 1027 if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::SingleLayout) { 1028 addContainment(containment); 1029 } else if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) { 1030 QString layoutId = containment->config().readEntry("layoutId", QString()); 1031 1032 if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { 1033 addContainment(containment); 1034 } 1035 } 1036 } 1037 } 1038 m_hasInitializedContainments = true; 1039 emit viewsCountChanged(); 1040 return true; 1041 } 1042 1043 void GenericLayout::updateLastUsedActivity() 1044 { 1045 if (!m_corona) { 1046 return; 1047 } 1048 1049 QString currentId = m_corona->activitiesConsumer()->currentActivity(); 1050 QStringList appliedActivitiesIds = appliedActivities(); 1051 1052 if (appliedActivitiesIds.contains(Data::Layout::ALLACTIVITIESID) 1053 || (m_lastUsedActivity != currentId && appliedActivitiesIds.contains(currentId))) { 1054 m_lastUsedActivity = currentId; 1055 emit lastUsedActivityChanged(); 1056 } 1057 } 1058 1059 void GenericLayout::assignToLayout(Latte::View *latteView, QList<Plasma::Containment *> containments) 1060 { 1061 if (!m_corona || containments.isEmpty()) { 1062 return; 1063 } 1064 1065 if (latteView) { 1066 m_latteViews[latteView->containment()] = latteView; 1067 } 1068 1069 m_containments << containments; 1070 1071 for (const auto containment : containments) { 1072 containment->config().writeEntry("layoutId", name()); 1073 1074 if (!latteView || (latteView && latteView->containment() != containment)) { 1075 //! assign signals only to subcontainments 1076 //! the View::setLayout() is responsible for the View::Containment signals 1077 connect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed); 1078 connect(containment, &Plasma::Applet::destroyedChanged, this, &GenericLayout::destroyedChanged); 1079 connect(containment, &Plasma::Containment::appletCreated, this, &GenericLayout::appletCreated); 1080 } 1081 } 1082 1083 if (latteView) { 1084 latteView->setLayout(this); 1085 } 1086 1087 emit viewsCountChanged(); 1088 1089 //! sync the original layout file for integrity 1090 if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) { 1091 Layouts::Storage::self()->syncToLayoutFile(this, false); 1092 } 1093 } 1094 1095 QList<Plasma::Containment *> GenericLayout::unassignFromLayout(Plasma::Containment *latteContainment) 1096 { 1097 QList<Plasma::Containment *> containments; 1098 1099 if (!m_corona || !latteContainment || !contains(latteContainment)) { 1100 return containments; 1101 } 1102 1103 containments << latteContainment; 1104 1105 for (const auto containment : m_containments) { 1106 Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent()); 1107 1108 //! add subcontainments from that latteView 1109 if (parentApplet && parentApplet->containment() && parentApplet->containment() == latteContainment) { 1110 containments << containment; 1111 //! unassign signals only to subcontainments 1112 //! the View::setLayout() is responsible for the View::Containment signals 1113 disconnect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed); 1114 disconnect(containment, &Plasma::Applet::destroyedChanged, this, &GenericLayout::destroyedChanged); 1115 disconnect(containment, &Plasma::Containment::appletCreated, this, &GenericLayout::appletCreated); 1116 } 1117 } 1118 1119 for (const auto containment : containments) { 1120 m_containments.removeAll(containment); 1121 } 1122 1123 if (containments.size() > 0) { 1124 m_latteViews.remove(latteContainment); 1125 } 1126 1127 //! sync the original layout file for integrity 1128 if (m_corona && m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) { 1129 Layouts::Storage::self()->syncToLayoutFile(this, false); 1130 } 1131 1132 return containments; 1133 } 1134 1135 void GenericLayout::recreateView(Plasma::Containment *containment, bool delayed) 1136 { 1137 if (!m_corona || m_viewsToRecreate.contains(containment) || !containment || !m_latteViews.contains(containment)) { 1138 return; 1139 } 1140 1141 int delay = delayed ? 350 : 0; 1142 m_viewsToRecreate << containment; 1143 1144 //! give the time to config window to close itself first and then recreate the dock 1145 //! step:1 remove the latteview 1146 QTimer::singleShot(delay, [this, containment]() { 1147 auto view = m_latteViews[containment]; 1148 view->disconnectSensitiveSignals(); 1149 1150 //! step:2 add the new latteview 1151 connect(view, &QObject::destroyed, this, [this, containment]() { 1152 auto view = m_latteViews.take(containment); 1153 QTimer::singleShot(250, this, [this, containment]() { 1154 if (!m_latteViews.contains(containment)) { 1155 qDebug() << "recreate - step 2: adding dock for containment:" << containment->id(); 1156 addView(containment); 1157 m_viewsToRecreate.removeAll(containment); 1158 } 1159 }); 1160 }); 1161 1162 view->deleteLater(); 1163 }); 1164 } 1165 1166 1167 bool GenericLayout::hasLatteView(Plasma::Containment *containment) 1168 { 1169 if (!m_corona) { 1170 return false; 1171 } 1172 1173 return m_latteViews.keys().contains(containment); 1174 } 1175 1176 QList<Plasma::Types::Location> GenericLayout::availableEdgesForView(QScreen *scr, Latte::View *forView) const 1177 { 1178 using Plasma::Types; 1179 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge, 1180 Types::TopEdge, Types::RightEdge}; 1181 1182 if (!m_corona) { 1183 return edges; 1184 } 1185 1186 for (const auto view : m_latteViews) { 1187 //! make sure that availabe edges takes into account only views that should be excluded, 1188 //! this is why the forView should not be excluded 1189 if (view && view != forView && view->positioner()->currentScreenName() == scr->name()) { 1190 edges.removeOne(view->location()); 1191 } 1192 } 1193 1194 return edges; 1195 } 1196 1197 bool GenericLayout::explicitDockOccupyEdge(int screen, Plasma::Types::Location location) const 1198 { 1199 if (!m_corona) { 1200 return false; 1201 } 1202 1203 for (const auto containment : m_containments) { 1204 if (Layouts::Storage::self()->isLatteContainment(containment)) { 1205 bool onPrimary = containment->config().readEntry("onPrimary", true); 1206 int id = containment->lastScreen(); 1207 Plasma::Types::Location contLocation = containment->location(); 1208 1209 if (!onPrimary && id == screen && contLocation == location) { 1210 return true; 1211 } 1212 } 1213 } 1214 1215 return false; 1216 } 1217 1218 bool GenericLayout::primaryDockOccupyEdge(Plasma::Types::Location location) const 1219 { 1220 if (!m_corona) { 1221 return false; 1222 } 1223 1224 for (const auto containment : m_containments) { 1225 if (Layouts::Storage::self()->isLatteContainment(containment)) { 1226 bool onPrimary{false}; 1227 1228 if (m_latteViews.contains(containment)) { 1229 onPrimary = m_latteViews[containment]->onPrimary(); 1230 } else { 1231 onPrimary = containment->config().readEntry("onPrimary", true); 1232 } 1233 1234 Plasma::Types::Location contLocation = containment->location(); 1235 1236 if (onPrimary && contLocation == location) { 1237 return true; 1238 } 1239 } 1240 } 1241 1242 return false; 1243 } 1244 1245 bool GenericLayout::mapContainsId(const Layout::ViewsMap *map, uint viewId) const 1246 { 1247 for(const auto &scr : map->keys()) { 1248 for(const auto &edge : (*map)[scr].keys()) { 1249 if ((*map)[scr][edge].contains(viewId)) { 1250 return true; 1251 } 1252 } 1253 } 1254 1255 return false; 1256 } 1257 1258 QString GenericLayout::mapScreenName(const ViewsMap *map, uint viewId) const 1259 { 1260 for(const auto &scr : map->keys()) { 1261 for(const auto &edge : (*map)[scr].keys()) { 1262 if ((*map)[scr][edge].contains(viewId)) { 1263 return scr; 1264 } 1265 } 1266 } 1267 1268 return QString::number(Latte::ScreenPool::NOSCREENID); 1269 } 1270 1271 //! screen name, location, containmentId 1272 Layout::ViewsMap GenericLayout::validViewsMap() 1273 { 1274 Layout::ViewsMap map; 1275 1276 if (!m_corona) { 1277 return map; 1278 } 1279 1280 QString prmScreenName = m_corona->screenPool()->primaryScreen()->name(); 1281 1282 for (const auto containment : m_containments) { 1283 if (Layouts::Storage::self()->isLatteContainment(containment) 1284 && !Layouts::Storage::self()->isClonedView(containment)) { 1285 Data::View view = hasLatteView(containment) ? m_latteViews[containment]->data() : Latte::Layouts::Storage::self()->view(this, containment); 1286 view.screen = Layouts::Storage::self()->expectedViewScreenId(m_corona, view); 1287 1288 if (view.onPrimary) { 1289 map[prmScreenName][view.edge] << containment->id(); 1290 } else { 1291 QString expScreenName = m_corona->screenPool()->connector(view.screen); 1292 1293 if (m_corona->screenPool()->isScreenActive(view.screen)) { 1294 map[expScreenName][view.edge] << containment->id(); 1295 } 1296 } 1297 } 1298 } 1299 1300 return map; 1301 } 1302 1303 1304 //! the central functions that updates loading/unloading latteviews 1305 //! concerning screen changed (for multi-screen setups mainly) 1306 void GenericLayout::syncLatteViewsToScreens() 1307 { 1308 if (!m_corona) { 1309 return; 1310 } 1311 1312 qDebug() << "START of SyncLatteViewsToScreens ...."; 1313 qDebug() << "LAYOUT ::: " << name(); 1314 qDebug() << "screen count changed -+-+ " << qGuiApp->screens().size(); 1315 1316 //! Clear up pendingContainmentUpdates when no-needed any more 1317 QStringList clearpendings; 1318 for(int i=0; i<m_pendingContainmentUpdates.rowCount(); ++i) { 1319 auto viewdata = m_pendingContainmentUpdates[i]; 1320 auto containment = containmentForId(viewdata.id.toUInt()); 1321 1322 if (containment) { 1323 if ((viewdata.onPrimary && containment->lastScreen() == m_corona->screenPool()->primaryScreenId()) 1324 || (!viewdata.onPrimary && containment->lastScreen() == viewdata.screen)) { 1325 clearpendings << viewdata.id; 1326 } 1327 } 1328 } 1329 1330 for(auto pendingid : clearpendings) { 1331 m_pendingContainmentUpdates.remove(pendingid); 1332 } 1333 1334 if (m_pendingContainmentUpdates.rowCount() > 0) { 1335 qDebug () << " Pending View updates still valid : "; 1336 m_pendingContainmentUpdates.print(); 1337 } 1338 1339 //! use valid views map based on active screens 1340 Layout::ViewsMap viewsMap = validViewsMap(); 1341 1342 QString prmScreenName = m_corona->screenPool()->primaryScreen()->name(); 1343 1344 qDebug() << "PRIMARY SCREEN :: " << prmScreenName; 1345 qDebug() << "LATTEVIEWS MAP :: " << viewsMap; 1346 1347 //! add views 1348 for (const auto containment : m_containments) { 1349 if (!hasLatteView(containment) && mapContainsId(&viewsMap, containment->id())) { 1350 qDebug() << "syncLatteViewsToScreens: view must be added... for containment:" << containment->id() << " at screen:" << mapScreenName(&viewsMap, containment->id()); 1351 addView(containment); 1352 } 1353 } 1354 1355 //! remove views 1356 QList<Plasma::Containment *> viewsToDelete; 1357 1358 for (auto view : m_latteViews) { 1359 auto containment = view->containment(); 1360 if (containment && view->isOriginal() && !mapContainsId(&viewsMap, containment->id())) { 1361 viewsToDelete << containment; 1362 } 1363 } 1364 1365 while(!viewsToDelete.isEmpty()) { 1366 auto containment = viewsToDelete.takeFirst(); 1367 auto view = m_latteViews.take(containment); 1368 qDebug() << "syncLatteViewsToScreens: view must be deleted... for containment:" << containment->id() << " at screen:" << view->positioner()->currentScreenName(); 1369 view->disconnectSensitiveSignals(); 1370 view->deleteLater(); 1371 } 1372 1373 //! reconsider views 1374 for (const auto view : m_latteViews) { 1375 if (view->containment() && view->isOriginal() && mapContainsId(&viewsMap, view->containment()->id())) { 1376 //! if the dock will not be deleted its a very good point to reconsider 1377 //! if the screen in which is running is the correct one 1378 qDebug() << "syncLatteViewsToScreens: view must consider its screen... for containment:" << view->containment()->id() << " at screen:" << view->positioner()->currentScreenName(); 1379 view->reconsiderScreen(); 1380 } 1381 } 1382 1383 qDebug() << "end of, syncLatteViewsToScreens ...."; 1384 } 1385 1386 QList<Plasma::Containment *> GenericLayout::subContainmentsOf(uint id) const 1387 { 1388 QList<Plasma::Containment *> subs; 1389 1390 auto containment = containmentForId(id); 1391 1392 if (!containment || !Layouts::Storage::self()->isLatteContainment(containment)) { 1393 return subs; 1394 } 1395 1396 auto applets = containment->config().group("Applets"); 1397 1398 for (const auto &applet : applets.groupList()) { 1399 int tSubId = Layouts::Storage::self()->subContainmentId(applets.group(applet)); 1400 1401 if (Layouts::Storage::isValid(tSubId)) { 1402 auto subcontainment = containmentForId(tSubId); 1403 1404 if (subcontainment) { 1405 subs << subcontainment; 1406 } 1407 } 1408 } 1409 1410 return subs; 1411 } 1412 1413 QList<int> GenericLayout::subContainmentsOf(Plasma::Containment *containment) const 1414 { 1415 QList<int> subs; 1416 1417 if (Layouts::Storage::self()->isLatteContainment(containment)) { 1418 auto applets = containment->config().group("Applets"); 1419 1420 for (const auto &applet : applets.groupList()) { 1421 int tSubId = Layouts::Storage::self()->subContainmentId(applets.group(applet)); 1422 1423 if (Layouts::Storage::isValid(tSubId)) { 1424 subs << tSubId; 1425 } 1426 } 1427 } 1428 1429 return subs; 1430 } 1431 1432 QList<int> GenericLayout::viewsExplicitScreens() 1433 { 1434 Data::ViewsTable views = viewsTable(); 1435 QList<int> screens; 1436 1437 for (int i=0; i<views.rowCount(); ++i) { 1438 if (!views[i].onPrimary && !screens.contains(views[i].screen)) { 1439 screens << views[i].screen; 1440 } 1441 } 1442 1443 return screens; 1444 } 1445 1446 //! STORAGE 1447 1448 bool GenericLayout::isWritable() const 1449 { 1450 return Layouts::Storage::self()->isWritable(this); 1451 } 1452 1453 void GenericLayout::lock() 1454 { 1455 Layouts::Storage::self()->lock(this); 1456 } 1457 1458 void GenericLayout::unlock() 1459 { 1460 Layouts::Storage::self()->unlock(this); 1461 } 1462 1463 void GenericLayout::syncToLayoutFile(bool removeLayoutId) 1464 { 1465 syncSettings(); 1466 Layouts::Storage::self()->syncToLayoutFile(this, removeLayoutId); 1467 } 1468 1469 bool GenericLayout::newView(const QString &templateName) 1470 { 1471 if (!isActive() || !m_corona->templatesManager()->hasViewTemplate(templateName)) { 1472 return false; 1473 } 1474 1475 QString templatefilepath = m_corona->templatesManager()->viewTemplateFilePath(templateName); 1476 Data::ViewsTable templateviews = Layouts::Storage::self()->views(templatefilepath); 1477 1478 if (templateviews.rowCount() <= 0) { 1479 return false; 1480 } 1481 1482 Data::View nextdata = templateviews[0]; 1483 int scrId = m_corona->screenPool()->primaryScreenId(); 1484 1485 QList<Plasma::Types::Location> freeedges = freeEdges(scrId); 1486 1487 if (!freeedges.contains(nextdata.edge)) { 1488 nextdata.edge = (freeedges.count() > 0 ? freeedges[0] : Plasma::Types::BottomEdge); 1489 } 1490 1491 nextdata.setState(Data::View::OriginFromViewTemplate, templatefilepath); 1492 1493 newView(nextdata); 1494 1495 return true; 1496 } 1497 1498 Data::View GenericLayout::newView(const Latte::Data::View &nextViewData) 1499 { 1500 if (nextViewData.state() == Data::View::IsInvalid) { 1501 return Data::View(); 1502 } 1503 1504 Data::View result = Layouts::Storage::self()->newView(this, nextViewData); 1505 emit viewEdgeChanged(); 1506 1507 return result; 1508 } 1509 1510 void GenericLayout::updateView(const Latte::Data::View &viewData) 1511 { 1512 //! storage -> storage [view scenario] 1513 if (!isActive()) { 1514 Layouts::Storage::self()->updateView(this, viewData); 1515 return; 1516 } 1517 1518 //! active -> active [view scenario] 1519 Latte::View *view = viewForContainment(viewData.id.toUInt()); 1520 bool viewMustBeDeleted = (view && !viewData.onPrimary && !m_corona->screenPool()->isScreenActive(viewData.screen)); 1521 1522 QString nextactivelayoutname = (viewData.state() == Data::View::OriginFromLayout && !viewData.originLayout().isEmpty() ? viewData.originLayout() : QString()); 1523 1524 if (view) { 1525 if (!viewMustBeDeleted) { 1526 QString scrName = Latte::Data::Screen::ONPRIMARYNAME; 1527 1528 if (!viewData.onPrimary) { 1529 if (m_corona->screenPool()->hasScreenId(viewData.screen)) { 1530 scrName = m_corona->screenPool()->connector(viewData.screen); 1531 } else { 1532 scrName = ""; 1533 } 1534 } 1535 1536 view->setName(viewData.name); 1537 view->positioner()->setNextLocation(nextactivelayoutname, viewData.screensGroup, scrName, viewData.edge, viewData.alignment); 1538 return; 1539 } else { 1540 //! viewMustBeDeleted 1541 m_latteViews.remove(view->containment()); 1542 view->disconnectSensitiveSignals(); 1543 delete view; 1544 } 1545 } 1546 1547 //! inactiveinmemory -> active/inactiveinmemory [viewscenario] 1548 //! active -> inactiveinmemory [viewscenario] 1549 auto containment = containmentForId(viewData.id.toUInt()); 1550 if (containment) { 1551 Layouts::Storage::self()->updateView(this, viewData); 1552 1553 //! by using pendingContainmentUpdates we make sure that when containment->screen() will be 1554 //! called though reactToScreenChange() the proper screen will be returned 1555 if (!m_pendingContainmentUpdates.containsId(viewData.id)) { 1556 m_pendingContainmentUpdates << viewData; 1557 } else { 1558 m_pendingContainmentUpdates[viewData.id] = viewData; 1559 } 1560 containment->reactToScreenChange(); 1561 } 1562 1563 if (!nextactivelayoutname.isEmpty()) { 1564 m_corona->layoutsManager()->moveView(name(), viewData.id.toUInt(), nextactivelayoutname); 1565 } 1566 1567 //! complete update circle and inform the others about the changes 1568 if (viewMustBeDeleted) { 1569 emit viewEdgeChanged(); 1570 emit viewsCountChanged(); 1571 } 1572 1573 syncLatteViewsToScreens(); 1574 } 1575 1576 void GenericLayout::removeView(const Latte::Data::View &viewData) 1577 { 1578 if (!containsView(viewData.id.toInt())) { 1579 return; 1580 } 1581 1582 if (!isActive()) { 1583 Layouts::Storage::self()->removeView(file(), viewData); 1584 return; 1585 } 1586 1587 Plasma::Containment *viewcontainment = containmentForId(viewData.id.toUInt()); 1588 destroyContainment(viewcontainment); 1589 } 1590 1591 void GenericLayout::removeOrphanedSubContainment(const int &containmentId) 1592 { 1593 Data::ViewsTable views = viewsTable(); 1594 QString cidstr = QString::number(containmentId); 1595 1596 if (views.hasContainmentId(cidstr)) { 1597 return; 1598 } 1599 1600 if (!isActive()) { 1601 Layouts::Storage::self()->removeContainment(file(), cidstr); 1602 return; 1603 } 1604 1605 Plasma::Containment *orphanedcontainment = containmentForId(cidstr.toUInt()); 1606 destroyContainment(orphanedcontainment); 1607 } 1608 1609 void GenericLayout::destroyContainment(Plasma::Containment *containment) 1610 { 1611 if (!containment || !m_corona || !contains(containment)) { 1612 return; 1613 } 1614 1615 containment->setImmutability(Plasma::Types::Mutable); 1616 containment->destroy(); 1617 } 1618 1619 QString GenericLayout::storedView(const int &containmentId) 1620 { 1621 return Layouts::Storage::self()->storedView(this, containmentId); 1622 } 1623 1624 void GenericLayout::importToCorona() 1625 { 1626 Layouts::Storage::self()->importToCorona(this); 1627 } 1628 1629 Data::ErrorsList GenericLayout::errors() const 1630 { 1631 return Layouts::Storage::self()->errors(this); 1632 } 1633 1634 Data::WarningsList GenericLayout::warnings() const 1635 { 1636 return Layouts::Storage::self()->warnings(this); 1637 } 1638 1639 Latte::Data::ViewsTable GenericLayout::viewsTable() const 1640 { 1641 return Layouts::Storage::self()->views(this); 1642 } 1643 1644 } 1645 }