LCOV - code coverage report
Current view: top level - tools/launcher-qml - launcher-qml.cpp (source / functions) Coverage Total Hit
Test: QtApplicationManager Lines: 66.0 % 344 227
Test Date: 2024-09-07 10:03:52 Functions: 75.0 % 12 9
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 30.8 % 968 298

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2021 The Qt Company Ltd.
       2                 :             : // Copyright (C) 2019 Luxoft Sweden AB
       3                 :             : // Copyright (C) 2018 Pelagicore AG
       4                 :             : // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
       5                 :             : 
       6                 :             : #include <memory>
       7                 :             : 
       8                 :             : #include <QQmlComponent>
       9                 :             : #include <QQmlContext>
      10                 :             : #include <QQmlDebuggingEnabler>
      11                 :             : 
      12                 :             : #include <QSocketNotifier>
      13                 :             : #include <QFile>
      14                 :             : #include <QFileInfo>
      15                 :             : #include <QDir>
      16                 :             : #include <QtEndian>
      17                 :             : #include <QMetaObject>
      18                 :             : #include <QRegularExpression>
      19                 :             : #include <QCommandLineParser>
      20                 :             : #include <QLibraryInfo>
      21                 :             : 
      22                 :             : #include <QDBusConnection>
      23                 :             : #include <QDBusInterface>
      24                 :             : #include <QDBusArgument>
      25                 :             : #include <QLoggingCategory>
      26                 :             : #include <private/qabstractanimation_p.h> // For QUnifiedTimer
      27                 :             : #include <qplatformdefs.h>
      28                 :             : 
      29                 :             : #include <QGuiApplication>
      30                 :             : #include <QQuickItem>
      31                 :             : #include <QQuickView>
      32                 :             : #include <QQuickWindow>
      33                 :             : 
      34                 :             : #include "applicationmain.h"
      35                 :             : #include "qtyaml.h"
      36                 :             : #include "global.h"
      37                 :             : #include "logging.h"
      38                 :             : #include "utilities.h"
      39                 :             : #include "exception.h"
      40                 :             : #include "crashhandler.h"
      41                 :             : #include "yamlpackagescanner.h"
      42                 :             : #include "packageinfo.h"
      43                 :             : #include "applicationinfo.h"
      44                 :             : #include "startupinterface.h"
      45                 :             : #include "dbus-utilities.h"
      46                 :             : #include "startuptimer.h"
      47                 :             : #include "processtitle.h"
      48                 :             : #include "qml-utilities.h"
      49                 :             : #include "launcher-qml_p.h"
      50                 :             : #include "applicationmanagerwindow.h"
      51                 :             : 
      52                 :             : using namespace Qt::StringLiterals;
      53                 :             : 
      54                 :             : 
      55                 :             : QT_USE_NAMESPACE_AM
      56                 :             : 
      57                 :             : 
      58                 :          72 : int main(int argc, char *argv[])
      59                 :             : {
      60                 :          72 :     StartupTimer::instance()->checkpoint("entered main");
      61                 :             : 
      62                 :          72 :     ProcessTitle::adjustArgumentCount(argc);
      63                 :             : 
      64         [ +  - ]:          72 :     QCoreApplication::setApplicationName(u"Qt Application Manager QML Launcher"_s);
      65         [ +  - ]:          72 :     QCoreApplication::setOrganizationName(u"QtProject"_s);
      66         [ +  - ]:          72 :     QCoreApplication::setOrganizationDomain(u"qt-project.org"_s);
      67         [ +  - ]:          72 :     QCoreApplication::setApplicationVersion(QString::fromLatin1(QT_AM_VERSION_STR));
      68                 :             : 
      69         [ +  - ]:          72 :     if (Logging::isDltAvailable()) {
      70         [ +  - ]:          72 :         if (qEnvironmentVariableIntValue("AM_NO_DLT_LOGGING") == 1)
      71                 :          72 :             Logging::setDltEnabled(false);
      72                 :             : 
      73                 :             :         // The common-lib is already registering the DLT Application for the application manager.
      74                 :             :         // As the appID needs to be unique within the system, we cannot use the same appID and
      75                 :             :         // need to change it as early as possible.
      76                 :             : 
      77                 :             :         // As we don't know the app-id yet, we are registering a place holder so we are able to see
      78                 :             :         // something in the dlt logs if general errors occur.
      79   [ +  -  +  - ]:         144 :         Logging::setDltApplicationId("QTLQ", "Qt Application Manager Launcher QML");
      80                 :             :     }
      81         [ +  - ]:          72 :     Logging::setApplicationId("qml-launcher");
      82                 :          72 :     Logging::initialize();
      83                 :             : 
      84                 :          72 :     std::unique_ptr<ApplicationMain> am;
      85                 :          72 :     std::unique_ptr<Controller> controller; // this needs to die BEFORE qApp does
      86                 :             : 
      87                 :          72 :     try {
      88   [ +  -  +  - ]:         144 :         const QString socket = QDir(qEnvironmentVariable("XDG_RUNTIME_DIR"))
      89   [ +  -  +  - ]:         144 :                           .filePath(qEnvironmentVariable("WAYLAND_DISPLAY"));
      90   [ +  -  -  + ]:          72 :         if (!QFileInfo::exists(socket))
      91                 :           0 :             throw Exception("Cannot start application: no wayland display - expected socket at: %1").arg(socket);
      92                 :             : 
      93         [ +  - ]:         144 :         am = std::make_unique<ApplicationMain>(argc, argv);
      94                 :             : 
      95         [ +  - ]:          72 :         QCommandLineParser clp;
      96         [ +  - ]:          72 :         clp.addHelpOption();
      97   [ +  -  +  - ]:          72 :         clp.addOption({ u"qml-debug"_s,   u"Enables QML debugging and profiling."_s });
      98   [ +  -  +  - ]:          72 :         clp.addOption({ u"quicklaunch"_s, u"Starts the launcher in the quicklaunching mode."_s });
      99   [ +  -  +  - ]:          72 :         clp.addOption({ u"directload"_s , u"The info.yaml to start (you can add '@<appid>' to start a specific app within the package, instead of the first one)."_s, u"info.yaml"_s });
     100   [ +  -  +  - ]:          72 :         clp.process(*am);
     101                 :             : 
     102         [ +  - ]:          72 :         bool quicklaunched = clp.isSet(u"quicklaunch"_s);
     103         [ +  - ]:          72 :         QString directLoadManifest = clp.value(u"directload"_s);
     104                 :             : 
     105         [ +  - ]:          72 :         if (directLoadManifest.isEmpty())
     106         [ +  - ]:         144 :             am->loadConfiguration();
     107                 :             : 
     108                 :             :         //CrashHandler::setCrashActionConfiguration(am->runtimeConfiguration().value(u"crashAction"_s).toMap());
     109                 :             :         // the verbose flag has already been factored into the rules:
     110   [ +  -  +  -  :         144 :         am->setupLogging(false, am->loggingRules(), QString(), am->useAMConsoleLogger());
                   +  - ]
     111   [ +  -  +  - ]:          72 :         am->setupQmlDebugging(clp.isSet(u"qml-debug"_s));
     112   [ +  -  +  - ]:          72 :         am->setupWatchdog(am->watchdogConfiguration());
     113   [ +  -  +  - ]:          72 :         am->setupOpenGL(am->openGLConfiguration());
     114   [ +  -  +  -  :         144 :         am->setupIconTheme(am->iconThemeSearchPaths(), am->iconThemeName());
                   +  - ]
     115                 :          72 :         am->registerWaylandExtensions();
     116                 :             : 
     117   [ +  -  +  - ]:          72 :         if (Logging::isDltAvailable())
     118   [ +  -  +  - ]:         144 :             Logging::setDltLongMessageBehavior(am->dltLongMessageBehavior());
     119                 :             : 
     120   [ +  -  +  - ]:          72 :         StartupTimer::instance()->checkpoint("after basic initialization");
     121                 :             : 
     122         [ -  + ]:          72 :         if (!directLoadManifest.isEmpty()) {
     123                 :           0 :             QString directLoadAppId;
     124         [ #  # ]:           0 :             qsizetype appPos = directLoadManifest.indexOf(u"@"_s);
     125         [ #  # ]:           0 :             if (appPos > 0) {
     126         [ #  # ]:           0 :                 directLoadAppId = directLoadManifest.mid(appPos + 1);
     127         [ #  # ]:           0 :                 directLoadManifest.truncate(appPos);
     128                 :             :             }
     129                 :             : 
     130         [ #  # ]:           0 :             QFileInfo fi(directLoadManifest);
     131   [ #  #  #  #  :           0 :             if (!fi.exists() || fi.fileName() != u"info.yaml"_s)
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     132                 :           0 :                 throw Exception("--directload needs a valid info.yaml file as parameter");
     133         [ #  # ]:           0 :             directLoadManifest = fi.absoluteFilePath();
     134   [ #  #  #  # ]:           0 :             controller.reset(new Controller(am.get(), quicklaunched, qMakePair(directLoadManifest, directLoadAppId)));
     135                 :           0 :         } else {
     136         [ +  - ]:          72 :             am->setupDBusConnections();
     137   [ +  -  +  - ]:          72 :             StartupTimer::instance()->checkpoint("after dbus initialization");
     138   [ +  -  +  - ]:         144 :             controller.reset(new Controller(am.get(), quicklaunched));
     139                 :             :         }
     140         [ -  - ]:          72 :     } catch (const std::exception &e) {
     141   [ -  -  -  -  :           0 :         qCCritical(LogQmlRuntime) << "ERROR:" << e.what();
          -  -  -  -  -  
                      - ]
     142                 :           0 :         return 2;
     143                 :           0 :     }
     144                 :             : 
     145                 :             :     // we want the exec() outside of the try/catch block, so stray user exceptions trigger the
     146                 :             :     // CrashHandler's set_terminate callback.
     147         [ +  - ]:          72 :     return ApplicationMainBase::exec();
     148                 :          67 : }
     149                 :             : 
     150         [ +  - ]:          72 : Controller::Controller(ApplicationMain *am, bool quickLaunched)
     151         [ +  - ]:         144 :     : Controller(am, quickLaunched, qMakePair(QString{}, QString{}))
     152                 :          72 : { }
     153                 :             : 
     154                 :          72 : Controller::Controller(ApplicationMain *am, bool quickLaunched, const QPair<QString, QString> &directLoad)
     155                 :             :     : QObject(am)
     156   [ +  -  +  - ]:          72 :     , m_quickLaunched(quickLaunched)
     157                 :             : {
     158         [ +  - ]:          72 :     connect(&m_engine, &QObject::destroyed, QCoreApplication::instance(), &QCoreApplication::quit);
     159         [ +  - ]:          72 :     CrashHandler::setQmlEngine(&m_engine);
     160                 :             : 
     161         [ +  - ]:          72 :     m_configuration = am->runtimeConfiguration();
     162                 :             : 
     163   [ +  -  +  - ]:         144 :     const QStringList resources = variantToStringList(m_configuration.value(u"resources"_s));
     164         [ +  + ]:          74 :     for (const QString &resource: resources) {
     165   [ +  -  +  -  :           4 :         const QString path = QFileInfo(resource).isRelative() ? am->baseDir() + resource : resource;
          +  -  +  -  +  
                -  -  - ]
     166                 :             : 
     167                 :           2 :         try {
     168         [ +  - ]:           2 :             loadResource(path);
     169         [ -  - ]:           0 :         } catch (const Exception &e) {
     170   [ -  -  -  -  :           0 :             qCWarning(LogSystem).noquote() << e.errorString();
             -  -  -  - ]
     171                 :           0 :         }
     172                 :           2 :     }
     173                 :             : 
     174                 :          72 :     QString absolutePluginPath;
     175   [ +  -  +  - ]:         144 :     QStringList pluginPaths = variantToStringList(m_configuration.value(u"pluginPaths"_s));
     176   [ +  -  +  -  :          72 :     for (QString &path : pluginPaths) {
                   -  + ]
     177   [ #  #  #  #  :           0 :         if (QFileInfo(path).isRelative())
                   #  # ]
     178         [ #  # ]:           0 :             path.prepend(am->baseDir());
     179         [ #  # ]:           0 :         else if (absolutePluginPath.isEmpty())
     180                 :           0 :             absolutePluginPath = path;
     181                 :             : 
     182         [ #  # ]:           0 :         qApp->addLibraryPath(path);
     183                 :             :     }
     184                 :             : 
     185         [ -  + ]:          72 :     if (!absolutePluginPath.isEmpty()) {
     186   [ #  #  #  #  :           0 :         qCWarning(LogDeployment).nospace() << "Absolute plugin path in the runtime configuration "
                   #  # ]
     187   [ #  #  #  #  :           0 :                             "can lead to problems inside containers (e.g. " << absolutePluginPath << ")";
                   #  # ]
     188                 :             :     }
     189                 :             : 
     190                 :          72 :     QString absoluteImportPath;
     191   [ +  -  +  - ]:         144 :     QStringList importPaths = variantToStringList(m_configuration.value(u"importPaths"_s));
     192   [ +  -  +  -  :          76 :     for (QString &path : importPaths) {
                   +  + ]
     193         [ +  - ]:           4 :         const QFileInfo fi(path);
     194   [ +  -  +  -  :           8 :         if (fi.isNativePath() && fi.isAbsolute() && absoluteImportPath.isEmpty())
             -  +  -  - ]
     195                 :           0 :             absoluteImportPath = path;
     196   [ +  -  +  -  :           8 :         m_engine.addImportPath(toAbsoluteFilePath(path, am->baseDir()));
                   +  - ]
     197                 :           4 :     }
     198                 :             : 
     199         [ -  + ]:          72 :     if (!absoluteImportPath.isEmpty()) {
     200   [ #  #  #  #  :           0 :         qCWarning(LogDeployment).nospace() << "Absolute import path in the runtime configuration "
                   #  # ]
     201   [ #  #  #  #  :           0 :                             "can lead to problems inside containers (e.g. " << absoluteImportPath << ")";
                   #  # ]
     202                 :             :     }
     203                 :             : 
     204   [ +  -  +  - ]:          72 :     StartupTimer::instance()->checkpoint("after application config initialization");
     205                 :             : 
     206         [ +  - ]:          72 :     if (directLoad.first.isEmpty()) {
     207         [ +  - ]:          72 :         am->connectDBusInterfaces(true);
     208                 :             : 
     209                 :          72 :         connect(am, &ApplicationMain::startApplication,
     210         [ +  - ]:         144 :                 this, &Controller::startApplication);
     211                 :             :     } else {
     212         [ #  # ]:           0 :         QMetaObject::invokeMethod(this, [this, directLoad]() {
     213                 :           0 :             PackageInfo *pi;
     214                 :           0 :             try {
     215         [ #  # ]:           0 :                 pi = YamlPackageScanner().scan(directLoad.first);
     216         [ -  - ]:           0 :             } catch (const Exception &e) {
     217   [ -  -  -  -  :           0 :                 qCCritical(LogQmlRuntime) << "Could not parse info.yaml file:" << e.what();
          -  -  -  -  -  
                      - ]
     218         [ -  - ]:           0 :                 QCoreApplication::exit(20);
     219                 :           0 :                 return;
     220                 :           0 :             }
     221                 :           0 :             const auto apps = pi->applications();
     222         [ #  # ]:           0 :             const ApplicationInfo *a = apps.constFirst();
     223         [ #  # ]:           0 :             if (!directLoad.second.isEmpty()) {
     224         [ #  # ]:           0 :                 auto it = std::find_if(apps.cbegin(), apps.cend(),
     225         [ #  # ]:           0 :                                        [appId = directLoad.second](ApplicationInfo *appInfo) -> bool {
     226                 :           0 :                     return (appInfo->id() == appId);
     227                 :             :                 });
     228         [ #  # ]:           0 :                 if (it == apps.end()) {
     229   [ #  #  #  #  :           0 :                     qCCritical(LogQmlRuntime) << "Could not find the requested application id"
             #  #  #  # ]
     230   [ #  #  #  # ]:           0 :                                               << directLoad.second << "within the info.yaml file";
     231         [ #  # ]:           0 :                     QCoreApplication::exit(21);
     232                 :           0 :                     return;
     233                 :             :                 }
     234                 :           0 :                 a = *it;
     235                 :             :             }
     236                 :             : 
     237   [ #  #  #  #  :           0 :             startApplication(QFileInfo(directLoad.first).absolutePath(), a->codeFilePath(),
                   #  # ]
     238   [ #  #  #  # ]:           0 :                              QString(), QString(), a->toVariantMap(), QVariantMap());
     239                 :           0 :         }, Qt::QueuedConnection);
     240                 :             :     }
     241                 :             : 
     242   [ +  -  +  - ]:         144 :     const QString quicklaunchQml = m_configuration.value((u"quicklaunchQml"_s)).toString();
     243   [ +  +  +  - ]:          72 :     if (!quicklaunchQml.isEmpty() && quickLaunched) {
     244   [ +  -  +  -  :           4 :         QQmlComponent quicklaunchComp(&m_engine, filePathToUrl(quicklaunchQml, am->baseDir()));
                   +  - ]
     245   [ +  -  +  - ]:           2 :         if (!quicklaunchComp.isError()) {
     246         [ +  - ]:           2 :             std::unique_ptr<QObject> quicklaunchInstance(quicklaunchComp.create());
     247                 :           2 :         } else {
     248         [ #  # ]:           0 :             const QList<QQmlError> errors = quicklaunchComp.errors();
     249         [ #  # ]:           0 :             for (const QQmlError &error : errors)
     250   [ #  #  #  #  :           0 :                 qCCritical(LogQmlRuntime) << error;
             #  #  #  # ]
     251                 :           0 :         }
     252                 :           2 :     }
     253                 :             : 
     254   [ +  -  +  - ]:          72 :     StartupTimer::instance()->checkpoint("after application interface initialization");
     255                 :          72 : }
     256                 :             : 
     257                 :          69 : void Controller::startApplication(const QString &baseDir, const QString &qmlFile, const QString &document,
     258                 :             :                                   const QString &mimeType, const QVariantMap &application,
     259                 :             :                                   const QVariantMap &systemProperties)
     260                 :             : {
     261         [ +  - ]:          69 :     if (m_launched)
     262                 :           0 :         return;
     263                 :          69 :     m_launched = true;
     264                 :             : 
     265   [ +  -  +  -  :          69 :     static const QString applicationId = application.value(u"id"_s).toString();
             +  -  +  - ]
     266                 :             : 
     267         [ -  + ]:          69 :     if (applicationId.isEmpty()) {
     268   [ #  #  #  # ]:           0 :         qCCritical(LogQmlRuntime) << "did not receive an application id";
     269                 :           0 :         QCoreApplication::exit(2);
     270                 :           0 :         return;
     271                 :             :     }
     272                 :             : 
     273                 :          69 :     const QStringList applicationIdParts = applicationId.split(u'.');
     274         [ +  + ]:          69 :     if (applicationIdParts.size() < 2) {
     275   [ +  -  +  - ]:          11 :         Logging::setApplicationId(applicationId.toLocal8Bit());
     276         [ +  - ]:          11 :         QCoreApplication::setApplicationName(applicationId);
     277                 :             :     } else {
     278                 :          58 :         const QString appName = applicationIdParts.last();
     279                 :          58 :         QString domainName;
     280                 :          58 :         QString loggingId;
     281                 :             : 
     282         [ +  + ]:         172 :         for (qsizetype i = 0; i < applicationIdParts.size() - 1; ++i) {
     283                 :             :             // reverse the reverse-DNS domain name
     284         [ +  + ]:         114 :             if (!domainName.isEmpty())
     285         [ +  - ]:          56 :                 domainName.prepend(u'.');
     286         [ +  - ]:         114 :             domainName.prepend(applicationIdParts.at(i));
     287                 :             : 
     288                 :             :             // shorten application id to make the debug output more readable
     289         [ +  - ]:         114 :             loggingId.append(applicationIdParts.at(i).at(0));
     290         [ +  - ]:         114 :             loggingId.append(u'.');
     291                 :             :         }
     292         [ +  - ]:          58 :         loggingId.append(applicationIdParts.last());
     293   [ +  -  +  - ]:          58 :         Logging::setApplicationId(loggingId.toLocal8Bit());
     294                 :             : 
     295                 :             :         // we need these to be unique, because other libraries (e.g. QtInsights) expect them to be
     296         [ +  - ]:          58 :         QCoreApplication::setApplicationName(appName);
     297         [ +  - ]:          58 :         QCoreApplication::setOrganizationName(domainName);
     298         [ +  - ]:          58 :         QCoreApplication::setOrganizationDomain(domainName);
     299                 :          58 :     }
     300   [ +  -  +  -  :         138 :     if (const auto version = application.value(u"version"_s).toString(); !version.isEmpty())
                   +  + ]
     301         [ +  - ]:          16 :         QCoreApplication::setApplicationVersion(version);
     302                 :             : 
     303   [ +  -  +  -  :          69 :     if (Logging::isDltAvailable() && Logging::isDltEnabled()) {
             +  -  -  + ]
     304                 :             :         // Change the DLT Application description, to easily identify the application on the DLT logs.
     305   [ #  #  #  # ]:           0 :         const QVariantMap dlt = qdbus_cast<QVariantMap>(application.value(u"dlt"_s));
     306   [ #  #  #  #  :           0 :         QByteArray dltId = dlt.value(u"id"_s).toString().toLocal8Bit();
                   #  # ]
     307   [ #  #  #  #  :           0 :         QByteArray dltDescription = dlt.value(u"description"_s).toString().toLocal8Bit();
                   #  # ]
     308                 :             : 
     309         [ #  # ]:           0 :         if (dltId.isEmpty()) {
     310   [ #  #  #  #  :           0 :             qCCritical(LogQmlRuntime) << "did not receive a DLT id, but DLT is enabled";
             #  #  #  # ]
     311         [ #  # ]:           0 :             QCoreApplication::exit(2);
     312                 :           0 :             return;
     313                 :             :         }
     314         [ #  # ]:           0 :         if (dltDescription.isEmpty())
     315   [ #  #  #  #  :           0 :             dltDescription = QByteArray("Qt Application Manager App: ") + applicationId.toLocal8Bit();
                   #  # ]
     316                 :             : 
     317         [ #  # ]:           0 :         Logging::setDltApplicationId(dltId, dltDescription);
     318         [ #  # ]:           0 :         Logging::registerUnregisteredDltContexts();
     319                 :           0 :     }
     320                 :             :     // Dress up the ps output to make it easier to correlate all the launcher processes
     321   [ +  -  +  - ]:         138 :     ProcessTitle::augmentCommand(applicationId.toLocal8Bit().constData());
     322                 :             : 
     323         [ +  - ]:          69 :     auto *am = ApplicationMain::instance();
     324   [ +  -  +  -  :         138 :     am->setApplication(convertFromDBusVariant(application).toMap());
                   +  - ]
     325   [ +  -  +  -  :         138 :     am->setSystemProperties(convertFromDBusVariant(systemProperties).toMap());
                   +  - ]
     326                 :             : 
     327         [ +  + ]:          69 :     if (m_quickLaunched) {
     328                 :             :         //StartupTimer::instance()->createReport(applicationId  + u" [process launch]"_s);
     329   [ +  -  +  - ]:           6 :         StartupTimer::instance()->reset();
     330                 :             :     } else {
     331   [ +  -  +  - ]:          63 :         StartupTimer::instance()->checkpoint("starting application");
     332                 :             :     }
     333                 :             : 
     334   [ +  -  +  - ]:         138 :     QVariantMap runtimeParameters = qdbus_cast<QVariantMap>(application.value(u"runtimeParameters"_s));
     335                 :             : 
     336   [ +  -  -  -  :         138 :     qCDebug(LogQmlRuntime) << "loading" << applicationId << "- main:" << qmlFile << "- document:" << document
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  + ]
     337   [ #  #  #  #  :           0 :                            << "- mimeType:" << mimeType << "- parameters:" << runtimeParameters
             #  #  #  # ]
     338   [ #  #  #  # ]:           0 :                            << "- baseDir:" << baseDir;
     339                 :             : 
     340   [ +  -  -  + ]:          69 :     if (!QDir::setCurrent(baseDir)) {
     341   [ #  #  #  #  :           0 :         qCCritical(LogQmlRuntime) << "could not set the current directory to" << baseDir;
          #  #  #  #  #  
                      # ]
     342         [ #  # ]:           0 :         QCoreApplication::exit(2);
     343                 :             :         return;
     344                 :             :     }
     345                 :             : 
     346         [ +  - ]:         138 :     QVariant resVar = runtimeParameters.value(u"resources"_s);
     347         [ +  - ]:          69 :     const QVariantList resources = (resVar.metaType() == QMetaType::fromType<QString>())
     348                 :           1 :             ? QVariantList{resVar}
     349   [ +  +  +  -  :          69 :             : qdbus_cast<QVariantList>(resVar);
             -  +  +  - ]
     350                 :             : 
     351         [ +  + ]:          72 :     for (const QVariant &resource : resources) {
     352                 :           3 :         try {
     353   [ +  -  +  - ]:           6 :             loadResource(resource.toString());
     354         [ -  - ]:           0 :         } catch (const Exception &e) {
     355   [ -  -  -  -  :           0 :             qCWarning(LogSystem).noquote() << e.errorString();
             -  -  -  - ]
     356                 :           0 :         }
     357                 :             :     }
     358                 :             : 
     359         [ +  - ]:          69 :     const QUrl qmlFileUrl = filePathToUrl(qmlFile, baseDir);
     360         [ +  - ]:          69 :     const QString qmlFileStr = urlToLocalFilePath(qmlFileUrl);
     361                 :             : 
     362   [ +  -  -  + ]:          69 :     if (!QFile::exists(qmlFileStr)) {
     363   [ #  #  #  #  :           0 :         qCCritical(LogQmlRuntime) << "could not load" << qmlFile << ": file does not exist";
          #  #  #  #  #  
                #  #  # ]
     364         [ #  # ]:           0 :         QCoreApplication::exit(2);
     365                 :             :         return;
     366                 :             :     }
     367                 :             : 
     368         [ +  - ]:          69 :     connect(ApplicationMain::instance(), &ApplicationMain::slowAnimationsChanged,
     369         [ +  - ]:          69 :             this, &Controller::updateSlowAnimations);
     370   [ +  -  +  -  :          69 :     updateSlowAnimations(ApplicationMain::instance()->slowAnimations());
                   +  - ]
     371                 :             : 
     372                 :             :     // we need to catch all show events to apply the slow-animations
     373         [ +  - ]:          69 :     QCoreApplication::instance()->installEventFilter(this);
     374                 :             : 
     375                 :          69 :     QStringList systemStartupPluginPaths;
     376   [ +  -  +  -  :         138 :     const QDir systemStartupPluginDir(QLibraryInfo::path(QLibraryInfo::PluginsPath) + QDir::separator() + u"appman_startup"_s);
             +  -  +  - ]
     377   [ +  -  +  -  :          69 :     for (const auto &pluginName : systemStartupPluginDir.entryList(QDir::Files | QDir::NoDotAndDotDot)) {
             +  -  -  + ]
     378         [ #  # ]:           0 :         const QString filePath = systemStartupPluginDir.absoluteFilePath(pluginName);
     379   [ #  #  #  # ]:           0 :         if (!QLibrary::isLibrary(filePath))
     380                 :           0 :             continue;
     381         [ #  # ]:           0 :         systemStartupPluginPaths += filePath;
     382                 :           0 :     }
     383                 :             : 
     384   [ +  -  +  -  :         138 :     QStringList startupPluginFiles = variantToStringList(m_configuration.value(u"plugins"_s).toMap().value(u"startup"_s));
             +  -  +  - ]
     385                 :          69 :     QVector<StartupInterface *> startupPlugins;
     386                 :          69 :     try {
     387   [ +  -  +  - ]:         138 :         startupPlugins = loadPlugins<StartupInterface>("startup", systemStartupPluginPaths + startupPluginFiles);
     388         [ -  - ]:           0 :     } catch (const Exception &e) {
     389   [ -  -  -  -  :           0 :         qCCritical(LogQmlRuntime) << qPrintable(e.errorString());
          -  -  -  -  -  
                      - ]
     390         [ -  - ]:           0 :         QCoreApplication::exit(2);
     391                 :           0 :         return;
     392                 :           0 :     }
     393         [ -  + ]:          69 :     for (StartupInterface *iface : std::as_const(startupPlugins))
     394   [ #  #  #  # ]:           0 :         iface->initialize(am->systemProperties());
     395                 :             : 
     396   [ +  -  +  - ]:         138 :     bool loadDummyData = runtimeParameters.value(u"loadDummyData"_s).toBool()
     397   [ +  -  +  -  :         207 :             || m_configuration.value(u"loadDummydata"_s).toBool();
          +  -  -  +  +  
          -  +  -  +  -  
          -  -  -  -  -  
                -  -  - ]
     398                 :             : 
     399         [ -  + ]:          69 :     if (loadDummyData) {
     400   [ #  #  #  #  :           0 :         qCWarning(LogDeployment) << "Loading dummy data is deprecated and will be removed soon";
             #  #  #  # ]
     401   [ #  #  #  #  :           0 :         qCDebug(LogQmlRuntime) << "loading dummy-data";
             #  #  #  # ]
     402   [ #  #  #  #  :           0 :         loadQmlDummyDataFiles(&m_engine, QFileInfo(qmlFileStr).path());
                   #  # ]
     403                 :             :     }
     404                 :             : 
     405         [ +  - ]:         138 :     QVariant pluginPaths = runtimeParameters.value(u"pluginPaths"_s);
     406         [ +  - ]:          69 :     const QVariantList ppvl = (pluginPaths.metaType() == QMetaType::fromType<QString>())
     407                 :           0 :             ? QVariantList{pluginPaths}
     408   [ -  +  -  -  :          69 :             : qdbus_cast<QVariantList>(pluginPaths);
             -  -  +  - ]
     409                 :             : 
     410         [ -  + ]:          69 :     for (const QVariant &v : ppvl) {
     411         [ #  # ]:           0 :         const QString path = v.toString();
     412   [ #  #  #  #  :           0 :         if (QFileInfo(path).isRelative())
                   #  # ]
     413   [ #  #  #  #  :           0 :             qApp->addLibraryPath(QDir().absoluteFilePath(path));
                   #  # ]
     414                 :             :         else
     415   [ #  #  #  #  :           0 :             qCWarning(LogQmlRuntime) << "Omitting absolute plugin path in info file for safety reasons:" << path;
          #  #  #  #  #  
                      # ]
     416                 :           0 :     }
     417   [ +  -  -  -  :         138 :     qCDebug(LogQmlRuntime) << "Plugin paths:" << qApp->libraryPaths();
          -  -  -  -  -  
                -  -  + ]
     418                 :             : 
     419         [ +  - ]:         138 :     QVariant imports = runtimeParameters.value(u"importPaths"_s);
     420         [ +  - ]:          69 :     const QVariantList ipvl = (imports.metaType() == QMetaType::fromType<QString>())
     421                 :           2 :             ? QVariantList{imports}
     422   [ +  +  +  -  :          69 :             : qdbus_cast<QVariantList>(imports);
             -  +  +  - ]
     423                 :             : 
     424         [ +  + ]:          76 :     for (const QVariant &v : ipvl) {
     425         [ +  - ]:           7 :         const QString path = v.toString();
     426         [ +  - ]:           7 :         const QFileInfo fi(path);
     427   [ +  -  +  -  :          14 :         if (!(fi.isNativePath() && fi.isAbsolute()))
                   -  + ]
     428   [ +  -  +  -  :          14 :             m_engine.addImportPath(toAbsoluteFilePath(path));
                   +  - ]
     429                 :             :         else
     430   [ #  #  #  #  :           0 :             qCWarning(LogQmlRuntime) << "Omitting absolute import path in info file for safety reasons:" << path;
          #  #  #  #  #  
                      # ]
     431                 :           7 :     }
     432   [ +  -  -  -  :         138 :     qCDebug(LogQmlRuntime) << "Qml import paths:" << m_engine.importPathList();
          -  -  -  -  -  
                -  -  + ]
     433                 :             : 
     434         [ -  + ]:          69 :     for (StartupInterface *iface : std::as_const(startupPlugins))
     435         [ #  # ]:           0 :         iface->beforeQmlEngineLoad(&m_engine);
     436                 :             : 
     437   [ +  -  +  - ]:          69 :     StartupTimer::instance()->checkpoint("after loading plugins and import paths");
     438                 :             : 
     439                 :             :     // protect our namespace from this point onward
     440         [ +  - ]:          69 :     qmlProtectModule("QtApplicationManager", 1);
     441         [ +  - ]:          69 :     qmlProtectModule("QtApplicationManager.Application", 1);
     442         [ +  - ]:          69 :     qmlProtectModule("QtApplicationManager", 2);
     443         [ +  - ]:          69 :     qmlProtectModule("QtApplicationManager.Application", 2);
     444                 :             : 
     445         [ +  - ]:          69 :     m_engine.load(qmlFileUrl);
     446                 :             : 
     447   [ +  -  +  - ]:          69 :     StartupTimer::instance()->checkpoint("after engine loading main qml file");
     448                 :             : 
     449         [ +  - ]:          69 :     auto topLevels = m_engine.rootObjects();
     450                 :             : 
     451         [ +  - ]:          69 :     if (Q_UNLIKELY(topLevels.isEmpty() || !topLevels.at(0))) {
     452   [ #  #  #  #  :           0 :         qCCritical(LogSystem) << "Failed to load component" << qmlFile << ": no root object";
          #  #  #  #  #  
                #  #  # ]
     453         [ #  # ]:           0 :         QCoreApplication::exit(3);
     454                 :           0 :         return;
     455                 :             :     }
     456                 :             : 
     457         [ -  + ]:          69 :     for (StartupInterface *iface : std::as_const(startupPlugins))
     458         [ #  # ]:           0 :         iface->afterQmlEngineLoad(&m_engine);
     459                 :             : 
     460         [ +  - ]:          69 :     QObject *topLevel = topLevels.at(0);
     461   [ +  -  +  + ]:          69 :     if (auto amw = qobject_cast<ApplicationManagerWindow*>(topLevel)) {
     462   [ +  -  +  - ]:          55 :         m_window = qobject_cast<QQuickWindow*>(amw->backingObject());
     463                 :             :     } else {
     464         [ +  - ]:          14 :         m_window = qobject_cast<QQuickWindow *>(topLevel);
     465         [ +  + ]:          14 :         if (!m_window) {
     466         [ +  - ]:          12 :             QQuickItem *contentItem = qobject_cast<QQuickItem *>(topLevel);
     467                 :           2 :             if (contentItem) {
     468   [ +  -  +  - ]:           2 :                 QQuickView* view = new QQuickView(&m_engine, nullptr);
     469                 :           2 :                 m_window = view;
     470         [ +  - ]:           2 :                 view->setContent(qmlFileUrl, nullptr, topLevel);
     471   [ +  -  +  - ]:           2 :                 view->setVisible(contentItem->isVisible());
     472         [ +  - ]:           2 :                 connect(contentItem, &QQuickItem::visibleChanged, this, [view, contentItem]() {
     473                 :           0 :                     view->setVisible(contentItem->isVisible());
     474                 :           0 :                 });
     475                 :             :             }
     476                 :             :         }
     477                 :             :     }
     478                 :             : 
     479   [ +  -  +  - ]:          69 :     StartupTimer::instance()->checkpoint("after creating and setting application window");
     480                 :             : 
     481                 :             :     // needed, even though we do not explicitly show() the window any more
     482         [ -  + ]:          69 :     for (StartupInterface *iface : std::as_const(startupPlugins))
     483         [ #  # ]:           0 :         iface->beforeWindowShow(m_window);
     484                 :             : 
     485   [ +  -  -  -  :         138 :     qCDebug(LogQmlRuntime) << "component loading and creating complete.";
             -  -  -  + ]
     486                 :             : 
     487   [ +  -  +  - ]:          69 :     StartupTimer::instance()->checkpoint("component loading and creating complete.");
     488                 :             : 
     489         [ +  + ]:          69 :     if (m_window) {
     490                 :          59 :         Q_ASSERT(m_engine.incubationController());
     491                 :             : 
     492                 :             :         // not sure if this is needed .. or even the best thing to do ... see connects above, they seem to work better
     493         [ +  - ]:          59 :         QObject::connect(&m_engine, &QQmlEngine::quit, m_window, &QObject::deleteLater);
     494                 :             : 
     495                 :             :         // create the startup report on first frame drawn
     496                 :         118 :         static QMetaObject::Connection conn = QObject::connect(m_window, &QQuickWindow::frameSwapped,
     497                 :          58 :                                                                this, [this, startupPlugins]() {
     498                 :             :             // this is a queued signal, so there may be still one in the queue after calling disconnect()
     499         [ +  - ]:          57 :             if (conn) {
     500                 :          57 :                 QObject::disconnect(conn);
     501                 :             : 
     502                 :          57 :                 auto st = StartupTimer::instance();
     503                 :          57 :                 st->checkFirstFrame();
     504                 :          57 :                 st->createAutomaticReport(applicationId);
     505                 :             : 
     506         [ -  + ]:          57 :                 for (StartupInterface *iface : std::as_const(startupPlugins))
     507                 :           0 :                     iface->afterWindowShow(m_window);
     508                 :             :             }
     509   [ +  -  +  -  :          59 :         });
                   +  - ]
     510                 :             :     } else {
     511   [ +  -  +  - ]:          10 :         StartupTimer::instance()->createAutomaticReport(applicationId);
     512                 :             :     }
     513                 :             : 
     514         [ +  + ]:          69 :     if (!document.isEmpty())
     515         [ +  - ]:          17 :         emit am->openDocument(document, mimeType);
     516                 :          69 : }
     517                 :             : 
     518                 :        3789 : bool Controller::eventFilter(QObject *o, QEvent *e)
     519                 :             : {
     520   [ +  -  +  +  :        3865 :     if (e && (e->type() == QEvent::Show) && qobject_cast<QQuickWindow *>(o)) {
                   +  - ]
     521                 :          76 :         auto window = static_cast<QQuickWindow *>(o);
     522   [ +  -  +  - ]:         228 :         m_allWindows.append(window);
     523                 :          76 :         updateSlowAnimationsForWindow(window);
     524                 :             :     }
     525                 :        3789 :     return QObject::eventFilter(o, e);
     526                 :             : }
     527                 :             : 
     528                 :          76 : void Controller::updateSlowAnimationsForWindow(QQuickWindow *window)
     529                 :             : {
     530                 :             :     // QUnifiedTimer are thread-local. To also slow down animations running in the SG thread
     531                 :             :     // we need to enable the slow mode in this timer as well.
     532         [ +  - ]:          76 :     QMetaObject::Connection *connection = new QMetaObject::Connection;
     533                 :          76 :     *connection = connect(window, &QQuickWindow::beforeRendering,
     534                 :         222 :                           this, [connection] {
     535   [ +  -  +  - ]:          74 :         if (connection && *connection) {
     536                 :             : #if defined(Q_CC_MSVC)
     537                 :             :             qApp->disconnect(*connection); // MSVC cannot distinguish between static and non-static overloads in lambdas
     538                 :             : #else
     539                 :          74 :             QObject::disconnect(*connection);
     540                 :             : #endif
     541         [ +  - ]:          74 :             QUnifiedTimer::instance()->setSlowModeEnabled(ApplicationMain::instance()->slowAnimations());
     542         [ +  - ]:          74 :             delete connection;
     543                 :             :         }
     544                 :          76 :     }, Qt::DirectConnection);
     545                 :          76 : }
     546                 :             : 
     547                 :          69 : void Controller::updateSlowAnimations(bool isSlow)
     548                 :             : {
     549                 :          69 :     QUnifiedTimer::instance()->setSlowModeEnabled(isSlow);
     550                 :             : 
     551         [ -  + ]:          69 :     for (auto it = m_allWindows.cbegin(); it != m_allWindows.cend(); ) {
     552         [ #  # ]:           0 :         QPointer<QQuickWindow> window = *it;
     553         [ #  # ]:           0 :         if (!window) {
     554         [ #  # ]:           0 :             m_allWindows.erase(it);
     555                 :             :         } else {
     556         [ #  # ]:           0 :             updateSlowAnimationsForWindow(window.data());
     557                 :           0 :             ++it;
     558                 :             :         }
     559                 :           0 :     }
     560                 :          69 : }
     561                 :             : 
     562                 :             : 
     563                 :             : #include "moc_launcher-qml_p.cpp"
        

Generated by: LCOV version 2.0-1