main.cpp 14.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/***************************************************************************
 *   Copyright (C) 2007 by Marco Gittler (g.marco@freenet.de)              *
 *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

21
#include "core.h"
Nicolas Carion's avatar
Nicolas Carion committed
22
#include "logger.hpp"
23
#include "dialogs/splash.hpp"
Nicolas Carion's avatar
Nicolas Carion committed
24
#include <config-kdenlive.h>
25
26

#include <mlt++/Mlt.h>
27

28
#include "kxmlgui_version.h"
29
#include "mainwindow.h"
30

31
#include <KAboutData>
Nicolas Carion's avatar
Nicolas Carion committed
32
#include <KConfigGroup>
Vincent Pinon's avatar
Vincent Pinon committed
33
#ifdef USE_DRMINGW
34
#include <exchndl.h>
Vincent Pinon's avatar
Vincent Pinon committed
35
#elif defined(KF5_USE_CRASH)
36
#include <KCrash>
Vincent Pinon's avatar
Vincent Pinon committed
37
#endif
Vincent Pinon's avatar
Vincent Pinon committed
38

39
#include <KIconLoader>
40
#include <KSharedConfig>
41

42
#include "definitions.h"
Laurent Montel's avatar
Laurent Montel committed
43
#include "kdenlive_debug.h"
Nicolas Carion's avatar
Nicolas Carion committed
44
#include <KDBusService>
45
#include <KIconTheme>
Vincent Pinon's avatar
Vincent Pinon committed
46
#include <kiconthemes_version.h>
Vincent Pinon's avatar
Vincent Pinon committed
47
#include <QResource>
48
49
#include <QApplication>
#include <QCommandLineOption>
Nicolas Carion's avatar
Nicolas Carion committed
50
51
#include <QCommandLineParser>
#include <QDir>
52
#include <QIcon>
Nicolas Carion's avatar
Nicolas Carion committed
53
#include <QProcess>
54
#include <QQmlEngine>
Nicolas Carion's avatar
Nicolas Carion committed
55
56
#include <QUrl> //new
#include <klocalizedstring.h>
57
#include <QSplashScreen>
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
58

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
59
60
61
62
#ifdef Q_OS_WIN
extern "C"
{
    // Inform the driver we could make use of the discrete gpu
63
64
    // __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
    // __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
65
66
67
68
}
#endif


69
70
int main(int argc, char *argv[])
{
71
72
73
#ifdef USE_DRMINGW
    ExcHndlInit();
#endif
74
    // Force QDomDocument to use a deterministic XML attribute order
75
    qSetGlobalQHashSeed(0);
76
77

    Logger::init();
78
    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
79
    //TODO: is it a good option ?
80
    QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
81

82
83
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
    QCoreApplication::setAttribute(Qt::AA_X11InitThreads);
84
#elif defined(Q_OS_WIN)
85
86
    KSharedConfigPtr configWin = KSharedConfig::openConfig("kdenliverc");
    KConfigGroup grp1(configWin, "misc");
87
88
89
90
91
    if (grp1.exists()) {
        int glMode = grp1.readEntry("opengl_backend", 0);
        if (glMode > 0) {
            QCoreApplication::setAttribute((Qt::ApplicationAttribute)glMode, true);
        }
92
93
94
    } else {
        // Default to OpenGLES (QtAngle) on first start
        QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);
95
    }
96
#endif
97
    QApplication app(argc, argv);
98
    app.setApplicationName(QStringLiteral("kdenlive"));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
99
    app.setOrganizationDomain(QStringLiteral("kde.org"));
Laurent Montel's avatar
Minor    
Laurent Montel committed
100
    app.setWindowIcon(QIcon(QStringLiteral(":/pics/kdenlive.png")));
101
    KLocalizedString::setApplicationDomain("kdenlive");
102
103
104

    QPixmap pixmap(":/pics/splash-background.png");
    qApp->processEvents(QEventLoop::AllEvents);
105
    Splash splash(pixmap);
106
    qApp->processEvents(QEventLoop::AllEvents);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
107
    splash.showMessage(i18n("Version %1", QString(KDENLIVE_VERSION)), Qt::AlignRight | Qt::AlignBottom, Qt::white);
108
109
110
    splash.show();
    qApp->processEvents(QEventLoop::AllEvents);

Vincent Pinon's avatar
Vincent Pinon committed
111
#ifdef Q_OS_WIN
112
113
114
115
    qputenv("KDE_FORK_SLAVES", "1");
    QString path = qApp->applicationDirPath() + QLatin1Char(';') + qgetenv("PATH");
    qputenv("PATH", path.toUtf8().constData());

Vincent Pinon's avatar
Vincent Pinon committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    const QStringList themes {"/icons/breeze/breeze-icons.rcc", "/icons/breeze-dark/breeze-icons-dark.rcc"};
    for(const QString theme : themes ) {
        const QString themePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, theme);
        if (!themePath.isEmpty()) {
            const QString iconSubdir = theme.left(theme.lastIndexOf('/'));
            if (QResource::registerResource(themePath, iconSubdir)) {
                if (QFileInfo::exists(QLatin1Char(':') + iconSubdir + QStringLiteral("/index.theme"))) {
                    qDebug() << "Loaded icon theme:" << theme;
                } else {
                    qWarning() << "No index.theme found in" << theme;
                    QResource::unregisterResource(themePath, iconSubdir);
                }
            } else {
                qWarning() << "Invalid rcc file" << theme;
            }
        }
    }
#endif
134
    KSharedConfigPtr config = KSharedConfig::openConfig();
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    KConfigGroup grp(config, "unmanaged");
    if (!grp.exists()) {
        QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
        if (env.contains(QStringLiteral("XDG_CURRENT_DESKTOP")) && env.value(QStringLiteral("XDG_CURRENT_DESKTOP")).toLower() == QLatin1String("kde")) {
            qCDebug(KDENLIVE_LOG) << "KDE Desktop detected, using system icons";
        } else {
            // We are not on a KDE desktop, force breeze icon theme
            // Check if breeze theme is available
            QStringList iconThemes = KIconTheme::list();
            if (iconThemes.contains(QStringLiteral("breeze"))) {
                grp.writeEntry("force_breeze", true);
                grp.writeEntry("use_dark_breeze", true);
                qCDebug(KDENLIVE_LOG) << "Non KDE Desktop detected, forcing Breeze icon theme";
            }
        }
        // Set breeze dark as default on first opening
        KConfigGroup cg(config, "UiSettings");
        cg.writeEntry("ColorScheme", "Breeze Dark");
    }
Vincent Pinon's avatar
Vincent Pinon committed
154
155
156
157
#if KICONTHEMES_VERSION < QT_VERSION_CHECK(5,60,0)
    // work around bug in Kirigami2 resetting icon theme path
    qputenv("XDG_CURRENT_DESKTOP","KDE");
#endif
158

159
160
161
162
    // Init DBus services
    KDBusService programDBusService;
    bool forceBreeze = grp.readEntry("force_breeze", QVariant(false)).toBool();
    if (forceBreeze) {
163
164
        bool darkBreeze = grp.readEntry("use_dark_breeze", QVariant(false)).toBool();
        QIcon::setThemeName(darkBreeze ? QStringLiteral("breeze-dark") : QStringLiteral("breeze"));
165
    }
166
    qApp->processEvents(QEventLoop::AllEvents);
167

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
168
    // Create KAboutData
Nicolas Carion's avatar
Nicolas Carion committed
169
    KAboutData aboutData(QByteArray("kdenlive"), i18n("Kdenlive"), KDENLIVE_VERSION, i18n("An open source video editor."), KAboutLicense::GPL,
170
                         i18n("Copyright © 2007–2020 Kdenlive authors"), i18n("Please report bugs to https://bugs.kde.org"),
171
172
                         QStringLiteral("https://kdenlive.org"));
    aboutData.addAuthor(i18n("Jean-Baptiste Mardelle"), i18n("MLT and KDE SC 4 / KF5 port, main developer and maintainer"), QStringLiteral("jb@kdenlive.org"));
Vincent Pinon's avatar
Vincent Pinon committed
173
174
    aboutData.addAuthor(i18n("Nicolas Carion"), i18n("Code re-architecture & timeline rewrite"), QStringLiteral("french.ebook.lover@gmail.com"));
    aboutData.addAuthor(i18n("Vincent Pinon"), i18n("KF5 port, Windows cross-build, bugs fixing"), QStringLiteral("vpinon@kde.org"));
175
    aboutData.addAuthor(i18n("Laurent Montel"), i18n("Bugs fixing, clean up code, optimization etc."), QStringLiteral("montel@kde.org"));
Vincent Pinon's avatar
Vincent Pinon committed
176
177
    aboutData.addAuthor(i18n("Till Theato"), i18n("Bug fixing, etc."), QStringLiteral("root@ttill.de"));
    aboutData.addAuthor(i18n("Simon A. Eugster"), i18n("Color scopes, bug fixing, etc."), QStringLiteral("simon.eu@gmail.com"));
178
179
180
181
182
183
184
    aboutData.addAuthor(i18n("Marco Gittler"), i18n("MLT transitions and effects, timeline, audio thumbs"), QStringLiteral("g.marco@freenet.de"));
    aboutData.addAuthor(i18n("Dan Dennedy"), i18n("Bug fixing, etc."), QStringLiteral("dan@dennedy.org"));
    aboutData.addAuthor(i18n("Alberto Villa"), i18n("Bug fixing, logo, etc."), QStringLiteral("avilla@FreeBSD.org"));
    aboutData.addAuthor(i18n("Jean-Michel Poure"), i18n("Rendering profiles customization"), QStringLiteral("jm@poure.com"));
    aboutData.addAuthor(i18n("Ray Lehtiniemi"), i18n("Bug fixing, etc."), QStringLiteral("rayl@mail.com"));
    aboutData.addAuthor(i18n("Steve Guilford"), i18n("Bug fixing, etc."), QStringLiteral("s.guilford@dbplugins.com"));
    aboutData.addAuthor(i18n("Jason Wood"), i18n("Original KDE 3 version author (not active anymore)"), QStringLiteral("jasonwood@blueyonder.co.uk"));
185
    aboutData.addCredit(i18n("Nara Oliveira and Farid Abdelnour | Estúdio Gunga"), i18n("Kdenlive 16.08 icon"));
186
    aboutData.setTranslator(i18n("NAME OF TRANSLATORS"), i18n("EMAIL OF TRANSLATORS"));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
187
    aboutData.setOrganizationDomain(QByteArray("kde.org"));
Nicolas Carion's avatar
Nicolas Carion committed
188
189
    aboutData.setOtherText(
        i18n("Using:\n<a href=\"https://mltframework.org\">MLT</a> version %1\n<a href=\"https://ffmpeg.org\">FFmpeg</a> libraries", mlt_version_get_string()));
190
    aboutData.setDesktopFileName(QStringLiteral("org.kde.kdenlive"));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
191
192

    // Register about data
193
    KAboutData::setApplicationData(aboutData);
194

195
196
197
198
    // Add rcc stored icons to the search path so that we always find our icons
    KIconLoader *loader = KIconLoader::global();
    loader->reconfigure("kdenlive", QStringList() << QStringLiteral(":/pics"));

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
199
200
201
202
    // Set app stuff from about data
    app.setApplicationDisplayName(aboutData.displayName());
    app.setOrganizationDomain(aboutData.organizationDomain());
    app.setApplicationVersion(aboutData.version());
203
    app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
204
    qApp->processEvents(QEventLoop::AllEvents);
205

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
206
207
    // Create command line parser with options
    QCommandLineParser parser;
208
    aboutData.setupCommandLine(&parser);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
209
    parser.setApplicationDescription(aboutData.shortDescription());
210

Nicolas Carion's avatar
Nicolas Carion committed
211
212
    parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("config"), i18n("Set a custom config file name"), QStringLiteral("config")));
    parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("mlt-path"), i18n("Set the path for MLT environment"), QStringLiteral("mlt-path")));
213
214
    parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("mlt-log"), i18n("MLT log level"), QStringLiteral("verbose/debug")));
    parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("i"), i18n("Comma separated list of clips to add"), QStringLiteral("clips")));
215
    parser.addPositionalArgument(QStringLiteral("file"), i18n("Document to open"));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
216
217
218
219
220

    // Parse command line
    parser.process(app);
    aboutData.processCommandLine(&parser);

221
222
    qApp->processEvents(QEventLoop::AllEvents);

Vincent Pinon's avatar
Vincent Pinon committed
223
224
225
#ifdef USE_DRMINGW
    ExcHndlInit();
#elif defined(KF5_USE_CRASH)
226
    KCrash::initialize();
Vincent Pinon's avatar
Vincent Pinon committed
227
#endif
228

229
230
231
232
233
    qmlRegisterUncreatableMetaObject(PlaylistState::staticMetaObject, // static meta object
                                     "com.enums",                     // import statement
                                     1, 0,                            // major and minor version of the import
                                     "ClipState",                     // name in QML
                                     "Error: only enums");
234
    qmlRegisterUncreatableMetaObject(ClipType::staticMetaObject, // static meta object
235
236
237
                                     "com.enums",                // import statement
                                     1, 0,                       // major and minor version of the import
                                     "ProducerType",             // name in QML
238
                                     "Error: only enums");
239
240
241
242
243
    qmlRegisterUncreatableMetaObject(AssetListType::staticMetaObject, // static meta object
                                     "com.enums",                // import statement
                                     1, 0,                       // major and minor version of the import
                                     "AssetType",             // name in QML
                                     "Error: only enums");
244
    if (parser.value(QStringLiteral("mlt-log")) == QStringLiteral("verbose")) {
245
        mlt_log_set_level(MLT_LOG_VERBOSE);
246
    } else if (parser.value(QStringLiteral("mlt-log")) == QStringLiteral("debug")) {
247
        mlt_log_set_level(MLT_LOG_DEBUG);
248
    }
249
    const QString clipsToLoad = parser.value(QStringLiteral("i"));
250
    QUrl url;
Nicolas Carion's avatar
Nicolas Carion committed
251
    if (parser.positionalArguments().count() != 0) {
252
253
254
255
256
257
        const QString inputFilename = parser.positionalArguments().at(0);
        const QFileInfo fileInfo(inputFilename);
        url = QUrl(inputFilename);
        if (fileInfo.exists() || url.scheme().isEmpty()) { // easiest way to detect "invalid"/unintended URLs is no scheme
            url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
        }
258
    }
259
    qApp->processEvents(QEventLoop::AllEvents);
260
    Core::build(!parser.value(QStringLiteral("config")).isEmpty(), parser.value(QStringLiteral("mlt-path")));
261
262
263
264
    QObject::connect(pCore.get(), &Core::loadingMessageUpdated, &splash, &Splash::showProgressMessage, Qt::DirectConnection);
    QObject::connect(pCore.get(), &Core::closeSplash, [&] () {
        splash.finish(pCore->window());
    });
265
    pCore->initGUI(url, clipsToLoad);
266
    int result = app.exec();
267
    Core::clean();
268

269
    if (result == EXIT_RESTART || result == EXIT_CLEAN_RESTART) {
Laurent Montel's avatar
Laurent Montel committed
270
        qCDebug(KDENLIVE_LOG) << "restarting app";
271
272
273
274
275
276
277
278
279
280
281
282
        if (result == EXIT_CLEAN_RESTART) {
            // Delete config file
            KSharedConfigPtr config = KSharedConfig::openConfig();
            if (config->name().contains(QLatin1String("kdenlive"))) {
                // Make sure we delete our config file
                QFile f(QStandardPaths::locate(QStandardPaths::ConfigLocation, config->name(), QStandardPaths::LocateFile));
                if (f.exists()) {
                    qDebug()<<" = = = =\nGOT Deleted file: "<<f.fileName();
                    f.remove();
                }
            }
        }
Laurent Montel's avatar
Laurent Montel committed
283
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
284
        QStringList progArgs = QString(*argv).split(QLatin1Char(' '), QString::SkipEmptyParts);
Laurent Montel's avatar
Laurent Montel committed
285
286
287
#else
        QStringList progArgs = QString(*argv).split(QLatin1Char(' '), Qt::SkipEmptyParts);
#endif
288
289
        // Remove app name
        progArgs.takeFirst();
Nicolas Carion's avatar
Nicolas Carion committed
290
        auto *restart = new QProcess;
291
        restart->start(app.applicationFilePath(), progArgs);
292
293
294
295
        restart->waitForReadyRead();
        restart->waitForFinished(1000);
        result = EXIT_SUCCESS;
    }
296
    return result;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
297
}