main.cpp 20 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
con's avatar
con committed
30

31
#include "../tools/qtcreatorcrashhandler/crashhandlersetup.h"
con's avatar
con committed
32

33
#include <app/app_version.h>
con's avatar
con committed
34
#include <extensionsystem/iplugin.h>
35
#include <extensionsystem/pluginerroroverview.h>
Yuchen Deng's avatar
Yuchen Deng committed
36
37
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
38
#include <qtsingleapplication.h>
39
#include <utils/fileutils.h>
Christian Kandeler's avatar
Christian Kandeler committed
40
#include <utils/hostosinfo.h>
con's avatar
con committed
41

42
43
44
45
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QLibraryInfo>
46
#include <QLoggingCategory>
47
#include <QSettings>
48
#include <QStyle>
49
50
51
52
53
54
#include <QTextStream>
#include <QThreadPool>
#include <QTimer>
#include <QTranslator>
#include <QUrl>
#include <QVariant>
con's avatar
con committed
55

56
#include <QNetworkProxyFactory>
57

58
59
#include <QApplication>
#include <QMessageBox>
60
#include <QStandardPaths>
61
#include <QTemporaryDir>
con's avatar
con committed
62

Marco Bubke's avatar
Marco Bubke committed
63
64
65
66
#ifdef ENABLE_QT_BREAKPAD
#include <qtsystemexceptionhandler.h>
#endif

67
68
using namespace ExtensionSystem;

69
enum { OptionIndent = 4, DescriptionIndent = 34 };
con's avatar
con committed
70

71
72
73
const char appNameC[] = "Qt Creator";
const char corePluginNameC[] = "Core";
const char fixedOptionsC[] =
con's avatar
con committed
74
75
" [OPTION]... [FILE]...\n"
"Options:\n"
76
77
"    -help                         Display this help\n"
"    -version                      Display program version\n"
78
79
"    -client                       Attempt to connect to already running first instance\n"
"    -settingspath <path>          Override the default path where user settings are stored\n"
80
"    -pid <pid>                    Attempt to connect to instance given by pid\n"
81
82
"    -block                        Block until editor is closed\n"
"    -pluginpath <path>            Add a custom search path for plugins\n";
con's avatar
con committed
83

84
85
86
87
88
89
90
91
92
93
94
const char HELP_OPTION1[] = "-h";
const char HELP_OPTION2[] = "-help";
const char HELP_OPTION3[] = "/h";
const char HELP_OPTION4[] = "--help";
const char VERSION_OPTION[] = "-version";
const char CLIENT_OPTION[] = "-client";
const char SETTINGS_OPTION[] = "-settingspath";
const char TEST_OPTION[] = "-test";
const char PID_OPTION[] = "-pid";
const char BLOCK_OPTION[] = "-block";
const char PLUGINPATH_OPTION[] = "-pluginpath";
con's avatar
con committed
95

96
typedef QList<PluginSpec *> PluginSpecSet;
con's avatar
con committed
97
98

// Helpers for displaying messages. Note that there is no console on Windows.
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
99
#ifdef Q_OS_WIN
con's avatar
con committed
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Format as <pre> HTML
static inline void toHtml(QString &t)
{
    t.replace(QLatin1Char('&'), QLatin1String("&amp;"));
    t.replace(QLatin1Char('<'), QLatin1String("&lt;"));
    t.replace(QLatin1Char('>'), QLatin1String("&gt;"));
    t.insert(0, QLatin1String("<html><pre>"));
    t.append(QLatin1String("</pre></html>"));
}

static void displayHelpText(QString t) // No console on Windows.
{
    toHtml(t);
    QMessageBox::information(0, QLatin1String(appNameC), t);
}

static void displayError(const QString &t) // No console on Windows.
{
    QMessageBox::critical(0, QLatin1String(appNameC), t);
}

#else

static void displayHelpText(const QString &t)
{
125
    qWarning("%s", qPrintable(t));
con's avatar
con committed
126
127
128
129
}

static void displayError(const QString &t)
{
130
    qCritical("%s", qPrintable(t));
con's avatar
con committed
131
132
133
134
}

#endif

135
static void printVersion(const PluginSpec *coreplugin)
con's avatar
con committed
136
137
138
139
{
    QString version;
    QTextStream str(&version);
    str << '\n' << appNameC << ' ' << coreplugin->version()<< " based on Qt " << qVersion() << "\n\n";
140
    PluginManager::formatPluginVersions(str);
con's avatar
con committed
141
142
143
144
    str << '\n' << coreplugin->copyright() << '\n';
    displayHelpText(version);
}

145
static void printHelp(const QString &a0)
con's avatar
con committed
146
147
148
{
    QString help;
    QTextStream str(&help);
Yuchen Deng's avatar
Yuchen Deng committed
149
    str << "Usage: " << a0 << fixedOptionsC;
150
151
    PluginManager::formatOptions(str, OptionIndent, DescriptionIndent);
    PluginManager::formatPluginOptions(str, OptionIndent, DescriptionIndent);
con's avatar
con committed
152
153
154
155
156
157
158
159
    displayHelpText(help);
}

static inline QString msgCoreLoadFailure(const QString &why)
{
    return QCoreApplication::translate("Application", "Failed to load core: %1").arg(why);
}

160
static inline int askMsgSendFailed()
con's avatar
con committed
161
{
162
    return QMessageBox::question(0, QApplication::translate("Application","Could not send message"),
163
                                 QCoreApplication::translate("Application", "Unable to send command line arguments to the already running instance. "
164
165
166
                                                             "It appears to be not responding. Do you want to start a new instance of Creator?"),
                                 QMessageBox::Yes | QMessageBox::No | QMessageBox::Retry,
                                 QMessageBox::Retry);
con's avatar
con committed
167
168
}

169
170
171
172
173
174
175
176
// taken from utils/fileutils.cpp. We can not use utils here since that depends app_version.h.
static bool copyRecursively(const QString &srcFilePath,
                            const QString &tgtFilePath)
{
    QFileInfo srcFileInfo(srcFilePath);
    if (srcFileInfo.isDir()) {
        QDir targetDir(tgtFilePath);
        targetDir.cdUp();
177
        if (!targetDir.mkdir(Utils::FileName::fromString(tgtFilePath).fileName()))
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
            return false;
        QDir sourceDir(srcFilePath);
        QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
        foreach (const QString &fileName, fileNames) {
            const QString newSrcFilePath
                    = srcFilePath + QLatin1Char('/') + fileName;
            const QString newTgtFilePath
                    = tgtFilePath + QLatin1Char('/') + fileName;
            if (!copyRecursively(newSrcFilePath, newTgtFilePath))
                return false;
        }
    } else {
        if (!QFile::copy(srcFilePath, tgtFilePath))
            return false;
    }
    return true;
}

Eike Ziller's avatar
Eike Ziller committed
196
static inline QStringList getPluginPaths()
con's avatar
con committed
197
198
199
200
201
{
    QStringList rc;
    // Figure out root:  Up one from 'bin'
    QDir rootDir = QApplication::applicationDirPath();
    rootDir.cdUp();
202
    const QString rootDirPath = rootDir.canonicalPath();
203
#if !defined(Q_OS_MAC)
204
    // 1) "plugins" (Win/Linux)
con's avatar
con committed
205
    QString pluginPath = rootDirPath;
206
    pluginPath += QLatin1Char('/');
207
    pluginPath += QLatin1String(IDE_LIBRARY_BASENAME);
208
    pluginPath += QLatin1String("/qtcreator/plugins");
con's avatar
con committed
209
    rc.push_back(pluginPath);
210
#else
211
    // 2) "PlugIns" (OS X)
212
    QString pluginPath = rootDirPath;
213
    pluginPath += QLatin1String("/PlugIns");
con's avatar
con committed
214
    rc.push_back(pluginPath);
215
#endif
216
217
    // 3) <localappdata>/plugins/<ideversion>
    //    where <localappdata> is e.g.
218
219
220
    //    "%LOCALAPPDATA%\QtProject\qtcreator" on Windows Vista and later
    //    "$XDG_DATA_HOME/data/QtProject/qtcreator" or "~/.local/share/data/QtProject/qtcreator" on Linux
    //    "~/Library/Application Support/QtProject/Qt Creator" on Mac
221
222
    pluginPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
            + QLatin1String("/data");
223
224
225
    pluginPath += QLatin1Char('/')
            + QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR)
            + QLatin1Char('/');
226
227
228
229
230
231
#if !defined(Q_OS_MAC)
    pluginPath += QLatin1String("qtcreator");
#else
    pluginPath += QLatin1String("Qt Creator");
#endif
    pluginPath += QLatin1String("/plugins/");
232
233
    pluginPath += QLatin1String(Core::Constants::IDE_VERSION_LONG);
    rc.push_back(pluginPath);
con's avatar
con committed
234
235
236
    return rc;
}

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
static QSettings *createUserSettings()
{
    return new QSettings(QSettings::IniFormat, QSettings::UserScope,
                         QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR),
                         QLatin1String("QtCreator"));
}

static inline QSettings *userSettings()
{
    QSettings *settings = createUserSettings();
    const QString fromVariant = QLatin1String(Core::Constants::IDE_COPY_SETTINGS_FROM_VARIANT_STR);
    if (fromVariant.isEmpty())
        return settings;

    // Copy old settings to new ones:
    QFileInfo pathFi = QFileInfo(settings->fileName());
    if (pathFi.exists()) // already copied.
        return settings;

    QDir destDir = pathFi.absolutePath();
    if (!destDir.exists())
        destDir.mkpath(pathFi.absolutePath());

    QDir srcDir = destDir;
    srcDir.cdUp();
    if (!srcDir.cd(fromVariant))
        return settings;

    if (srcDir == destDir) // Nothing to copy and no settings yet
        return settings;

    QStringList entries = srcDir.entryList();
    foreach (const QString &file, entries) {
        const QString lowerFile = file.toLower();
        if (lowerFile.startsWith(QLatin1String("profiles.xml"))
                || lowerFile.startsWith(QLatin1String("toolchains.xml"))
                || lowerFile.startsWith(QLatin1String("qtversion.xml"))
                || lowerFile.startsWith(QLatin1String("devices.xml"))
275
                || lowerFile.startsWith(QLatin1String("debuggers.xml"))
276
277
278
279
280
281
282
283
284
285
286
                || lowerFile.startsWith(QLatin1String("qtcreator.")))
            QFile::copy(srcDir.absoluteFilePath(file), destDir.absoluteFilePath(file));
        if (file == QLatin1String("qtcreator"))
            copyRecursively(srcDir.absoluteFilePath(file), destDir.absoluteFilePath(file));
    }

    // Make sure to use the copied settings:
    delete settings;
    return createUserSettings();
}

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
287
288
289
290
291
292
#ifdef Q_OS_MAC
#  define SHARE_PATH "/../Resources"
#else
#  define SHARE_PATH "/../share/qtcreator"
#endif

con's avatar
con committed
293
294
int main(int argc, char **argv)
{
295
#if (QT_VERSION < QT_VERSION_CHECK(5, 6, 0))
296
297
    if (Utils::HostOsInfo().isWindowsHost()
            && !qEnvironmentVariableIsSet("QT_DEVICE_PIXEL_RATIO")) {
298
        qputenv("QT_DEVICE_PIXEL_RATIO", "auto");
299
    }
300
301
#endif // < Qt 5.6

302
    QLoggingCategory::setFilterRules(QLatin1String("qtc.*.debug=false"));
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
303
#ifdef Q_OS_MAC
con's avatar
con committed
304
305
306
    // increase the number of file that can be opened in Qt Creator.
    struct rlimit rl;
    getrlimit(RLIMIT_NOFILE, &rl);
307
308

    rl.rlim_cur = qMin((rlim_t)OPEN_MAX, rl.rlim_max);
con's avatar
con committed
309
310
311
312
    setrlimit(RLIMIT_NOFILE, &rl);
#endif

    SharedTools::QtSingleApplication app((QLatin1String(appNameC)), argc, argv);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
313

314
315
    if (Utils::HostOsInfo().isWindowsHost()
            && !qFuzzyCompare(qApp->devicePixelRatio(), 1.0)
316
317
318
319
            && QApplication::style()->objectName().startsWith(
                QLatin1String("windows"), Qt::CaseInsensitive)) {
        QApplication::setStyle(QLatin1String("fusion"));
    }
320
321
322
    const int threadCount = QThreadPool::globalInstance()->maxThreadCount();
    QThreadPool::globalInstance()->setMaxThreadCount(qMax(4, 2 * threadCount));

323
    CrashHandlerSetup setupCrashHandler; // Display a backtrace once a serious signal is delivered.
324

Marco Bubke's avatar
Marco Bubke committed
325
326
327
328
#ifdef ENABLE_QT_BREAKPAD
    QtSystemExceptionHandler systemExceptionHandler;
#endif

329
330
    app.setAttribute(Qt::AA_UseHighDpiPixmaps);

331
    // Manually determine -settingspath command line option
332
    // We can't use the regular way of the plugin manager, because that needs to parse plugin meta data
333
334
    // but the settings path can influence which plugins are enabled
    QString settingsPath;
335
    QStringList customPluginPaths;
Yuchen Deng's avatar
Yuchen Deng committed
336
    QStringList arguments = app.arguments(); // adapted arguments list is passed to plugin manager later
337
    QMutableStringListIterator it(arguments);
338
    bool testOptionProvided = false;
339
340
341
342
343
344
345
346
    while (it.hasNext()) {
        const QString &arg = it.next();
        if (arg == QLatin1String(SETTINGS_OPTION)) {
            it.remove();
            if (it.hasNext()) {
                settingsPath = QDir::fromNativeSeparators(it.next());
                it.remove();
            }
347
348
349
350
351
352
        } else if (arg == QLatin1String(PLUGINPATH_OPTION)) {
            it.remove();
            if (it.hasNext()) {
                customPluginPaths << QDir::fromNativeSeparators(it.next());
                it.remove();
            }
353
354
        } else if (arg == QLatin1String(TEST_OPTION)) {
            testOptionProvided = true;
355
356
        }
    }
357
    QScopedPointer<QTemporaryDir> temporaryCleanSettingsDir;
358
    if (settingsPath.isEmpty() && testOptionProvided) {
359
360
361
362
363
364
        const QString settingsPathTemplate = QDir::cleanPath(QDir::tempPath()
            + QString::fromLatin1("/qtc-test-settings-XXXXXX"));
        temporaryCleanSettingsDir.reset(new QTemporaryDir(settingsPathTemplate));
        if (!temporaryCleanSettingsDir->isValid())
            return 1;
        settingsPath = temporaryCleanSettingsDir->path();
365
    }
366
367
368
    if (!settingsPath.isEmpty())
        QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, settingsPath);

369
    // Must be done before any QSettings class is created
con's avatar
con committed
370
    QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope,
Yuchen Deng's avatar
Yuchen Deng committed
371
                       QCoreApplication::applicationDirPath() + QLatin1String(SHARE_PATH));
372
    QSettings::setDefaultFormat(QSettings::IniFormat);
373
    // plugin manager takes control of this settings object
374
375
    QSettings *settings = userSettings();

376
    QSettings *globalSettings = new QSettings(QSettings::IniFormat, QSettings::SystemScope,
377
378
                                              QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR),
                                              QLatin1String("QtCreator"));
379
    PluginManager pluginManager;
380
    PluginManager::setPluginIID(QLatin1String("org.qt-project.Qt.QtCreatorPlugin"));
381
382
    PluginManager::setGlobalSettings(globalSettings);
    PluginManager::setSettings(settings);
383

384
385
386
387
    QTranslator translator;
    QTranslator qtTranslator;
    QStringList uiLanguages;
    uiLanguages = QLocale::system().uiLanguages();
388
    QString overrideLanguage = settings->value(QLatin1String("General/OverrideLanguage")).toString();
389
390
    if (!overrideLanguage.isEmpty())
        uiLanguages.prepend(overrideLanguage);
391
    const QString &creatorTrPath = QCoreApplication::applicationDirPath()
Yuchen Deng's avatar
Yuchen Deng committed
392
            + QLatin1String(SHARE_PATH "/translations");
393
    foreach (QString locale, uiLanguages) {
Liang Qi's avatar
Liang Qi committed
394
        locale = QLocale(locale).name();
395
396
397
398
399
400
401
402
403
404
        if (translator.load(QLatin1String("qtcreator_") + locale, creatorTrPath)) {
            const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
            const QString &qtTrFile = QLatin1String("qt_") + locale;
            // Binary installer puts Qt tr files into creatorTrPath
            if (qtTranslator.load(qtTrFile, qtTrPath) || qtTranslator.load(qtTrFile, creatorTrPath)) {
                app.installTranslator(&translator);
                app.installTranslator(&qtTranslator);
                app.setProperty("qtc_locale", locale);
                break;
            }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
405
            translator.load(QString()); // unload()
406
407
408
409
410
411
        } else if (locale == QLatin1String("C") /* overrideLanguage == "English" */) {
            // use built-in
            break;
        } else if (locale.startsWith(QLatin1String("en")) /* "English" is built-in */) {
            // use built-in
            break;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
412
413
414
        }
    }

415
    // Make sure we honor the system's proxy settings
Eike Ziller's avatar
Eike Ziller committed
416
    QNetworkProxyFactory::setUseSystemConfiguration(true);
417

con's avatar
con committed
418
    // Load
419
    const QStringList pluginPaths = getPluginPaths() + customPluginPaths;
420
    PluginManager::setPluginPaths(pluginPaths);
hjk's avatar
hjk committed
421
    QMap<QString, QString> foundAppOptions;
con's avatar
con committed
422
    if (arguments.size() > 1) {
hjk's avatar
hjk committed
423
        QMap<QString, bool> appOptions;
con's avatar
con committed
424
425
426
427
428
429
        appOptions.insert(QLatin1String(HELP_OPTION1), false);
        appOptions.insert(QLatin1String(HELP_OPTION2), false);
        appOptions.insert(QLatin1String(HELP_OPTION3), false);
        appOptions.insert(QLatin1String(HELP_OPTION4), false);
        appOptions.insert(QLatin1String(VERSION_OPTION), false);
        appOptions.insert(QLatin1String(CLIENT_OPTION), false);
430
        appOptions.insert(QLatin1String(PID_OPTION), true);
431
        appOptions.insert(QLatin1String(BLOCK_OPTION), false);
con's avatar
con committed
432
        QString errorMessage;
433
        if (!PluginManager::parseOptions(arguments, appOptions, &foundAppOptions, &errorMessage)) {
con's avatar
con committed
434
            displayError(errorMessage);
435
            printHelp(QFileInfo(app.applicationFilePath()).baseName());
con's avatar
con committed
436
437
438
439
            return -1;
        }
    }

440
441
442
    const PluginSpecSet plugins = PluginManager::plugins();
    PluginSpec *coreplugin = 0;
    foreach (PluginSpec *spec, plugins) {
con's avatar
con committed
443
444
445
446
447
448
        if (spec->name() == QLatin1String(corePluginNameC)) {
            coreplugin = spec;
            break;
        }
    }
    if (!coreplugin) {
hjk's avatar
hjk committed
449
        QString nativePaths = QDir::toNativeSeparators(pluginPaths.join(QLatin1Char(',')));
450
        const QString reason = QCoreApplication::translate("Application", "Could not find Core plugin in %1").arg(nativePaths);
con's avatar
con committed
451
452
453
        displayError(msgCoreLoadFailure(reason));
        return 1;
    }
454
455
456
457
458
    if (!coreplugin->isEffectivelyEnabled()) {
        const QString reason = QCoreApplication::translate("Application", "Core plugin is disabled.");
        displayError(msgCoreLoadFailure(reason));
        return 1;
    }
con's avatar
con committed
459
460
461
462
463
    if (coreplugin->hasError()) {
        displayError(msgCoreLoadFailure(coreplugin->errorString()));
        return 1;
    }
    if (foundAppOptions.contains(QLatin1String(VERSION_OPTION))) {
464
        printVersion(coreplugin);
con's avatar
con committed
465
466
467
468
469
470
        return 0;
    }
    if (foundAppOptions.contains(QLatin1String(HELP_OPTION1))
            || foundAppOptions.contains(QLatin1String(HELP_OPTION2))
            || foundAppOptions.contains(QLatin1String(HELP_OPTION3))
            || foundAppOptions.contains(QLatin1String(HELP_OPTION4))) {
471
        printHelp(QFileInfo(app.applicationFilePath()).baseName());
con's avatar
con committed
472
473
474
        return 0;
    }

475
476
477
478
479
480
481
482
483
    qint64 pid = -1;
    if (foundAppOptions.contains(QLatin1String(PID_OPTION))) {
        QString pidString = foundAppOptions.value(QLatin1String(PID_OPTION));
        bool pidOk;
        qint64 tmpPid = pidString.toInt(&pidOk);
        if (pidOk)
            pid = tmpPid;
    }

484
485
486
487
    bool isBlock = foundAppOptions.contains(QLatin1String(BLOCK_OPTION));
    if (app.isRunning() && (pid != -1 || isBlock
                            || foundAppOptions.contains(QLatin1String(CLIENT_OPTION)))) {
        app.setBlock(isBlock);
488
        if (app.sendMessage(PluginManager::serializedArguments(), 5000 /*timeout*/, pid))
489
490
491
            return 0;

        // Message could not be send, maybe it was in the process of quitting
492
        if (app.isRunning(pid)) {
493
494
            // Nah app is still running, ask the user
            int button = askMsgSendFailed();
495
            while (button == QMessageBox::Retry) {
496
                if (app.sendMessage(PluginManager::serializedArguments(), 5000 /*timeout*/, pid))
497
                    return 0;
498
                if (!app.isRunning(pid)) // App quit while we were trying so start a new creator
499
500
501
502
503
504
                    button = QMessageBox::Yes;
                else
                    button = askMsgSendFailed();
            }
            if (button == QMessageBox::No)
                return -1;
505
506
        }
    }
con's avatar
con committed
507

508
    PluginManager::loadPlugins();
con's avatar
con committed
509
510
511
512
    if (coreplugin->hasError()) {
        displayError(msgCoreLoadFailure(coreplugin->errorString()));
        return 1;
    }
513

Orgad Shaneh's avatar
Orgad Shaneh committed
514
    // Set up remote arguments.
515
516
    QObject::connect(&app, SIGNAL(messageReceived(QString,QObject*)),
                     &pluginManager, SLOT(remoteArguments(QString,QObject*)));
Yuchen Deng's avatar
Yuchen Deng committed
517
518
519

    QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(),
                     SLOT(fileOpenRequest(QString)));
con's avatar
con committed
520

521
522
523
    // shutdown plugin manager on the exit
    QObject::connect(&app, SIGNAL(aboutToQuit()), &pluginManager, SLOT(shutdown()));

524
    return app.exec();
con's avatar
con committed
525
}