1 /*
2     SPDX-FileCopyrightText: 2016 Smith AR <audoban@openmaibox.org>
3     SPDX-FileCopyrightText: 2016 Michail Vourlakos <mvourlakos@gmail.com>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "lattecorona.h"
9 
10 // local
11 #include <coretypes.h>
12 #include "alternativeshelper.h"
13 #include "apptypes.h"
14 #include "lattedockadaptor.h"
15 #include "screenpool.h"
16 #include "data/generictable.h"
17 #include "data/layouticondata.h"
18 #include "declarativeimports/interfaces.h"
19 #include "indicator/factory.h"
20 #include "layout/abstractlayout.h"
21 #include "layout/centrallayout.h"
22 #include "layout/genericlayout.h"
23 #include "layouts/importer.h"
24 #include "layouts/manager.h"
25 #include "layouts/synchronizer.h"
26 #include "shortcuts/globalshortcuts.h"
27 #include "package/lattepackage.h"
28 #include "plasma/extended/backgroundcache.h"
29 #include "plasma/extended/backgroundtracker.h"
30 #include "plasma/extended/screengeometries.h"
31 #include "plasma/extended/screenpool.h"
32 #include "plasma/extended/theme.h"
33 #include "settings/universalsettings.h"
34 #include "templates/templatesmanager.h"
35 #include "view/view.h"
36 #include "view/settings/viewsettingsfactory.h"
37 #include "view/windowstracker/windowstracker.h"
38 #include "view/windowstracker/allscreenstracker.h"
39 #include "view/windowstracker/currentscreentracker.h"
40 #include "wm/abstractwindowinterface.h"
41 #include "wm/schemecolors.h"
42 #include "wm/waylandinterface.h"
43 #include "wm/xwindowinterface.h"
44 #include "wm/tracker/lastactivewindow.h"
45 #include "wm/tracker/schemes.h"
46 #include "wm/tracker/windowstracker.h"
47 
48 // Qt
49 #include <QAction>
50 #include <QApplication>
51 #include <QScreen>
52 #include <QDBusConnection>
53 #include <QDebug>
54 #include <QDesktopWidget>
55 #include <QFile>
56 #include <QFontDatabase>
57 #include <QQmlContext>
58 #include <QProcess>
59 
60 // Plasma
61 #include <Plasma>
62 #include <Plasma/Corona>
63 #include <Plasma/Containment>
64 #include <PlasmaQuick/ConfigView>
65 
66 // KDE
67 #include <KActionCollection>
68 #include <KPluginMetaData>
69 #include <KGlobalAccel>
70 #include <KLocalizedString>
71 #include <KPackage/Package>
72 #include <KPackage/PackageLoader>
73 #include <KAboutData>
74 #include <KActivities/Consumer>
75 #include <KDeclarative/QmlObjectSharedEngine>
76 #include <KWindowSystem>
77 #include <KWayland/Client/connection_thread.h>
78 #include <KWayland/Client/registry.h>
79 #include <KWayland/Client/plasmashell.h>
80 #include <KWayland/Client/plasmawindowmanagement.h>
81 
82 namespace Latte {
83 
Corona(bool defaultLayoutOnStartup,QString layoutNameOnStartUp,QString addViewTemplateName,int userSetMemoryUsage,QObject * parent)84 Corona::Corona(bool defaultLayoutOnStartup, QString layoutNameOnStartUp, QString addViewTemplateName, int userSetMemoryUsage, QObject *parent)
85     : Plasma::Corona(parent),
86       m_defaultLayoutOnStartup(defaultLayoutOnStartup),
87       m_startupAddViewTemplateName(addViewTemplateName),
88       m_userSetMemoryUsage(userSetMemoryUsage),
89       m_layoutNameOnStartUp(layoutNameOnStartUp),
90       m_activitiesConsumer(new KActivities::Consumer(this)),
91       m_screenPool(new ScreenPool(KSharedConfig::openConfig(), this)),
92       m_indicatorFactory(new Indicator::Factory(this)),
93       m_universalSettings(new UniversalSettings(KSharedConfig::openConfig(), this)),
94       m_globalShortcuts(new GlobalShortcuts(this)),
95       m_plasmaScreenPool(new PlasmaExtended::ScreenPool(this)),
96       m_themeExtended(new PlasmaExtended::Theme(KSharedConfig::openConfig(), this)),
97       m_viewSettingsFactory(new ViewSettingsFactory(this)),
98       m_templatesManager(new Templates::Manager(this)),
99       m_layoutsManager(new Layouts::Manager(this)),
100       m_plasmaGeometries(new PlasmaExtended::ScreenGeometries(this)),
101       m_dialogShadows(new PanelShadows(this, QStringLiteral("dialogs/background")))
102 {
103     connect(qApp, &QApplication::aboutToQuit, this, &Corona::onAboutToQuit);
104 
105     //! create the window manager
106     if (KWindowSystem::isPlatformWayland()) {
107         m_wm = new WindowSystem::WaylandInterface(this);
108     } else {
109         m_wm = new WindowSystem::XWindowInterface(this);
110     }
111 
112     setupWaylandIntegration();
113 
114     KPackage::Package package(new Latte::Package(this));
115 
116     m_screenPool->load();
117 
118     if (!package.isValid()) {
119         qWarning() << staticMetaObject.className()
120                    << "the package" << package.metadata().rawData() << "is invalid!";
121         return;
122     } else {
123         qDebug() << staticMetaObject.className()
124                  << "the package" << package.metadata().rawData() << "is valid!";
125     }
126 
127     setKPackage(package);
128     //! universal settings / extendedtheme must be loaded after the package has been set
129     m_universalSettings->load();
130     m_themeExtended->load();
131 
132     qmlRegisterTypes();
133 
134     if (m_activitiesConsumer && (m_activitiesConsumer->serviceStatus() == KActivities::Consumer::Running)) {
135         load();
136     }
137 
138     connect(m_activitiesConsumer, &KActivities::Consumer::serviceStatusChanged, this, &Corona::load);
139 
140     m_viewsScreenSyncTimer.setSingleShot(true);
141     m_viewsScreenSyncTimer.setInterval(m_universalSettings->screenTrackerInterval());
142     connect(&m_viewsScreenSyncTimer, &QTimer::timeout, this, &Corona::syncLatteViewsToScreens);
143     connect(m_universalSettings, &UniversalSettings::screenTrackerIntervalChanged, this, [this]() {
144         m_viewsScreenSyncTimer.setInterval(m_universalSettings->screenTrackerInterval());
145     });
146 
147     //! Dbus adaptor initialization
148     new LatteDockAdaptor(this);
149     QDBusConnection dbus = QDBusConnection::sessionBus();
150     dbus.registerObject(QStringLiteral("/Latte"), this);
151 }
152 
~Corona()153 Corona::~Corona()
154 {
155     /*m_inQuit = true;
156 
157     //! BEGIN: Give the time to slide-out views when closing
158     m_layoutsManager->synchronizer()->hideAllViews();
159     m_viewSettingsFactory->deleteLater();
160 
161     m_viewsScreenSyncTimer.stop();
162 
163     if (m_layoutsManager->memoryUsage() == MemoryUsage::SingleLayout) {
164         cleanConfig();
165     }
166 
167     qDebug() << "Latte Corona - unload: containments ...";
168     m_layoutsManager->unload();*/
169 
170     m_plasmaGeometries->deleteLater();
171     m_wm->deleteLater();
172     m_dialogShadows->deleteLater();
173     m_globalShortcuts->deleteLater();
174     m_layoutsManager->deleteLater();
175     m_screenPool->deleteLater();
176     m_universalSettings->deleteLater();
177     m_plasmaScreenPool->deleteLater();
178     m_themeExtended->deleteLater();
179     m_indicatorFactory->deleteLater();
180 
181     disconnect(m_activitiesConsumer, &KActivities::Consumer::serviceStatusChanged, this, &Corona::load);
182     delete m_activitiesConsumer;
183 
184     qDebug() << "Latte Corona - deleted...";
185 
186     if (!m_importFullConfigurationFile.isEmpty()) {
187         //!NOTE: Restart latte to import the new configuration
188         QString importCommand = "latte-dock --import-full \"" + m_importFullConfigurationFile + "\"";
189         qDebug() << "Executing Import Full Configuration command : " << importCommand;
190 
191         QProcess::startDetached(importCommand);
192     }
193 }
194 
onAboutToQuit()195 void Corona::onAboutToQuit()
196 {
197     m_inQuit = true;
198 
199     //! BEGIN: Give the time to slide-out views when closing
200     m_layoutsManager->synchronizer()->hideAllViews();
201     m_viewSettingsFactory->deleteLater();
202 
203     m_viewsScreenSyncTimer.stop();
204 
205     if (m_layoutsManager->memoryUsage() == MemoryUsage::SingleLayout) {
206         cleanConfig();
207     }
208 
209     qDebug() << "Latte Corona - unload: containments ...";
210     m_layoutsManager->unload();
211 }
212 
load()213 void Corona::load()
214 {
215     if (m_activitiesConsumer && (m_activitiesConsumer->serviceStatus() == KActivities::Consumer::Running) && m_activitiesStarting) {
216         m_activitiesStarting = false;
217 
218         disconnect(m_activitiesConsumer, &KActivities::Consumer::serviceStatusChanged, this, &Corona::load);
219 
220         m_templatesManager->init();
221         m_layoutsManager->init();
222 
223         connect(this, &Corona::availableScreenRectChangedFrom, this, &Plasma::Corona::availableScreenRectChanged);
224         connect(this, &Corona::availableScreenRegionChangedFrom, this, &Plasma::Corona::availableScreenRegionChanged);
225         connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &Corona::primaryOutputChanged, Qt::UniqueConnection);
226         connect(m_screenPool, &ScreenPool::primaryPoolChanged, this, &Corona::screenCountChanged);
227 
228         QString loadLayoutName = "";
229 
230         if (m_userSetMemoryUsage != -1) {
231             MemoryUsage::LayoutsMemory usage = static_cast<MemoryUsage::LayoutsMemory>(m_userSetMemoryUsage);
232             m_universalSettings->setLayoutsMemoryUsage(usage);
233         }
234 
235         if (!m_defaultLayoutOnStartup && m_layoutNameOnStartUp.isEmpty()) {
236             if (m_universalSettings->layoutsMemoryUsage() == MemoryUsage::MultipleLayouts) {
237                 loadLayoutName = "";
238             } else {
239                 loadLayoutName = m_universalSettings->singleModeLayoutName();
240 
241                 if (!m_layoutsManager->synchronizer()->layoutExists(loadLayoutName)) {
242                     //! If chosen layout does not exist, force Default layout loading
243                     QString defaultLayoutTemplateName = i18n(Templates::DEFAULTLAYOUTTEMPLATENAME);
244                     loadLayoutName = defaultLayoutTemplateName;
245 
246                     if (!m_layoutsManager->synchronizer()->layoutExists(defaultLayoutTemplateName)) {
247                         //! If Default layout does not exist at all, create it
248                         QString path = m_templatesManager->newLayout("", defaultLayoutTemplateName);
249                         m_layoutsManager->setOnAllActivities(Layout::AbstractLayout::layoutName(path));
250                     }
251                 }
252             }
253         } else if (m_defaultLayoutOnStartup) {
254             //! force loading a NEW default layout even though a default layout may already exists
255             QString newDefaultLayoutPath = m_templatesManager->newLayout("", i18n(Templates::DEFAULTLAYOUTTEMPLATENAME));
256             loadLayoutName = Layout::AbstractLayout::layoutName(newDefaultLayoutPath);
257             m_universalSettings->setLayoutsMemoryUsage(MemoryUsage::SingleLayout);
258         } else {
259             loadLayoutName = m_layoutNameOnStartUp;
260             m_universalSettings->setLayoutsMemoryUsage(MemoryUsage::SingleLayout);
261         }
262 
263         m_layoutsManager->loadLayoutOnStartup(loadLayoutName);
264 
265         //! load screens signals such screenGeometryChanged in order to support
266         //! plasmoid.screenGeometry properly
267         for (QScreen *screen : qGuiApp->screens()) {
268             addOutput(screen);
269         }
270 
271         connect(m_layoutsManager->synchronizer(), &Layouts::Synchronizer::initializationFinished, [this]() {
272             if (!m_startupAddViewTemplateName.isEmpty()) {
273                 //! user requested through cmd startup to add view from specific view template and we can add it after the startup
274                 //! sequence has loaded all required layouts properly
275                 addView(0, m_startupAddViewTemplateName);
276                 m_startupAddViewTemplateName = "";
277             }
278         });
279 
280         m_inStartup = false;
281 
282         connect(qGuiApp, &QGuiApplication::screenAdded, this, &Corona::addOutput, Qt::UniqueConnection);
283         connect(qGuiApp, &QGuiApplication::screenRemoved, this, &Corona::screenRemoved, Qt::UniqueConnection);
284     }
285 }
286 
unload()287 void Corona::unload()
288 {
289     qDebug() << "unload: removing containments...";
290 
291     while (!containments().isEmpty()) {
292         //deleting a containment will remove it from the list due to QObject::destroyed connect in Corona
293         //this form doesn't crash, while qDeleteAll(containments()) does
294         delete containments().first();
295     }
296 }
297 
setupWaylandIntegration()298 void Corona::setupWaylandIntegration()
299 {
300     if (!KWindowSystem::isPlatformWayland()) {
301         return;
302     }
303 
304     using namespace KWayland::Client;
305 
306     auto connection = ConnectionThread::fromApplication(this);
307 
308     if (!connection) {
309         return;
310     }
311 
312     Registry *registry{new Registry(this)};
313     registry->create(connection);
314 
315     connect(registry, &Registry::plasmaShellAnnounced, this
316             , [this, registry](quint32 name, quint32 version) {
317         m_waylandCorona = registry->createPlasmaShell(name, version, this);
318     });
319 
320     QObject::connect(registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced,
321                      [this, registry](quint32 name, quint32 version) {
322         KWayland::Client::PlasmaWindowManagement *pwm = registry->createPlasmaWindowManagement(name, version, this);
323 
324         WindowSystem::WaylandInterface *wI = qobject_cast<WindowSystem::WaylandInterface *>(m_wm);
325 
326         if (wI) {
327             wI->initWindowManagement(pwm);
328         }
329     });
330 
331 #if KF5_VERSION_MINOR >= 52
332     QObject::connect(registry, &KWayland::Client::Registry::plasmaVirtualDesktopManagementAnnounced,
333                      [this, registry] (quint32 name, quint32 version) {
334         KWayland::Client::PlasmaVirtualDesktopManagement *vdm = registry->createPlasmaVirtualDesktopManagement(name, version, this);
335 
336         WindowSystem::WaylandInterface *wI = qobject_cast<WindowSystem::WaylandInterface *>(m_wm);
337 
338         if (wI) {
339             wI->initVirtualDesktopManagement(vdm);
340         }
341     });
342 #endif
343 
344     registry->setup();
345     connection->roundtrip();
346 }
347 
waylandCoronaInterface() const348 KWayland::Client::PlasmaShell *Corona::waylandCoronaInterface() const
349 {
350     return m_waylandCorona;
351 }
352 
cleanConfig()353 void Corona::cleanConfig()
354 {
355     auto containmentsEntries = config()->group("Containments");
356     bool changed = false;
357 
358     for(const auto &cId : containmentsEntries.groupList()) {
359         if (!containmentExists(cId.toUInt())) {
360             //cleanup obsolete containments
361             containmentsEntries.group(cId).deleteGroup();
362             changed = true;
363             qDebug() << "obsolete containment configuration deleted:" << cId;
364         } else {
365             //cleanup obsolete applets of running containments
366             auto appletsEntries = containmentsEntries.group(cId).group("Applets");
367 
368             for(const auto &appletId : appletsEntries.groupList()) {
369                 if (!appletExists(cId.toUInt(), appletId.toUInt())) {
370                     appletsEntries.group(appletId).deleteGroup();
371                     changed = true;
372                     qDebug() << "obsolete applet configuration deleted:" << appletId;
373                 }
374             }
375         }
376     }
377 
378     if (changed) {
379         config()->sync();
380         qDebug() << "configuration file cleaned...";
381     }
382 }
383 
containmentExists(uint id) const384 bool Corona::containmentExists(uint id) const
385 {
386     for(const auto containment : containments()) {
387         if (id == containment->id()) {
388             return true;
389         }
390     }
391 
392     return false;
393 }
394 
appletExists(uint containmentId,uint appletId) const395 bool Corona::appletExists(uint containmentId, uint appletId) const
396 {
397     Plasma::Containment *containment = nullptr;
398 
399     for(const auto cont : containments()) {
400         if (containmentId == cont->id()) {
401             containment = cont;
402             break;
403         }
404     }
405 
406     if (!containment) {
407         return false;
408     }
409 
410     for(const auto applet : containment->applets()) {
411         if (applet->id() == appletId) {
412             return true;
413         }
414     }
415 
416     return false;
417 }
418 
inQuit() const419 bool Corona::inQuit() const
420 {
421     return m_inQuit;
422 }
423 
activitiesConsumer() const424 KActivities::Consumer *Corona::activitiesConsumer() const
425 {
426     return m_activitiesConsumer;
427 }
428 
dialogShadows() const429 PanelShadows *Corona::dialogShadows() const
430 {
431     return m_dialogShadows;
432 }
433 
globalShortcuts() const434 GlobalShortcuts *Corona::globalShortcuts() const
435 {
436     return m_globalShortcuts;
437 }
438 
screenPool() const439 ScreenPool *Corona::screenPool() const
440 {
441     return m_screenPool;
442 }
443 
universalSettings() const444 UniversalSettings *Corona::universalSettings() const
445 {
446     return m_universalSettings;
447 }
448 
viewSettingsFactory() const449 ViewSettingsFactory *Corona::viewSettingsFactory() const
450 {
451     return m_viewSettingsFactory;
452 }
453 
wm() const454 WindowSystem::AbstractWindowInterface *Corona::wm() const
455 {
456     return m_wm;
457 }
458 
indicatorFactory() const459 Indicator::Factory *Corona::indicatorFactory() const
460 {
461     return m_indicatorFactory;
462 }
463 
layoutsManager() const464 Layouts::Manager *Corona::layoutsManager() const
465 {
466     return m_layoutsManager;
467 }
468 
templatesManager() const469 Templates::Manager *Corona::templatesManager() const
470 {
471     return m_templatesManager;
472 }
473 
plasmaScreenPool() const474 PlasmaExtended::ScreenPool *Corona::plasmaScreenPool() const
475 {
476     return m_plasmaScreenPool;
477 }
478 
themeExtended() const479 PlasmaExtended::Theme *Corona::themeExtended() const
480 {
481     return m_themeExtended;
482 }
483 
numScreens() const484 int Corona::numScreens() const
485 {
486     return qGuiApp->screens().count();
487 }
488 
screenGeometry(int id) const489 QRect Corona::screenGeometry(int id) const
490 {
491     const auto screens = qGuiApp->screens();
492     const QScreen *screen{qGuiApp->primaryScreen()};
493 
494     QString screenName;
495 
496     if (m_screenPool->hasScreenId(id)) {
497         screenName = m_screenPool->connector(id);
498     }
499 
500     for(const auto scr : screens) {
501         if (scr->name() == screenName) {
502             screen = scr;
503             break;
504         }
505     }
506 
507     return screen->geometry();
508 }
509 
centralLayout(QString name) const510 CentralLayout *Corona::centralLayout(QString name) const
511 {
512     CentralLayout *result{nullptr};
513 
514     if (!name.isEmpty()) {
515         result = m_layoutsManager->synchronizer()->centralLayout(name);
516     }
517 
518     return result;
519 }
520 
layout(QString name) const521 Layout::GenericLayout *Corona::layout(QString name) const
522 {
523     Layout::GenericLayout *result{nullptr};
524 
525     if (!name.isEmpty()) {
526         result = m_layoutsManager->synchronizer()->layout(name);
527     }
528 
529     return result;
530 }
531 
availableScreenRegion(int id) const532 QRegion Corona::availableScreenRegion(int id) const
533 {
534     //! ignore modes are added in order for notifications to be placed
535     //! in better positioning and not overlap with sidebars or usually hidden views
536     QList<Types::Visibility> ignoremodes({Latte::Types::AutoHide,
537                                           Latte::Types::SidebarOnDemand,
538                                           Latte::Types::SidebarAutoHide});
539 
540 
541     return availableScreenRegionWithCriteria(id,
542                                              QString(),
543                                              ignoremodes);
544 }
545 
availableScreenRegionWithCriteria(int id,QString activityid,QList<Types::Visibility> ignoreModes,QList<Plasma::Types::Location> ignoreEdges,bool ignoreExternalPanels,bool desktopUse) const546 QRegion Corona::availableScreenRegionWithCriteria(int id,
547                                                   QString activityid,
548                                                   QList<Types::Visibility> ignoreModes,
549                                                   QList<Plasma::Types::Location> ignoreEdges,
550                                                   bool ignoreExternalPanels,
551                                                   bool desktopUse) const
552 {
553     const QScreen *screen = m_screenPool->screenForId(id);
554     bool inCurrentActivity{activityid.isEmpty()};
555 
556     if (!screen) {
557         return {};
558     }
559 
560     QRegion available = ignoreExternalPanels ? screen->geometry() : screen->availableGeometry();
561 
562     QList<Latte::View *> views;
563 
564     if (inCurrentActivity) {
565         views = m_layoutsManager->synchronizer()->viewsBasedOnActivityId(m_activitiesConsumer->currentActivity());
566     } else {
567         views = m_layoutsManager->synchronizer()->viewsBasedOnActivityId(activityid);
568     }
569 
570     if (views.isEmpty()) {
571         return available;
572     }
573 
574     //! blacklist irrelevant visibility modes
575     if (!ignoreModes.contains(Latte::Types::None)) {
576         ignoreModes << Latte::Types::None;
577     }
578 
579     if (!ignoreModes.contains(Latte::Types::NormalWindow)) {
580         ignoreModes << Latte::Types::NormalWindow;
581     }
582 
583     bool allEdges = ignoreEdges.isEmpty();
584 
585     for (const auto *view : views) {
586         if (view && view->containment() && view->screen() == screen
587                 && ((allEdges || !ignoreEdges.contains(view->location()))
588                     && (view->visibility() && !ignoreModes.contains(view->visibility()->mode())))) {
589             int realThickness = view->normalThickness();
590 
591             int x = 0; int y = 0; int w = 0; int h = 0;
592 
593             switch (view->formFactor()) {
594             case Plasma::Types::Horizontal:
595                 if (view->behaveAsPlasmaPanel()) {
596                     w = view->width();
597                     x = view->x();
598                 } else {
599                     w = view->maxLength() * view->width();
600                     int offsetW = view->offset() * view->width();
601 
602                     switch (view->alignment()) {
603                     case Latte::Types::Left:
604                         x = view->x() + offsetW;
605                         break;
606 
607                     case Latte::Types::Center:
608                     case Latte::Types::Justify:
609                         x = (view->geometry().center().x() - w/2) + offsetW;
610                         break;
611 
612                     case Latte::Types::Right:
613                         x = view->geometry().right() - w - offsetW;
614                         break;
615                     }
616                 }
617                 break;
618             case Plasma::Types::Vertical:
619                 if (view->behaveAsPlasmaPanel()) {
620                     h = view->height();
621                     y = view->y();
622                 } else {
623                     h = view->maxLength() * view->height();
624                     int offsetH = view->offset() * view->height();
625 
626                     switch (view->alignment()) {
627                     case Latte::Types::Top:
628                         y = view->y() + offsetH;
629                         break;
630 
631                     case Latte::Types::Center:
632                     case Latte::Types::Justify:
633                         y = (view->geometry().center().y() - h/2) + offsetH;
634                         break;
635 
636                     case Latte::Types::Bottom:
637                         y = view->geometry().bottom() - h - offsetH;
638                         break;
639                     }
640                 }
641                 break;
642             }
643 
644             // Usually availableScreenRect is used by the desktop,
645             // but Latte don't have desktop, then here just
646             // need calculate available space for top and bottom location,
647             // because the left and right are those who dodge others views
648             switch (view->location()) {
649             case Plasma::Types::TopEdge:
650                 if (view->behaveAsPlasmaPanel()) {
651                     QRect viewGeometry = view->geometry();
652 
653                     if (desktopUse) {
654                         //! ignore any real window slide outs in all cases
655                         viewGeometry.moveTop(view->screen()->geometry().top() + view->screenEdgeMargin());
656                     }
657 
658                     available -= viewGeometry;
659                 } else {
660                     y = view->y();
661                     available -= QRect(x, y, w, realThickness);
662                 }
663 
664                 break;
665 
666             case Plasma::Types::BottomEdge:
667                 if (view->behaveAsPlasmaPanel()) {
668                     QRect viewGeometry = view->geometry();
669 
670                     if (desktopUse) {
671                         //! ignore any real window slide outs in all cases
672                         viewGeometry.moveTop(view->screen()->geometry().bottom() - view->screenEdgeMargin() - viewGeometry.height());
673                     }
674 
675                     available -= viewGeometry;
676                 } else {
677                     y = view->geometry().bottom() - realThickness + 1;
678                     available -= QRect(x, y, w, realThickness);
679                 }
680 
681                 break;
682 
683             case Plasma::Types::LeftEdge:
684                 if (view->behaveAsPlasmaPanel()) {
685                     QRect viewGeometry = view->geometry();
686 
687                     if (desktopUse) {
688                         //! ignore any real window slide outs in all cases
689                         viewGeometry.moveLeft(view->screen()->geometry().left() + view->screenEdgeMargin());
690                     }
691 
692                     available -= viewGeometry;
693                 } else {
694                     x = view->x();
695                     available -= QRect(x, y, realThickness, h);
696                 }
697 
698                 break;
699 
700             case Plasma::Types::RightEdge:
701                 if (view->behaveAsPlasmaPanel()) {
702                     QRect viewGeometry = view->geometry();
703 
704                     if (desktopUse) {
705                         //! ignore any real window slide outs in all cases
706                         viewGeometry.moveLeft(view->screen()->geometry().right() - view->screenEdgeMargin() - viewGeometry.width());
707                     }
708 
709                     available -= viewGeometry;
710                 } else {
711                     x = view->geometry().right() - realThickness + 1;
712                     available -= QRect(x, y, realThickness, h);
713                 }
714 
715                 break;
716 
717             default:
718                 //! bypass clang warnings
719                 break;
720             }
721         }
722     }
723 
724     /*qDebug() << "::::: FREE AREAS :::::";
725 
726     for (int i = 0; i < available.rectCount(); ++i) {
727         qDebug() << available.rects().at(i);
728     }
729 
730     qDebug() << "::::: END OF FREE AREAS :::::";*/
731 
732     return available;
733 }
734 
availableScreenRect(int id) const735 QRect Corona::availableScreenRect(int id) const
736 {
737     //! ignore modes are added in order for notifications to be placed
738     //! in better positioning and not overlap with sidebars or usually hidden views
739     QList<Types::Visibility> ignoremodes({Latte::Types::AutoHide,
740                                           Latte::Types::SidebarOnDemand,
741                                           Latte::Types::SidebarAutoHide});
742 
743     return availableScreenRectWithCriteria(id,
744                                            QString(),
745                                            ignoremodes);
746 }
747 
availableScreenRectWithCriteria(int id,QString activityid,QList<Types::Visibility> ignoreModes,QList<Plasma::Types::Location> ignoreEdges,bool ignoreExternalPanels,bool desktopUse) const748 QRect Corona::availableScreenRectWithCriteria(int id,
749                                               QString activityid,
750                                               QList<Types::Visibility> ignoreModes,
751                                               QList<Plasma::Types::Location> ignoreEdges,
752                                               bool ignoreExternalPanels,
753                                               bool desktopUse) const
754 {
755     const QScreen *screen = m_screenPool->screenForId(id);
756     bool inCurrentActivity{activityid.isEmpty()};
757 
758     if (!screen) {
759         return {};
760     }
761 
762     QRect available = ignoreExternalPanels ? screen->geometry() : screen->availableGeometry();
763 
764     QList<Latte::View *> views;
765 
766     if (inCurrentActivity) {
767         views = m_layoutsManager->synchronizer()->viewsBasedOnActivityId(m_activitiesConsumer->currentActivity());
768     } else {
769         views = m_layoutsManager->synchronizer()->viewsBasedOnActivityId(activityid);
770     }
771 
772     if (views.isEmpty()) {
773         return available;
774     }
775 
776     //! blacklist irrelevant visibility modes
777     if (!ignoreModes.contains(Latte::Types::None)) {
778         ignoreModes << Latte::Types::None;
779     }
780 
781     if (!ignoreModes.contains(Latte::Types::NormalWindow)) {
782         ignoreModes << Latte::Types::NormalWindow;
783     }
784 
785     bool allEdges = ignoreEdges.isEmpty();
786 
787     for (const auto *view : views) {
788         if (view && view->containment() && view->screen() == screen
789                 && ((allEdges || !ignoreEdges.contains(view->location()))
790                     && (view->visibility() && !ignoreModes.contains(view->visibility()->mode())))) {
791 
792             int appliedThickness = view->behaveAsPlasmaPanel() ? view->screenEdgeMargin() + view->normalThickness() : view->normalThickness();
793 
794             // Usually availableScreenRect is used by the desktop,
795             // but Latte don't have desktop, then here just
796             // need calculate available space for top and bottom location,
797             // because the left and right are those who dodge others docks
798             switch (view->location()) {
799             case Plasma::Types::TopEdge:
800                 if (view->behaveAsPlasmaPanel() && desktopUse) {
801                     //! ignore any real window slide outs in all cases
802                     available.setTop(qMax(available.top(), view->screen()->geometry().top() + appliedThickness));
803                 } else {
804                     available.setTop(qMax(available.top(), view->y() + appliedThickness));
805                 }
806                 break;
807 
808             case Plasma::Types::BottomEdge:
809                 if (view->behaveAsPlasmaPanel() && desktopUse) {
810                     //! ignore any real window slide outs in all cases
811                     available.setBottom(qMin(available.bottom(), view->screen()->geometry().bottom() - appliedThickness));
812                 } else {
813                     available.setBottom(qMin(available.bottom(), view->y() + view->height() - appliedThickness));
814                 }
815                 break;
816 
817             case Plasma::Types::LeftEdge:
818                 if (view->behaveAsPlasmaPanel() && desktopUse) {
819                     //! ignore any real window slide outs in all cases
820                     available.setLeft(qMax(available.left(), view->screen()->geometry().left() + appliedThickness));
821                 } else {
822                     available.setLeft(qMax(available.left(), view->x() + appliedThickness));
823                 }
824                 break;
825 
826             case Plasma::Types::RightEdge:
827                 if (view->behaveAsPlasmaPanel() && desktopUse) {
828                     //! ignore any real window slide outs in all cases
829                     available.setRight(qMin(available.right(), view->screen()->geometry().right() - appliedThickness));
830                 } else {
831                     available.setRight(qMin(available.right(), view->x() + view->width() - appliedThickness));
832                 }
833                 break;
834 
835             default:
836                 //! bypass clang warnings
837                 break;
838             }
839         }
840     }
841 
842     return available;
843 }
844 
addOutput(QScreen * screen)845 void Corona::addOutput(QScreen *screen)
846 {
847     Q_ASSERT(screen);
848 
849     int id = m_screenPool->id(screen->name());
850 
851     if (id == -1) {
852         m_screenPool->insertScreenMapping(screen->name());
853     }
854 
855     connect(screen, &QScreen::geometryChanged, this, [ = ]() {
856         const int id = m_screenPool->id(screen->name());
857 
858         if (id >= 0) {
859             emit screenGeometryChanged(id);
860             emit availableScreenRegionChanged();
861             emit availableScreenRectChanged();
862         }
863     });
864 
865     emit availableScreenRectChanged();
866     emit screenAdded(m_screenPool->id(screen->name()));
867 
868     screenCountChanged();
869 }
870 
primaryOutputChanged()871 void Corona::primaryOutputChanged()
872 {
873     m_viewsScreenSyncTimer.start();
874 }
875 
screenRemoved(QScreen * screen)876 void Corona::screenRemoved(QScreen *screen)
877 {
878     screenCountChanged();
879 }
880 
screenCountChanged()881 void Corona::screenCountChanged()
882 {
883     m_viewsScreenSyncTimer.start();
884 }
885 
886 //! the central functions that updates loading/unloading latteviews
887 //! concerning screen changed (for multi-screen setups mainly)
syncLatteViewsToScreens()888 void Corona::syncLatteViewsToScreens()
889 {
890     m_layoutsManager->synchronizer()->syncLatteViewsToScreens();
891 }
892 
primaryScreenId() const893 int Corona::primaryScreenId() const
894 {
895     return m_screenPool->id(qGuiApp->primaryScreen()->name());
896 }
897 
quitApplication()898 void Corona::quitApplication()
899 {
900     m_inQuit = true;
901 
902     //! this code must be called asynchronously because it is called
903     //! also from qml (Settings window).
904     QTimer::singleShot(300, [this]() {
905         m_layoutsManager->hideLatteSettingsDialog();
906         m_layoutsManager->synchronizer()->hideAllViews();
907     });
908 
909     //! give the time for the views to hide themselves
910     QTimer::singleShot(800, [this]() {
911         qGuiApp->quit();
912     });
913 }
914 
aboutApplication()915 void Corona::aboutApplication()
916 {
917     if (aboutDialog) {
918         aboutDialog->hide();
919         aboutDialog->deleteLater();
920     }
921 
922     aboutDialog = new KAboutApplicationDialog(KAboutData::applicationData());
923     connect(aboutDialog.data(), &QDialog::finished, aboutDialog.data(), &QObject::deleteLater);
924     m_wm->skipTaskBar(*aboutDialog);
925     m_wm->setKeepAbove(aboutDialog->winId(), true);
926 
927     aboutDialog->show();
928 }
929 
loadDefaultLayout()930 void Corona::loadDefaultLayout()
931 {
932   //disabled
933 }
934 
screenForContainment(const Plasma::Containment * containment) const935 int Corona::screenForContainment(const Plasma::Containment *containment) const
936 {
937     //FIXME: indexOf is not a proper way to support multi-screen
938     // as for environment to environment the indexes change
939     // also there is the following issue triggered
940     // from latteView adaptToScreen()
941     //
942     // in a multi-screen environment that
943     // primary screen is not set to 0 it was
944     // created an endless showing loop at
945     // startup (catch-up race) between
946     // screen:0 and primaryScreen
947 
948     //case in which this containment is child of an applet, hello systray :)
949     if (Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent())) {
950         if (Plasma::Containment *cont = parentApplet->containment()) {
951             return screenForContainment(cont);
952         } else {
953             return -1;
954         }
955     }
956 
957     Plasma::Containment *c = const_cast<Plasma::Containment *>(containment);
958     int scrId = m_layoutsManager->synchronizer()->screenForContainment(c);
959 
960     if (scrId >= 0) {
961         return scrId;
962     }
963 
964     return containment->lastScreen();
965 }
966 
showAlternativesForApplet(Plasma::Applet * applet)967 void Corona::showAlternativesForApplet(Plasma::Applet *applet)
968 {
969     const QString alternativesQML = kPackage().filePath("appletalternativesui");
970 
971     if (alternativesQML.isEmpty()) {
972         return;
973     }
974 
975     Latte::View *latteView =  m_layoutsManager->synchronizer()->viewForContainment(applet->containment());
976 
977     KDeclarative::QmlObjectSharedEngine *qmlObj{nullptr};
978 
979     if (latteView) {
980         latteView->setAlternativesIsShown(true);
981         qmlObj = new KDeclarative::QmlObjectSharedEngine(latteView);
982     } else {
983         qmlObj = new KDeclarative::QmlObjectSharedEngine(this);
984     }
985 
986     qmlObj->setInitializationDelayed(true);
987     qmlObj->setSource(QUrl::fromLocalFile(alternativesQML));
988 
989     AlternativesHelper *helper = new AlternativesHelper(applet, qmlObj);
990     qmlObj->rootContext()->setContextProperty(QStringLiteral("alternativesHelper"), helper);
991 
992     m_alternativesObjects << qmlObj;
993     qmlObj->completeInitialization();
994 
995     //! Alternative dialog signals
996     connect(helper, &QObject::destroyed, this, [latteView]() {
997         latteView->setAlternativesIsShown(false);
998     });
999 
1000     connect(qmlObj->rootObject(), SIGNAL(visibleChanged(bool)),
1001             this, SLOT(alternativesVisibilityChanged(bool)));
1002 
1003     connect(applet, &Plasma::Applet::destroyedChanged, this, [this, qmlObj](bool destroyed) {
1004         if (!destroyed) {
1005             return;
1006         }
1007 
1008         QMutableListIterator<KDeclarative::QmlObjectSharedEngine *> it(m_alternativesObjects);
1009 
1010         while (it.hasNext()) {
1011             KDeclarative::QmlObjectSharedEngine *obj = it.next();
1012 
1013             if (obj == qmlObj) {
1014                 it.remove();
1015                 obj->deleteLater();
1016             }
1017         }
1018     });
1019 }
1020 
alternativesVisibilityChanged(bool visible)1021 void Corona::alternativesVisibilityChanged(bool visible)
1022 {
1023     if (visible) {
1024         return;
1025     }
1026 
1027     QObject *root = sender();
1028 
1029     QMutableListIterator<KDeclarative::QmlObjectSharedEngine *> it(m_alternativesObjects);
1030 
1031     while (it.hasNext()) {
1032         KDeclarative::QmlObjectSharedEngine *obj = it.next();
1033 
1034         if (obj->rootObject() == root) {
1035             it.remove();
1036             obj->deleteLater();
1037         }
1038     }
1039 }
1040 
containmentsIds()1041 QStringList Corona::containmentsIds()
1042 {
1043     QStringList ids;
1044 
1045     for(const auto containment : containments()) {
1046         ids << QString::number(containment->id());
1047     }
1048 
1049     return ids;
1050 }
1051 
appletsIds()1052 QStringList Corona::appletsIds()
1053 {
1054     QStringList ids;
1055 
1056     for(const auto containment : containments()) {
1057         auto applets = containment->config().group("Applets");
1058         ids << applets.groupList();
1059     }
1060 
1061     return ids;
1062 }
1063 
1064 //! Activate launcher menu through dbus interface
activateLauncherMenu()1065 void Corona::activateLauncherMenu()
1066 {
1067     m_globalShortcuts->activateLauncherMenu();
1068 }
1069 
windowColorScheme(QString windowIdAndScheme)1070 void Corona::windowColorScheme(QString windowIdAndScheme)
1071 {
1072     int firstSlash = windowIdAndScheme.indexOf("-");
1073     QString windowIdStr = windowIdAndScheme.mid(0, firstSlash);
1074     QString schemeStr = windowIdAndScheme.mid(firstSlash + 1);
1075 
1076     if (KWindowSystem::isPlatformWayland()) {
1077         QTimer::singleShot(200, [this, schemeStr]() {
1078             //! [Wayland Case] - give the time to be informed correctly for the active window id
1079             //! otherwise the active window id may not be the same with the one trigerred
1080             //! the color scheme dbus signal
1081             QString windowIdStr = m_wm->activeWindow().toString();
1082             m_wm->schemesTracker()->setColorSchemeForWindow(windowIdStr.toUInt(), schemeStr);
1083         });
1084     } else {
1085         m_wm->schemesTracker()->setColorSchemeForWindow(windowIdStr.toUInt(), schemeStr);
1086     }
1087 }
1088 
1089 //! update badge for specific view item
updateDockItemBadge(QString identifier,QString value)1090 void Corona::updateDockItemBadge(QString identifier, QString value)
1091 {
1092     m_globalShortcuts->updateViewItemBadge(identifier, value);
1093 }
1094 
setAutostart(const bool & enabled)1095 void Corona::setAutostart(const bool &enabled)
1096 {
1097     m_universalSettings->setAutostart(enabled);
1098 }
1099 
switchToLayout(QString layout)1100 void Corona::switchToLayout(QString layout)
1101 {
1102     if ((layout.startsWith("file:/") || layout.startsWith("/")) && layout.endsWith(".layout.latte")) {
1103         importLayoutFile(layout);
1104     } else {
1105         m_layoutsManager->switchToLayout(layout);
1106     }
1107 }
1108 
importLayoutFile(const QString & filepath,const QString & suggestedLayoutName)1109 void Corona::importLayoutFile(const QString &filepath, const QString &suggestedLayoutName)
1110 {
1111     bool isFilepathValid = (filepath.startsWith("file:/") || filepath.startsWith("/")) && filepath.endsWith(".layout.latte");
1112 
1113     if (!isFilepathValid) {
1114         qDebug() << i18n("The layout cannot be imported from file :: ") << filepath;
1115         return;
1116     }
1117 
1118     //! Import and load runtime a layout through dbus interface
1119     //! It can be used from external programs that want to update runtime
1120     //! the Latte shown layout
1121     QString layoutPath = filepath;
1122 
1123     //! cleanup layout path
1124     if (layoutPath.startsWith("file:///")) {
1125         layoutPath = layoutPath.remove("file://");
1126     } else if (layoutPath.startsWith("file://")) {
1127         layoutPath = layoutPath.remove("file:/");
1128     }
1129 
1130     //! check out layoutpath existence
1131     if (QFileInfo(layoutPath).exists()) {
1132         qDebug() << " Layout is going to be imported and loaded from file :: " << layoutPath << " with suggested name :: " << suggestedLayoutName;
1133 
1134         QString importedLayout = m_layoutsManager->importer()->importLayout(layoutPath, suggestedLayoutName);
1135 
1136         if (importedLayout.isEmpty()) {
1137             qDebug() << i18n("The layout cannot be imported from file :: ") << layoutPath;
1138         } else {
1139            m_layoutsManager->switchToLayout(importedLayout, MemoryUsage::SingleLayout);
1140         }
1141     } else {
1142         qDebug() << " Layout from missing file can not be imported and loaded :: " << layoutPath;
1143     }
1144 }
1145 
showSettingsWindow(int page)1146 void Corona::showSettingsWindow(int page)
1147 {
1148     if (m_inStartup) {
1149         return;
1150     }
1151 
1152     Settings::Dialog::ConfigurationPage p = Settings::Dialog::LayoutPage;
1153 
1154     if (page >= Settings::Dialog::LayoutPage && page <= Settings::Dialog::PreferencesPage) {
1155         p = static_cast<Settings::Dialog::ConfigurationPage>(page);
1156     }
1157 
1158     m_layoutsManager->showLatteSettingsDialog(p);
1159 }
1160 
contextMenuData(const uint & containmentId)1161 QStringList Corona::contextMenuData(const uint &containmentId)
1162 {
1163     QStringList data;
1164     Types::ViewType viewType{Types::DockView};
1165     auto view = m_layoutsManager->synchronizer()->viewForContainment(containmentId);
1166 
1167     if (view) {
1168         viewType = view->type();
1169     }
1170 
1171     data << QString::number((int)m_layoutsManager->memoryUsage()); // Memory Usage
1172     data << m_layoutsManager->centralLayoutsNames().join(";;"); // All Active layouts
1173     data << m_layoutsManager->synchronizer()->currentLayoutsNames().join(";;"); // All Current layouts
1174     data << m_universalSettings->contextMenuActionsAlwaysShown().join(";;");
1175 
1176     QStringList layoutsmenu;
1177 
1178     for(const auto &layoutName : m_layoutsManager->synchronizer()->menuLayouts()) {
1179         if (m_layoutsManager->synchronizer()->centralLayout(layoutName)
1180                 || m_layoutsManager->memoryUsage() == Latte::MemoryUsage::SingleLayout) {
1181             QStringList layoutdata;
1182             Data::LayoutIcon layouticon = m_layoutsManager->iconForLayout(layoutName);
1183             layoutdata << layoutName;
1184             layoutdata << QString::number(layouticon.isBackgroundFile);
1185             layoutdata << layouticon.name;
1186             layoutsmenu << layoutdata.join("**");
1187         }
1188     }
1189 
1190     data << layoutsmenu.join(";;");
1191     data << QString::number((int)viewType); //Selected View type
1192     data << (view ? view->layout()->name() : QString());   //Selected View layout*/
1193 
1194     return data;
1195 }
1196 
viewTemplatesData()1197 QStringList Corona::viewTemplatesData()
1198 {
1199     QStringList data;
1200 
1201     Latte::Data::GenericTable<Data::Generic> viewtemplates = m_templatesManager->viewTemplates();
1202 
1203     for(int i=0; i<viewtemplates.rowCount(); ++i) {
1204         data << viewtemplates[i].name;
1205         data << viewtemplates[i].id;
1206     }
1207 
1208     return data;
1209 }
1210 
addView(const uint & containmentId,const QString & templateId)1211 void Corona::addView(const uint &containmentId, const QString &templateId)
1212 {
1213     if (containmentId <= 0) {
1214         auto currentlayouts = m_layoutsManager->currentLayouts();
1215         if (currentlayouts.count() > 0) {
1216             currentlayouts[0]->newView(templateId);
1217         }
1218     } else {
1219         auto view = m_layoutsManager->synchronizer()->viewForContainment((int)containmentId);
1220         if (view) {
1221             view->newView(templateId);
1222         }
1223     }
1224 }
1225 
duplicateView(const uint & containmentId)1226 void Corona::duplicateView(const uint &containmentId)
1227 {
1228     auto view = m_layoutsManager->synchronizer()->viewForContainment((int)containmentId);
1229     if (view) {
1230         view->duplicateView();
1231     }
1232 }
1233 
exportViewTemplate(const uint & containmentId)1234 void Corona::exportViewTemplate(const uint &containmentId)
1235 {
1236     auto view = m_layoutsManager->synchronizer()->viewForContainment((int)containmentId);
1237     if (view) {
1238         view->exportTemplate();
1239     }
1240 }
1241 
moveViewToLayout(const uint & containmentId,const QString & layoutName)1242 void Corona::moveViewToLayout(const uint &containmentId, const QString &layoutName)
1243 {
1244     auto view = m_layoutsManager->synchronizer()->viewForContainment((int)containmentId);
1245     if (view && !layoutName.isEmpty() && view->layout()->name() != layoutName) {
1246         view->positioner()->setNextLocation(layoutName, "", Plasma::Types::Floating, Latte::Types::NoneAlignment);
1247     }
1248 }
1249 
removeView(const uint & containmentId)1250 void Corona::removeView(const uint &containmentId)
1251 {
1252     auto view = m_layoutsManager->synchronizer()->viewForContainment((int)containmentId);
1253     if (view) {
1254         view->removeView();
1255     }
1256 }
1257 
setBackgroundFromBroadcast(QString activity,QString screenName,QString filename)1258 void Corona::setBackgroundFromBroadcast(QString activity, QString screenName, QString filename)
1259 {
1260     if (filename.startsWith("file://")) {
1261         filename = filename.remove(0,7);
1262     }
1263 
1264     PlasmaExtended::BackgroundCache::self()->setBackgroundFromBroadcast(activity, screenName, filename);
1265 }
1266 
setBroadcastedBackgroundsEnabled(QString activity,QString screenName,bool enabled)1267 void Corona::setBroadcastedBackgroundsEnabled(QString activity, QString screenName, bool enabled)
1268 {
1269     PlasmaExtended::BackgroundCache::self()->setBroadcastedBackgroundsEnabled(activity, screenName, enabled);
1270 }
1271 
toggleHiddenState(QString layoutName,QString viewName,QString screenName,int screenEdge)1272 void Corona::toggleHiddenState(QString layoutName, QString viewName, QString screenName, int screenEdge)
1273 {
1274     if (layoutName.isEmpty()) {
1275         for(auto layout : m_layoutsManager->currentLayouts()) {
1276             layout->toggleHiddenState(viewName, screenName, (Plasma::Types::Location)screenEdge);
1277         }
1278     } else {
1279         Layout::GenericLayout *gLayout = layout(layoutName);
1280 
1281         if (gLayout) {
1282             gLayout->toggleHiddenState(viewName, screenName, (Plasma::Types::Location)screenEdge);
1283         }
1284     }
1285 }
1286 
importFullConfiguration(const QString & file)1287 void Corona::importFullConfiguration(const QString &file)
1288 {
1289     m_importFullConfigurationFile = file;
1290     quitApplication();
1291 }
1292 
qmlRegisterTypes() const1293 inline void Corona::qmlRegisterTypes() const
1294 {
1295     qmlRegisterUncreatableMetaObject(Latte::Settings::staticMetaObject,
1296                                      "org.kde.latte.private.app",          // import statement
1297                                      0, 1,                                 // major and minor version of the import
1298                                      "Settings",                           // name in QML
1299                                      "Error: only enums of latte app settings");
1300 
1301     qmlRegisterType<Latte::BackgroundTracker>("org.kde.latte.private.app", 0, 1, "BackgroundTracker");
1302     qmlRegisterType<Latte::Interfaces>("org.kde.latte.private.app", 0, 1, "Interfaces");
1303 
1304 
1305 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1306     qmlRegisterType<QScreen>();
1307     qmlRegisterType<Latte::View>();
1308     qmlRegisterType<Latte::ViewPart::WindowsTracker>();
1309     qmlRegisterType<Latte::ViewPart::TrackerPart::CurrentScreenTracker>();
1310     qmlRegisterType<Latte::ViewPart::TrackerPart::AllScreensTracker>();
1311     qmlRegisterType<Latte::WindowSystem::SchemeColors>();
1312     qmlRegisterType<Latte::WindowSystem::Tracker::LastActiveWindow>();
1313     qmlRegisterType<Latte::Types>();
1314 #else
1315     qmlRegisterAnonymousType<QScreen>("latte-dock", 1);
1316     qmlRegisterAnonymousType<Latte::View>("latte-dock", 1);
1317     qmlRegisterAnonymousType<Latte::ViewPart::WindowsTracker>("latte-dock", 1);
1318     qmlRegisterAnonymousType<Latte::ViewPart::TrackerPart::CurrentScreenTracker>("latte-dock", 1);
1319     qmlRegisterAnonymousType<Latte::ViewPart::TrackerPart::AllScreensTracker>("latte-dock", 1);
1320     qmlRegisterAnonymousType<Latte::WindowSystem::SchemeColors>("latte-dock", 1);
1321     qmlRegisterAnonymousType<Latte::WindowSystem::Tracker::LastActiveWindow>("latte-dock", 1);
1322     qmlRegisterAnonymousType<Latte::Types>("latte-dock", 1);
1323 #endif
1324 }
1325 
1326 }
1327