Changeset View
Changeset View
Standalone View
Standalone View
plugins/debuggercommon/midebuggerplugin.cpp
Show All 31 Lines | |||||
32 | 32 | | |||
33 | #include <interfaces/context.h> | 33 | #include <interfaces/context.h> | ||
34 | #include <interfaces/contextmenuextension.h> | 34 | #include <interfaces/contextmenuextension.h> | ||
35 | #include <interfaces/icore.h> | 35 | #include <interfaces/icore.h> | ||
36 | #include <interfaces/idebugcontroller.h> | 36 | #include <interfaces/idebugcontroller.h> | ||
37 | #include <interfaces/iruncontroller.h> | 37 | #include <interfaces/iruncontroller.h> | ||
38 | #include <interfaces/iuicontroller.h> | 38 | #include <interfaces/iuicontroller.h> | ||
39 | #include <language/interfaces/editorcontext.h> | 39 | #include <language/interfaces/editorcontext.h> | ||
40 | #include <isession.h> | ||||
40 | 41 | | |||
41 | #include <KActionCollection> | 42 | #include <KActionCollection> | ||
42 | #include <KLocalizedString> | 43 | #include <KLocalizedString> | ||
43 | #include <KMessageBox> | 44 | #include <KMessageBox> | ||
44 | #include <KParts/MainWindow> | 45 | #include <KParts/MainWindow> | ||
45 | #include <KStringHandler> | 46 | #include <KStringHandler> | ||
46 | 47 | | |||
47 | #include <QAction> | 48 | #include <QAction> | ||
48 | #include <QApplication> | 49 | #include <QApplication> | ||
49 | #include <QDBusConnection> | 50 | #include <QDBusConnection> | ||
50 | #include <QDBusConnectionInterface> | 51 | #include <QDBusConnectionInterface> | ||
51 | #include <QDBusInterface> | 52 | #include <QDBusInterface> | ||
52 | #include <QDBusServiceWatcher> | | |||
53 | #include <QPointer> | 53 | #include <QPointer> | ||
54 | #include <QSignalMapper> | | |||
55 | #include <QTimer> | 54 | #include <QTimer> | ||
56 | 55 | | |||
57 | using namespace KDevelop; | 56 | using namespace KDevelop; | ||
58 | using namespace KDevMI; | 57 | using namespace KDevMI; | ||
59 | 58 | | |||
59 | class KDevMI::DBusProxy : public QObject | ||||
60 | { | ||||
61 | Q_OBJECT | ||||
62 | | ||||
63 | public: | ||||
64 | DBusProxy(const QString& service, const QString& name, QObject* parent) | ||||
65 | : QObject(parent), | ||||
66 | m_dbusInterface(service, QStringLiteral("/debugger")), | ||||
67 | m_name(name), m_valid(true) | ||||
68 | {} | ||||
69 | | ||||
70 | ~DBusProxy() | ||||
71 | { | ||||
72 | if (m_valid) { | ||||
73 | m_dbusInterface.call(QStringLiteral("debuggerClosed"), m_name); | ||||
74 | } | ||||
75 | } | ||||
76 | | ||||
77 | QDBusInterface* interface() | ||||
78 | { | ||||
79 | return &m_dbusInterface; | ||||
80 | } | ||||
81 | | ||||
82 | void Invalidate() | ||||
83 | { | ||||
84 | m_valid = false; | ||||
85 | } | ||||
86 | | ||||
87 | public Q_SLOTS: | ||||
88 | void debuggerAccepted(const QString& name) | ||||
89 | { | ||||
90 | if (name == m_name) { | ||||
91 | emit debugProcess(this); | ||||
92 | } | ||||
93 | } | ||||
94 | | ||||
95 | void debuggingFinished() | ||||
96 | { | ||||
97 | m_dbusInterface.call(QStringLiteral("debuggingFinished"), m_name); | ||||
98 | } | ||||
99 | | ||||
100 | Q_SIGNALS: | ||||
101 | void debugProcess(DBusProxy*); | ||||
102 | | ||||
103 | private: | ||||
104 | QDBusInterface m_dbusInterface; | ||||
mwolff: m_dbusInterface | |||||
105 | QString m_name; | ||||
106 | bool m_valid; | ||||
mwolff: m_valid | |||||
107 | }; | ||||
108 | | ||||
109 | const QString drkonqiservice = QLatin1String("org.kde.drkonqi"); | ||||
110 | | ||||
60 | MIDebuggerPlugin::MIDebuggerPlugin(const QString &componentName, const QString& displayName, QObject *parent) | 111 | MIDebuggerPlugin::MIDebuggerPlugin(const QString &componentName, const QString& displayName, QObject *parent) | ||
61 | : KDevelop::IPlugin(componentName, parent) | 112 | : KDevelop::IPlugin(componentName, parent), m_displayName(displayName) | ||
62 | { | 113 | { | ||
63 | core()->debugController()->initializeUi(); | 114 | core()->debugController()->initializeUi(); | ||
64 | 115 | | |||
65 | setupActions(displayName); | 116 | setupActions(); | ||
66 | setupDBus(); | 117 | setupDBus(); | ||
67 | } | 118 | } | ||
68 | 119 | | |||
69 | void MIDebuggerPlugin::setupActions(const QString& displayName) | 120 | void MIDebuggerPlugin::setupActions() | ||
70 | { | 121 | { | ||
71 | KActionCollection* ac = actionCollection(); | 122 | KActionCollection* ac = actionCollection(); | ||
72 | 123 | | |||
73 | QAction * action = new QAction(this); | 124 | QAction * action = new QAction(this); | ||
74 | action->setIcon(QIcon::fromTheme(QStringLiteral("core"))); | 125 | action->setIcon(QIcon::fromTheme(QStringLiteral("core"))); | ||
75 | action->setText(i18n("Examine Core File with %1", displayName)); | 126 | action->setText(i18n("Examine Core File with %1", m_displayName)); | ||
76 | action->setWhatsThis(i18n("<b>Examine core file</b>" | 127 | action->setWhatsThis(i18n("<b>Examine core file</b>" | ||
77 | "<p>This loads a core file, which is typically created " | 128 | "<p>This loads a core file, which is typically created " | ||
78 | "after the application has crashed, e.g. with a " | 129 | "after the application has crashed, e.g. with a " | ||
79 | "segmentation fault. The core file contains an " | 130 | "segmentation fault. The core file contains an " | ||
80 | "image of the program memory at the time it crashed, " | 131 | "image of the program memory at the time it crashed, " | ||
81 | "allowing you to do a post-mortem analysis.</p>")); | 132 | "allowing you to do a post-mortem analysis.</p>")); | ||
82 | connect(action, &QAction::triggered, this, &MIDebuggerPlugin::slotExamineCore); | 133 | connect(action, &QAction::triggered, this, &MIDebuggerPlugin::slotExamineCore); | ||
83 | ac->addAction(QStringLiteral("debug_core"), action); | 134 | ac->addAction(QStringLiteral("debug_core"), action); | ||
84 | 135 | | |||
85 | #if KF5SysGuard_FOUND | 136 | #if KF5SysGuard_FOUND | ||
86 | action = new QAction(this); | 137 | action = new QAction(this); | ||
87 | action->setIcon(QIcon::fromTheme(QStringLiteral("connect_creating"))); | 138 | action->setIcon(QIcon::fromTheme(QStringLiteral("connect_creating"))); | ||
88 | action->setText(i18n("Attach to Process with %1", displayName)); | 139 | action->setText(i18n("Attach to Process with %1", m_displayName)); | ||
89 | action->setWhatsThis(i18n("<b>Attach to process</b>" | 140 | action->setWhatsThis(i18n("<b>Attach to process</b>" | ||
90 | "<p>Attaches the debugger to a running process.</p>")); | 141 | "<p>Attaches the debugger to a running process.</p>")); | ||
91 | connect(action, &QAction::triggered, this, &MIDebuggerPlugin::slotAttachProcess); | 142 | connect(action, &QAction::triggered, this, &MIDebuggerPlugin::slotAttachProcess); | ||
92 | ac->addAction(QStringLiteral("debug_attach"), action); | 143 | ac->addAction(QStringLiteral("debug_attach"), action); | ||
93 | #endif | 144 | #endif | ||
94 | } | 145 | } | ||
95 | 146 | | |||
96 | void MIDebuggerPlugin::setupDBus() | 147 | void MIDebuggerPlugin::setupDBus() | ||
97 | { | 148 | { | ||
98 | m_drkonqiMap = new QSignalMapper(this); | | |||
99 | connect(m_drkonqiMap, static_cast<void(QSignalMapper::*)(QObject*)>(&QSignalMapper::mapped), | | |||
100 | this, &MIDebuggerPlugin::slotDebugExternalProcess); | | |||
101 | | ||||
102 | QDBusConnectionInterface* dbusInterface = QDBusConnection::sessionBus().interface(); | 149 | QDBusConnectionInterface* dbusInterface = QDBusConnection::sessionBus().interface(); | ||
103 | for (const auto &service : dbusInterface->registeredServiceNames().value()) { | 150 | for (const auto &service : dbusInterface->registeredServiceNames().value()) { | ||
104 | slotDBusServiceRegistered(service); | 151 | slotDBusOwnerChanged(service, QString(), QString('n')); | ||
105 | } | 152 | } | ||
106 | 153 | | |||
107 | QDBusServiceWatcher* watcher = new QDBusServiceWatcher(this); | 154 | connect(dbusInterface, &QDBusConnectionInterface::serviceOwnerChanged, | ||
108 | connect(watcher, &QDBusServiceWatcher::serviceRegistered, | 155 | this, &MIDebuggerPlugin::slotDBusOwnerChanged); | ||
109 | this, &MIDebuggerPlugin::slotDBusServiceRegistered); | | |||
110 | connect(watcher, &QDBusServiceWatcher::serviceUnregistered, | | |||
111 | this, &MIDebuggerPlugin::slotDBusServiceUnregistered); | | |||
112 | } | 156 | } | ||
113 | 157 | | |||
114 | void MIDebuggerPlugin::unload() | 158 | void MIDebuggerPlugin::unload() | ||
115 | { | 159 | { | ||
116 | unloadToolViews(); | 160 | unloadToolViews(); | ||
117 | } | 161 | } | ||
118 | 162 | | |||
119 | MIDebuggerPlugin::~MIDebuggerPlugin() | 163 | MIDebuggerPlugin::~MIDebuggerPlugin() | ||
120 | { | 164 | { | ||
121 | } | 165 | } | ||
122 | 166 | | |||
123 | void MIDebuggerPlugin::slotDBusServiceRegistered(const QString& service) | 167 | void MIDebuggerPlugin::slotDBusOwnerChanged(const QString& service, const QString& oldOwner, const QString& newOwner) | ||
124 | { | 168 | { | ||
125 | if (service.startsWith(QLatin1String("org.kde.drkonqi"))) { | 169 | if (oldOwner.isEmpty() && service.startsWith(drkonqiservice)) { | ||
126 | // New registration | 170 | if (m_drkonqis.contains(service)) { | ||
127 | QDBusInterface* drkonqiInterface = new QDBusInterface(service, QStringLiteral("/krashinfo"), | 171 | return; | ||
128 | QString(), QDBusConnection::sessionBus(), | | |||
129 | this); | | |||
130 | m_drkonqis.insert(service, drkonqiInterface); | | |||
131 | | ||||
132 | connect(drkonqiInterface, SIGNAL(acceptDebuggingApplication()), m_drkonqiMap, SLOT(map())); | | |||
133 | m_drkonqiMap->setMapping(drkonqiInterface, drkonqiInterface); | | |||
134 | | ||||
135 | drkonqiInterface->call(QStringLiteral("registerDebuggingApplication"), i18n("KDevelop")); | | |||
136 | } | | |||
137 | } | 172 | } | ||
173 | // New registration | ||||
174 | const QString name = i18n("KDevelop (%1) - %2", m_displayName, core()->activeSession()->name()); | ||||
175 | auto drkonqiProxy = new DBusProxy(service, name, this); | ||||
176 | m_drkonqis.insert(service, drkonqiProxy); | ||||
177 | connect(drkonqiProxy->interface(), SIGNAL(acceptDebuggingApplication(const QString&)), | ||||
178 | drkonqiProxy, SLOT(debuggerAccepted(const QString&))); | ||||
179 | connect(drkonqiProxy, &DBusProxy::debugProcess, | ||||
180 | this, &MIDebuggerPlugin::slotDebugExternalProcess); | ||||
138 | 181 | | |||
139 | void MIDebuggerPlugin::slotDBusServiceUnregistered(const QString& service) | 182 | drkonqiProxy->interface()->call(QStringLiteral("registerDebuggingApplication"), name); | ||
140 | { | 183 | } else if (newOwner.isEmpty() && service.startsWith(drkonqiservice)) { | ||
141 | if (service.startsWith(QLatin1String("org.kde.drkonqi"))) { | | |||
142 | // Deregistration | 184 | // Deregistration | ||
143 | if (m_drkonqis.contains(service)) | 185 | if (m_drkonqis.contains(service)) { | ||
144 | delete m_drkonqis.take(service); | 186 | auto proxy = m_drkonqis.take(service); | ||
187 | proxy->Invalidate(); | ||||
188 | delete proxy; | ||||
189 | } | ||||
145 | } | 190 | } | ||
146 | } | 191 | } | ||
147 | 192 | | |||
148 | void MIDebuggerPlugin::slotDebugExternalProcess(QObject* interface) | 193 | void MIDebuggerPlugin::slotDebugExternalProcess(DBusProxy* proxy) | ||
149 | { | 194 | { | ||
150 | auto dbusInterface = static_cast<QDBusInterface*>(interface); | 195 | QDBusReply<int> reply = proxy->interface()->call(QStringLiteral("pid")); | ||
151 | | ||||
152 | QDBusReply<int> reply = dbusInterface->call(QStringLiteral("pid")); | | |||
153 | if (reply.isValid()) { | 196 | if (reply.isValid()) { | ||
154 | attachProcess(reply.value()); | 197 | connect(attachProcess(reply.value()), &KJob::result, | ||
155 | QTimer::singleShot(500, this, &MIDebuggerPlugin::slotCloseDrKonqi); | 198 | proxy, &DBusProxy::debuggingFinished); | ||
156 | | ||||
157 | m_drkonqi = m_drkonqis.key(dbusInterface); | | |||
158 | } | 199 | } | ||
159 | 200 | | |||
160 | core()->uiController()->activeMainWindow()->raise(); | 201 | core()->uiController()->activeMainWindow()->raise(); | ||
161 | } | 202 | } | ||
162 | 203 | | |||
163 | void MIDebuggerPlugin::slotCloseDrKonqi() | | |||
164 | { | | |||
165 | if (!m_drkonqi.isEmpty()) { | | |||
166 | QDBusInterface drkonqiInterface(m_drkonqi, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.KApplication")); | | |||
167 | drkonqiInterface.call(QStringLiteral("quit")); | | |||
168 | m_drkonqi.clear(); | | |||
169 | } | | |||
170 | } | | |||
171 | | ||||
172 | ContextMenuExtension MIDebuggerPlugin::contextMenuExtension(Context* context, QWidget* parent) | 204 | ContextMenuExtension MIDebuggerPlugin::contextMenuExtension(Context* context, QWidget* parent) | ||
173 | { | 205 | { | ||
174 | ContextMenuExtension menuExt = IPlugin::contextMenuExtension(context, parent); | 206 | ContextMenuExtension menuExt = IPlugin::contextMenuExtension(context, parent); | ||
175 | 207 | | |||
176 | if (context->type() != KDevelop::Context::EditorContext) | 208 | if (context->type() != KDevelop::Context::EditorContext) | ||
177 | return menuExt; | 209 | return menuExt; | ||
178 | 210 | | |||
179 | EditorContext *econtext = dynamic_cast<EditorContext*>(context); | 211 | EditorContext *econtext = dynamic_cast<EditorContext*>(context); | ||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Line(s) | 262 | { | |||
251 | if (QApplication::applicationPid() == pid) | 283 | if (QApplication::applicationPid() == pid) | ||
252 | KMessageBox::error(core()->uiController()->activeMainWindow(), | 284 | KMessageBox::error(core()->uiController()->activeMainWindow(), | ||
253 | i18n("Not attaching to process %1: cannot attach the debugger to itself.", pid)); | 285 | i18n("Not attaching to process %1: cannot attach the debugger to itself.", pid)); | ||
254 | else | 286 | else | ||
255 | attachProcess(pid); | 287 | attachProcess(pid); | ||
256 | } | 288 | } | ||
257 | #endif | 289 | #endif | ||
258 | 290 | | |||
259 | void MIDebuggerPlugin::attachProcess(int pid) | 291 | MIAttachProcessJob* MIDebuggerPlugin::attachProcess(int pid) | ||
260 | { | 292 | { | ||
261 | MIAttachProcessJob *job = new MIAttachProcessJob(this, pid, core()->runController()); | 293 | MIAttachProcessJob *job = new MIAttachProcessJob(this, pid, core()->runController()); | ||
262 | core()->runController()->registerJob(job); | 294 | core()->runController()->registerJob(job); | ||
263 | // job->start() is called in registerJob | 295 | // job->start() is called in registerJob | ||
296 | | ||||
297 | return job; | ||||
264 | } | 298 | } | ||
265 | 299 | | |||
266 | QString MIDebuggerPlugin::statusName() const | 300 | QString MIDebuggerPlugin::statusName() const | ||
267 | { | 301 | { | ||
268 | return i18n("Debugger"); | 302 | return i18n("Debugger"); | ||
269 | } | 303 | } | ||
270 | 304 | | |||
271 | void MIDebuggerPlugin::showStatusMessage(const QString& msg, int timeout) | 305 | void MIDebuggerPlugin::showStatusMessage(const QString& msg, int timeout) | ||
272 | { | 306 | { | ||
273 | emit showMessage(this, msg, timeout); | 307 | emit showMessage(this, msg, timeout); | ||
274 | } | 308 | } | ||
309 | | ||||
310 | #include "midebuggerplugin.moc" |
m_dbusInterface