1 /*
2 SPDX-FileCopyrightText: 2019 Michail Vourlakos <mvourlakos@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "genericlayout.h"
8
9 // local
10 #include "abstractlayout.h"
11 #include "../apptypes.h"
12 #include "../lattecorona.h"
13 #include "../screenpool.h"
14 #include "../layouts/importer.h"
15 #include "../layouts/manager.h"
16 #include "../layouts/storage.h"
17 #include "../layouts/synchronizer.h"
18 #include "../shortcuts/shortcutstracker.h"
19 #include "../templates/templatesmanager.h"
20 #include "../view/view.h"
21 #include "../view/positioner.h"
22
23 // Qt
24 #include <QDebug>
25 #include <QScreen>
26
27 // Plasma
28 #include <Plasma>
29 #include <Plasma/Applet>
30 #include <Plasma/Containment>
31
32 // KDE
33 #include <KActionCollection>
34 #include <KConfigGroup>
35
36 namespace Latte {
37 namespace Layout {
38
GenericLayout(QObject * parent,QString layoutFile,QString assignedName)39 GenericLayout::GenericLayout(QObject *parent, QString layoutFile, QString assignedName)
40 : AbstractLayout (parent, layoutFile, assignedName)
41 {
42 }
43
~GenericLayout()44 GenericLayout::~GenericLayout()
45 {
46 }
47
type() const48 Type GenericLayout::type() const
49 {
50 return Type::Generic;
51 }
52
unloadContainments()53 void GenericLayout::unloadContainments()
54 {
55 if (!m_corona) {
56 return;
57 }
58
59 qDebug() << "Layout - " + name() + " : [unloadContainments]"
60 << "containments ::: " << m_containments.size()
61 << " ,latteViews in memory ::: " << m_latteViews.size()
62 << " ,hidden latteViews in memory ::: " << m_waitingLatteViews.size();
63
64 for (const auto view : m_latteViews) {
65 view->disconnectSensitiveSignals();
66 }
67
68 for (const auto view : m_waitingLatteViews) {
69 view->disconnectSensitiveSignals();
70 }
71
72 m_unloadedContainmentsIds.clear();
73
74 QList<Plasma::Containment *> subcontainments;
75
76 //!identify subcontainments and unload them first
77 for (const auto containment : m_containments) {
78 if (Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent())) {
79 subcontainments.append(containment);
80 }
81 }
82
83 while (!subcontainments.isEmpty()) {
84 Plasma::Containment *sub = subcontainments.at(0);
85 m_unloadedContainmentsIds << QString::number(sub->id());
86 subcontainments.removeFirst();
87 m_containments.removeAll(sub);
88 delete sub;
89 }
90
91 while (!m_containments.isEmpty()) {
92 Plasma::Containment *containment = m_containments.at(0);
93 m_unloadedContainmentsIds << QString::number(containment->id());
94 m_containments.removeFirst();
95 delete containment;
96 }
97 }
98
unloadLatteViews()99 void GenericLayout::unloadLatteViews()
100 {
101 if (!m_corona) {
102 return;
103 }
104
105 qDebug() << "Layout - " + name() + " : [unloadLatteViews]"
106 << "containments ::: " << m_containments.size()
107 << " ,latteViews in memory ::: " << m_latteViews.size()
108 << " ,hidden latteViews in memory ::: " << m_waitingLatteViews.size();
109
110 //!disconnect signals in order to avoid crashes when the layout is unloading
111 disconnect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRectChanged);
112 disconnect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRegionChanged);
113 disconnect(this, &GenericLayout::activitiesChanged, this, &GenericLayout::updateLastUsedActivity);
114 disconnect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, &GenericLayout::updateLastUsedActivity);
115
116 for (const auto view : m_latteViews) {
117 view->disconnectSensitiveSignals();
118 }
119
120 for (const auto view : m_waitingLatteViews) {
121 view->disconnectSensitiveSignals();
122 }
123
124 qDeleteAll(m_latteViews);
125 qDeleteAll(m_waitingLatteViews);
126 m_latteViews.clear();
127 m_waitingLatteViews.clear();
128 }
129
blockAutomaticLatteViewCreation() const130 bool GenericLayout::blockAutomaticLatteViewCreation() const
131 {
132 return m_blockAutomaticLatteViewCreation;
133 }
134
setBlockAutomaticLatteViewCreation(bool block)135 void GenericLayout::setBlockAutomaticLatteViewCreation(bool block)
136 {
137 if (m_blockAutomaticLatteViewCreation == block) {
138 return;
139 }
140
141 m_blockAutomaticLatteViewCreation = block;
142 }
143
isActive() const144 bool GenericLayout::isActive() const
145 {
146 return m_corona && (m_corona->layoutsManager()->synchronizer()->layout(m_layoutName) != nullptr);
147 }
148
isCurrent()149 bool GenericLayout::isCurrent()
150 {
151 if (!m_corona) {
152 return false;
153 }
154
155 return m_corona->layoutsManager()->currentLayoutsNames().contains(name());
156 }
157
background() const158 QString GenericLayout::background() const
159 {
160 QString colorsPath = m_corona->kPackage().path() + "../../shells/org.kde.latte.shell/contents/images/canvas/";
161
162 if (backgroundStyle() == Layout::PatternBackgroundStyle) {
163 if (customBackground().isEmpty()) {
164
165 return colorsPath + "defaultcustomprint.jpg";
166 } else {
167 return AbstractLayout::customBackground();
168 }
169 }
170
171 return colorsPath + AbstractLayout::color() + "print.jpg";
172 }
173
textColor() const174 QString GenericLayout::textColor() const
175 {
176 if (backgroundStyle() == Layout::PatternBackgroundStyle && customBackground().isEmpty() && customTextColor().isEmpty()) {
177 return AbstractLayout::defaultCustomTextColor();
178 }
179
180 return AbstractLayout::textColor();
181 }
182
viewsCount(int screen) const183 int GenericLayout::viewsCount(int screen) const
184 {
185 if (!m_corona) {
186 return 0;
187 }
188
189 QScreen *scr = m_corona->screenPool()->screenForId(screen);
190
191 int views{0};
192
193 for (const auto view : m_latteViews) {
194 if (view && view->screen() == scr && !view->containment()->destroyed()) {
195 ++views;
196 }
197 }
198
199 return views;
200 }
201
viewsCount(QScreen * screen) const202 int GenericLayout::viewsCount(QScreen *screen) const
203 {
204 if (!m_corona) {
205 return 0;
206 }
207
208 int views{0};
209
210 for (const auto view : m_latteViews) {
211 if (view && view->screen() == screen && !view->containment()->destroyed()) {
212 ++views;
213 }
214 }
215
216 return views;
217 }
218
viewsCount() const219 int GenericLayout::viewsCount() const
220 {
221 if (!m_corona) {
222 return 0;
223 }
224
225 int views{0};
226
227 for (const auto view : m_latteViews) {
228 if (view && view->containment() && !view->containment()->destroyed()) {
229 ++views;
230 }
231 }
232
233 return views;
234 }
235
qmlFreeEdges(int screen) const236 QList<int> GenericLayout::qmlFreeEdges(int screen) const
237 {
238 if (!m_corona) {
239 const QList<int> emptyEdges;
240 return emptyEdges;
241 }
242
243 const auto edges = freeEdges(screen);
244 QList<int> edgesInt;
245
246 for (const Plasma::Types::Location &edge : edges) {
247 edgesInt.append(static_cast<int>(edge));
248 }
249
250 return edgesInt;
251 }
252
freeEdges(QScreen * scr) const253 QList<Plasma::Types::Location> GenericLayout::freeEdges(QScreen *scr) const
254 {
255 using Plasma::Types;
256 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge,
257 Types::TopEdge, Types::RightEdge};
258
259 if (!m_corona) {
260 return edges;
261 }
262
263 for (const auto view : m_latteViews) {
264 if (view && view->positioner()->currentScreenName() == scr->name()) {
265 edges.removeOne(view->location());
266 }
267 }
268
269 return edges;
270 }
271
freeEdges(int screen) const272 QList<Plasma::Types::Location> GenericLayout::freeEdges(int screen) const
273 {
274 using Plasma::Types;
275 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge,
276 Types::TopEdge, Types::RightEdge};
277
278 if (!m_corona) {
279 return edges;
280 }
281
282 QScreen *scr = m_corona->screenPool()->screenForId(screen);
283
284 for (const auto view : m_latteViews) {
285 if (view && scr && view->positioner()->currentScreenName() == scr->name()) {
286 edges.removeOne(view->location());
287 }
288 }
289
290 return edges;
291 }
292
viewsWithTasks() const293 int GenericLayout::viewsWithTasks() const
294 {
295 if (!m_corona) {
296 return 0;
297 }
298
299 int result = 0;
300
301 for (const auto view : m_latteViews) {
302 if (view->extendedInterface()->hasLatteTasks() || view->extendedInterface()->hasPlasmaTasks()) {
303 result++;
304 }
305 }
306
307 return result;
308 }
309
unloadedContainmentsIds()310 QStringList GenericLayout::unloadedContainmentsIds()
311 {
312 return m_unloadedContainmentsIds;
313 }
314
corona() const315 Latte::Corona *GenericLayout::corona() const
316 {
317 return m_corona;
318 }
319
latteViewType(uint containmentId) const320 Types::ViewType GenericLayout::latteViewType(uint containmentId) const
321 {
322 for (const auto view : m_latteViews) {
323 if (view->containment() && view->containment()->id() == containmentId) {
324 return view->type();
325 }
326 }
327
328 return Types::DockView;
329 }
330
highestPriorityView()331 Latte::View *GenericLayout::highestPriorityView()
332 {
333 QList<Latte::View *> views = sortedLatteViews();
334
335 return (views.count() > 0 ? views[0] : nullptr);
336 }
337
lastConfigViewFor()338 Latte::View *GenericLayout::lastConfigViewFor()
339 {
340 return m_lastConfigViewFor;
341 }
342
setLastConfigViewFor(Latte::View * view)343 void GenericLayout::setLastConfigViewFor(Latte::View *view)
344 {
345 if (m_lastConfigViewFor == view) {
346 return;
347 }
348
349 m_lastConfigViewFor = view;
350
351 if (view) {
352 emit lastConfigViewForChanged(view);
353 }
354 }
355
onLastConfigViewChangedFrom(Latte::View * view)356 void GenericLayout::onLastConfigViewChangedFrom(Latte::View *view)
357 {
358 if (!m_latteViews.values().contains(view)) {
359 setLastConfigViewFor(nullptr);
360 }
361 }
362
viewForContainment(uint id) const363 Latte::View *GenericLayout::viewForContainment(uint id) const
364 {
365 for(auto view : m_latteViews) {
366 if (view && view->containment()->id() == id) {
367 return view;
368 }
369 }
370
371 return nullptr;
372 }
373
containmentForId(uint id) const374 Plasma::Containment *GenericLayout::containmentForId(uint id) const
375 {
376 for(auto containment : m_containments) {
377 if (containment->id() == id) {
378 return containment;
379 }
380 }
381
382 return nullptr;
383 }
384
contains(Plasma::Containment * containment) const385 bool GenericLayout::contains(Plasma::Containment *containment) const
386 {
387 return m_containments.contains(containment);
388 }
389
screenForContainment(Plasma::Containment * containment)390 int GenericLayout::screenForContainment(Plasma::Containment *containment)
391 {
392 if (!containment) {
393 return -1;
394 }
395
396 //! there is a pending update
397 QString containmentid = QString::number(containment->id());
398 if (m_pendingContainmentUpdates.containsId(containmentid)) {
399 if (m_corona && m_pendingContainmentUpdates[containmentid].onPrimary) {
400 return m_corona->screenPool()->primaryScreenId();
401 } else {
402 return m_pendingContainmentUpdates[containmentid].screen;
403 }
404 }
405
406 //! there is a view present
407 Latte::View *view{nullptr};
408
409 if (m_latteViews.contains(containment)) {
410 view = m_latteViews[containment];
411 } else if (m_waitingLatteViews.contains(containment)) {
412 view = m_waitingLatteViews[containment];
413 }
414
415 if (view && view->screen()) {
416 return m_corona->screenPool()->id(view->screen()->name());
417 }
418
419 //! fallback scenario
420 return containment->lastScreen();
421 }
422
containsView(const int & containmentId) const423 bool GenericLayout::containsView(const int &containmentId) const
424 {
425 if (!isActive()) {
426 return Layouts::Storage::self()->containsView(file(), containmentId);
427 }
428
429 for(auto containment : m_containments) {
430 if ((int)containment->id() == containmentId && Layouts::Storage::self()->isLatteContainment(containment)) {
431 return true;
432 }
433 }
434
435 return false;
436 }
437
viewForContainment(Plasma::Containment * containment) const438 Latte::View *GenericLayout::viewForContainment(Plasma::Containment *containment) const
439 {
440 if (m_containments.contains(containment) && m_latteViews.contains(containment)) {
441 return m_latteViews[containment];
442 }
443
444 return nullptr;
445 }
446
latteViews()447 QList<Latte::View *> GenericLayout::latteViews()
448 {
449 return m_latteViews.values();
450 }
451
sortedLatteViews()452 QList<Latte::View *> GenericLayout::sortedLatteViews()
453 {
454 return sortedLatteViews(latteViews());
455 }
456
sortedLatteViews(QList<Latte::View * > views)457 QList<Latte::View *> GenericLayout::sortedLatteViews(QList<Latte::View *> views)
458 {
459 QList<Latte::View *> sortedViews = views;
460
461 qDebug() << " -------- ";
462
463 for (int i = 0; i < sortedViews.count(); ++i) {
464 qDebug() << i << ". " << sortedViews[i]->screen()->name() << " - " << sortedViews[i]->location();
465 }
466
467 //! sort the views based on screens and edges priorities
468 //! views on primary screen have higher priority and
469 //! for views in the same screen the priority goes to
470 //! Bottom,Left,Top,Right
471 for (int i = 0; i < sortedViews.size(); ++i) {
472 for (int j = 0; j < sortedViews.size() - i - 1; ++j) {
473 if (viewAtLowerScreenPriority(sortedViews[j], sortedViews[j + 1])
474 || (sortedViews[j]->screen() == sortedViews[j + 1]->screen()
475 && viewAtLowerEdgePriority(sortedViews[j], sortedViews[j + 1]))) {
476 Latte::View *temp = sortedViews[j + 1];
477 sortedViews[j + 1] = sortedViews[j];
478 sortedViews[j] = temp;
479 }
480 }
481 }
482
483 Latte::View *highestPriorityView{nullptr};
484
485 for (int i = 0; i < sortedViews.size(); ++i) {
486 if (sortedViews[i]->isPreferredForShortcuts()) {
487 highestPriorityView = sortedViews[i];
488 sortedViews.removeAt(i);
489 break;
490 }
491 }
492
493 if (highestPriorityView) {
494 sortedViews.prepend(highestPriorityView);
495 }
496
497 qDebug() << " -------- sorted -----";
498
499 for (int i = 0; i < sortedViews.count(); ++i) {
500 qDebug() << i << ". " << sortedViews[i]->isPreferredForShortcuts() << " - " << sortedViews[i]->screen()->name() << " - " << sortedViews[i]->location();
501 }
502
503 return sortedViews;
504 }
505
viewAtLowerScreenPriority(Latte::View * test,Latte::View * base)506 bool GenericLayout::viewAtLowerScreenPriority(Latte::View *test, Latte::View *base)
507 {
508 if (!base || ! test) {
509 return true;
510 }
511
512 if (base->screen() == test->screen()) {
513 return false;
514 } else if (base->screen() != qGuiApp->primaryScreen() && test->screen() == qGuiApp->primaryScreen()) {
515 return false;
516 } else if (base->screen() == qGuiApp->primaryScreen() && test->screen() != qGuiApp->primaryScreen()) {
517 return true;
518 } else {
519 int basePriority = -1;
520 int testPriority = -1;
521
522 for (int i = 0; i < qGuiApp->screens().count(); ++i) {
523 if (base->screen() == qGuiApp->screens()[i]) {
524 basePriority = i;
525 }
526
527 if (test->screen() == qGuiApp->screens()[i]) {
528 testPriority = i;
529 }
530 }
531
532 if (testPriority <= basePriority) {
533 return true;
534 } else {
535 return false;
536 }
537
538 }
539
540 qDebug() << "viewAtLowerScreenPriority : shouldn't had reached here...";
541 return false;
542 }
543
viewAtLowerEdgePriority(Latte::View * test,Latte::View * base)544 bool GenericLayout::viewAtLowerEdgePriority(Latte::View *test, Latte::View *base)
545 {
546 if (!base || ! test) {
547 return true;
548 }
549
550 QList<Plasma::Types::Location> edges{Plasma::Types::RightEdge, Plasma::Types::TopEdge,
551 Plasma::Types::LeftEdge, Plasma::Types::BottomEdge};
552
553 int testPriority = -1;
554 int basePriority = -1;
555
556 for (int i = 0; i < edges.count(); ++i) {
557 if (edges[i] == base->location()) {
558 basePriority = i;
559 }
560
561 if (edges[i] == test->location()) {
562 testPriority = i;
563 }
564 }
565
566 if (testPriority < basePriority) {
567 return true;
568 } else {
569 return false;
570 }
571 }
572
viewDataAtLowerScreenPriority(const Latte::Data::View & test,const Latte::Data::View & base) const573 bool GenericLayout::viewDataAtLowerScreenPriority(const Latte::Data::View &test, const Latte::Data::View &base) const
574 {
575 if (test.onPrimary && base.onPrimary) {
576 return false;
577 } else if (!base.onPrimary && test.onPrimary) {
578 return false;
579 } else if (base.onPrimary && !test.onPrimary) {
580 return true;
581 } else {
582 return test.screen <= base.screen;
583 }
584 }
585
viewDataAtLowerStatePriority(const Latte::Data::View & test,const Latte::Data::View & base) const586 bool GenericLayout::viewDataAtLowerStatePriority(const Latte::Data::View &test, const Latte::Data::View &base) const
587 {
588 if (test.isActive == base.isActive) {
589 return false;
590 } else if (!base.isActive && test.isActive) {
591 return false;
592 } else if (base.isActive && !test.isActive) {
593 return true;
594 }
595
596 return false;
597 }
598
viewDataAtLowerEdgePriority(const Latte::Data::View & test,const Latte::Data::View & base) const599 bool GenericLayout::viewDataAtLowerEdgePriority(const Latte::Data::View &test, const Latte::Data::View &base) const
600 {
601 QList<Plasma::Types::Location> edges{Plasma::Types::RightEdge, Plasma::Types::TopEdge,
602 Plasma::Types::LeftEdge, Plasma::Types::BottomEdge};
603
604 int testPriority = -1;
605 int basePriority = -1;
606
607 for (int i = 0; i < edges.count(); ++i) {
608 if (edges[i] == base.edge) {
609 basePriority = i;
610 }
611
612 if (edges[i] == test.edge) {
613 testPriority = i;
614 }
615 }
616
617 if (testPriority < basePriority) {
618 return true;
619 } else {
620 return false;
621 }
622 }
623
sortedViewsData(const QList<Latte::Data::View> & viewsData)624 QList<Latte::Data::View> GenericLayout::sortedViewsData(const QList<Latte::Data::View> &viewsData)
625 {
626 QList<Latte::Data::View> sortedData = viewsData;
627
628 //! sort the views based on screens and edges priorities
629 //! views on primary screen have higher priority and
630 //! for views in the same screen the priority goes to
631 //! Bottom,Left,Top,Right
632 for (int i = 0; i < sortedData.size(); ++i) {
633 for (int j = 0; j < sortedData.size() - i - 1; ++j) {
634 if (viewDataAtLowerStatePriority(sortedData[j], sortedData[j + 1])
635 || viewDataAtLowerScreenPriority(sortedData[j], sortedData[j + 1])
636 || (!viewDataAtLowerScreenPriority(sortedData[j], sortedData[j + 1])
637 && viewDataAtLowerEdgePriority(sortedData[j], sortedData[j + 1])) ) {
638 Latte::Data::View temp = sortedData[j + 1];
639 sortedData[j + 1] = sortedData[j];
640 sortedData[j] = temp;
641 }
642 }
643 }
644
645 return sortedData;
646 }
647
648
containments() const649 const QList<Plasma::Containment *> *GenericLayout::containments() const
650 {
651 return &m_containments;
652 }
653
viewsWithPlasmaShortcuts()654 QList<Latte::View *> GenericLayout::viewsWithPlasmaShortcuts()
655 {
656 QList<Latte::View *> views;
657
658 if (!m_corona) {
659 return views;
660 }
661
662 QList<uint> appletsWithShortcuts = m_corona->globalShortcuts()->shortcutsTracker()->appletsWithPlasmaShortcuts();
663
664 for (const auto &appletId : appletsWithShortcuts) {
665 for (const auto view : m_latteViews) {
666 bool found{false};
667 for (const auto applet : view->containment()->applets()) {
668 if (appletId == applet->id()) {
669 if (!views.contains(view)) {
670 views.append(view);
671 found = true;
672 break;
673 }
674 }
675 }
676
677 if (found) {
678 break;
679 }
680 }
681 }
682
683 return views;
684 }
685
686
687 //! Containments Actions
addContainment(Plasma::Containment * containment)688 void GenericLayout::addContainment(Plasma::Containment *containment)
689 {
690 if (!containment || m_containments.contains(containment)) {
691 return;
692 }
693
694 bool containmentInLayout{false};
695
696 if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::SingleLayout) {
697 m_containments.append(containment);
698 containmentInLayout = true;
699 } else if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) {
700 QString layoutId = containment->config().readEntry("layoutId", QString());
701
702 if (!layoutId.isEmpty() && (layoutId == m_layoutName)) {
703 m_containments.append(containment);
704 containmentInLayout = true;
705 }
706 }
707
708 if (containmentInLayout) {
709 if (!blockAutomaticLatteViewCreation()) {
710 addView(containment);
711 } else {
712 qDebug() << "delaying LatteView creation for containment :: " << containment->id();
713 }
714
715 connect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed);
716 }
717 }
718
appletCreated(Plasma::Applet * applet)719 void GenericLayout::appletCreated(Plasma::Applet *applet)
720 {
721 //! In Multiple Layout the orphaned subcontainments must be assigned to layouts
722 //! when the user adds them
723 KConfigGroup appletSettings = applet->containment()->config().group("Applets").group(QString::number(applet->id()));
724
725 int subId = Layouts::Storage::self()->subContainmentId(appletSettings);
726
727 if (Layouts::Storage::isValid(subId)) {
728 uint sId = (uint)subId;
729
730 for (const auto containment : m_corona->containments()) {
731 if (containment->id() == sId) {
732 containment->config().writeEntry("layoutId", m_layoutName);
733 }
734
735 addContainment(containment);
736 }
737 }
738 }
739
containmentDestroyed(QObject * cont)740 void GenericLayout::containmentDestroyed(QObject *cont)
741 {
742 if (!m_corona) {
743 return;
744 }
745
746 Plasma::Containment *containment = static_cast<Plasma::Containment *>(cont);
747
748 if (containment) {
749 int containmentIndex = m_containments.indexOf(containment);
750
751 if (containmentIndex >= 0) {
752 m_containments.removeAt(containmentIndex);
753 }
754
755 qDebug() << "Layout " << name() << " :: containment destroyed!!!!";
756 auto view = m_latteViews.take(containment);
757
758 if (!view) {
759 view = m_waitingLatteViews.take(containment);
760 }
761
762 if (view) {
763 view->disconnectSensitiveSignals();
764 view->positioner()->slideOutDuringExit(containment->location());
765 view->deleteLater();
766
767 emit viewEdgeChanged();
768 emit viewsCountChanged();
769 }
770 }
771 }
772
destroyedChanged(bool destroyed)773 void GenericLayout::destroyedChanged(bool destroyed)
774 {
775 if (!m_corona) {
776 return;
777 }
778
779 qDebug() << "dock containment destroyed changed!!!!";
780 Plasma::Containment *sender = qobject_cast<Plasma::Containment *>(QObject::sender());
781
782 if (!sender) {
783 return;
784 }
785
786 Latte::View *view;
787
788 if (destroyed) {
789 view = m_latteViews.take(static_cast<Plasma::Containment *>(sender));
790 m_waitingLatteViews[sender] = view;
791 } else {
792 view = m_waitingLatteViews.take(static_cast<Plasma::Containment *>(sender));
793 m_latteViews[sender] =view;
794 }
795
796 if (view) {
797 emit m_corona->availableScreenRectChangedFrom(view);
798 emit m_corona->availableScreenRegionChangedFrom(view);
799 emit viewEdgeChanged();
800 emit viewsCountChanged();
801 }
802 }
803
renameLayout(QString newName)804 void GenericLayout::renameLayout(QString newName)
805 {
806 if (!m_corona || m_corona->layoutsManager()->memoryUsage() != MemoryUsage::MultipleLayouts) {
807 return;
808 }
809
810 if (m_layoutFile != Layouts::Importer::layoutUserFilePath(newName)) {
811 setFile(Layouts::Importer::layoutUserFilePath(newName));
812 }
813
814 setName(newName);
815
816 for (const auto containment : m_containments) {
817 qDebug() << "Cont ID :: " << containment->id();
818 containment->config().writeEntry("layoutId", m_layoutName);
819 }
820 }
821
addView(Plasma::Containment * containment,bool forceOnPrimary,int explicitScreen,Layout::ViewsMap * occupied)822 void GenericLayout::addView(Plasma::Containment *containment, bool forceOnPrimary, int explicitScreen, Layout::ViewsMap *occupied)
823 {
824 qDebug() << "Layout :::: " << m_layoutName << " ::: addView was called... m_containments :: " << m_containments.size();
825
826 if (!containment || !m_corona || !containment->kPackage().isValid()) {
827 qWarning() << "the requested containment plugin can not be located or loaded";
828 return;
829 }
830
831 qDebug() << "step 1...";
832
833 if (!Layouts::Storage::self()->isLatteContainment(containment)) {
834 return;
835 }
836
837 qDebug() << "step 2...";
838
839 for (auto *dock : m_latteViews) {
840 if (dock->containment() == containment)
841 return;
842 }
843
844 qDebug() << "step 3...";
845
846 QScreen *nextScreen{qGuiApp->primaryScreen()};
847
848 bool onPrimary = containment->config().readEntry("onPrimary", true);
849 int id = containment->screen();
850
851 if (!Layouts::Storage::isValid(id) && !Layouts::Storage::isValid(explicitScreen)) {
852 id = containment->lastScreen();
853 }
854
855 if (onPrimary) {
856 id = m_corona->screenPool()->primaryScreenId();
857 } else if (Layouts::Storage::isValid(explicitScreen)) {
858 id = explicitScreen;
859 }
860
861 Plasma::Types::Location edge = containment->location();
862
863 QString connector = m_corona->screenPool()->hasScreenId(id) ? m_corona->screenPool()->connector(id) : "";
864
865 qDebug() << "Adding view - containment id:" << containment->id() << " ,screen :" << id << " - " << connector
866 << " ,onprimary:" << onPrimary << " - " << " edge:" << edge << " ,screenName:" << qGuiApp->primaryScreen()->name() << " ,forceOnPrimary:" << forceOnPrimary;
867
868 if (occupied && m_corona->screenPool()->hasScreenId(id) && (*occupied).contains(connector) && (*occupied)[connector].contains(edge)) {
869 qDebug() << "Rejected : adding view because the edge is already occupied by a higher priority view ! : " << (*occupied)[connector][edge];
870 return;
871 }
872
873 if (Layouts::Storage::isValid(id) && !onPrimary && !forceOnPrimary) {
874 qDebug() << "Add view - connector : " << connector;
875 bool found{false};
876
877 if (m_corona->screenPool()->hasScreenId(id)) {
878 for (const auto scr : qGuiApp->screens()) {
879 if (scr && scr->name() == connector) {
880 found = true;
881 nextScreen = scr;
882 break;
883 }
884 }
885 }
886
887 if (!found) {
888 qDebug() << "Rejected : adding explicit view, screen not available ! : " << connector;
889 return;
890 }
891
892 //! explicit dock can not be added at explicit screen when that screen is the same with
893 //! primary screen and that edge is already occupied by a primary dock
894 //! CAN BE REMOVED because we now accept primary and explicit views on ACTIVE SCREENS at ALL CASES
895 //if (nextScreen == qGuiApp->primaryScreen() && primaryDockOccupyEdge(containment->location())) {
896 // qDebug() << "Rejected : adding explicit view, primary dock occupies edge at screen ! : " << connector;
897 // return;
898 // }
899 }
900
901 if (Layouts::Storage::isValid(id) && onPrimary) {
902 qDebug() << "add dock - connector : " << connector;
903
904 for (const Plasma::Containment *testContainment : m_latteViews.keys()) {
905 int testScreenId = testContainment->screen();
906
907 if (!Layouts::Storage::isValid(testScreenId)) {
908 testScreenId = testContainment->lastScreen();
909 }
910
911 bool testOnPrimary = testContainment->config().readEntry("onPrimary", true);
912 Plasma::Types::Location testLocation = static_cast<Plasma::Types::Location>((int)testContainment->config().readEntry("location", (int)Plasma::Types::BottomEdge));
913
914 if (!testOnPrimary && m_corona->screenPool()->primaryScreenId() == testScreenId && testLocation == containment->location()) {
915 qDebug() << "Rejected explicit latteView and removing it in order add an onPrimary with higher priority at screen: " << connector;
916 auto viewToDelete = m_latteViews.take(testContainment);
917 viewToDelete->disconnectSensitiveSignals();
918 viewToDelete->deleteLater();
919 }
920 }
921 }
922
923 qDebug() << "Adding view passed ALL checks" << " ,onPrimary:" << onPrimary << " ,screen:" << nextScreen->name() << " !!!";
924
925 //! it is used to set the correct flag during the creation
926 //! of the window... This of course is also used during
927 //! recreations of the window between different visibility modes
928 auto mode = static_cast<Types::Visibility>(containment->config().readEntry("visibility", static_cast<int>(Types::DodgeActive)));
929 bool byPassWM{false};
930
931 if (mode == Types::AlwaysVisible
932 || mode == Types::WindowsGoBelow
933 || mode == Types::WindowsCanCover
934 || mode == Types::WindowsAlwaysCover) {
935 byPassWM = false;
936 } else {
937 byPassWM = containment->config().readEntry("byPassWM", false);
938 }
939
940 auto latteView = new Latte::View(m_corona, nextScreen, byPassWM);
941
942 latteView->init(containment);
943 latteView->setContainment(containment);
944
945 //! force this special dock case to become primary
946 //! even though it isnt
947 if (forceOnPrimary) {
948 qDebug() << "Enforcing onPrimary:true as requested for LatteView...";
949 latteView->setOnPrimary(true);
950 }
951
952 latteView->setLayout(this);
953
954
955 //! Qt 5.9 creates a crash for this in wayland, that is why the check is used
956 //! but on the other hand we need this for copy to work correctly and show
957 //! the copied dock under X11
958 //if (!KWindowSystem::isPlatformWayland()) {
959 latteView->show();
960 //}
961
962 m_latteViews[containment] = latteView;
963
964 emit viewsCountChanged();
965 }
966
toggleHiddenState(QString viewName,QString screenName,Plasma::Types::Location edge)967 void GenericLayout::toggleHiddenState(QString viewName, QString screenName, Plasma::Types::Location edge)
968 {
969 if (!m_corona) {
970 return;
971 }
972
973 QString validScreenName = qGuiApp->primaryScreen()->name();
974 if (!screenName.isEmpty()) {
975 validScreenName = screenName;
976 }
977
978 int viewsOnEdge{0};
979
980 for(const auto view : latteViews()) {
981 if ((viewName.isEmpty() || (!viewName.isEmpty() && viewName == view->name()))
982 && view->positioner()->currentScreenName() == validScreenName
983 && (edge == Plasma::Types::Floating || ((edge != Plasma::Types::Floating) && view->location() == edge))) {
984 viewsOnEdge++;
985 }
986 }
987
988 if (viewsOnEdge >= 1) {
989 for(const auto view : latteViews()) {
990 if ((viewName.isEmpty() || (!viewName.isEmpty() && viewName == view->name()))
991 && view->positioner()->currentScreenName() == validScreenName
992 && (edge == Plasma::Types::Floating || ((edge != Plasma::Types::Floating) && view->location() == edge))) {
993 view->visibility()->toggleHiddenState();
994 }
995 }
996 }
997 }
998
initToCorona(Latte::Corona * corona)999 bool GenericLayout::initToCorona(Latte::Corona *corona)
1000 {
1001 if (m_corona) {
1002 return false;
1003 }
1004
1005 m_corona = corona;
1006
1007 for (const auto containment : m_corona->containments()) {
1008 if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::SingleLayout) {
1009 addContainment(containment);
1010 } else if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) {
1011 QString layoutId = containment->config().readEntry("layoutId", QString());
1012
1013 if (!layoutId.isEmpty() && (layoutId == m_layoutName)) {
1014 addContainment(containment);
1015 }
1016 }
1017 }
1018
1019 qDebug() << "Layout ::::: " << name() << " added containments ::: " << m_containments.size();
1020
1021 updateLastUsedActivity();
1022
1023 //! signals
1024 connect(this, &GenericLayout::activitiesChanged, this, &GenericLayout::updateLastUsedActivity);
1025 connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, &GenericLayout::updateLastUsedActivity);
1026 connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, &GenericLayout::updateLastUsedActivity);
1027
1028 connect(m_corona, &Plasma::Corona::containmentAdded, this, &GenericLayout::addContainment);
1029
1030 connect(this, &GenericLayout::lastConfigViewForChanged, m_corona->layoutsManager(), &Layouts::Manager::lastConfigViewChangedFrom);
1031 connect(m_corona->layoutsManager(), &Layouts::Manager::lastConfigViewChangedFrom, this, &GenericLayout::onLastConfigViewChangedFrom);
1032
1033 //!connect signals after adding the containment
1034 connect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRectChanged);
1035 connect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRegionChanged);
1036
1037 emit viewsCountChanged();
1038
1039 return true;
1040 }
1041
updateLastUsedActivity()1042 void GenericLayout::updateLastUsedActivity()
1043 {
1044 if (!m_corona) {
1045 return;
1046 }
1047
1048 QString currentId = m_corona->activitiesConsumer()->currentActivity();
1049 QStringList appliedActivitiesIds = appliedActivities();
1050
1051 if (appliedActivitiesIds.contains(Data::Layout::ALLACTIVITIESID)
1052 || (m_lastUsedActivity != currentId && appliedActivitiesIds.contains(currentId))) {
1053 m_lastUsedActivity = currentId;
1054 emit lastUsedActivityChanged();
1055 }
1056 }
1057
assignToLayout(Latte::View * latteView,QList<Plasma::Containment * > containments)1058 void GenericLayout::assignToLayout(Latte::View *latteView, QList<Plasma::Containment *> containments)
1059 {
1060 if (!m_corona || containments.isEmpty()) {
1061 return;
1062 }
1063
1064 if (latteView) {
1065 m_latteViews[latteView->containment()] = latteView;
1066 }
1067
1068 m_containments << containments;
1069
1070 for (const auto containment : containments) {
1071 containment->config().writeEntry("layoutId", name());
1072
1073 if (!latteView || (latteView && latteView->containment() != containment)) {
1074 //! assign signals only to subcontainments
1075 //! the View::setLayout() is responsible for the View::Containment signals
1076 connect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed);
1077 connect(containment, &Plasma::Applet::destroyedChanged, this, &GenericLayout::destroyedChanged);
1078 connect(containment, &Plasma::Containment::appletCreated, this, &GenericLayout::appletCreated);
1079 }
1080 }
1081
1082 if (latteView) {
1083 latteView->setLayout(this);
1084 }
1085
1086 emit viewsCountChanged();
1087
1088 //! sync the original layout file for integrity
1089 if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) {
1090 Layouts::Storage::self()->syncToLayoutFile(this, false);
1091 }
1092 }
1093
unassignFromLayout(Plasma::Containment * latteContainment)1094 QList<Plasma::Containment *> GenericLayout::unassignFromLayout(Plasma::Containment *latteContainment)
1095 {
1096 QList<Plasma::Containment *> containments;
1097
1098 if (!m_corona || !latteContainment || !contains(latteContainment)) {
1099 return containments;
1100 }
1101
1102 containments << latteContainment;
1103
1104 for (const auto containment : m_containments) {
1105 Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent());
1106
1107 //! add subcontainments from that latteView
1108 if (parentApplet && parentApplet->containment() && parentApplet->containment() == latteContainment) {
1109 containments << containment;
1110 //! unassign signals only to subcontainments
1111 //! the View::setLayout() is responsible for the View::Containment signals
1112 disconnect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed);
1113 disconnect(containment, &Plasma::Applet::destroyedChanged, this, &GenericLayout::destroyedChanged);
1114 disconnect(containment, &Plasma::Containment::appletCreated, this, &GenericLayout::appletCreated);
1115 }
1116 }
1117
1118 for (const auto containment : containments) {
1119 m_containments.removeAll(containment);
1120 }
1121
1122 if (containments.size() > 0) {
1123 m_latteViews.remove(latteContainment);
1124 }
1125
1126 //! sync the original layout file for integrity
1127 if (m_corona && m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) {
1128 Layouts::Storage::self()->syncToLayoutFile(this, false);
1129 }
1130
1131 return containments;
1132 }
1133
recreateView(Plasma::Containment * containment,bool delayed)1134 void GenericLayout::recreateView(Plasma::Containment *containment, bool delayed)
1135 {
1136 if (!m_corona || m_viewsToRecreate.contains(containment) || !containment || !m_latteViews.contains(containment)) {
1137 return;
1138 }
1139
1140 int delay = delayed ? 350 : 0;
1141 m_viewsToRecreate << containment;
1142
1143 //! give the time to config window to close itself first and then recreate the dock
1144 //! step:1 remove the latteview
1145 QTimer::singleShot(delay, [this, containment]() {
1146 auto view = m_latteViews[containment];
1147 view->disconnectSensitiveSignals();
1148
1149 //! step:2 add the new latteview
1150 connect(view, &QObject::destroyed, this, [this, containment]() {
1151 auto view = m_latteViews.take(containment);
1152 QTimer::singleShot(250, this, [this, containment]() {
1153 if (!m_latteViews.contains(containment)) {
1154 qDebug() << "recreate - step 2: adding dock for containment:" << containment->id();
1155 addView(containment);
1156 m_viewsToRecreate.removeAll(containment);
1157 }
1158 });
1159 });
1160
1161 view->deleteLater();
1162 });
1163 }
1164
1165
latteViewExists(Plasma::Containment * containment)1166 bool GenericLayout::latteViewExists(Plasma::Containment *containment)
1167 {
1168 if (!m_corona) {
1169 return false;
1170 }
1171
1172 return m_latteViews.keys().contains(containment);
1173 }
1174
availableEdgesForView(QScreen * scr,Latte::View * forView) const1175 QList<Plasma::Types::Location> GenericLayout::availableEdgesForView(QScreen *scr, Latte::View *forView) const
1176 {
1177 using Plasma::Types;
1178 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge,
1179 Types::TopEdge, Types::RightEdge};
1180
1181 if (!m_corona) {
1182 return edges;
1183 }
1184
1185 for (const auto view : m_latteViews) {
1186 //! make sure that availabe edges takes into account only views that should be excluded,
1187 //! this is why the forView should not be excluded
1188 if (view && view != forView && view->positioner()->currentScreenName() == scr->name()) {
1189 edges.removeOne(view->location());
1190 }
1191 }
1192
1193 return edges;
1194 }
1195
explicitDockOccupyEdge(int screen,Plasma::Types::Location location) const1196 bool GenericLayout::explicitDockOccupyEdge(int screen, Plasma::Types::Location location) const
1197 {
1198 if (!m_corona) {
1199 return false;
1200 }
1201
1202 for (const auto containment : m_containments) {
1203 if (Layouts::Storage::self()->isLatteContainment(containment)) {
1204 bool onPrimary = containment->config().readEntry("onPrimary", true);
1205 int id = containment->lastScreen();
1206 Plasma::Types::Location contLocation = containment->location();
1207
1208 if (!onPrimary && id == screen && contLocation == location) {
1209 return true;
1210 }
1211 }
1212 }
1213
1214 return false;
1215 }
1216
primaryDockOccupyEdge(Plasma::Types::Location location) const1217 bool GenericLayout::primaryDockOccupyEdge(Plasma::Types::Location location) const
1218 {
1219 if (!m_corona) {
1220 return false;
1221 }
1222
1223 for (const auto containment : m_containments) {
1224 if (Layouts::Storage::self()->isLatteContainment(containment)) {
1225 bool onPrimary{false};
1226
1227 if (m_latteViews.contains(containment)) {
1228 onPrimary = m_latteViews[containment]->onPrimary();
1229 } else {
1230 onPrimary = containment->config().readEntry("onPrimary", true);
1231 }
1232
1233 Plasma::Types::Location contLocation = containment->location();
1234
1235 if (onPrimary && contLocation == location) {
1236 return true;
1237 }
1238 }
1239 }
1240
1241 return false;
1242 }
1243
mapContainsId(const Layout::ViewsMap * map,uint viewId) const1244 bool GenericLayout::mapContainsId(const Layout::ViewsMap *map, uint viewId) const
1245 {
1246 for(const auto &scr : map->keys()) {
1247 for(const auto &edge : (*map)[scr].keys()) {
1248 if ((*map)[scr][edge].contains(viewId)) {
1249 return true;
1250 }
1251 }
1252 }
1253
1254 return false;
1255 }
1256
1257 //! screen name, location, containmentId
validViewsMap(Layout::ViewsMap * occupiedMap)1258 Layout::ViewsMap GenericLayout::validViewsMap(Layout::ViewsMap *occupiedMap)
1259 {
1260 //! Shared Views occupy the screen edge first
1261 //! Primary Views occupy the screen edge if Shared Views do not exist already on that screen edge
1262 //! Explicity Views occypy the screen edge if Shared Views and Primary Views do not exist already on that screen edge
1263 Layout::ViewsMap map;
1264
1265 if (!m_corona) {
1266 return map;
1267 }
1268
1269 if (occupiedMap != nullptr) {
1270 map = (*occupiedMap);
1271 }
1272
1273 QString prmScreenName = qGuiApp->primaryScreen()->name();
1274
1275 //! first step: primary docks must be placed in primary screen free edges
1276 for (const auto containment : m_containments) {
1277 if (Layouts::Storage::self()->isLatteContainment(containment)) {
1278 int screenId{Layouts::Storage::IDNULL};
1279
1280 //! valid screen id
1281 if (latteViewExists(containment)) {
1282 screenId = m_latteViews[containment]->positioner()->currentScreenId();
1283 } else {
1284 screenId = containment->screen();
1285
1286 if (!Layouts::Storage::isValid(screenId)) {
1287 screenId = containment->lastScreen();
1288 }
1289 }
1290
1291 bool onPrimary{true};
1292
1293 //! valid onPrimary flag
1294 if (latteViewExists(containment)) {
1295 onPrimary = m_latteViews[containment]->onPrimary();
1296 } else {
1297 onPrimary = containment->config().readEntry("onPrimary", true);
1298 }
1299
1300 //! valid location
1301 Plasma::Types::Location location = containment->location();
1302
1303 if (onPrimary) {
1304 map[prmScreenName][location] << containment->id();
1305 } else {
1306 QString expScreenName = m_corona->screenPool()->connector(screenId);
1307
1308 if (m_corona->screenPool()->isScreenActive(screenId)) {
1309 map[expScreenName][location] << containment->id();
1310 }
1311 }
1312 }
1313 }
1314
1315 /*
1316 //! CAN BE REMOVED because we now accept primary and explicit views on ACTIVE SCREENS at ALL CASES
1317 Layout::ViewsMap explicitMap;
1318
1319 //! second step: explicit docks must be placed in their screens if the screen edge is free
1320 for (const auto containment : m_containments) {
1321 if (Layouts::Storage::self()->isLatteContainment(containment)) {
1322 int screenId{Layouts::Storage::IDNULL};
1323
1324 //! valid screen id
1325 if (latteViewExists(containment)) {
1326 screenId = m_latteViews[containment]->positioner()->currentScreenId();
1327 } else {
1328 screenId = containment->screen();
1329
1330 if (!Layouts::Storage::isValid(screenId)) {
1331 screenId = containment->lastScreen();
1332 }
1333 }
1334
1335 bool onPrimary{true};
1336
1337 //! valid onPrimary flag
1338 if (latteViewExists(containment)) {
1339 onPrimary = m_latteViews[containment]->onPrimary();
1340 } else {
1341 onPrimary = containment->config().readEntry("onPrimary", true);
1342 }
1343
1344 //! valid location
1345 Plasma::Types::Location location = containment->location();
1346
1347 if (!onPrimary) {
1348 QString expScreenName = m_corona->screenPool()->connector(screenId);
1349
1350 if (m_corona->screenPool()->isScreenActive(screenId) && !map[expScreenName].contains(location)) {
1351 explicitMap[expScreenName][location] << containment->id();
1352 }
1353 }
1354 }
1355 }
1356
1357 for(const QString &expScreenName : explicitMap.keys()) {
1358 for(const Plasma::Types::Location &expLocation : explicitMap[expScreenName].keys()) {
1359 map[expScreenName][expLocation] << explicitMap[expScreenName][expLocation];
1360 }
1361 }*/
1362
1363 return map;
1364 }
1365
1366
1367 //! the central functions that updates loading/unloading latteviews
1368 //! concerning screen changed (for multi-screen setups mainly)
syncLatteViewsToScreens(Layout::ViewsMap * occupiedMap)1369 void GenericLayout::syncLatteViewsToScreens(Layout::ViewsMap *occupiedMap)
1370 {
1371 if (!m_corona) {
1372 return;
1373 }
1374
1375 qDebug() << "START of SyncLatteViewsToScreens ....";
1376 qDebug() << "LAYOUT ::: " << name();
1377 qDebug() << "screen count changed -+-+ " << qGuiApp->screens().size();
1378
1379 //! Clear up pendingContainmentUpdates when no-needed any more
1380 QStringList clearpendings;
1381 for(int i=0; i<m_pendingContainmentUpdates.rowCount(); ++i) {
1382 auto viewdata = m_pendingContainmentUpdates[i];
1383 auto containment = containmentForId(viewdata.id.toUInt());
1384
1385 if (containment) {
1386 if ((viewdata.onPrimary && containment->lastScreen() == m_corona->screenPool()->primaryScreenId())
1387 || (!viewdata.onPrimary && containment->lastScreen() == viewdata.screen)) {
1388 clearpendings << viewdata.id;
1389 }
1390 }
1391 }
1392
1393 for(auto pendingid : clearpendings) {
1394 m_pendingContainmentUpdates.remove(pendingid);
1395 }
1396
1397 if (m_pendingContainmentUpdates.rowCount() > 0) {
1398 qDebug () << " Pending View updates still valid : ";
1399 m_pendingContainmentUpdates.print();
1400 }
1401
1402 //! use valid views map based on active screens
1403 Layout::ViewsMap viewsMap = validViewsMap(occupiedMap);
1404
1405 if (occupiedMap != nullptr) {
1406 qDebug() << "Occupied map used :: " << *occupiedMap;
1407 }
1408
1409 QString prmScreenName = qGuiApp->primaryScreen()->name();
1410
1411 qDebug() << "PRIMARY SCREEN :: " << prmScreenName;
1412 qDebug() << "LATTEVIEWS MAP :: " << viewsMap;
1413
1414 //! add views
1415 for (const auto containment : m_containments) {
1416 int screenId = containment->screen();
1417
1418 if (!Layouts::Storage::isValid(screenId)) {
1419 screenId = containment->lastScreen();
1420 }
1421
1422 if (!latteViewExists(containment) && mapContainsId(&viewsMap, containment->id())) {
1423 qDebug() << "syncLatteViewsToScreens: view must be added... for containment:" << containment->id() << " at screen:" << m_corona->screenPool()->connector(screenId);
1424 addView(containment);
1425 }
1426 }
1427
1428 //! remove views
1429 QList<Plasma::Containment *> viewsToDelete;
1430
1431 for (auto view : m_latteViews) {
1432 auto containment = view->containment();
1433 if (containment && !mapContainsId(&viewsMap, containment->id())) {
1434 viewsToDelete << containment;
1435 }
1436 }
1437
1438 while(!viewsToDelete.isEmpty()) {
1439 auto containment = viewsToDelete.takeFirst();
1440 auto view = m_latteViews.take(containment);
1441 qDebug() << "syncLatteViewsToScreens: view must be deleted... for containment:" << containment->id() << " at screen:" << view->positioner()->currentScreenName();
1442 view->disconnectSensitiveSignals();
1443 view->deleteLater();
1444 }
1445
1446 //! reconsider views
1447 for (const auto view : m_latteViews) {
1448 if (view->containment() && mapContainsId(&viewsMap, view->containment()->id())) {
1449 //! if the dock will not be deleted its a very good point to reconsider
1450 //! if the screen in which is running is the correct one
1451 qDebug() << "syncLatteViewsToScreens: view must consider its screen... for containment:" << view->containment()->id() << " at screen:" << view->positioner()->currentScreenName();
1452 view->reconsiderScreen();
1453 }
1454 }
1455
1456 qDebug() << "end of, syncLatteViewsToScreens ....";
1457 }
1458
subContainmentsOf(uint id) const1459 QList<Plasma::Containment *> GenericLayout::subContainmentsOf(uint id) const
1460 {
1461 QList<Plasma::Containment *> subs;
1462
1463 auto containment = containmentForId(id);
1464
1465 if (!containment || !Layouts::Storage::self()->isLatteContainment(containment)) {
1466 return subs;
1467 }
1468
1469 auto applets = containment->config().group("Applets");
1470
1471 for (const auto &applet : applets.groupList()) {
1472 int tSubId = Layouts::Storage::self()->subContainmentId(applets.group(applet));
1473
1474 if (Layouts::Storage::isValid(tSubId)) {
1475 auto subcontainment = containmentForId(tSubId);
1476
1477 if (subcontainment) {
1478 subs << subcontainment;
1479 }
1480 }
1481 }
1482
1483 return subs;
1484 }
1485
subContainmentsOf(Plasma::Containment * containment) const1486 QList<int> GenericLayout::subContainmentsOf(Plasma::Containment *containment) const
1487 {
1488 QList<int> subs;
1489
1490 if (Layouts::Storage::self()->isLatteContainment(containment)) {
1491 auto applets = containment->config().group("Applets");
1492
1493 for (const auto &applet : applets.groupList()) {
1494 int tSubId = Layouts::Storage::self()->subContainmentId(applets.group(applet));
1495
1496 if (Layouts::Storage::isValid(tSubId)) {
1497 subs << tSubId;
1498 }
1499 }
1500 }
1501
1502 return subs;
1503 }
1504
viewsExplicitScreens()1505 QList<int> GenericLayout::viewsExplicitScreens()
1506 {
1507 Data::ViewsTable views = viewsTable();
1508 QList<int> screens;
1509
1510 for (int i=0; i<views.rowCount(); ++i) {
1511 if (!views[i].onPrimary && !screens.contains(views[i].screen)) {
1512 screens << views[i].screen;
1513 }
1514 }
1515
1516 return screens;
1517 }
1518
1519 //! STORAGE
1520
isWritable() const1521 bool GenericLayout::isWritable() const
1522 {
1523 return Layouts::Storage::self()->isWritable(this);
1524 }
1525
lock()1526 void GenericLayout::lock()
1527 {
1528 Layouts::Storage::self()->lock(this);
1529 }
1530
unlock()1531 void GenericLayout::unlock()
1532 {
1533 Layouts::Storage::self()->unlock(this);
1534 }
1535
syncToLayoutFile(bool removeLayoutId)1536 void GenericLayout::syncToLayoutFile(bool removeLayoutId)
1537 {
1538 syncSettings();
1539 Layouts::Storage::self()->syncToLayoutFile(this, removeLayoutId);
1540 }
1541
newView(const QString & templateName)1542 bool GenericLayout::newView(const QString &templateName)
1543 {
1544 if (!isActive() || !m_corona->templatesManager()->hasViewTemplate(templateName)) {
1545 return false;
1546 }
1547
1548 QString templatefilepath = m_corona->templatesManager()->viewTemplateFilePath(templateName);
1549 Data::ViewsTable templateviews = Layouts::Storage::self()->views(templatefilepath);
1550
1551 if (templateviews.rowCount() <= 0) {
1552 return false;
1553 }
1554
1555 Data::View nextdata = templateviews[0];
1556 int scrId = m_corona->screenPool()->primaryScreenId();
1557
1558 QList<Plasma::Types::Location> freeedges = freeEdges(scrId);
1559
1560 if (!freeedges.contains(nextdata.edge)) {
1561 nextdata.edge = (freeedges.count() > 0 ? freeedges[0] : Plasma::Types::BottomEdge);
1562 }
1563
1564 nextdata.setState(Data::View::OriginFromViewTemplate, templatefilepath);
1565
1566 newView(nextdata);
1567
1568 return true;
1569 }
1570
newView(const Latte::Data::View & nextViewData)1571 Data::View GenericLayout::newView(const Latte::Data::View &nextViewData)
1572 {
1573 if (nextViewData.state() == Data::View::IsInvalid) {
1574 return Data::View();
1575 }
1576
1577 Data::View result = Layouts::Storage::self()->newView(this, nextViewData);
1578 emit viewEdgeChanged();
1579
1580 return result;
1581 }
1582
updateView(const Latte::Data::View & viewData)1583 void GenericLayout::updateView(const Latte::Data::View &viewData)
1584 {
1585 //! storage -> storage [view scenario]
1586 if (!isActive()) {
1587 Layouts::Storage::self()->updateView(this, viewData);
1588 return;
1589 }
1590
1591 //! active -> active [view scenario]
1592 Latte::View *view = viewForContainment(viewData.id.toUInt());
1593 bool viewMustBeDeleted = (view && !viewData.onPrimary && !m_corona->screenPool()->isScreenActive(viewData.screen));
1594
1595 QString nextactivelayoutname = (viewData.state() == Data::View::OriginFromLayout && !viewData.originLayout().isEmpty() ? viewData.originLayout() : QString());
1596
1597 if (view) {
1598 if (!viewMustBeDeleted) {
1599 QString scrName = Latte::Data::Screen::ONPRIMARYNAME;
1600
1601 if (!viewData.onPrimary) {
1602 if (m_corona->screenPool()->hasScreenId(viewData.screen)) {
1603 scrName = m_corona->screenPool()->connector(viewData.screen);
1604 } else {
1605 scrName = "";
1606 }
1607 }
1608
1609 view->setName(viewData.name);
1610 view->positioner()->setNextLocation(nextactivelayoutname, scrName, viewData.edge, viewData.alignment);
1611 return;
1612 } else {
1613 //! viewMustBeDeleted
1614 m_latteViews.remove(view->containment());
1615 view->disconnectSensitiveSignals();
1616 delete view;
1617 }
1618 }
1619
1620 //! inactiveinmemory -> active/inactiveinmemory [viewscenario]
1621 //! active -> inactiveinmemory [viewscenario]
1622 auto containment = containmentForId(viewData.id.toUInt());
1623 if (containment) {
1624 Layouts::Storage::self()->updateView(this, viewData);
1625
1626 //! by using pendingContainmentUpdates we make sure that when containment->screen() will be
1627 //! called though reactToScreenChange() the proper screen will be returned
1628 if (!m_pendingContainmentUpdates.containsId(viewData.id)) {
1629 m_pendingContainmentUpdates << viewData;
1630 } else {
1631 m_pendingContainmentUpdates[viewData.id] = viewData;
1632 }
1633 containment->reactToScreenChange();
1634 }
1635
1636 if (!nextactivelayoutname.isEmpty()) {
1637 m_corona->layoutsManager()->moveView(name(), viewData.id.toUInt(), nextactivelayoutname);
1638 }
1639
1640 //! complete update circle and inform the others about the changes
1641 if (viewMustBeDeleted) {
1642 emit viewEdgeChanged();
1643 emit viewsCountChanged();
1644 }
1645
1646 syncLatteViewsToScreens();
1647 }
1648
removeView(const Latte::Data::View & viewData)1649 void GenericLayout::removeView(const Latte::Data::View &viewData)
1650 {
1651 if (!containsView(viewData.id.toInt())) {
1652 return;
1653 }
1654
1655 if (!isActive()) {
1656 Layouts::Storage::self()->removeView(file(), viewData);
1657 return;
1658 }
1659
1660 Plasma::Containment *viewcontainment = containmentForId(viewData.id.toUInt());
1661 destroyContainment(viewcontainment);
1662 }
1663
removeOrphanedSubContainment(const int & containmentId)1664 void GenericLayout::removeOrphanedSubContainment(const int &containmentId)
1665 {
1666 Data::ViewsTable views = viewsTable();
1667 QString cidstr = QString::number(containmentId);
1668
1669 if (views.hasContainmentId(cidstr)) {
1670 return;
1671 }
1672
1673 if (!isActive()) {
1674 Layouts::Storage::self()->removeContainment(file(), cidstr);
1675 return;
1676 }
1677
1678 Plasma::Containment *orphanedcontainment = containmentForId(cidstr.toUInt());
1679 destroyContainment(orphanedcontainment);
1680 }
1681
destroyContainment(Plasma::Containment * containment)1682 void GenericLayout::destroyContainment(Plasma::Containment *containment)
1683 {
1684 if (!containment || !m_corona || !contains(containment)) {
1685 return;
1686 }
1687
1688 containment->setImmutability(Plasma::Types::Mutable);
1689 containment->destroy();
1690 }
1691
storedView(const int & containmentId)1692 QString GenericLayout::storedView(const int &containmentId)
1693 {
1694 return Layouts::Storage::self()->storedView(this, containmentId);
1695 }
1696
importToCorona()1697 void GenericLayout::importToCorona()
1698 {
1699 Layouts::Storage::self()->importToCorona(this);
1700 }
1701
errors() const1702 Data::ErrorsList GenericLayout::errors() const
1703 {
1704 return Layouts::Storage::self()->errors(this);
1705 }
1706
warnings() const1707 Data::WarningsList GenericLayout::warnings() const
1708 {
1709 return Layouts::Storage::self()->warnings(this);
1710 }
1711
viewsTable() const1712 Latte::Data::ViewsTable GenericLayout::viewsTable() const
1713 {
1714 return Layouts::Storage::self()->views(this);
1715 }
1716
1717 }
1718 }
1719