File indexing completed on 2024-12-08 04:27:18
0001 /* 0002 SPDX-FileCopyrightText: 2007 Marco Gittler <g.marco@freenet.de> 0003 SPDX-FileCopyrightText: 2008 Jean-Baptiste Mardelle <jb@kdenlive.org> 0004 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "core.h" 0009 #ifdef CRASH_AUTO_TEST 0010 #include "logger.hpp" 0011 #endif 0012 #include "dialogs/splash.hpp" 0013 #include <config-kdenlive.h> 0014 0015 #include <mlt++/Mlt.h> 0016 0017 #include "kcoreaddons_version.h" 0018 #include "kxmlgui_version.h" 0019 #include "mainwindow.h" 0020 #include <project/projectmanager.h> 0021 0022 #include <KAboutData> 0023 #include <KConfigGroup> 0024 #ifdef USE_DRMINGW 0025 #include <exchndl.h> 0026 #elif defined(KF5_USE_CRASH) 0027 #include <KCrash> 0028 #endif 0029 0030 #include <KIconLoader> 0031 #include <KSharedConfig> 0032 0033 #include "definitions.h" 0034 #include "kdenlive_debug.h" 0035 #ifndef NODBUS 0036 #include <KDBusService> 0037 #endif 0038 #include <KIconTheme> 0039 #include <KLocalizedString> 0040 #include <QApplication> 0041 #include <QCommandLineOption> 0042 #include <QCommandLineParser> 0043 #include <QDir> 0044 #include <QIcon> 0045 #include <QProcess> 0046 #include <QQmlEngine> 0047 #include <QQuickWindow> 0048 #include <QResource> 0049 #include <QSplashScreen> 0050 #include <QUrl> //new 0051 #include <kiconthemes_version.h> 0052 0053 #include "render/renderrequest.h" 0054 0055 // TODO: remove 0056 #include "doc/docundostack.hpp" 0057 #include "doc/kdenlivedoc.h" 0058 #include <QUndoGroup> 0059 0060 #include "kdenlivesettings.h" 0061 #include <KNotification> 0062 0063 #ifdef Q_OS_WIN 0064 extern "C" { 0065 // Inform the driver we could make use of the discrete gpu 0066 // __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; 0067 // __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; 0068 } 0069 #endif 0070 0071 int main(int argc, char *argv[]) 0072 { 0073 int result = EXIT_SUCCESS; 0074 #ifdef USE_DRMINGW 0075 ExcHndlInit(); 0076 #endif 0077 // Force QDomDocument to use a deterministic XML attribute order 0078 qSetGlobalQHashSeed(0); 0079 0080 #ifdef CRASH_AUTO_TEST 0081 Logger::init(); 0082 #endif 0083 0084 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0085 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 0086 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 0087 #endif 0088 0089 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0090 #if defined(Q_OS_WIN) 0091 QQuickWindow::setGraphicsApi(QSGRendererInterface::Direct3D11); 0092 #elif defined(Q_OS_MACOS) 0093 QQuickWindow::setGraphicsApi(QSGRendererInterface::Metal); 0094 #else 0095 QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); 0096 QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true); 0097 #endif 0098 #endif 0099 0100 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0101 // blacklist MLT Qt5 module to prevent crashes 0102 qputenv("MLT_REPOSITORY_DENY", "libmltqt:libmltglaxnimate"); 0103 #endif 0104 0105 #if defined(Q_OS_WIN) 0106 QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor); 0107 #endif 0108 // TODO: is it a good option ? 0109 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); 0110 0111 QApplication app(argc, argv); 0112 0113 // Try to detect package type 0114 QString packageType; 0115 if (qEnvironmentVariableIsSet("PACKAGE_TYPE")) { 0116 packageType = qgetenv("PACKAGE_TYPE").toLower(); 0117 } else { 0118 // no package type defined, try to detected it 0119 QString appPath = app.applicationDirPath(); 0120 if (appPath.contains(QStringLiteral("/tmp/.mount_"))) { 0121 packageType = QStringLiteral("appimage"); 0122 } 0123 if (appPath.contains(QStringLiteral("/snap"))) { 0124 packageType = QStringLiteral("snap"); 0125 } else { 0126 qDebug() << "Could not detect package type, probably default? App dir is" << app.applicationDirPath(); 0127 } 0128 } 0129 0130 bool inSandbox = false; 0131 if (packageType == QStringLiteral("appimage") || packageType == QStringLiteral("flatpak") || packageType == QStringLiteral("snap")) { 0132 inSandbox = true; 0133 // use a dedicated config file for sandbox packages, 0134 // however the next line has no effect if the --config cmd option is used 0135 KConfig::setMainConfigName(QStringLiteral("kdenlive-%1rc").arg(packageType)); 0136 } 0137 0138 KLocalizedString::setApplicationDomain("kdenlive"); 0139 qApp->processEvents(QEventLoop::AllEvents); 0140 0141 // Create KAboutData 0142 QString otherText = i18n("Please report bugs to <a href=\"%1\">%2</a>", QStringLiteral("https://bugs.kde.org/enter_bug.cgi?product=kdenlive"), 0143 QStringLiteral("https://bugs.kde.org/")); 0144 if (!packageType.isEmpty()) { 0145 otherText.prepend(i18n("You are using the %1 package.<br>", packageType)); 0146 } 0147 KAboutData aboutData(QByteArray("kdenlive"), i18n("Kdenlive"), KDENLIVE_VERSION, i18n("An open source video editor."), KAboutLicense::GPL_V3, 0148 i18n("Copyright © 2007–2024 Kdenlive authors"), otherText, QStringLiteral("https://kdenlive.org")); 0149 // main developers (alphabetical) 0150 aboutData.addAuthor(i18n("Jean-Baptiste Mardelle"), i18n("MLT and KDE SC 4 / KF5 port, main developer and maintainer"), QStringLiteral("jb@kdenlive.org")); 0151 // active developers with major involvement 0152 aboutData.addAuthor(i18n("Nicolas Carion"), i18n("Code re-architecture & timeline rewrite (2019)"), QStringLiteral("french.ebook.lover@gmail.com")); 0153 aboutData.addAuthor(i18n("Julius Künzel"), i18n("Feature development, packaging, bug fixing"), QStringLiteral("jk.kdedev@smartlab.uber.space")); 0154 aboutData.addAuthor(i18n("Vincent Pinon"), i18n("KF5 port, Windows cross-build, packaging, bug fixing"), QStringLiteral("vpinon@kde.org")); 0155 // other active developers (alphabetical) 0156 aboutData.addAuthor(i18n("Dan Dennedy"), i18n("MLT maintainer, Bug fixing, etc."), QStringLiteral("dan@dennedy.org")); 0157 aboutData.addAuthor(i18n("Simon A. Eugster"), i18n("Color scopes, bug fixing, etc."), QStringLiteral("simon.eu@gmail.com")); 0158 aboutData.addAuthor(i18n("Eric Jiang"), i18n("Bug fixing and test improvements"), QStringLiteral("jk.kdedev@smartlab.uber.space")); 0159 // non active developers with major improvement (alphabetical) 0160 aboutData.addAuthor(i18n("Jason Wood"), i18n("Original KDE 3 version author (not active anymore)"), QStringLiteral("jasonwood@blueyonder.co.uk")); 0161 // non developers (alphabetical) 0162 aboutData.addCredit(i18n("Farid Abdelnour"), i18n("Logo, Promotion, testing")); 0163 aboutData.addCredit(i18n("Eugen Mohr"), i18n("Bug triage, testing, documentation maintainer")); 0164 aboutData.addCredit(i18n("Nara Oliveira"), i18n("Logo")); 0165 aboutData.addCredit(i18n("Bruno Santos"), i18n("Testing")); 0166 aboutData.addCredit(i18n("Massimo Stella"), i18n("Expert advice, testing")); 0167 0168 aboutData.setTranslator(i18n("NAME OF TRANSLATORS"), i18n("EMAIL OF TRANSLATORS")); 0169 aboutData.setOrganizationDomain(QByteArray("kde.org")); 0170 0171 aboutData.addComponent(i18n("MLT"), i18n("Open source multimedia framework."), mlt_version_get_string(), 0172 QStringLiteral("https://mltframework.org") /*, KAboutLicense::LGPL_V2_1*/); 0173 aboutData.addComponent(i18n("FFmpeg"), i18n("A complete, cross-platform solution to record, convert and stream audio and video."), QString(), 0174 QStringLiteral("https://ffmpeg.org")); 0175 0176 aboutData.setDesktopFileName(QStringLiteral("org.kde.kdenlive")); 0177 0178 // Register about data 0179 KAboutData::setApplicationData(aboutData); 0180 0181 // Set app stuff from about data 0182 app.setApplicationName(QStringLiteral("kdenlive")); 0183 app.setWindowIcon(QIcon(QStringLiteral(":/pics/kdenlive.png"))); 0184 app.setApplicationDisplayName(aboutData.displayName()); 0185 app.setOrganizationDomain(aboutData.organizationDomain()); 0186 app.setApplicationVersion(aboutData.version()); 0187 app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true); 0188 0189 qApp->processEvents(QEventLoop::AllEvents); 0190 0191 // Create command line parser with options 0192 QCommandLineParser parser; 0193 aboutData.setupCommandLine(&parser); 0194 parser.setApplicationDescription(aboutData.shortDescription()); 0195 0196 // config option is processed in KConfig (src/core/kconfig.cpp) 0197 parser.addOption(QCommandLineOption(QStringLiteral("config"), i18n("Set a custom config file name."), QStringLiteral("config file"))); 0198 QCommandLineOption mltPathOption(QStringLiteral("mlt-path"), i18n("Set the path for MLT environment."), QStringLiteral("mlt-path")); 0199 parser.addOption(mltPathOption); 0200 QCommandLineOption mltLogLevelOption(QStringLiteral("mlt-log"), i18n("Set the MLT log level. Leave this unset for level \"warning\"."), 0201 QStringLiteral("verbose/debug")); 0202 parser.addOption(mltLogLevelOption); 0203 QCommandLineOption clipsOption(QStringLiteral("i"), i18n("Comma separated list of files to add as clips to the bin."), QStringLiteral("clips")); 0204 parser.addOption(clipsOption); 0205 0206 // render options 0207 QCommandLineOption renderOption(QStringLiteral("render"), i18n("Directly render the project and exit.")); 0208 parser.addOption(renderOption); 0209 0210 QCommandLineOption presetOption(QStringLiteral("render-preset"), i18n("Kdenlive render preset name (MP4-H264/AAC will be used if none given)."), 0211 QStringLiteral("renderPreset"), QString()); 0212 parser.addOption(presetOption); 0213 0214 QCommandLineOption exitOption(QStringLiteral("render-async"), 0215 i18n("Exit after (detached) render process started, without this flag it exists only after it finished.")); 0216 parser.addOption(exitOption); 0217 0218 parser.addPositionalArgument(QStringLiteral("file"), i18n("Kdenlive document to open.")); 0219 parser.addPositionalArgument(QStringLiteral("rendering"), i18n("Output file for rendered video.")); 0220 0221 // Parse command line 0222 parser.process(app); 0223 aboutData.processCommandLine(&parser); 0224 0225 QUrl url; 0226 QUrl renderUrl; 0227 QString presetName; 0228 if (parser.positionalArguments().count() != 0) { 0229 const QString inputFilename = parser.positionalArguments().at(0); 0230 const QFileInfo fileInfo(inputFilename); 0231 url = QUrl(inputFilename); 0232 if (fileInfo.exists() || url.scheme().isEmpty()) { // easiest way to detect "invalid"/unintended URLs is no scheme 0233 url = QUrl::fromLocalFile(fileInfo.absoluteFilePath()); 0234 } 0235 if (parser.positionalArguments().count() > 1) { 0236 // Output render 0237 const QString outputFilename = parser.positionalArguments().at(1); 0238 const QFileInfo outFileInfo(outputFilename); 0239 if (!outFileInfo.exists()) { // easiest way to detect "invalid"/unintended URLs is no scheme 0240 renderUrl = QUrl::fromLocalFile(outFileInfo.absoluteFilePath()); 0241 } 0242 } 0243 } 0244 0245 qApp->processEvents(QEventLoop::AllEvents); 0246 0247 if (parser.isSet(renderOption)) { 0248 if (url.isEmpty()) { 0249 qCritical() << "You need to give a valid file if you want to render from the command line."; 0250 return EXIT_FAILURE; 0251 } 0252 if (renderUrl.isEmpty()) { 0253 qCritical() << "You need to give a non existing output file to render from the command line."; 0254 return EXIT_FAILURE; 0255 } 0256 if (parser.isSet(presetOption)) { 0257 presetName = parser.value(presetOption); 0258 } else { 0259 presetName = QStringLiteral("MP4-H264/AAC"); 0260 qDebug() << "No render preset given, using default:" << presetName; 0261 } 0262 if (!Core::build(packageType, true)) { 0263 return EXIT_FAILURE; 0264 } 0265 pCore->initHeadless(url); 0266 app.processEvents(); 0267 0268 RenderRequest *renderrequest = new RenderRequest(); 0269 renderrequest->setOutputFile(renderUrl.toLocalFile()); 0270 renderrequest->loadPresetParams(presetName); 0271 // request->setPresetParams(m_params); 0272 renderrequest->setDelayedRendering(false); 0273 renderrequest->setProxyRendering(false); 0274 renderrequest->setEmbedSubtitles(false); 0275 renderrequest->setTwoPass(false); 0276 renderrequest->setAudioFilePerTrack(false); 0277 0278 /*bool guideMultiExport = false; 0279 int guideCategory = m_view.guideCategoryChooser->currentCategory(); 0280 renderrequest->setGuideParams(m_guidesModel, guideMultiExport, guideCategory);*/ 0281 0282 renderrequest->setOverlayData(QString()); 0283 std::vector<RenderRequest::RenderJob> renderjobs = renderrequest->process(); 0284 app.processEvents(); 0285 0286 if (!renderrequest->errorMessages().isEmpty()) { 0287 qInfo() << "The following errors occurred while trying to render:\n" << renderrequest->errorMessages().join(QLatin1Char('\n')); 0288 } 0289 0290 int exitCode = EXIT_SUCCESS; 0291 0292 for (const auto &job : renderjobs) { 0293 const QStringList argsJob = RenderRequest::argsByJob(job); 0294 qDebug() << "* CREATED JOB WITH ARGS: " << argsJob; 0295 qDebug() << "starting kdenlive_render process using: " << KdenliveSettings::kdenliverendererpath(); 0296 if (!parser.isSet(exitOption)) { 0297 if (QProcess::execute(KdenliveSettings::kdenliverendererpath(), argsJob) != EXIT_SUCCESS) { 0298 exitCode = EXIT_FAILURE; 0299 break; 0300 } 0301 } else { 0302 if (!QProcess::startDetached(KdenliveSettings::kdenliverendererpath(), argsJob)) { 0303 qCritical() << "Error starting render job" << argsJob; 0304 exitCode = EXIT_FAILURE; 0305 break; 0306 } else { 0307 KNotification::event(QStringLiteral("RenderStarted"), i18n("Rendering <i>%1</i> started", job.outputPath), QPixmap()); 0308 } 0309 } 0310 } 0311 /*QMapIterator<QString, QString> i(rendermanager->m_renderFiles); 0312 while (i.hasNext()) { 0313 i.next(); 0314 // qDebug() << i.key() << i.value() << rendermanager->startRendering(i.key(), i.value(), {}); 0315 }*/ 0316 pCore->projectManager()->closeCurrentDocument(false, false); 0317 app.processEvents(); 0318 Core::clean(); 0319 app.processEvents(); 0320 return exitCode; 0321 } 0322 0323 #if defined(Q_OS_WIN) 0324 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0325 KSharedConfigPtr configWin = KSharedConfig::openConfig("kdenliverc"); 0326 KConfigGroup grp1(configWin, "misc"); 0327 if (grp1.exists()) { 0328 int glMode = grp1.readEntry("opengl_backend", 0); 0329 if (glMode > 0) { 0330 QCoreApplication::setAttribute((Qt::ApplicationAttribute)glMode, true); 0331 } 0332 } else { 0333 // Default to OpenGLES (QtAngle) on first start 0334 QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true); 0335 grp1.writeEntry("opengl_backend", int(Qt::AA_UseOpenGLES)); 0336 } 0337 configWin->sync(); 0338 #endif 0339 #endif 0340 0341 qApp->processEvents(QEventLoop::AllEvents); 0342 Splash splash; 0343 qApp->processEvents(QEventLoop::AllEvents); 0344 splash.showMessage(i18n("Version %1", QString(KDENLIVE_VERSION)), Qt::AlignRight | Qt::AlignBottom, Qt::white); 0345 splash.show(); 0346 qApp->processEvents(QEventLoop::AllEvents); 0347 0348 #ifdef Q_OS_WIN 0349 QString path = qApp->applicationDirPath() + QLatin1Char(';') + qgetenv("PATH"); 0350 qputenv("PATH", path.toUtf8().constData()); 0351 #endif 0352 0353 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) 0354 const QStringList themes{"/icons/breeze/breeze-icons.rcc", "/icons/breeze-dark/breeze-icons-dark.rcc"}; 0355 for (const QString &theme : themes) { 0356 const QString themePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, theme); 0357 if (!themePath.isEmpty()) { 0358 const QString iconSubdir = theme.left(theme.lastIndexOf('/')); 0359 if (QResource::registerResource(themePath, iconSubdir)) { 0360 if (QFileInfo::exists(QLatin1Char(':') + iconSubdir + QStringLiteral("/index.theme"))) { 0361 qDebug() << "Loaded icon theme:" << theme; 0362 } else { 0363 qWarning() << "No index.theme found in" << theme; 0364 QResource::unregisterResource(themePath, iconSubdir); 0365 } 0366 } else { 0367 qWarning() << "Invalid rcc file" << theme; 0368 } 0369 } 0370 } 0371 #else 0372 // AppImage 0373 if (packageType == QStringLiteral("appimage")) { 0374 QMap<QString, QString> themeMap; 0375 themeMap.insert("breeze", "/../icons/breeze/breeze-icons.rcc"); 0376 themeMap.insert("breeze-dark", "/../icons/breeze-dark/breeze-icons-dark.rcc"); 0377 0378 QMapIterator<QString, QString> i(themeMap); 0379 while (i.hasNext()) { 0380 i.next(); 0381 QString themePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, i.value()); 0382 if (!themePath.isEmpty()) { 0383 const QString iconSubdir = "/icons/" + i.key(); 0384 if (QResource::registerResource(themePath, iconSubdir)) { 0385 if (QFileInfo::exists(QLatin1Char(':') + iconSubdir + QStringLiteral("/index.theme"))) { 0386 qDebug() << "Loaded icon theme:" << i.key(); 0387 } else { 0388 qWarning() << "No index.theme found for" << i.key(); 0389 QResource::unregisterResource(themePath, iconSubdir); 0390 } 0391 } else { 0392 qWarning() << "Invalid rcc file" << i.key(); 0393 } 0394 } 0395 } 0396 } 0397 #endif 0398 0399 KSharedConfigPtr config = KSharedConfig::openConfig(); 0400 KConfigGroup grp(config, "unmanaged"); 0401 if (!grp.exists()) { 0402 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 0403 if (env.value(QStringLiteral("XDG_CURRENT_DESKTOP")).toLower() == QLatin1String("kde") && packageType != QStringLiteral("appimage")) { 0404 qCDebug(KDENLIVE_LOG) << "KDE Desktop detected and not Appimage, using system icons"; 0405 } else { 0406 // We are not on a KDE desktop or in an Appimage, force breeze icon theme 0407 // Check if breeze theme is available 0408 QStringList iconThemes = KIconTheme::list(); 0409 if (iconThemes.contains(QStringLiteral("breeze"))) { 0410 grp.writeEntry("force_breeze", true); 0411 grp.writeEntry("use_dark_breeze", true); 0412 qCDebug(KDENLIVE_LOG) << "Non KDE Desktop or Appimage detected, forcing Breeze icon theme"; 0413 } 0414 } 0415 } 0416 KConfigGroup uicg(config, "UiSettings"); 0417 if (!uicg.exists()) { 0418 uicg.writeEntry("ColorSchemePath", "BreezeDark.colors"); 0419 uicg.sync(); 0420 } 0421 0422 #ifndef NODBUS 0423 // Init DBus services 0424 KDBusService programDBusService; 0425 #endif 0426 bool forceBreeze = grp.readEntry("force_breeze", QVariant(false)).toBool(); 0427 if (forceBreeze) { 0428 bool darkBreeze = grp.readEntry("use_dark_breeze", QVariant(false)).toBool(); 0429 QIcon::setThemeName(darkBreeze ? QStringLiteral("breeze-dark") : QStringLiteral("breeze")); 0430 } 0431 qApp->processEvents(QEventLoop::AllEvents); 0432 0433 #ifdef USE_DRMINGW 0434 ExcHndlInit(); 0435 #elif defined(KF5_USE_CRASH) 0436 KCrash::initialize(); 0437 #endif 0438 0439 qmlRegisterUncreatableMetaObject(PlaylistState::staticMetaObject, // static meta object 0440 "com.enums", // import statement 0441 1, 0, // major and minor version of the import 0442 "ClipState", // name in QML 0443 "Error: only enums"); 0444 qmlRegisterUncreatableMetaObject(FileStatus::staticMetaObject, // static meta object 0445 "com.enums", // import statement 0446 1, 0, // major and minor version of the import 0447 "ClipStatus", // name in QML 0448 "Error: only enums"); 0449 qmlRegisterUncreatableMetaObject(ClipType::staticMetaObject, // static meta object 0450 "com.enums", // import statement 0451 1, 0, // major and minor version of the import 0452 "ProducerType", // name in QML 0453 "Error: only enums"); 0454 qmlRegisterUncreatableMetaObject(AssetListType::staticMetaObject, // static meta object 0455 "com.enums", // import statement 0456 1, 0, // major and minor version of the import 0457 "AssetType", // name in QML 0458 "Error: only enums"); 0459 qmlRegisterUncreatableMetaObject(ToolType::staticMetaObject, // static meta object 0460 "com.enums", // import statement 0461 1, 0, // major and minor version of the import 0462 "ProjectTool", // name in QML 0463 "Error: only enums"); 0464 if (parser.value(mltLogLevelOption) == QStringLiteral("verbose")) { 0465 mlt_log_set_level(MLT_LOG_VERBOSE); 0466 } else if (parser.value(mltLogLevelOption) == QStringLiteral("debug")) { 0467 mlt_log_set_level(MLT_LOG_DEBUG); 0468 } 0469 const QString clipsToLoad = parser.value(clipsOption); 0470 qApp->processEvents(QEventLoop::AllEvents); 0471 if (!Core::build(packageType)) { 0472 // App is crashing, delete config files and restart 0473 result = EXIT_CLEAN_RESTART; 0474 } else { 0475 QObject::connect(pCore.get(), &Core::loadingMessageNewStage, &splash, &Splash::showProgressMessage, Qt::DirectConnection); 0476 QObject::connect(pCore.get(), &Core::loadingMessageIncrease, &splash, &Splash::increaseProgressMessage, Qt::DirectConnection); 0477 QObject::connect(pCore.get(), &Core::loadingMessageHide, &splash, &Splash::clearMessage, Qt::DirectConnection); 0478 QObject::connect(pCore.get(), &Core::closeSplash, &splash, [&]() { splash.finish(pCore->window()); }); 0479 pCore->initGUI(inSandbox, parser.value(mltPathOption), url, clipsToLoad); 0480 result = app.exec(); 0481 } 0482 Core::clean(); 0483 if (result == EXIT_RESTART || result == EXIT_CLEAN_RESTART) { 0484 qCDebug(KDENLIVE_LOG) << "restarting app"; 0485 if (result == EXIT_CLEAN_RESTART) { 0486 // Delete config file 0487 KSharedConfigPtr config = KSharedConfig::openConfig(); 0488 if (config->name().contains(QLatin1String("kdenlive"))) { 0489 // Make sure we delete our config file 0490 QFile f(QStandardPaths::locate(QStandardPaths::GenericConfigLocation, config->name(), QStandardPaths::LocateFile)); 0491 if (f.exists()) { 0492 qDebug() << " = = = =\nGOT Deleted file: " << f.fileName(); 0493 f.remove(); 0494 } 0495 } 0496 // Delete xml ui rc file 0497 const QString configLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); 0498 if (!configLocation.isEmpty()) { 0499 QDir dir(configLocation); 0500 if (dir.cd(QStringLiteral("kxmlgui5")) && dir.cd(QStringLiteral("kdenlive"))) { 0501 QFile f(dir.absoluteFilePath(QStringLiteral("kdenliveui.rc"))); 0502 if (f.exists() && f.open(QIODevice::ReadOnly)) { 0503 bool shortcutFound = false; 0504 QDomDocument doc; 0505 doc.setContent(&f); 0506 f.close(); 0507 if (!doc.documentElement().isNull()) { 0508 QDomElement shortcuts = doc.documentElement().firstChildElement(QStringLiteral("ActionProperties")); 0509 if (!shortcuts.isNull()) { 0510 qDebug() << "==== FOUND CUSTOM SHORTCUTS!!!"; 0511 // Copy the original settings and append custom shortcuts 0512 QFile f2(QStringLiteral(":/kxmlgui5/kdenlive/kdenliveui.rc")); 0513 if (f2.exists() && f2.open(QIODevice::ReadOnly)) { 0514 QDomDocument doc2; 0515 doc2.setContent(&f2); 0516 f2.close(); 0517 if (!doc2.documentElement().isNull()) { 0518 doc2.documentElement().appendChild(doc2.importNode(shortcuts, true)); 0519 shortcutFound = true; 0520 if (f.open(QIODevice::WriteOnly | QIODevice::Text)) { 0521 // overwrite local xml config 0522 QTextStream out(&f); 0523 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0524 out.setCodec("UTF-8"); 0525 #endif 0526 out << doc2.toString(); 0527 f.close(); 0528 } 0529 } 0530 } 0531 } 0532 } 0533 if (!shortcutFound) { 0534 // No custom shortcuts found, simply delete the xmlui file 0535 f.remove(); 0536 } 0537 } 0538 } 0539 } 0540 } 0541 QStringList progArgs; 0542 if (argc > 1) { 0543 // Start at 1 to remove app name 0544 for (int i = 1; i < argc; i++) { 0545 progArgs << QString(argv[i]); 0546 } 0547 } 0548 auto *restart = new QProcess; 0549 restart->start(app.applicationFilePath(), progArgs); 0550 restart->waitForReadyRead(); 0551 restart->waitForFinished(1000); 0552 result = EXIT_SUCCESS; 0553 } 0554 return result; 0555 }