diff --git a/src/app/main.cpp b/src/app/main.cpp index 9ed1cf10ddaddc103358f27583713cbc412288dc..f4d17c4bf43d9c231cb4a27c4e5ed29ebe9f7357 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -134,40 +134,6 @@ static inline QString msgSendArgumentFailed() return QCoreApplication::translate("Application", "Unable to send command line arguments to the already running instance. It appears to be not responding."); } -// Prepare a remote argument: If it is a relative file, add the current directory -// since the the central instance might be running in a different directory. - -static inline QString prepareRemoteArgument(const QString &a) -{ - QFileInfo fi(a); - if (!fi.exists()) - return a; - if (fi.isRelative()) - return fi.absoluteFilePath(); - return a; -} - -// Send the arguments to an already running instance of Qt Creator -static bool sendArguments(SharedTools::QtSingleApplication &app, const QStringList &arguments) -{ - if (!arguments.empty()) { - // Send off arguments - const QStringList::const_iterator acend = arguments.constEnd(); - for (QStringList::const_iterator it = arguments.constBegin(); it != acend; ++it) { - if (!app.sendMessage(prepareRemoteArgument(*it))) { - displayError(msgSendArgumentFailed()); - return false; - } - } - } - // Special empty argument means: Show and raise (the slot just needs to be triggered) - if (!app.sendMessage(QString())) { - displayError(msgSendArgumentFailed()); - return false; - } - return true; -} - static inline QStringList getPluginPaths() { QStringList rc; @@ -287,8 +253,13 @@ int main(int argc, char **argv) } const bool isFirstInstance = !app.isRunning(); - if (!isFirstInstance && foundAppOptions.contains(QLatin1String(CLIENT_OPTION))) - return sendArguments(app, pluginManager.arguments()) ? 0 : -1; + if (!isFirstInstance && foundAppOptions.contains(QLatin1String(CLIENT_OPTION))) { + if (!app.sendMessage(pluginManager.serializedArguments())) { + displayError(msgSendArgumentFailed()); + return -1; + } + return 0; + } pluginManager.loadPlugins(); if (coreplugin->hasError()) { @@ -311,9 +282,10 @@ int main(int argc, char **argv) // Silently fallback to unconnected instances for any subsequent // instances. app.initialize(); - QObject::connect(&app, SIGNAL(messageReceived(QString)), coreplugin->plugin(), SLOT(remoteArgument(QString))); + QObject::connect(&app, SIGNAL(messageReceived(QString)), + &pluginManager, SLOT(remoteArguments(QString))); } - QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(), SLOT(remoteArgument(QString))); + QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(), SLOT(fileOpenRequest(QString))); // Do this after the event loop has started QTimer::singleShot(100, &pluginManager, SLOT(startTests())); diff --git a/src/libs/extensionsystem/iplugin.h b/src/libs/extensionsystem/iplugin.h index e546b72db8bd5ba32ce11ca27b9db28f2dde3637..39bd3671eee5e77ce70fc7569d5fc78ec038f003 100644 --- a/src/libs/extensionsystem/iplugin.h +++ b/src/libs/extensionsystem/iplugin.h @@ -55,6 +55,7 @@ public: virtual bool initialize(const QStringList &arguments, QString *errorString) = 0; virtual void extensionsInitialized() = 0; virtual void shutdown() { } + virtual void remoteCommand(const QStringList & /* options */, const QStringList & /* arguments */) { } PluginSpec *pluginSpec() const; diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 8cf365b67041cb2223a11bc9e823912390e7c7d3..6d2be40413b97218b8c54038c25510bb30600a75 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -320,6 +320,91 @@ QList<PluginSpec *> PluginManager::plugins() const return d->pluginSpecs; } +/*! + \fn QString PluginManager::serializedArguments() const + + Serialize plugin options and arguments for sending in a single string + via QtSingleApplication: + ":myplugin|-option1|-option2|:arguments|argument1|argument2", + as a list of lists started by a keyword with a colon. Arguments are last. + + \sa setPluginPaths() +*/ + +static const char argumentKeywordC[] = ":arguments"; + +QString PluginManager::serializedArguments() const +{ + const QChar separator = QLatin1Char('|'); + QString rc; + foreach (const PluginSpec *ps, plugins()) { + if (!ps->arguments().isEmpty()) { + if (!rc.isEmpty()) + rc += separator; + rc += QLatin1Char(':'); + rc += ps->name(); + rc += separator; + rc += ps->arguments().join(QString(separator)); + } + } + if (!d->arguments.isEmpty()) { + if (!rc.isEmpty()) + rc += separator; + rc += QLatin1String(argumentKeywordC); + // If the argument appears to be a file, make it absolute + // when sending to another instance. + foreach(const QString &argument, d->arguments) { + rc += separator; + const QFileInfo fi(argument); + if (fi.exists() && fi.isRelative()) { + rc += fi.absoluteFilePath(); + } else { + rc += argument; + } + } + } + return rc; +} + +/* Extract a sublist from the serialized arguments + * indicated by a keyword starting with a colon indicator: + * ":a,i1,i2,:b:i3,i4" with ":a" -> "i1,i2" + */ +static QStringList subList(const QStringList &in, const QString &key) +{ + QStringList rc; + // Find keyword and copy arguments until end or next keyword + const QStringList::const_iterator inEnd = in.constEnd(); + QStringList::const_iterator it = qFind(in.constBegin(), inEnd, key); + if (it != inEnd) { + const QChar nextIndicator = QLatin1Char(':'); + for (++it; it != inEnd && !it->startsWith(nextIndicator); ++it) + rc.append(*it); + } + return rc; +} + +/*! + \fn PluginManager::remoteArguments(const QString &argument) + + Parses the options encoded by serializedArguments() const + and passes them on to the respective plugins along with the arguments. +*/ + +void PluginManager::remoteArguments(const QString &serializedArgument) +{ + if (serializedArgument.isEmpty()) + return; + QStringList serializedArguments = serializedArgument.split(QLatin1Char('|')); + const QStringList arguments = subList(serializedArguments, QLatin1String(argumentKeywordC)); + foreach (const PluginSpec *ps, plugins()) { + if (ps->state() == PluginSpec::Running) { + const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->name()); + ps->plugin()->remoteCommand(pluginOptions, arguments); + } + } +} + /*! \fn bool PluginManager::parseOptions(const QStringList &args, const QMap<QString, bool> &appOptions, QMap<QString, QString> *foundAppOptions, QString *errorString) Takes the list of command line options in \a args and parses them. diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h index 79c0b683564b0547cbf8b296208281351a13ade8..f4140da9d14624413ba48b1a62f7ba859a04a6c0 100644 --- a/src/libs/extensionsystem/pluginmanager.h +++ b/src/libs/extensionsystem/pluginmanager.h @@ -108,6 +108,8 @@ public: void formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const; void formatPluginVersions(QTextStream &str) const; + QString serializedArguments() const; + bool runningTests() const; QString testDataDirectory() const; @@ -116,6 +118,10 @@ signals: void aboutToRemoveObject(QObject *obj); void pluginsChanged(); + +public slots: + void remoteArguments(const QString &serializedArguments); + private slots: void startTests(); diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index da2825ecf84c11dc2aa42da4bbeca0e58b41c3eb..8b9317fb65131c06125586a9597cdec9064e4f76 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -87,16 +87,15 @@ void CorePlugin::extensionsInitialized() m_mainWindow->extensionsInitialized(); } -void CorePlugin::remoteArgument(const QString& arg) +void CorePlugin::remoteCommand(const QStringList & /* options */, const QStringList &args) { - // An empty argument is sent to trigger activation - // of the window via QtSingleApplication. It should be - // the last of a sequence. - if (arg.isEmpty()) { - m_mainWindow->activateWindow(); - } else { - m_mainWindow->openFiles(QStringList(arg)); - } + m_mainWindow->openFiles(args); + m_mainWindow->activateWindow(); +} + +void CorePlugin::fileOpenRequest(const QString &f) +{ + remoteCommand(QStringList(), QStringList(f)); } void CorePlugin::shutdown() diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index 58e5958cc85ef5eb97793ae4ba734106bf72de7c..3c03c7b836c72d0f38a9c4d35bc5c8d4e3ade616 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -49,9 +49,10 @@ public: virtual bool initialize(const QStringList &arguments, QString *errorMessage = 0); virtual void extensionsInitialized(); virtual void shutdown(); + virtual void remoteCommand(const QStringList & /* options */, const QStringList &args); public slots: - void remoteArgument(const QString&); + void fileOpenRequest(const QString&); private: void parseArguments(const QStringList & arguments); diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index b538b7fe67578706753db8da04fe9736c42b154f..333a84dfc9405df3059bd5b39ad1748c4cf1092f 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -812,8 +812,14 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6 if (!crashParameter.isEmpty()) { ULONG64 evtNr = crashParameter.toULongLong(); const HRESULT hr = m_cif.debugControl->SetNotifyEventHandle(evtNr); - if (FAILED(hr)) + // Unless QtCreator is spawned by the debugger and inherits the handles, + // the event handling does not work reliably + // (that is, the crash event is not delivered). + if (SUCCEEDED(hr)) { + QTimer::singleShot(0, m_engine, SLOT(slotBreakAttachToCrashed())); + } else { m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(msgComFailed("SetNotifyEventHandle", hr))); + } } } m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__); @@ -1234,6 +1240,17 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage) return true; } +void CdbDebugEngine::slotBreakAttachToCrashed() +{ + // Force a break when attaching to crashed process (if Creator was not spawned + // from handler). + if (state() != InferiorStopped) { + manager()->showDebuggerOutput(LogMisc, QLatin1String("Forcing break...")); + m_d->m_dumper->disable(); + interruptInferior(); + } +} + void CdbDebugEngine::interruptInferior() { if (!m_d->m_hDebuggeeProcess || !m_d->isDebuggeeRunning()) diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h index 077faf4e14fe1d2b6085af2c373971dfab106416..59d7658a925c5a3d3791ab961e18ba9cfefcd16c 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.h +++ b/src/plugins/debugger/cdb/cdbdebugengine.h @@ -111,6 +111,7 @@ private slots: void slotConsoleStubStarted(); void slotConsoleStubError(const QString &msg); void slotConsoleStubTerminated(); + void slotBreakAttachToCrashed(); void warning(const QString &w); private: diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 1e91222a06b545fddb73668e0c0694139fd70656..e1b938815c1c3291787429bfe88cefe64146bac0 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -505,14 +505,19 @@ bool DebuggingHelperOptionPage::matches(const QString &s) const // /////////////////////////////////////////////////////////////////////// + +DebuggerPlugin::AttachRemoteParameters::AttachRemoteParameters() : + attachPid(0), + winCrashEvent(0) +{ +} + DebuggerPlugin::DebuggerPlugin() : m_manager(0), m_debugMode(0), m_locationMark(0), m_gdbRunningContext(0), m_cmdLineEnabledEngines(AllEngineTypes), - m_cmdLineAttachPid(0), - m_cmdLineWinCrashEvent(0), m_toggleLockedAction(0) {} @@ -555,9 +560,10 @@ static QString msgInvalidNumericParameter(const QString &a, const QString &numbe } // Parse arguments -bool DebuggerPlugin::parseArgument(QStringList::const_iterator &it, - const QStringList::const_iterator &cend, - QString *errorMessage) +static bool parseArgument(QStringList::const_iterator &it, + const QStringList::const_iterator &cend, + DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters, + unsigned *enabledEngines, QString *errorMessage) { const QString &option = *it; // '-debug <pid>' @@ -568,10 +574,10 @@ bool DebuggerPlugin::parseArgument(QStringList::const_iterator &it, return false; } bool ok; - m_cmdLineAttachPid = it->toULongLong(&ok); + attachRemoteParameters->attachPid = it->toULongLong(&ok); if (!ok) { - m_cmdLineAttachPid = 0; - m_cmdLineAttachCore = *it; + attachRemoteParameters->attachPid = 0; + attachRemoteParameters->attachCore = *it; } return true; } @@ -584,7 +590,7 @@ bool DebuggerPlugin::parseArgument(QStringList::const_iterator &it, return false; } bool ok; - m_cmdLineWinCrashEvent = it->toULongLong(&ok); + attachRemoteParameters->winCrashEvent = it->toULongLong(&ok); if (!ok) { *errorMessage = msgInvalidNumericParameter(option, *it); return false; @@ -593,40 +599,55 @@ bool DebuggerPlugin::parseArgument(QStringList::const_iterator &it, } // engine disabling if (option == QLatin1String("-disable-cdb")) { - m_cmdLineEnabledEngines &= ~CdbEngineType; + *enabledEngines &= ~Debugger::CdbEngineType; return true; } if (option == QLatin1String("-disable-gdb")) { - m_cmdLineEnabledEngines &= ~GdbEngineType; + *enabledEngines &= ~Debugger::GdbEngineType; return true; } if (option == QLatin1String("-disable-sdb")) { - m_cmdLineEnabledEngines &= ~ScriptEngineType; + *enabledEngines &= ~Debugger::ScriptEngineType; return true; } - *errorMessage = tr("Invalid debugger option: %1").arg(option); + *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option); return false; } -bool DebuggerPlugin::parseArguments(const QStringList &args, QString *errorMessage) +static bool parseArguments(const QStringList &args, + DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters, + unsigned *enabledEngines, QString *errorMessage) { const QStringList::const_iterator cend = args.constEnd(); for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it) - if (!parseArgument(it, cend, errorMessage)) + if (!parseArgument(it, cend, attachRemoteParameters, enabledEngines, errorMessage)) return false; if (Debugger::Constants::Internal::debug) qDebug().nospace() << args << "engines=0x" - << QString::number(m_cmdLineEnabledEngines, 16) - << " pid" << m_cmdLineAttachPid - << " core" << m_cmdLineAttachCore << '\n'; + << QString::number(*enabledEngines, 16) + << " pid" << attachRemoteParameters->attachPid + << " core" << attachRemoteParameters->attachCore << '\n'; return true; } +void DebuggerPlugin::remoteCommand(const QStringList &options, const QStringList &) +{ + QString errorMessage; + AttachRemoteParameters parameters; + unsigned dummy = 0; + // Did we receive a request for debugging (unless it is ourselves)? + if (parseArguments(options, ¶meters, &dummy, &errorMessage) + && parameters.attachPid != quint64(QCoreApplication::applicationPid())) { + m_attachRemoteParameters = parameters; + attachCmdLine(); + } +} + bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMessage) { // Do not fail the whole plugin if something goes wrong here - if (!parseArguments(arguments, errorMessage)) { + if (!parseArguments(arguments, &m_attachRemoteParameters, &m_cmdLineEnabledEngines, errorMessage)) { *errorMessage = tr("Error evaluating command line arguments: %1") .arg(*errorMessage); qWarning("%s\n", qPrintable(*errorMessage)); @@ -1000,18 +1021,25 @@ void DebuggerPlugin::extensionsInitialized() //qDebug() << "EXTENSIONS INITIALIZED:" << env; if (!env.isEmpty()) m_manager->runTest(QString::fromLocal8Bit(env)); - if (m_cmdLineAttachPid) - QTimer::singleShot(0, this, SLOT(attachCmdLinePid())); - if (!m_cmdLineAttachCore.isEmpty()) - QTimer::singleShot(0, this, SLOT(attachCmdLineCore())); + if (m_attachRemoteParameters.attachPid || !m_attachRemoteParameters.attachCore.isEmpty()) + QTimer::singleShot(0, this, SLOT(attachCmdLine())); } -void DebuggerPlugin::attachCmdLinePid() +void DebuggerPlugin::attachCmdLine() { - m_manager->showStatusMessage(tr("Attaching to PID %1.").arg(m_cmdLineAttachPid)); - const QString crashParameter = - m_cmdLineWinCrashEvent ? QString::number(m_cmdLineWinCrashEvent) : QString(); - attachExternalApplication(m_cmdLineAttachPid, crashParameter); + if (m_manager->state() != DebuggerNotReady) + return; + if (m_attachRemoteParameters.attachPid) { + m_manager->showStatusMessage(tr("Attaching to PID %1.").arg(m_attachRemoteParameters.attachPid)); + const QString crashParameter = + m_attachRemoteParameters.winCrashEvent ? QString::number(m_attachRemoteParameters.winCrashEvent) : QString(); + attachExternalApplication(m_attachRemoteParameters.attachPid, crashParameter); + return; + } + if (!m_attachRemoteParameters.attachCore.isEmpty()) { + m_manager->showStatusMessage(tr("Attaching to core %1.").arg(m_attachRemoteParameters.attachCore)); + attachCore(m_attachRemoteParameters.attachCore, QString()); + } } /*! Activates the previous mode when the current mode is the debug mode. */ @@ -1326,12 +1354,6 @@ void DebuggerPlugin::attachExternalApplication(qint64 pid, const QString &crashP ProjectExplorerPlugin::instance()->startRunControl(runControl, ProjectExplorer::Constants::DEBUGMODE); } -void DebuggerPlugin::attachCmdLineCore() -{ - m_manager->showStatusMessage(tr("Attaching to core %1.").arg(m_cmdLineAttachCore)); - attachCore(m_cmdLineAttachCore, QString()); -} - void DebuggerPlugin::attachCore() { AttachCoreDialog dlg(m_manager->mainWindow()); diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h index 1e1af9cb8f7419e094e1451360876bd8f35d5bef..db064b20b2a2a56cc7cac3943f9dad7f70b59b31 100644 --- a/src/plugins/debugger/debuggerplugin.h +++ b/src/plugins/debugger/debuggerplugin.h @@ -36,7 +36,6 @@ #include <QtCore/QStringList> QT_BEGIN_NAMESPACE -class QAbstractItemView; class QAction; class QCursor; class QMenu; @@ -68,6 +67,15 @@ class DebuggerPlugin : public ExtensionSystem::IPlugin Q_OBJECT public: + struct AttachRemoteParameters { + AttachRemoteParameters(); + + quint64 attachPid; + QString attachCore; + // Event handle for attaching to crashed Windows processes. + quint64 winCrashEvent; + }; + DebuggerPlugin(); ~DebuggerPlugin(); @@ -75,6 +83,7 @@ private: virtual bool initialize(const QStringList &arguments, QString *error_message); virtual void shutdown(); virtual void extensionsInitialized(); + virtual void remoteCommand(const QStringList &options, const QStringList &arguments); QVariant configValue(const QString &name) const; @@ -106,16 +115,11 @@ private slots: void startRemoteApplication(); void attachExternalApplication(); void attachCore(); - void attachCmdLinePid(); - void attachCmdLineCore(); + void attachCmdLine(); private: void readSettings(); void writeSettings() const; - bool parseArguments(const QStringList &args, QString *errorMessage); - inline bool parseArgument(QStringList::const_iterator &it, - const QStringList::const_iterator& end, - QString *errorMessage); void attachExternalApplication(qint64 pid, const QString &crashParameter = QString()); void attachCore(const QString &core, const QString &exeFileName); @@ -131,11 +135,9 @@ private: QString m_previousMode; TextEditor::BaseTextMark *m_locationMark; int m_gdbRunningContext; + AttachRemoteParameters m_attachRemoteParameters; unsigned m_cmdLineEnabledEngines; - quint64 m_cmdLineAttachPid; - QString m_cmdLineAttachCore; - // Event handle for attaching to crashed Windows processes. - quint64 m_cmdLineWinCrashEvent; + QAction *m_toggleLockedAction; QAction *m_startExternalAction; diff --git a/src/tools/qtcdebugger/main.cpp b/src/tools/qtcdebugger/main.cpp index 8be595a0ce1201e1e30a6a9994056289fcc67cff..616fc82727db75e11830feac7212b43d890c428d 100644 --- a/src/tools/qtcdebugger/main.cpp +++ b/src/tools/qtcdebugger/main.cpp @@ -41,6 +41,7 @@ #include <QtCore/QByteArray> #include <QtCore/QString> #include <QtCore/QDir> +#include <QtCore/QTime> #include <QtCore/QProcess> #include <QtGui/QPushButton> @@ -61,6 +62,7 @@ static const WCHAR *debuggerRegistryValueNameC = L"Debugger"; static const WCHAR *debuggerRegistryDefaultValueNameC = L"Debugger.Default"; static const char *linkC = "http://msdn.microsoft.com/en-us/library/cc266343.aspx"; +static const char *creatorBinaryC = "qtcreator.exe"; static inline QString wCharToQString(const WCHAR *w) { return QString::fromUtf16(reinterpret_cast<const ushort *>(w)); } #ifdef __GNUC__ @@ -343,23 +345,49 @@ static QString getProcessBaseName(DWORD pid) // ------- main modes -bool startCreatorAsDebugger(QString *errorMessage) +static bool waitForProcess(DWORD pid) +{ + HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION|READ_CONTROL|SYNCHRONIZE, false, pid); + if (handle == NULL) + return false; + const DWORD waitResult = WaitForSingleObject(handle, INFINITE); + CloseHandle(handle); + return waitResult == WAIT_OBJECT_0; +} + +bool startCreatorAsDebugger(bool asClient, QString *errorMessage) { const QString dir = QApplication::applicationDirPath(); - const QString binary = dir + QLatin1String("/qtcreator.exe"); + const QString binary = dir + QLatin1Char('/') + QLatin1String(creatorBinaryC); QStringList args; + if (asClient) + args << QLatin1String("-client"); args << QLatin1String("-debug") << QString::number(argProcessId) << QLatin1String("-wincrashevent") << QString::number(argWinCrashEvent); if (debug) qDebug() << binary << args; QProcess p; p.setWorkingDirectory(dir); + QTime executionTime; + executionTime.start(); p.start(binary, args, QIODevice::NotOpen); if (!p.waitForStarted()) { *errorMessage = QString::fromLatin1("Unable to start %1!").arg(binary); return false; } - p.waitForFinished(-1); + // Short execution time: indicates that -client was passed on attach to + // another running instance of Qt Creator. Keep alive as long as user + // does not close the process. If that fails, try to launch 2nd instance. + const bool waitResult = p.waitForFinished(-1); + const bool ranAsClient = asClient && (executionTime.elapsed() < 10000); + if (waitResult && p.exitStatus() == QProcess::NormalExit && ranAsClient) { + if (p.exitCode() == 0) { + waitForProcess(argProcessId); + } else { + errorMessage->clear(); + return startCreatorAsDebugger(false, errorMessage); + } + } return true; } @@ -408,7 +436,8 @@ bool startDefaultDebugger(QString *errorMessage) bool chooseDebugger(QString *errorMessage) { QString defaultDebugger; - const QString msg = QString::fromLatin1("The application \"%1\" (process id %2) crashed. Would you like to debug it?").arg(getProcessBaseName(argProcessId)).arg(argProcessId); + const QString processName = getProcessBaseName(argProcessId); + const QString msg = QString::fromLatin1("The application \"%1\" (process id %2) crashed. Would you like to debug it?").arg(processName).arg(argProcessId); QMessageBox msgBox(QMessageBox::Information, QLatin1String(titleC), msg, QMessageBox::Cancel); QPushButton *creatorButton = msgBox.addButton(QLatin1String("Debug with Qt Creator"), QMessageBox::AcceptRole); QPushButton *defaultButton = msgBox.addButton(QLatin1String("Debug with default debugger"), QMessageBox::AcceptRole); @@ -416,8 +445,10 @@ bool chooseDebugger(QString *errorMessage) && !defaultDebugger.isEmpty()); msgBox.exec(); if (msgBox.clickedButton() == creatorButton) { - // Just in case, default to standard - if (startCreatorAsDebugger(errorMessage)) + // Just in case, default to standard. Do not run as client in the unlikely case + // Creator crashed + const bool canRunAsClient = !processName.contains(QLatin1String(creatorBinaryC), Qt::CaseInsensitive); + if (startCreatorAsDebugger(canRunAsClient, errorMessage)) return true; return startDefaultDebugger(errorMessage); } @@ -552,7 +583,7 @@ int main(int argc, char *argv[]) usage(QCoreApplication::applicationFilePath(), errorMessage); break; case ForceCreatorMode: - ex = startCreatorAsDebugger(&errorMessage) ? 0 : -1; + ex = startCreatorAsDebugger(true, &errorMessage) ? 0 : -1; break; case ForceDefaultMode: ex = startDefaultDebugger(&errorMessage) ? 0 : -1;