LCOV - code coverage report
Current view: top level - muse/framework/ui/internal - guiapplication.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 103 0
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) 2026 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              : 
      23              : #include "guiapplication.h"
      24              : 
      25              : #include <algorithm>
      26              : 
      27              : #include <QTimer>
      28              : #include <QQuickWindow>
      29              : #include <QQmlApplicationEngine>
      30              : #include <QQmlContext>
      31              : #include <QQmlComponent>
      32              : 
      33              : #include "ui/graphicsapiprovider.h"
      34              : #include "ui/iuiengine.h"
      35              : 
      36              : #include "global/globalmodule.h"
      37              : 
      38              : #include "muse_framework_config.h"
      39              : 
      40              : using namespace muse;
      41              : using namespace muse::ui;
      42              : 
      43              : static constexpr int DELAYED_INIT_INTERVAL_MS = 5000;
      44              : 
      45            0 : GuiApplication::GuiApplication(const std::shared_ptr<CmdOptions>& options)
      46            0 :     : BaseApplication(options)
      47              : {
      48            0 : }
      49              : 
      50            0 : void GuiApplication::doSetup(const std::shared_ptr<CmdOptions>& options)
      51              : {
      52            0 :     BaseApplication::doSetup(options);
      53              : 
      54              :     // ====================================================
      55              :     // Setup modules: onDelayedInit
      56              :     // ====================================================
      57            0 :     m_delayedInitTimer.setSingleShot(true);
      58            0 :     m_delayedInitTimer.setInterval(DELAYED_INIT_INTERVAL_MS);
      59            0 :     QObject::connect(&m_delayedInitTimer, &QTimer::timeout, [this]() {
      60            0 :         m_globalModule->onDelayedInit();
      61            0 :         for (modularity::IModuleSetup* m : m_modules) {
      62            0 :             m->onDelayedInit();
      63              :         }
      64            0 :     });
      65            0 :     m_delayedInitTimer.start();
      66              : 
      67              :     // ====================================================
      68              :     // Setup Graphics Api check
      69              :     // ====================================================
      70              :     //! Needs to be set because we use transparent windows for PopupView.
      71              :     //! Needs to be called before any QQuickWindows are shown.
      72            0 :     QQuickWindow::setDefaultAlphaBuffer(true);
      73              : 
      74            0 :     setupGraphicsApi();
      75            0 : }
      76              : 
      77            0 : void GuiApplication::setupGraphicsApi()
      78              : {
      79              :     //! NOTE Adjust GS Api
      80              :     //! We can hide this algorithm in GSApiProvider,
      81              :     //! but it is intentionally left here to illustrate what is happening.
      82              : 
      83            0 :     GraphicsApiProvider* gApiProvider = new GraphicsApiProvider(BaseApplication::appVersion());
      84              : 
      85            0 :     GraphicsApi required = gApiProvider->requiredGraphicsApi();
      86            0 :     if (required != GraphicsApi::Default) {
      87            0 :         LOGI() << "Setting required graphics api: " << GraphicsApiProvider::apiName(required);
      88            0 :         GraphicsApiProvider::setGraphicsApi(required);
      89              :     }
      90              : 
      91            0 :     LOGI() << "Using graphics api: " << GraphicsApiProvider::graphicsApiName();
      92            0 :     LOGI() << "Gui platform: " << QGuiApplication::platformName();
      93              : 
      94            0 :     if (GraphicsApiProvider::graphicsApi() == GraphicsApi::Software) {
      95            0 :         gApiProvider->destroy();
      96              :     } else {
      97            0 :         LOGI() << "Detecting problems with graphics api";
      98            0 :         gApiProvider->listen([this, gApiProvider, required](bool res) {
      99            0 :             if (res) {
     100            0 :                 LOGI() << "No problems detected with graphics api";
     101            0 :                 gApiProvider->setGraphicsApiStatus(required, GraphicsApiProvider::Status::Checked);
     102              :             } else {
     103            0 :                 GraphicsApi next = gApiProvider->switchToNextGraphicsApi(required);
     104            0 :                 LOGE() << "Detected problems with graphics api; switching from " << GraphicsApiProvider::apiName(required)
     105            0 :                        << " to " << GraphicsApiProvider::apiName(next);
     106              : 
     107            0 :                 this->restart();
     108              :             }
     109            0 :             gApiProvider->destroy();
     110            0 :         });
     111              :     }
     112            0 : }
     113              : 
     114            0 : void GuiApplication::doFinish()
     115              : {
     116            0 :     m_delayedInitTimer.stop();
     117              : 
     118            0 :     BaseApplication::doFinish();
     119            0 : }
     120              : 
     121            0 : void GuiApplication::startupScenario(const muse::modularity::ContextPtr& ctxId)
     122              : {
     123            0 :     TRACEFUNC;
     124              : 
     125            0 :     QMetaObject::invokeMethod(qApp, [this, ctxId]() {
     126            0 :         bool ok = loadMainWindow(ctxId);
     127            0 :         if (ok) {
     128            0 :             QMetaObject::invokeMethod(qApp, [this, ctxId]() {
     129            0 :                 doStartupScenario(ctxId);
     130              : 
     131            0 :                 QTimer::singleShot(DELAYED_INIT_INTERVAL_MS, qApp, [this, ctxId]() {
     132            0 :                     contextDelayedInit(ctxId);
     133            0 :                 });
     134            0 :             }, Qt::QueuedConnection);
     135              :         }
     136            0 :     }, Qt::QueuedConnection);
     137            0 : }
     138              : 
     139            0 : void GuiApplication::contextDelayedInit(const muse::modularity::ContextPtr& ctxId)
     140              : {
     141              :     //! NOTE: The context may have been destroyed (its window closed) in the meantime
     142            0 :     auto it = std::find_if(m_contexts.begin(), m_contexts.end(), [&ctxId](const ContextData& c) {
     143            0 :         return c.ctxId->id == ctxId->id;
     144              :     });
     145              : 
     146            0 :     if (it == m_contexts.end()) {
     147            0 :         return;
     148              :     }
     149              : 
     150            0 :     for (modularity::IContextSetup* s : it->setups) {
     151            0 :         s->onDelayedInit();
     152              :     }
     153              : }
     154              : 
     155            0 : bool GuiApplication::loadMainWindow(const muse::modularity::ContextPtr& ctxId)
     156              : {
     157            0 :     TRACEFUNC;
     158              : 
     159            0 :     IF_ASSERT_FAILED(ctxId) {
     160            0 :         return false;
     161              :     }
     162              : 
     163              : #if defined(Q_OS_MAC)
     164              :     QString platform = "mac";
     165              : #elif defined(Q_OS_WIN)
     166              :     QString platform = "win";
     167              : #else
     168            0 :     QString platform = "linux";
     169              : #endif
     170              : 
     171            0 :     auto uiengine = muse::modularity::ioc(ctxId)->resolve<muse::ui::IUiEngine>("app");
     172            0 :     IF_ASSERT_FAILED(uiengine) {
     173            0 :         return false;
     174              :     }
     175              : 
     176            0 :     QQmlApplicationEngine* engine = uiengine->qmlAppEngine();
     177            0 :     IF_ASSERT_FAILED(engine) {
     178            0 :         return false;
     179              :     }
     180              : 
     181            0 :     QString path = mainWindowQmlPath(platform);
     182            0 :     QQmlComponent component = QQmlComponent(engine, path);
     183            0 :     if (!component.isReady()) {
     184            0 :         LOGE() << "Failed to load main qml file, err: " << component.errorString();
     185            0 :         return false;
     186              :     }
     187              : 
     188            0 :     QQmlContext* qmlCtx = new QQmlContext(engine);
     189            0 :     qmlCtx->setObjectName(QString("QQmlContext: %1").arg(ctxId->id));
     190            0 :     QmlIoCContext* iocCtx = new QmlIoCContext(qmlCtx);
     191            0 :     iocCtx->ctx = ctxId;
     192            0 :     qmlCtx->setContextProperty("ioc_context", QVariant::fromValue(iocCtx));
     193              : 
     194            0 :     QObject* obj = component.create(qmlCtx);
     195            0 :     if (!obj) {
     196            0 :         LOGE() << "failed Qml load\n";
     197            0 :         QCoreApplication::exit(-1);
     198            0 :         return false;
     199              :     }
     200              : 
     201              :     // The main window must be shown at this point so KDDockWidgets can read its size correctly
     202              :     // and scale all sizes properly. https://github.com/musescore/MuseScore/issues/21148
     203            0 :     QQuickWindow* window = dynamic_cast<QQuickWindow*>(obj);
     204            0 :     window->setVisible(true);
     205              : 
     206            0 :     m_windows[ctxId->id] = window;
     207              : 
     208            0 :     return true;
     209            0 : }
     210              : 
     211            0 : void GuiApplication::doDestroyContext(const ContextData& data)
     212              : {
     213            0 :     auto wit = m_windows.find(data.ctxId->id);
     214            0 :     if (wit != m_windows.end()) {
     215            0 :         QQuickWindow* window = wit->second;
     216            0 :         window->setVisible(false);
     217            0 :         m_windows.erase(wit);
     218            0 :         delete window;
     219              :     }
     220              : 
     221              :     // Engine quit
     222            0 :     muse::modularity::ioc(data.ctxId)->resolve<muse::ui::IUiEngine>("app")->quit();
     223              : 
     224            0 :     BaseApplication::doDestroyContext(data);
     225            0 : }
        

Generated by: LCOV version 2.0-1