d->m_inferiorPid = d->m_startParameters.attachPID > 0
? d->m_startParameters.attachPID : 0;
+ if (d->m_inferiorPid)
+ d->m_runControl->setApplicationProcessHandle(ProcessHandle(d->m_inferiorPid));
if (!d->m_startParameters.environment.size())
d->m_startParameters.environment = Utils::Environment();
return;
d->m_inferiorPid = pid;
if (pid) {
+ d->m_runControl->setApplicationProcessHandle(ProcessHandle(pid));
showMessage(tr("Taking notice of pid %1").arg(pid));
if (d->m_startParameters.startMode == StartInternal
|| d->m_startParameters.startMode == StartExternal
void startRemoteApplication();
void startRemoteEngine();
void attachExternalApplication();
+ Q_SLOT void attachExternalApplication(ProjectExplorer::RunControl *rc);
void attachExternalApplication(qint64 pid, const QString &binary,
- const ProjectExplorer::Abi &abi = ProjectExplorer::Abi(),
- const QString &debuggerCommand = QString());
+ const ProjectExplorer::Abi &abi,
+ const QString &debuggerCommand);
void runScheduled();
void attachCore();
void attachCore(const QString &core, const QString &exeFileName,
m_dummyEngine(0),
m_globalDebuggerOptions(new GlobalDebuggerOptions)
{
+ setObjectName("DebuggerCore");
qRegisterMetaType<WatchData>("WatchData");
qRegisterMetaType<ContextData>("ContextData");
qRegisterMetaType<DebuggerStartParameters>("DebuggerStartParameters");
startDebugger(rc);
}
+void DebuggerPluginPrivate::attachExternalApplication(ProjectExplorer::RunControl *rc)
+{
+ DebuggerStartParameters sp;
+ sp.attachPID = rc->applicationProcessHandle().pid();
+ sp.displayName = tr("Debugger attached to %1").arg(rc->displayName());
+ sp.startMode = AttachExternal;
+ //sp.toolChainAbi = abiOfBinary(sp.executable);
+ sp.toolChainAbi = ProjectExplorer::Abi::hostAbi(); // FIXME: Extract from RunControl?
+ if (DebuggerRunControl *rc = createDebugger(sp))
+ startDebugger(rc);
+}
+
void DebuggerPluginPrivate::attachCore()
{
AttachCoreDialog dlg(mainWindow());
Core::ActionManager *am = core->actionManager();
QTC_ASSERT(am, return);
+ m_plugin->addObject(this);
+
const Context globalcontext(CC::C_GLOBAL);
const Context cppDebuggercontext(C_CPPDEBUGGER);
const Context qmlDebuggerContext(C_QMLDEBUGGER);
void DebuggerPluginPrivate::aboutToShutdown()
{
+ m_plugin->removeObject(this);
disconnect(sessionManager(),
SIGNAL(startupProjectChanged(ProjectExplorer::Project*)),
this, 0);
#include <aggregation/aggregate.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorsettings.h>
+#include <extensionsystem/pluginmanager.h>
+#include <extensionsystem/invoker.h>
#include <utils/qtcassert.h>
#include <utils/outputformatter.h>
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
+static QObject *debuggerCore()
+{
+ return ExtensionSystem::PluginManager::instance()->getObjectByName("DebuggerCore");
+}
+
AppOutputPane::RunControlTab::RunControlTab(RunControl *rc, Core::OutputWindow *w) :
runControl(rc), window(w), asyncClosing(false)
{
m_tabWidget(new QTabWidget),
m_stopAction(new QAction(QIcon(QLatin1String(Constants::ICON_STOP)), tr("Stop"), this)),
m_reRunButton(new QToolButton),
- m_stopButton(new QToolButton)
+ m_stopButton(new QToolButton),
+ m_attachButton(new QToolButton)
{
// Rerun
m_reRunButton->setIcon(QIcon(ProjectExplorer::Constants::ICON_RUN_SMALL));
connect(m_stopAction, SIGNAL(triggered()),
this, SLOT(stopRunControl()));
+ // Attach
+ m_attachButton->setToolTip(tr("Attach debugger to this process"));
+ m_attachButton->setEnabled(false);
+ m_attachButton->setIcon(QIcon(ProjectExplorer::Constants::ICON_DEBUG_SMALL));
+ m_attachButton->setAutoRaise(true);
+
+ connect(m_attachButton, SIGNAL(clicked()),
+ this, SLOT(attachToRunControl()));
+
// Spacer (?)
QVBoxLayout *layout = new QVBoxLayout;
QList<QWidget*> AppOutputPane::toolBarWidgets() const
{
- return QList<QWidget*>() << m_reRunButton << m_stopButton;
+ return QList<QWidget*>() << m_reRunButton << m_stopButton << m_attachButton;
}
QString AppOutputPane::displayName() const
tab.runControl->start();
}
+void AppOutputPane::attachToRunControl()
+{
+ const int index = currentIndex();
+ QTC_ASSERT(index != -1, return);
+ ProjectExplorer::RunControl *rc = m_runControlTabs.at(index).runControl;
+ QTC_ASSERT(rc->isRunning(), return);
+ ExtensionSystem::Invoker<void>(debuggerCore(), "attachExternalApplication", rc);
+}
+
void AppOutputPane::stopRunControl()
{
const int index = currentIndex();
if (i == -1) {
m_stopAction->setEnabled(false);
m_reRunButton->setEnabled(false);
+ m_attachButton->setEnabled(false);
} else {
const int index = indexOf(m_tabWidget->widget(i));
QTC_ASSERT(index != -1, return; )
m_stopAction->setEnabled(rc->isRunning());
m_reRunButton->setEnabled(!rc->isRunning());
m_reRunButton->setIcon(rc->icon());
+ m_attachButton->setEnabled(debuggerCore());
}
}
if (current && current == sender()) {
m_reRunButton->setEnabled(false);
m_stopAction->setEnabled(true);
+ m_attachButton->setEnabled(debuggerCore());
m_reRunButton->setIcon(current->icon());
}
}
if (current && current == sender()) {
m_reRunButton->setEnabled(true);
m_stopAction->setEnabled(false);
+ m_attachButton->setEnabled(false);
m_reRunButton->setIcon(current->icon());
}
// Check for asynchronous close. Close the tab.
private slots:
void reRunRunControl();
void stopRunControl();
+ void attachToRunControl();
bool closeTab(int index);
void tabChanged(int);
void runControlStarted();
QAction *m_stopAction;
QToolButton *m_reRunButton;
QToolButton *m_stopButton;
+ QToolButton *m_attachButton;
};
} // namespace Internal
emit finished();
} else {
m_applicationLauncher.start(m_runMode, m_executable, m_commandLineArguments);
+ setApplicationProcessHandle(ProcessHandle(m_applicationLauncher.applicationPID()));
QString msg = tr("Starting %1...\n").arg(QDir::toNativeSeparators(m_executable));
appendMessage(msg, Utils::NormalMessageFormat);
}
QString m_executable;
QString m_commandLineArguments;
ProjectExplorer::ApplicationLauncher::Mode m_runMode;
+ ProcessHandle m_applicationProcessHandle;
};
} // namespace Internal
} // namespace
/*!
+ \class ProjectExplorer::ProcessHandle
+ \brief Helper class to describe a process.
+
+*/
+
+/*!
\class ProjectExplorer::RunConfiguration
\brief Base class for a run configuration. A run configuration specifies how a
target should be run, while the runner (see below) does the actual running.
return new Utils::OutputFormatter();
}
+
/*!
\class ProjectExplorer::IRunConfigurationFactory
return m_displayName;
}
+ProcessHandle RunControl::applicationProcessHandle() const
+{
+ return m_applicationProcessHandle;
+}
+
+void RunControl::setApplicationProcessHandle(const ProcessHandle &handle)
+{
+ m_applicationProcessHandle = handle;
+}
+
bool RunControl::promptToStop(bool *optionalPrompt) const
{
QTC_ASSERT(isRunning(), return true;)
class RunControl;
class Target;
+// FIXME: This should also contain a handle to an remote device if used.
+class PROJECTEXPLORER_EXPORT ProcessHandle
+{
+public:
+ explicit ProcessHandle(quint64 pid = 0) : m_pid(pid) {}
+
+ bool isValid() const { return m_pid != 0; }
+ void setPid(quint64 pid) { m_pid = pid; }
+ quint64 pid() const { return m_pid; }
+
+private:
+ quint64 m_pid;
+};
+
// Documentation inside.
class PROJECTEXPLORER_EXPORT RunConfiguration : public ProjectConfiguration
{
virtual QString displayName() const;
virtual QIcon icon() const = 0;
+ ProcessHandle applicationProcessHandle() const;
+ void setApplicationProcessHandle(const ProcessHandle &handle);
+
bool sameRunConfiguration(const RunControl *other) const;
Utils::OutputFormatter *outputFormatter();
const QWeakPointer<RunConfiguration> m_runConfiguration;
Utils::OutputFormatter *m_outputFormatter;
+ // A handle to the actual application process.
+ ProcessHandle m_applicationProcessHandle;
+
#ifdef Q_OS_MAC
//these two are used to bring apps in the foreground on Mac
qint64 m_internalPid;
// Allow a RunConfiguration to be stored in a QVariant
Q_DECLARE_METATYPE(ProjectExplorer::RunConfiguration*)
+Q_DECLARE_METATYPE(ProjectExplorer::RunControl*)
#endif // RUNCONFIGURATION_H
{
m_applicationLauncher.start(ApplicationLauncher::Gui, m_executable,
m_commandLineArguments);
-
+ setApplicationProcessHandle(ProcessHandle(m_applicationLauncher.applicationPID()));
emit started();
QString msg = tr("Starting %1 %2\n")
.arg(QDir::toNativeSeparators(m_executable), m_commandLineArguments);
this, SLOT(slotAppendMessage(QString, Utils::OutputFormat)));
connect(&m_applicationLauncher, SIGNAL(processExited(int)),
this, SLOT(processExited(int)));
- connect(&m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
- this, SLOT(bringApplicationToForeground(qint64)));
+ connect(&m_applicationLauncher, SIGNAL(bringToForegroundRequested(quint64)),
+ this, SLOT(bringApplicationToForeground(quint64)));
}
void S60EmulatorRunControl::start()
{
m_applicationLauncher.start(ApplicationLauncher::Gui, m_executable, QString());
+ setApplicationProcessHandle(ProcessHandle(m_applicationLauncher.applicationPID()));
emit started();
QString msg = tr("Starting %1...\n").arg(QDir::toNativeSeparators(m_executable));