LCOV - code coverage report
Current view: top level - muse/framework/global/internal - baseapplication.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 1.0 % 205 2
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "baseapplication.h"
      23              : 
      24              : #include "global/types/version.h"
      25              : #include "global/globalmodule.h"
      26              : #include "global/async/processevents.h"
      27              : 
      28              : #include "muse_framework_config.h"
      29              : 
      30              : #ifndef NO_QT_SUPPORT
      31              : #include <QApplication>
      32              : #endif
      33              : 
      34              : #ifdef QT_QPROCESS_SUPPORTED
      35              : #include <QProcess>
      36              : #endif
      37              : 
      38              : #ifdef QT_CONCURRENT_SUPPORTED
      39              : #include <QThreadPool>
      40              : #endif
      41              : 
      42              : #include "log.h"
      43              : 
      44              : using namespace muse;
      45              : 
      46           92 : String BaseApplication::appName()
      47              : {
      48              : #ifdef MUSE_APP_NAME_MACHINE_READABLE
      49           92 :     return String::fromAscii(MUSE_APP_NAME_MACHINE_READABLE);
      50              : #else
      51              :     return String();
      52              : #endif
      53              : }
      54              : 
      55            0 : String BaseApplication::appTitle()
      56              : {
      57              : #ifdef MUSE_APP_NAME_HUMAN_READABLE
      58              : #ifdef MUSE_APP_UNSTABLE
      59            0 :     return String::fromAscii(MUSE_APP_NAME_HUMAN_READABLE) + u" Development";
      60              : #else
      61              :     return String::fromAscii(MUSE_APP_NAME_HUMAN_READABLE);
      62              : #endif
      63              : #else
      64              :     return String();
      65              : #endif
      66              : }
      67              : 
      68            0 : bool BaseApplication::appUnstable()
      69              : {
      70              : #ifdef MUSE_APP_UNSTABLE
      71            0 :     return true;
      72              : #else
      73              :     return false;
      74              : #endif
      75              : }
      76              : 
      77            0 : Version BaseApplication::appVersion()
      78              : {
      79              : #ifdef MUSE_APP_VERSION
      80            0 :     static Version v(MUSE_APP_VERSION);
      81              : #else
      82              :     static Version v("0.0.0");
      83              : #endif
      84            0 :     return v;
      85              : }
      86              : 
      87            0 : Version BaseApplication::appFullVersion()
      88              : {
      89            0 :     static Version fv(appVersion());
      90              : 
      91              : #ifdef MUSE_APP_VERSION_LABEL
      92              :     static bool once = false;
      93              :     if (!once) {
      94              :         String versionLabel = String::fromAscii(MUSE_APP_VERSION_LABEL);
      95              :         if (!versionLabel.isEmpty()) {
      96              :             fv.setSuffix(versionLabel);
      97              :         }
      98              :         once = true;
      99              :     }
     100              : #endif
     101              : 
     102            0 :     return fv;
     103              : }
     104              : 
     105            0 : String BaseApplication::appBuild()
     106              : {
     107              : #ifdef MUSE_APP_BUILD_NUMBER
     108            0 :     return String::fromAscii(MUSE_APP_BUILD_NUMBER);
     109              : #else
     110              :     return String();
     111              : #endif
     112              : }
     113              : 
     114            0 : String BaseApplication::appRevision()
     115              : {
     116              : #ifdef MUSE_APP_REVISION
     117            0 :     return String::fromAscii(MUSE_APP_REVISION);
     118              : #else
     119              :     return String();
     120              : #endif
     121              : }
     122              : 
     123            0 : BaseApplication::BaseApplication(const std::shared_ptr<CmdOptions>& appOptions)
     124            0 :     : m_appOptions(appOptions)
     125              : {
     126            0 : }
     127              : 
     128            0 : void BaseApplication::setRunMode(const RunMode& mode)
     129              : {
     130            0 :     m_runMode = mode;
     131            0 : }
     132              : 
     133            0 : IApplication::RunMode BaseApplication::runMode() const
     134              : {
     135            0 :     return m_runMode;
     136              : }
     137              : 
     138            0 : bool BaseApplication::noGui() const
     139              : {
     140            0 :     switch (m_runMode) {
     141            0 :     case RunMode::GuiApp: return false;
     142            0 :     case RunMode::ConsoleApp: return true;
     143            0 :     case RunMode::AudioPluginRegistration: return true;
     144              :     }
     145            0 :     return false;
     146              : }
     147              : 
     148            0 : void BaseApplication::addModule(muse::modularity::IModuleSetup* module)
     149              : {
     150            0 :     m_modules.push_back(module);
     151            0 : }
     152              : 
     153            0 : void BaseApplication::setup()
     154              : {
     155            0 :     doSetup(m_appOptions);
     156            0 : }
     157              : 
     158            0 : void BaseApplication::doSetup(const std::shared_ptr<CmdOptions>& options)
     159              : {
     160            0 :     IF_ASSERT_FAILED(options) {
     161            0 :         return;
     162              :     }
     163              : 
     164            0 :     const IApplication::RunMode runMode = options->runMode;
     165              : 
     166            0 :     setRunMode(runMode);
     167              : 
     168              :     // ====================================================
     169              :     // Setup modules: Resources, Exports, Imports, UiTypes
     170              :     // ====================================================
     171              : 
     172            0 :     modularity::globalIoc()->registerExport<IApplication>("global", shared_from_this());
     173              : 
     174            0 :     m_globalModule = new GlobalModule();
     175            0 :     m_globalModule->registerResources();
     176            0 :     m_globalModule->registerExports();
     177            0 :     m_globalModule->registerUiTypes();
     178              : 
     179            0 :     for (modularity::IModuleSetup* m : m_modules) {
     180            0 :         m->registerResources();
     181            0 :         m->registerExports();
     182              :     }
     183              : 
     184            0 :     m_globalModule->resolveImports();
     185            0 :     m_globalModule->registerApi();
     186            0 :     for (modularity::IModuleSetup* m : m_modules) {
     187            0 :         m->registerUiTypes();
     188            0 :         m->resolveImports();
     189              :     }
     190              : 
     191              :     // ====================================================
     192              :     // Setup modules: apply the command line options
     193              :     // ====================================================
     194            0 :     applyCommandLineOptions(options);
     195              : 
     196              :     // ====================================================
     197              :     // Setup modules: onPreInit
     198              :     // ====================================================
     199            0 :     m_globalModule->onPreInit(runMode);
     200            0 :     for (modularity::IModuleSetup* m : m_modules) {
     201            0 :         m->onPreInit(runMode);
     202              :     }
     203              : 
     204              :     // ====================================================
     205              :     // Setup modules: onInit
     206              :     // ====================================================
     207            0 :     m_globalModule->onInit(runMode);
     208            0 :     for (modularity::IModuleSetup* m : m_modules) {
     209            0 :         m->onInit(runMode);
     210            0 :         m->registerApi();
     211              :     }
     212              : 
     213              :     // ====================================================
     214              :     // Setup modules: onAllInited
     215              :     // ====================================================
     216            0 :     m_globalModule->onAllInited(runMode);
     217            0 :     for (modularity::IModuleSetup* m : m_modules) {
     218            0 :         m->onAllInited(runMode);
     219              :     }
     220              : 
     221              :     // ====================================================
     222              :     // Setup modules: onStartApp (on next event loop)
     223              :     // ====================================================
     224            0 :     QMetaObject::invokeMethod(qApp, [this]() {
     225            0 :         m_globalModule->onStartApp();
     226            0 :         for (modularity::IModuleSetup* m : m_modules) {
     227            0 :             m->onStartApp();
     228              :         }
     229            0 :     }, Qt::QueuedConnection);
     230              : }
     231              : 
     232            0 : void BaseApplication::applyCommandLineOptions(const std::shared_ptr<CmdOptions>& options)
     233              : {
     234            0 :     if (options->global.loggerLevel) {
     235            0 :         m_globalModule->setLoggerLevel(options->global.loggerLevel.value());
     236              :     }
     237            0 : }
     238              : 
     239            0 : BaseApplication::ContextData& BaseApplication::contextData(const muse::modularity::ContextPtr& ctx)
     240              : {
     241            0 :     for (ContextData& c : m_contexts) {
     242            0 :         if (c.ctxId->id == ctx->id) {
     243            0 :             return c;
     244              :         }
     245              :     }
     246              : 
     247            0 :     m_contexts.emplace_back();
     248              : 
     249            0 :     ContextData& ref = m_contexts.back();
     250            0 :     ref.ctxId = ctx;
     251              : 
     252            0 :     modularity::IContextSetup* global = m_globalModule->newContext(ctx);
     253            0 :     if (global) {
     254            0 :         ref.setups.push_back(global);
     255              :     }
     256              : 
     257            0 :     for (modularity::IModuleSetup* m : m_modules) {
     258            0 :         modularity::IContextSetup* s = m->newContext(ctx);
     259            0 :         if (s) {
     260            0 :             ref.setups.push_back(s);
     261              :         }
     262              :     }
     263              : 
     264            0 :     return ref;
     265              : }
     266              : 
     267            0 : std::vector<muse::modularity::ContextPtr> BaseApplication::contexts() const
     268              : {
     269            0 :     std::vector<muse::modularity::ContextPtr> ctxs;
     270            0 :     ctxs.reserve(m_contexts.size());
     271            0 :     for (const ContextData& c : m_contexts) {
     272            0 :         ctxs.push_back(c.ctxId);
     273              :     }
     274            0 :     return ctxs;
     275            0 : }
     276              : 
     277            0 : size_t BaseApplication::contextCount() const
     278              : {
     279            0 :     return m_contexts.size();
     280              : }
     281              : 
     282            0 : std::shared_ptr<CmdOptions> BaseApplication::makeContextOptions(const muse::StringList&) const
     283              : {
     284            0 :     return m_appOptions;
     285              : }
     286              : 
     287            0 : void BaseApplication::showContextSplash(const muse::modularity::ContextPtr&)
     288              : {
     289            0 : }
     290              : 
     291            0 : muse::modularity::ContextPtr BaseApplication::setupNewContext(const StringList& args)
     292              : {
     293              : #ifndef MUSE_MODULE_MULTIWINDOWS_SINGLEPROC_MODE
     294              :     static bool once = false;
     295              :     IF_ASSERT_FAILED(!once) {
     296              :         return nullptr;
     297              :     }
     298              :     once = true;
     299              : #endif
     300              : 
     301              :     static int lastId = 0;
     302              : 
     303            0 :     modularity::ContextPtr ctxId = std::make_shared<modularity::Context>();
     304            0 :     ++lastId;
     305            0 :     ctxId->id = lastId;
     306              : 
     307            0 :     ContextData& ctx = contextData(ctxId);
     308            0 :     ctx.initializing = true;
     309            0 :     ctx.options = makeContextOptions(args);
     310              : 
     311            0 :     LOGI() << "Creating new context with id: " << ctxId->id;
     312              : 
     313            0 :     QMetaObject::invokeMethod(qApp, [this, ctxId]() {
     314            0 :         showContextSplash(ctxId);
     315            0 :         QMetaObject::invokeMethod(qApp, [this, ctxId]() {
     316            0 :             setupContext(ctxId);
     317            0 :             QMetaObject::invokeMethod(qApp, [this, ctxId]() {
     318            0 :                 ContextData& ctx = contextData(ctxId);
     319            0 :                 ctx.initializing = false;
     320            0 :                 startupScenario(ctxId);
     321            0 :             }, Qt::QueuedConnection);
     322            0 :         }, Qt::QueuedConnection);
     323            0 :     }, Qt::QueuedConnection);
     324              : 
     325            0 :     return ctxId;
     326            0 : }
     327              : 
     328            0 : void BaseApplication::setupContext(const muse::modularity::ContextPtr& ctxId)
     329              : {
     330            0 :     const IApplication::RunMode runMode = m_appOptions->runMode;
     331              :     // Setup
     332            0 :     std::vector<muse::modularity::IContextSetup*>& csetups = contextData(ctxId).setups;
     333              : 
     334            0 :     for (modularity::IContextSetup* s : csetups) {
     335            0 :         s->registerExports();
     336              :     }
     337              : 
     338            0 :     for (modularity::IContextSetup* s : csetups) {
     339            0 :         s->resolveImports();
     340              :     }
     341              : 
     342            0 :     for (modularity::IContextSetup* s : csetups) {
     343            0 :         s->onPreInit(runMode);
     344              :     }
     345              : 
     346            0 :     for (modularity::IContextSetup* s : csetups) {
     347            0 :         s->onInit(runMode);
     348              :     }
     349              : 
     350            0 :     for (modularity::IContextSetup* s : csetups) {
     351            0 :         s->onAllInited(runMode);
     352              :     }
     353            0 : }
     354              : 
     355            0 : void BaseApplication::destroyContext(const modularity::ContextPtr& ctx)
     356              : {
     357            0 :     TRACEFUNC;
     358              : 
     359            0 :     IF_ASSERT_FAILED(ctx) {
     360            0 :         return;
     361              :     }
     362              : 
     363            0 :     LOGI() << "Destroying context with id: " << ctx->id;
     364              : 
     365            0 :     auto it = std::find_if(m_contexts.begin(), m_contexts.end(),
     366            0 :                            [&ctx](const ContextData& c) { return c.ctxId->id == ctx->id; });
     367            0 :     if (it == m_contexts.end()) {
     368            0 :         LOGW() << "Context not found: " << ctx->id;
     369            0 :         return;
     370              :     }
     371              : 
     372              :     //! The context is in the process of initializing.
     373              :     //! It is not possible to delete the context until initialization is complete.
     374            0 :     IF_ASSERT_FAILED(!it->initializing) {
     375            0 :         return;
     376              :     }
     377              : 
     378            0 :     doDestroyContext(*it);
     379              : 
     380            0 :     m_contexts.erase(it);
     381            0 : }
     382              : 
     383            0 : void BaseApplication::doDestroyContext(const ContextData& data)
     384              : {
     385            0 :     for (modularity::IContextSetup* s : data.setups) {
     386            0 :         s->onDeinit();
     387              :     }
     388              : 
     389            0 :     for (modularity::IContextSetup* s : data.setups) {
     390            0 :         s->onDestroy();
     391              :     }
     392              : 
     393            0 :     qDeleteAll(data.setups);
     394              : 
     395            0 :     modularity::removeIoC(data.ctxId);
     396            0 : }
     397              : 
     398              : #ifndef NO_QT_SUPPORT
     399            0 : QWindow* BaseApplication::focusWindow() const
     400              : {
     401            0 :     return qApp->focusWindow();
     402              : }
     403              : 
     404            0 : bool BaseApplication::notify(QObject* object, QEvent* event)
     405              : {
     406            0 :     return qApp->notify(object, event);
     407              : }
     408              : 
     409            0 : Qt::KeyboardModifiers BaseApplication::keyboardModifiers() const
     410              : {
     411            0 :     return QApplication::keyboardModifiers();
     412              : }
     413              : 
     414              : #endif
     415              : 
     416            0 : void BaseApplication::restart()
     417              : {
     418            0 :     m_finishMode = FinishMode::Restart;
     419            0 :     QCoreApplication::exit();
     420            0 : }
     421              : 
     422            0 : void BaseApplication::finish()
     423              : {
     424            0 :     TRACEFUNC;
     425              : 
     426            0 :     doFinish();
     427              : 
     428            0 :     PROFILER_PRINT;
     429            0 : }
     430              : 
     431            0 : void BaseApplication::doFinish()
     432              : {
     433              :     // Wait Thread Poll
     434              : #ifdef QT_CONCURRENT_SUPPORTED
     435            0 :     QThreadPool* globalThreadPool = QThreadPool::globalInstance();
     436            0 :     if (globalThreadPool) {
     437            0 :         LOGI() << "activeThreadCount: " << globalThreadPool->activeThreadCount();
     438            0 :         globalThreadPool->waitForDone();
     439              :     }
     440              : #endif
     441              : 
     442              : // Deinit
     443            0 :     async::processMessages();
     444              : 
     445              : // Deinit and delete contexts
     446            0 :     std::vector<muse::modularity::ContextPtr> ctxs = contexts();
     447            0 :     for (auto& c : ctxs) {
     448            0 :         destroyContext(c);
     449              :     }
     450              : 
     451            0 :     for (modularity::IModuleSetup* m : m_modules) {
     452            0 :         m->onDeinit();
     453              :     }
     454              : 
     455            0 :     m_globalModule->onDeinit();
     456              : 
     457            0 :     for (modularity::IModuleSetup* m : m_modules) {
     458            0 :         m->onDestroy();
     459              :     }
     460              : 
     461            0 :     m_globalModule->onDestroy();
     462              : 
     463              : // Delete modules
     464            0 :     qDeleteAll(m_modules);
     465            0 :     m_modules.clear();
     466              : 
     467            0 :     delete m_globalModule;
     468            0 :     m_globalModule = nullptr;
     469              : 
     470            0 :     muse::modularity::resetAll();
     471              : 
     472            0 :     if (m_finishMode == IApplication::FinishMode::Restart) {
     473              : #ifdef QT_QPROCESS_SUPPORTED
     474            0 :         QString program = qApp->arguments()[0];
     475              : 
     476              :         // NOTE: remove the first argument - the program name
     477            0 :         QStringList arguments = qApp->arguments().mid(1);
     478              : 
     479            0 :         QProcess::startDetached(program, arguments);
     480              : #else
     481              :         NOT_SUPPORTED;
     482              : #endif
     483            0 :     }
     484            0 : }
     485              : 
     486            0 : void BaseApplication::processEvents()
     487              : {
     488            0 :     qApp->processEvents();
     489            0 :     tickerProvider()->forceSchedule();
     490            0 : }
        

Generated by: LCOV version 2.0-1