Convert from Qt 3 to Qt 4 using qt3to4.
[kdbg.git] / kdbg / dbgmainwnd.cpp
blob8f3cf13cd3339088e8b4949265ece034430ac69a
1 /*
2 * Copyright Johannes Sixt
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
5 */
7 #include <kapplication.h>
8 #include <klocale.h> /* i18n */
9 #include <kmessagebox.h>
10 #include <kconfig.h>
11 #include <kstatusbar.h>
12 #include <kiconloader.h>
13 #include <kstdaccel.h>
14 #include <kstdaction.h>
15 #include <kaction.h>
16 #include <kpopupmenu.h>
17 #include <kfiledialog.h>
18 #include <kprocess.h>
19 #include <kkeydialog.h>
20 #include <kanimwidget.h>
21 #include <kwin.h>
22 #include <q3listbox.h>
23 #include <qfile.h>
24 #include <qfileinfo.h>
25 #include <q3tabdialog.h>
26 #include <q3textstream.h>
27 #include <Q3ValueList>
28 #include <Q3PopupMenu>
29 #include "dbgmainwnd.h"
30 #include "debugger.h"
31 #include "commandids.h"
32 #include "winstack.h"
33 #include "brkpt.h"
34 #include "threadlist.h"
35 #include "memwindow.h"
36 #include "ttywnd.h"
37 #include "watchwindow.h"
38 #include "procattach.h"
39 #include "prefdebugger.h"
40 #include "prefmisc.h"
41 #include "gdbdriver.h"
42 #include "xsldbgdriver.h"
43 #include "mydebug.h"
44 #include <sys/stat.h> /* mknod(2) */
45 #include <unistd.h> /* getpid */
48 static const char defaultTermCmdStr[] = "xterm -name kdbgio -title %T -e sh -c %C";
49 static const char defaultSourceFilter[] = "*.c *.cc *.cpp *.c++ *.C *.CC";
50 static const char defaultHeaderFilter[] = "*.h *.hh *.hpp *.h++";
52 DebuggerMainWnd::DebuggerMainWnd(const char* name) :
53 KMainWindow(0, name),
54 m_debugger(0),
55 #ifdef GDB_TRANSCRIPT
56 m_transcriptFile(GDB_TRANSCRIPT),
57 #endif
58 m_outputTermCmdStr(defaultTermCmdStr),
59 m_outputTermProc(0),
60 m_ttyLevel(-1), /* no tty yet */
61 m_popForeground(false),
62 m_backTimeout(1000),
63 m_tabWidth(0),
64 m_sourceFilter(defaultSourceFilter),
65 m_headerFilter(defaultHeaderFilter),
66 m_statusActive(i18n("active"))
68 m_filesWindow = new WinStack(this);
69 setCentralWidget(m_filesWindow);
71 QDockWidget* dw1 = createDockWidget("Stack", i18n("Stack"));
72 m_btWindow = new Q3ListBox(dw1);
73 dw1->setWidget(m_btWindow);
74 QDockWidget* dw2 = createDockWidget("Locals", i18n("Locals"));
75 m_localVariables = new ExprWnd(dw2, i18n("Variable"));
76 dw2->setWidget(m_localVariables);
77 QDockWidget* dw3 = createDockWidget("Watches", i18n("Watches"));
78 m_watches = new WatchWindow(dw3);
79 dw3->setWidget(m_watches);
80 QDockWidget* dw4 = createDockWidget("Registers", i18n("Registers"));
81 m_registers = new RegisterView(dw4);
82 dw4->setWidget(m_registers);
83 QDockWidget* dw5 = createDockWidget("Breakpoints", i18n("Breakpoints"));
84 m_bpTable = new BreakpointTable(dw5);
85 dw5->setWidget(m_bpTable);
86 QDockWidget* dw6 = createDockWidget("Output", i18n("Output"));
87 m_ttyWindow = new TTYWindow(dw6);
88 dw6->setWidget(m_ttyWindow);
89 QDockWidget* dw7 = createDockWidget("Threads", i18n("Threads"));
90 m_threads = new ThreadList(dw7);
91 dw7->setWidget(m_threads);
92 QDockWidget* dw8 = createDockWidget("Memory", i18n("Memory"));
93 m_memoryWindow = new MemoryWindow(dw8);
94 dw8->setWidget(m_memoryWindow);
96 m_debugger = new KDebugger(this, m_localVariables, m_watches->watchVariables(), m_btWindow);
98 connect(m_debugger, SIGNAL(updateStatusMessage()), SLOT(slotNewStatusMsg()));
99 connect(m_debugger, SIGNAL(updateUI()), SLOT(updateUI()));
100 connect(m_debugger, SIGNAL(breakpointsChanged()), SLOT(updateLineItems()));
101 connect(m_debugger, SIGNAL(debuggerStarting()), SLOT(slotDebuggerStarting()));
102 m_bpTable->setDebugger(m_debugger);
103 m_memoryWindow->setDebugger(m_debugger);
105 setStandardToolBarMenuEnabled(true);
106 initKAction();
107 initToolbar(); // kind of obsolete?
109 connect(m_watches, SIGNAL(addWatch()), SLOT(slotAddWatch()));
110 connect(m_watches, SIGNAL(deleteWatch()), m_debugger, SLOT(slotDeleteWatch()));
111 connect(m_watches, SIGNAL(textDropped(const QString&)), SLOT(slotAddWatch(const QString&)));
113 connect(&m_filesWindow->m_findDlg, SIGNAL(closed()), SLOT(updateUI()));
114 connect(m_filesWindow, SIGNAL(newFileLoaded()),
115 SLOT(slotNewFileLoaded()));
116 connect(m_filesWindow, SIGNAL(toggleBreak(const QString&,int,const DbgAddr&,bool)),
117 this, SLOT(slotToggleBreak(const QString&,int,const DbgAddr&,bool)));
118 connect(m_filesWindow, SIGNAL(enadisBreak(const QString&,int,const DbgAddr&)),
119 this, SLOT(slotEnaDisBreak(const QString&,int,const DbgAddr&)));
120 connect(m_debugger, SIGNAL(activateFileLine(const QString&,int,const DbgAddr&)),
121 m_filesWindow, SLOT(activate(const QString&,int,const DbgAddr&)));
122 connect(m_debugger, SIGNAL(executableUpdated()),
123 m_filesWindow, SLOT(reloadAllFiles()));
124 connect(m_debugger, SIGNAL(updatePC(const QString&,int,const DbgAddr&,int)),
125 m_filesWindow, SLOT(updatePC(const QString&,int,const DbgAddr&,int)));
126 // value popup communication
127 connect(m_filesWindow, SIGNAL(initiateValuePopup(const QString&)),
128 m_debugger, SLOT(slotValuePopup(const QString&)));
129 connect(m_debugger, SIGNAL(valuePopup(const QString&)),
130 m_filesWindow, SLOT(slotShowValueTip(const QString&)));
131 // disassembling
132 connect(m_filesWindow, SIGNAL(disassemble(const QString&, int)),
133 m_debugger, SLOT(slotDisassemble(const QString&, int)));
134 connect(m_debugger, SIGNAL(disassembled(const QString&,int,const std::list<DisassembledCode>&)),
135 m_filesWindow, SLOT(slotDisassembled(const QString&,int,const std::list<DisassembledCode>&)));
136 connect(m_filesWindow, SIGNAL(moveProgramCounter(const QString&,int,const DbgAddr&)),
137 m_debugger, SLOT(setProgramCounter(const QString&,int,const DbgAddr&)));
138 // program stopped
139 connect(m_debugger, SIGNAL(programStopped()), SLOT(slotProgramStopped()));
140 connect(&m_backTimer, SIGNAL(timeout()), SLOT(slotBackTimer()));
141 // tab width
142 connect(this, SIGNAL(setTabWidth(int)), m_filesWindow, SIGNAL(setTabWidth(int)));
144 // connect breakpoint table
145 connect(m_bpTable, SIGNAL(activateFileLine(const QString&,int,const DbgAddr&)),
146 m_filesWindow, SLOT(activate(const QString&,int,const DbgAddr&)));
147 connect(m_debugger, SIGNAL(updateUI()), m_bpTable, SLOT(updateUI()));
148 connect(m_debugger, SIGNAL(breakpointsChanged()), m_bpTable, SLOT(updateBreakList()));
149 connect(m_debugger, SIGNAL(breakpointsChanged()), m_bpTable, SLOT(updateUI()));
151 connect(m_debugger, SIGNAL(registersChanged(const std::list<RegisterInfo>&)),
152 m_registers, SLOT(updateRegisters(const std::list<RegisterInfo>&)));
154 connect(m_debugger, SIGNAL(memoryDumpChanged(const QString&, const std::list<MemoryDump>&)),
155 m_memoryWindow, SLOT(slotNewMemoryDump(const QString&, const std::list<MemoryDump>&)));
156 connect(m_debugger, SIGNAL(saveProgramSpecific(KConfigBase*)),
157 m_memoryWindow, SLOT(saveProgramSpecific(KConfigBase*)));
158 connect(m_debugger, SIGNAL(restoreProgramSpecific(KConfigBase*)),
159 m_memoryWindow, SLOT(restoreProgramSpecific(KConfigBase*)));
161 // thread window
162 connect(m_debugger, SIGNAL(threadsChanged(const std::list<ThreadInfo>&)),
163 m_threads, SLOT(updateThreads(const std::list<ThreadInfo>&)));
164 connect(m_threads, SIGNAL(setThread(int)),
165 m_debugger, SLOT(setThread(int)));
167 // popup menu of the local variables window
168 connect(m_localVariables, SIGNAL(contextMenuRequested(Q3ListViewItem*, const QPoint&, int)),
169 this, SLOT(slotLocalsPopup(Q3ListViewItem*, const QPoint&)));
171 restoreSettings(kapp->config());
173 updateUI();
174 m_bpTable->updateUI();
177 DebuggerMainWnd::~DebuggerMainWnd()
179 saveSettings(kapp->config());
180 // must delete m_debugger early since it references our windows
181 delete m_debugger;
182 m_debugger = 0;
184 delete m_memoryWindow;
185 delete m_threads;
186 delete m_ttyWindow;
187 delete m_bpTable;
188 delete m_registers;
189 delete m_watches;
190 delete m_localVariables;
191 delete m_btWindow;
192 delete m_filesWindow;
194 // if the output window is open, close it
195 if (m_outputTermProc != 0) {
196 m_outputTermProc->disconnect(); /* ignore signals */
197 m_outputTermProc->kill();
198 shutdownTermWindow();
202 QDockWidget* DebuggerMainWnd::createDockWidget(const char* name, const QString& title)
204 QDockWidget* w = new QDockWidget(this, name);
205 w->setCaption(title);
206 // view menu changes when docking state changes
207 connect(w, SIGNAL(visibilityChanged(bool)), SLOT(updateUI()));
208 return w;
211 KAction* DebuggerMainWnd::createAction(const QString& text, const char* icon,
212 int shortcut, const QObject* receiver,
213 const char* slot, const char* name)
215 KAction* a = new KAction(text, icon, shortcut, receiver, slot,
216 actionCollection(), name);
217 return a;
220 KAction* DebuggerMainWnd::createAction(const QString& text,
221 int shortcut, const QObject* receiver,
222 const char* slot, const char* name)
224 KAction* a = new KAction(text, shortcut, receiver, slot,
225 actionCollection(), name);
226 return a;
230 void DebuggerMainWnd::initKAction()
232 // file menu
233 KAction* open = KStdAction::open(this, SLOT(slotFileOpen()),
234 actionCollection());
235 open->setText(i18n("&Open Source..."));
236 m_closeAction = KStdAction::close(m_filesWindow, SLOT(slotClose()), actionCollection());
237 m_reloadAction = createAction(i18n("&Reload Source"), "reload", 0,
238 m_filesWindow, SLOT(slotFileReload()), "file_reload");
239 m_fileExecAction = createAction(i18n("&Executable..."), "execopen", 0,
240 this, SLOT(slotFileExe()), "file_executable");
241 m_recentExecAction = new KRecentFilesAction(i18n("Recent E&xecutables"), 0,
242 this, SLOT(slotRecentExec(const KURL&)),
243 actionCollection(), "file_executable_recent");
244 m_coreDumpAction = createAction(i18n("&Core dump..."), 0,
245 this, SLOT(slotFileCore()), "file_core_dump");
246 KStdAction::quit(kapp, SLOT(closeAllWindows()), actionCollection());
248 // settings menu
249 m_settingsAction = createAction(i18n("This &Program..."), 0,
250 this, SLOT(slotFileProgSettings()), "settings_program");
251 createAction(i18n("&Global Options..."), 0,
252 this, SLOT(slotFileGlobalSettings()), "settings_global");
253 KStdAction::keyBindings(this, SLOT(slotConfigureKeys()), actionCollection());
254 KStdAction::showStatusbar(this, SLOT(slotViewStatusbar()), actionCollection());
256 // view menu
257 m_findAction = new KToggleAction(i18n("&Find"), "find", CTRL+Key_F, m_filesWindow,
258 SLOT(slotViewFind()), actionCollection(),
259 "view_find");
260 (void)KStdAction::findNext(m_filesWindow, SLOT(slotFindForward()), actionCollection(), "view_findnext");
261 (void)KStdAction::findPrev(m_filesWindow, SLOT(slotFindBackward()), actionCollection(), "view_findprev");
263 i18n("Source &code");
264 struct { QString text; QWidget* w; QString id; KToggleAction** act; } dw[] = {
265 { i18n("Stac&k"), m_btWindow, "view_stack", &m_btWindowAction },
266 { i18n("&Locals"), m_localVariables, "view_locals", &m_localVariablesAction },
267 { i18n("&Watched expressions"), m_watches, "view_watched_expressions", &m_watchesAction },
268 { i18n("&Registers"), m_registers, "view_registers", &m_registersAction },
269 { i18n("&Breakpoints"), m_bpTable, "view_breakpoints", &m_bpTableAction },
270 { i18n("T&hreads"), m_threads, "view_threads", &m_threadsAction },
271 { i18n("&Output"), m_ttyWindow, "view_output", &m_ttyWindowAction },
272 { i18n("&Memory"), m_memoryWindow, "view_memory", &m_memoryWindowAction }
274 for (unsigned i = 0; i < sizeof(dw)/sizeof(dw[0]); i++) {
275 QDockWidget* d = dockParent(dw[i].w);
276 *dw[i].act = new KToggleAction(dw[i].text, 0, d, SLOT(show()),
277 actionCollection(), dw[i].id);
280 // execution menu
281 m_runAction = createAction(i18n("&Run"), "pgmrun", Qt::Key_F5,
282 m_debugger, SLOT(programRun()), "exec_run");
283 connect(m_runAction, SIGNAL(activated()), this, SLOT(intoBackground()));
284 m_stepIntoAction = createAction(i18n("Step &into"), "pgmstep", Qt::Key_F8,
285 m_debugger, SLOT(programStep()), "exec_step_into");
286 connect(m_stepIntoAction, SIGNAL(activated()), this, SLOT(intoBackground()));
287 m_stepOverAction = createAction(i18n("Step &over"), "pgmnext", Qt::Key_F10,
288 m_debugger, SLOT(programNext()), "exec_step_over");
289 connect(m_stepOverAction, SIGNAL(activated()), this, SLOT(intoBackground()));
290 m_stepOutAction = createAction(i18n("Step o&ut"), "pgmfinish", Qt::Key_F6,
291 m_debugger, SLOT(programFinish()), "exec_step_out");
292 connect(m_stepOutAction, SIGNAL(activated()), this, SLOT(intoBackground()));
293 m_toCursorAction = createAction(i18n("Run to &cursor"), Qt::Key_F7,
294 this, SLOT(slotExecUntil()), "exec_run_to_cursor");
295 connect(m_toCursorAction, SIGNAL(activated()), this, SLOT(intoBackground()));
296 m_stepIntoIAction = createAction(i18n("Step i&nto by instruction"), "pgmstepi", Qt::SHIFT+Qt::Key_F8,
297 m_debugger, SLOT(programStepi()), "exec_step_into_by_insn");
298 connect(m_stepIntoIAction, SIGNAL(activated()), this, SLOT(intoBackground()));
299 m_stepOverIAction = createAction(i18n("Step o&ver by instruction"), "pgmnexti", Qt::SHIFT+Qt::Key_F10,
300 m_debugger, SLOT(programNexti()), "exec_step_over_by_insn");
301 connect(m_stepOverIAction, SIGNAL(activated()), this, SLOT(intoBackground()));
302 m_execMovePCAction = createAction(i18n("&Program counter to current line"), 0,
303 m_filesWindow, SLOT(slotMoveProgramCounter()), "exec_movepc");
304 m_breakAction = createAction(i18n("&Break"), 0,
305 m_debugger, SLOT(programBreak()), "exec_break");
306 m_killAction = createAction(i18n("&Kill"), 0,
307 m_debugger, SLOT(programKill()), "exec_kill");
308 m_restartAction = createAction(i18n("Re&start"), 0,
309 m_debugger, SLOT(programRunAgain()), "exec_restart");
310 m_attachAction = createAction(i18n("A&ttach..."), 0,
311 this, SLOT(slotExecAttach()), "exec_attach");
312 m_argumentsAction = createAction(i18n("&Arguments..."), 0,
313 this, SLOT(slotExecArgs()), "exec_arguments");
315 // breakpoint menu
316 m_bpSetAction = createAction(i18n("Set/Clear &breakpoint"), "brkpt", Qt::Key_F9,
317 m_filesWindow, SLOT(slotBrkptSet()), "breakpoint_set");
318 m_bpSetTempAction = createAction(i18n("Set &temporary breakpoint"), Qt::SHIFT+Qt::Key_F9,
319 m_filesWindow, SLOT(slotBrkptSetTemp()), "breakpoint_set_temporary");
320 m_bpEnableAction = createAction(i18n("&Enable/Disable breakpoint"), Qt::CTRL+Qt::Key_F9,
321 m_filesWindow, SLOT(slotBrkptEnable()), "breakpoint_enable");
323 // only in popup menus
324 createAction(i18n("Watch Expression"), 0,
325 this, SLOT(slotLocalsToWatch()), "watch_expression");
326 m_editValueAction = createAction(i18n("Edit Value"), Qt::Key_F2,
327 this, SLOT(slotEditValue()), "edit_value");
329 // all actions force an UI update
330 Q3ValueList<KAction*> actions = actionCollection()->actions();
331 Q3ValueList<KAction*>::Iterator it = actions.begin();
332 for (; it != actions.end(); ++it) {
333 connect(*it, SIGNAL(activated()), this, SLOT(updateUI()));
336 createGUI("kdbgui.rc");
339 void DebuggerMainWnd::initToolbar()
341 KToolBar* toolbar = toolBar("mainToolBar");
342 toolbar->insertAnimatedWidget(ID_STATUS_BUSY,
343 m_breakAction, SLOT(activate()), "pulse", -1);
344 toolbar->alignItemRight(ID_STATUS_BUSY, true);
345 m_animRunning = false;
347 KStatusBar* statusbar = statusBar();
348 statusbar->insertItem(m_statusActive, ID_STATUS_ACTIVE);
349 m_lastActiveStatusText = m_statusActive;
350 statusbar->insertItem("", ID_STATUS_MSG); /* message pane */
352 // reserve some translations
353 i18n("Restart");
354 i18n("Core dump");
357 bool DebuggerMainWnd::queryClose()
359 if (m_debugger != 0) {
360 m_debugger->shutdown();
362 return true;
366 // instance properties
367 void DebuggerMainWnd::saveProperties(KConfig* config)
369 // session management
370 QString executable = "";
371 if (m_debugger != 0) {
372 executable = m_debugger->executable();
374 config->writeEntry("executable", executable);
377 void DebuggerMainWnd::readProperties(KConfig* config)
379 // session management
380 QString execName = config->readEntry("executable");
382 TRACE("readProperties: executable=" + execName);
383 if (!execName.isEmpty()) {
384 debugProgram(execName, "");
388 static const char WindowGroup[] = "Windows";
389 static const char RecentExecutables[] = "RecentExecutables";
390 static const char LastSession[] = "LastSession";
391 static const char OutputWindowGroup[] = "OutputWindow";
392 static const char TermCmdStr[] = "TermCmdStr";
393 static const char KeepScript[] = "KeepScript";
394 static const char DebuggerGroup[] = "Debugger";
395 static const char DebuggerCmdStr[] = "DebuggerCmdStr";
396 static const char PreferencesGroup[] = "Preferences";
397 static const char PopForeground[] = "PopForeground";
398 static const char BackTimeout[] = "BackTimeout";
399 static const char TabWidth[] = "TabWidth";
400 static const char SourceFileFilter[] = "SourceFileFilter";
401 static const char HeaderFileFilter[] = "HeaderFileFilter";
403 void DebuggerMainWnd::saveSettings(KConfig* config)
405 KConfigGroupSaver g(config, WindowGroup);
407 QString layout;
409 Q3TextStream stream(&layout, QIODevice::WriteOnly);
410 stream << *this;
412 config->writeEntry("Layout", layout);
414 m_recentExecAction->saveEntries(config, RecentExecutables);
416 KConfigGroupSaver g2(config, LastSession);
417 config->writeEntry("Width0Locals", m_localVariables->columnWidth(0));
418 config->writeEntry("Width0Watches", m_watches->columnWidth(0));
420 if (m_debugger != 0) {
421 m_debugger->saveSettings(config);
424 KConfigGroupSaver g3(config, OutputWindowGroup);
425 config->writeEntry(TermCmdStr, m_outputTermCmdStr);
427 config->setGroup(DebuggerGroup);
428 config->writeEntry(DebuggerCmdStr, m_debuggerCmdStr);
430 config->setGroup(PreferencesGroup);
431 config->writeEntry(PopForeground, m_popForeground);
432 config->writeEntry(BackTimeout, m_backTimeout);
433 config->writeEntry(TabWidth, m_tabWidth);
434 config->writeEntry(SourceFileFilter, m_sourceFilter);
435 config->writeEntry(HeaderFileFilter, m_headerFilter);
438 void DebuggerMainWnd::restoreSettings(KConfig* config)
440 KConfigGroupSaver g(config, WindowGroup);
442 QString layout = config->readEntry("Layout");
444 Q3TextStream stream(&layout, QIODevice::ReadOnly);
445 stream >> *this;
448 m_recentExecAction->loadEntries(config, RecentExecutables);
450 KConfigGroupSaver g2(config, LastSession);
451 int w;
452 w = config->readNumEntry("Width0Locals", -1);
453 if (w >= 0 && w < 30000)
454 m_localVariables->setColumnWidth(0, w);
455 w = config->readNumEntry("Width0Watches", -1);
456 if (w >= 0 && w < 30000)
457 m_watches->setColumnWidth(0, w);
459 if (m_debugger != 0) {
460 m_debugger->restoreSettings(config);
463 KConfigGroupSaver g3(config, OutputWindowGroup);
465 * For debugging and emergency purposes, let the config file override
466 * the shell script that is used to keep the output window open. This
467 * string must have EXACTLY 1 %s sequence in it.
469 setTerminalCmd(config->readEntry(TermCmdStr, defaultTermCmdStr));
470 m_outputTermKeepScript = config->readEntry(KeepScript);
472 config->setGroup(DebuggerGroup);
473 setDebuggerCmdStr(config->readEntry(DebuggerCmdStr));
475 config->setGroup(PreferencesGroup);
476 m_popForeground = config->readBoolEntry(PopForeground, false);
477 m_backTimeout = config->readNumEntry(BackTimeout, 1000);
478 m_tabWidth = config->readNumEntry(TabWidth, 0);
479 m_sourceFilter = config->readEntry(SourceFileFilter, m_sourceFilter);
480 m_headerFilter = config->readEntry(HeaderFileFilter, m_headerFilter);
482 emit setTabWidth(m_tabWidth);
485 void DebuggerMainWnd::updateUI()
487 m_findAction->setChecked(m_filesWindow->m_findDlg.isVisible());
488 m_findAction->setEnabled(m_filesWindow->hasWindows());
489 m_bpSetAction->setEnabled(m_debugger->canChangeBreakpoints());
490 m_bpSetTempAction->setEnabled(m_debugger->canChangeBreakpoints());
491 m_bpEnableAction->setEnabled(m_debugger->canChangeBreakpoints());
492 m_bpTableAction->setChecked(isDockVisible(m_bpTable));
493 m_btWindowAction->setChecked(isDockVisible(m_btWindow));
494 m_localVariablesAction->setChecked(isDockVisible(m_localVariables));
495 m_watchesAction->setChecked(isDockVisible(m_watches));
496 m_registersAction->setChecked(isDockVisible(m_registers));
497 m_threadsAction->setChecked(isDockVisible(m_threads));
498 m_memoryWindowAction->setChecked(isDockVisible(m_memoryWindow));
499 m_ttyWindowAction->setChecked(isDockVisible(m_ttyWindow));
501 m_fileExecAction->setEnabled(m_debugger->isIdle());
502 m_settingsAction->setEnabled(m_debugger->haveExecutable());
503 m_coreDumpAction->setEnabled(m_debugger->canStart());
504 m_closeAction->setEnabled(m_filesWindow->hasWindows());
505 m_reloadAction->setEnabled(m_filesWindow->hasWindows());
506 m_stepIntoAction->setEnabled(m_debugger->canSingleStep());
507 m_stepIntoIAction->setEnabled(m_debugger->canSingleStep());
508 m_stepOverAction->setEnabled(m_debugger->canSingleStep());
509 m_stepOverIAction->setEnabled(m_debugger->canSingleStep());
510 m_stepOutAction->setEnabled(m_debugger->canSingleStep());
511 m_toCursorAction->setEnabled(m_debugger->canSingleStep());
512 m_execMovePCAction->setEnabled(m_debugger->canSingleStep());
513 m_restartAction->setEnabled(m_debugger->canSingleStep());
514 m_attachAction->setEnabled(m_debugger->isReady());
515 m_runAction->setEnabled(m_debugger->canStart() || m_debugger->canSingleStep());
516 m_killAction->setEnabled(m_debugger->haveExecutable() && m_debugger->isProgramActive());
517 m_breakAction->setEnabled(m_debugger->isProgramRunning());
518 m_argumentsAction->setEnabled(m_debugger->haveExecutable());
519 m_editValueAction->setEnabled(m_debugger->canSingleStep());
521 // animation
522 KAnimWidget* w = toolBar("mainToolBar")->animatedWidget(ID_STATUS_BUSY);
523 if (m_debugger->isIdle()) {
524 if (m_animRunning) {
525 w->stop();
526 m_animRunning = false;
528 } else {
529 if (!m_animRunning) {
530 w->start();
531 m_animRunning = true;
535 // update statusbar
536 QString newStatus;
537 if (m_debugger->isProgramActive())
538 newStatus = m_statusActive;
539 if (newStatus != m_lastActiveStatusText) {
540 statusBar()->changeItem(newStatus, ID_STATUS_ACTIVE);
541 m_lastActiveStatusText = newStatus;
545 void DebuggerMainWnd::updateLineItems()
547 m_filesWindow->updateLineItems(m_debugger);
550 void DebuggerMainWnd::slotAddWatch()
552 if (m_debugger != 0) {
553 QString t = m_watches->watchText();
554 m_debugger->addWatch(t);
558 void DebuggerMainWnd::slotAddWatch(const QString& text)
560 if (m_debugger != 0) {
561 m_debugger->addWatch(text);
565 void DebuggerMainWnd::slotNewFileLoaded()
567 // updates program counter in the new file
568 if (m_debugger != 0)
569 m_filesWindow->updateLineItems(m_debugger);
572 QDockWidget* DebuggerMainWnd::dockParent(QWidget* w)
574 while ((w = w->parentWidget()) != 0) {
575 if (w->isA("QDockWindow"))
576 return static_cast<QDockWidget*>(w);
578 return 0;
581 bool DebuggerMainWnd::isDockVisible(QWidget* w)
583 QDockWidget* d = dockParent(w);
584 return d != 0 && d->isVisible();
587 bool DebuggerMainWnd::debugProgram(const QString& exe, const QString& lang)
589 // check the file name
590 QFileInfo fi(exe);
592 bool success = fi.isFile();
593 if (!success)
595 QString msg = i18n("`%1' is not a file or does not exist");
596 KMessageBox::sorry(this, msg.arg(exe));
598 else
600 success = startDriver(fi.absFilePath(), lang);
603 if (success)
605 m_recentExecAction->addURL(KURL(fi.absFilePath()));
607 // keep the directory
608 m_lastDirectory = fi.dirPath(true);
609 m_filesWindow->setExtraDirectory(m_lastDirectory);
611 // set caption to basename part of executable
612 QString caption = fi.fileName();
613 setCaption(caption);
615 else
617 m_recentExecAction->removeURL(KURL(fi.absFilePath()));
620 return success;
623 static const char GeneralGroup[] = "General";
625 bool DebuggerMainWnd::startDriver(const QString& executable, QString lang)
627 assert(m_debugger != 0);
629 TRACE(QString("trying language '%1'...").arg(lang));
630 DebuggerDriver* driver = driverFromLang(lang);
632 if (driver == 0)
634 // see if there is a language in the per-program config file
635 QString configName = m_debugger->getConfigForExe(executable);
636 if (QFile::exists(configName))
638 KSimpleConfig c(configName, true); // read-only
639 c.setGroup(GeneralGroup);
641 // Using "GDB" as default here is for backwards compatibility:
642 // The config file exists but doesn't have an entry,
643 // so it must have been created by an old version of KDbg
644 // that had only the GDB driver.
645 lang = c.readEntry(KDebugger::DriverNameEntry, "GDB");
647 TRACE(QString("...bad, trying config driver %1...").arg(lang));
648 driver = driverFromLang(lang);
652 if (driver == 0)
654 QString name = driverNameFromFile(executable);
656 TRACE(QString("...no luck, trying %1 derived"
657 " from file contents").arg(name));
658 driver = driverFromLang(name);
660 if (driver == 0)
662 // oops
663 QString msg = i18n("Don't know how to debug language `%1'");
664 KMessageBox::sorry(this, msg.arg(lang));
665 return false;
668 driver->setLogFileName(m_transcriptFile);
670 bool success = m_debugger->debugProgram(executable, driver);
672 if (!success)
674 delete driver;
676 QString msg = i18n("Could not start the debugger process.\n"
677 "Please shut down KDbg and resolve the problem.");
678 KMessageBox::sorry(this, msg);
681 return success;
684 // derive driver from language
685 DebuggerDriver* DebuggerMainWnd::driverFromLang(QString lang)
687 // lang is needed in all lowercase
688 lang = lang.lower();
690 // The following table relates languages and debugger drivers
691 static const struct L {
692 const char* shortest; // abbreviated to this is still unique
693 const char* full; // full name of language
694 int driver;
695 } langs[] = {
696 { "c", "c++", 1 },
697 { "f", "fortran", 1 },
698 { "p", "python", 3 },
699 { "x", "xslt", 2 },
700 // the following are actually driver names
701 { "gdb", "gdb", 1 },
702 { "xsldbg", "xsldbg", 2 },
704 const int N = sizeof(langs)/sizeof(langs[0]);
706 // lookup the language name
707 int driverID = 0;
708 for (int i = 0; i < N; i++)
710 const L& l = langs[i];
712 // shortest must match
713 if (!lang.startsWith(l.shortest))
714 continue;
716 // lang must not be longer than the full name, and it must match
717 if (QString(l.full).startsWith(lang))
719 driverID = l.driver;
720 break;
723 DebuggerDriver* driver = 0;
724 switch (driverID) {
725 case 1:
727 GdbDriver* gdb = new GdbDriver;
728 gdb->setDefaultInvocation(m_debuggerCmdStr);
729 driver = gdb;
731 break;
732 case 2:
733 driver = new XsldbgDriver;
734 break;
735 default:
736 // unknown language
737 break;
739 return driver;
743 * Try to guess the language to use from the contents of the file.
745 QString DebuggerMainWnd::driverNameFromFile(const QString& exe)
747 /* Inprecise but simple test to see if file is in XSLT language */
748 if (exe.right(4).lower() == ".xsl")
749 return "XSLT";
751 return "GDB";
754 void DebuggerMainWnd::setCoreFile(const QString& corefile)
756 assert(m_debugger != 0);
757 m_debugger->useCoreFile(corefile, true);
760 void DebuggerMainWnd::setRemoteDevice(const QString& remoteDevice)
762 if (m_debugger != 0) {
763 m_debugger->setRemoteDevice(remoteDevice);
767 void DebuggerMainWnd::overrideProgramArguments(const QString& args)
769 assert(m_debugger != 0);
770 m_debugger->overrideProgramArguments(args);
773 void DebuggerMainWnd::setTranscript(const QString& name)
775 m_transcriptFile = name;
776 if (m_debugger != 0 && m_debugger->driver() != 0)
777 m_debugger->driver()->setLogFileName(m_transcriptFile);
780 void DebuggerMainWnd::setAttachPid(const QString& pid)
782 assert(m_debugger != 0);
783 m_debugger->setAttachPid(pid);
786 void DebuggerMainWnd::slotNewStatusMsg()
788 QString msg = m_debugger->statusMessage();
789 statusBar()->changeItem(msg, ID_STATUS_MSG);
792 void DebuggerMainWnd::slotFileGlobalSettings()
794 int oldTabWidth = m_tabWidth;
796 Q3TabDialog dlg(this, "global_options", true);
797 QString title = kapp->caption();
798 title += i18n(": Global options");
799 dlg.setCaption(title);
800 dlg.setCancelButton(i18n("Cancel"));
801 dlg.setOKButton(i18n("OK"));
803 PrefDebugger prefDebugger(&dlg);
804 prefDebugger.setDebuggerCmd(m_debuggerCmdStr.isEmpty() ?
805 GdbDriver::defaultGdb() : m_debuggerCmdStr);
806 prefDebugger.setTerminal(m_outputTermCmdStr);
808 PrefMisc prefMisc(&dlg);
809 prefMisc.setPopIntoForeground(m_popForeground);
810 prefMisc.setBackTimeout(m_backTimeout);
811 prefMisc.setTabWidth(m_tabWidth);
812 prefMisc.setSourceFilter(m_sourceFilter);
813 prefMisc.setHeaderFilter(m_headerFilter);
815 dlg.addTab(&prefDebugger, i18n("&Debugger"));
816 dlg.addTab(&prefMisc, i18n("&Miscellaneous"));
817 if (dlg.exec() == QDialog::Accepted)
819 setDebuggerCmdStr(prefDebugger.debuggerCmd());
820 setTerminalCmd(prefDebugger.terminal());
821 m_popForeground = prefMisc.popIntoForeground();
822 m_backTimeout = prefMisc.backTimeout();
823 m_tabWidth = prefMisc.tabWidth();
824 m_sourceFilter = prefMisc.sourceFilter();
825 if (m_sourceFilter.isEmpty())
826 m_sourceFilter = defaultSourceFilter;
827 m_headerFilter = prefMisc.headerFilter();
828 if (m_headerFilter.isEmpty())
829 m_headerFilter = defaultHeaderFilter;
832 if (m_tabWidth != oldTabWidth) {
833 emit setTabWidth(m_tabWidth);
837 void DebuggerMainWnd::setTerminalCmd(const QString& cmd)
839 m_outputTermCmdStr = cmd;
840 // revert to default if empty
841 if (m_outputTermCmdStr.isEmpty()) {
842 m_outputTermCmdStr = defaultTermCmdStr;
846 void DebuggerMainWnd::setDebuggerCmdStr(const QString& cmd)
848 m_debuggerCmdStr = cmd;
849 // make empty if it is the default
850 if (m_debuggerCmdStr == GdbDriver::defaultGdb()) {
851 m_debuggerCmdStr = QString();
855 void DebuggerMainWnd::slotDebuggerStarting()
857 if (m_debugger == 0) /* paranoia check */
858 return;
860 if (m_ttyLevel == m_debugger->ttyLevel())
861 return;
863 // shut down terminal emulations we will not need
864 switch (m_ttyLevel) {
865 case KDebugger::ttySimpleOutputOnly:
866 m_ttyWindow->deactivate();
867 break;
868 case KDebugger::ttyFull:
869 if (m_outputTermProc != 0) {
870 m_outputTermProc->kill();
871 // will be deleted in slot
873 break;
874 default: break;
877 m_ttyLevel = m_debugger->ttyLevel();
879 QString ttyName;
880 switch (m_ttyLevel) {
881 case KDebugger::ttySimpleOutputOnly:
882 ttyName = m_ttyWindow->activate();
883 break;
884 case KDebugger::ttyFull:
885 if (m_outputTermProc == 0) {
886 // create an output window
887 ttyName = createOutputWindow();
888 TRACE(ttyName.isEmpty() ?
889 "createOuputWindow failed" : "successfully created output window");
891 break;
892 default: break;
895 m_debugger->setTerminal(ttyName);
898 void DebuggerMainWnd::slotToggleBreak(const QString& fileName, int lineNo,
899 const DbgAddr& address, bool temp)
901 // lineNo is zero-based
902 if (m_debugger != 0) {
903 m_debugger->setBreakpoint(fileName, lineNo, address, temp);
907 void DebuggerMainWnd::slotEnaDisBreak(const QString& fileName, int lineNo,
908 const DbgAddr& address)
910 // lineNo is zero-based
911 if (m_debugger != 0) {
912 m_debugger->enableDisableBreakpoint(fileName, lineNo, address);
916 QString DebuggerMainWnd::createOutputWindow()
918 // create a name for a fifo
919 QString fifoName;
920 fifoName.sprintf("/tmp/kdbgttywin%05d", ::getpid());
922 // create a fifo that will pass in the tty name
923 QFile::remove(fifoName); // remove remnants
924 #ifdef HAVE_MKFIFO
925 if (::mkfifo(fifoName.local8Bit(), S_IRUSR|S_IWUSR) < 0) {
926 // failed
927 TRACE("mkfifo " + fifoName + " failed");
928 return QString();
930 #else
931 if (::mknod(fifoName.local8Bit(), S_IFIFO | S_IRUSR|S_IWUSR, 0) < 0) {
932 // failed
933 TRACE("mknod " + fifoName + " failed");
934 return QString();
936 #endif
938 m_outputTermProc = new KProcess;
941 * Spawn an xterm that in turn runs a shell script that passes us
942 * back the terminal name and then only sits and waits.
944 static const char shellScriptFmt[] =
945 "tty>%s;"
946 "trap \"\" INT QUIT TSTP;" /* ignore various signals */
947 "exec<&-;exec>&-;" /* close stdin and stdout */
948 "while :;do sleep 3600;done";
949 // let config file override this script
950 QString shellScript;
951 if (!m_outputTermKeepScript.isEmpty()) {
952 shellScript = m_outputTermKeepScript;
953 } else {
954 shellScript = shellScriptFmt;
957 shellScript.replace("%s", fifoName);
958 TRACE("output window script is " + shellScript);
960 QString title = kapp->caption();
961 title += i18n(": Program output");
963 // parse the command line specified in the preferences
964 QStringList cmdParts = QStringList::split(' ', m_outputTermCmdStr);
967 * Build the argv array. Thereby substitute special sequences:
969 struct {
970 char seq[4];
971 QString replace;
972 } substitute[] = {
973 { "%T", title },
974 { "%C", shellScript }
977 for (QStringList::iterator i = cmdParts.begin(); i != cmdParts.end(); ++i)
979 QString& str = *i;
980 for (int j = sizeof(substitute)/sizeof(substitute[0])-1; j >= 0; j--) {
981 int pos = str.find(substitute[j].seq);
982 if (pos >= 0) {
983 str.replace(pos, 2, substitute[j].replace);
984 break; /* substitute only one sequence */
987 *m_outputTermProc << str;
990 QString tty;
992 if (m_outputTermProc->start())
994 // read the ttyname from the fifo
995 QFile f(fifoName);
996 if (f.open(QIODevice::ReadOnly))
998 QByteArray t = f.readAll();
999 tty = QString::fromLocal8Bit(t, t.size());
1000 f.close();
1002 f.remove();
1004 // remove whitespace
1005 tty = tty.stripWhiteSpace();
1006 TRACE("tty=" + tty);
1008 connect(m_outputTermProc, SIGNAL(processExited(KProcess*)),
1009 SLOT(slotTermEmuExited()));
1011 else
1013 // error, could not start xterm
1014 TRACE("fork failed for fifo " + fifoName);
1015 QFile::remove(fifoName);
1016 shutdownTermWindow();
1019 return tty;
1022 void DebuggerMainWnd::slotTermEmuExited()
1024 shutdownTermWindow();
1027 void DebuggerMainWnd::shutdownTermWindow()
1029 delete m_outputTermProc;
1030 m_outputTermProc = 0;
1033 void DebuggerMainWnd::slotProgramStopped()
1035 // when the program stopped, move the window to the foreground
1036 if (m_popForeground) {
1037 // unfortunately, this requires quite some force to work :-(
1038 KWin::raiseWindow(winId());
1039 KWin::forceActiveWindow(winId());
1041 m_backTimer.stop();
1044 void DebuggerMainWnd::intoBackground()
1046 if (m_popForeground) {
1047 m_backTimer.start(m_backTimeout, true); /* single-shot */
1051 void DebuggerMainWnd::slotBackTimer()
1053 lower();
1056 void DebuggerMainWnd::slotRecentExec(const KURL& url)
1058 QString exe = url.path();
1059 debugProgram(exe, "");
1062 QString DebuggerMainWnd::makeSourceFilter()
1064 QString f;
1065 f = m_sourceFilter + " " + m_headerFilter + i18n("|All source files\n");
1066 f += m_sourceFilter + i18n("|Source files\n");
1067 f += m_headerFilter + i18n("|Header files\n");
1068 f += i18n("*|All files");
1069 return f;
1073 * Pop up the context menu in the locals window
1075 void DebuggerMainWnd::slotLocalsPopup(Q3ListViewItem*, const QPoint& pt)
1077 Q3PopupMenu* popup =
1078 static_cast<Q3PopupMenu*>(factory()->container("popup_locals", this));
1079 if (popup == 0) {
1080 return;
1082 if (popup->isVisible()) {
1083 popup->hide();
1084 } else {
1085 popup->popup(pt);
1090 * Copies the currently selected item to the watch window.
1092 void DebuggerMainWnd::slotLocalsToWatch()
1094 VarTree* item = m_localVariables->selectedItem();
1096 if (item != 0 && m_debugger != 0) {
1097 QString text = item->computeExpr();
1098 m_debugger->addWatch(text);
1103 * Starts editing a value in a value display
1105 void DebuggerMainWnd::slotEditValue()
1107 // does one of the value trees have the focus
1108 QWidget* f = kapp->focusWidget();
1109 ExprWnd* wnd;
1110 if (f == m_localVariables) {
1111 wnd = m_localVariables;
1112 } else if (f == m_watches->watchVariables()) {
1113 wnd = m_watches->watchVariables();
1114 } else {
1115 return;
1118 if (m_localVariables->isEditing() ||
1119 m_watches->watchVariables()->isEditing())
1121 return; /* don't edit twice */
1124 VarTree* expr = wnd->currentItem();
1125 if (expr != 0 && m_debugger != 0 && m_debugger->canSingleStep())
1127 TRACE("edit value");
1128 // determine the text to edit
1129 QString text = m_debugger->driver()->editableValue(expr);
1130 wnd->editValue(expr, text);
1134 // helper that gets a file name (it only differs in the caption of the dialog)
1135 static QString myGetFileName(QString caption,
1136 QString dir, QString filter,
1137 QWidget* parent)
1139 QString filename;
1140 KFileDialog dlg(dir, filter, parent, "filedialog", true);
1142 dlg.setCaption(caption);
1144 if (dlg.exec() == QDialog::Accepted)
1145 filename = dlg.selectedFile();
1147 return filename;
1150 void DebuggerMainWnd::slotFileOpen()
1152 // start browsing in the active file's directory
1153 // fall back to last used directory (executable)
1154 QString dir = m_lastDirectory;
1155 QString fileName = m_filesWindow->activeFileName();
1156 if (!fileName.isEmpty()) {
1157 QFileInfo fi(fileName);
1158 dir = fi.dirPath();
1161 fileName = myGetFileName(i18n("Open"),
1162 dir,
1163 makeSourceFilter(), this);
1165 if (!fileName.isEmpty())
1167 QFileInfo fi(fileName);
1168 m_lastDirectory = fi.dirPath();
1169 m_filesWindow->setExtraDirectory(m_lastDirectory);
1170 m_filesWindow->activateFile(fileName);
1174 void DebuggerMainWnd::slotFileExe()
1176 if (m_debugger->isIdle())
1178 // open a new executable
1179 QString executable = myGetFileName(i18n("Select the executable to debug"),
1180 m_lastDirectory, 0, this);
1181 if (executable.isEmpty())
1182 return;
1184 debugProgram(executable, "");
1188 void DebuggerMainWnd::slotFileCore()
1190 if (m_debugger->canStart())
1192 QString corefile = myGetFileName(i18n("Select core dump"),
1193 m_lastDirectory, 0, this);
1194 if (!corefile.isEmpty()) {
1195 m_debugger->useCoreFile(corefile, false);
1200 void DebuggerMainWnd::slotFileProgSettings()
1202 if (m_debugger != 0) {
1203 m_debugger->programSettings(this);
1207 void DebuggerMainWnd::slotViewStatusbar()
1209 if (statusBar()->isVisible())
1210 statusBar()->hide();
1211 else
1212 statusBar()->show();
1213 setSettingsDirty();
1216 void DebuggerMainWnd::slotExecUntil()
1218 if (m_debugger != 0)
1220 QString file;
1221 int lineNo;
1222 if (m_filesWindow->activeLine(file, lineNo))
1223 m_debugger->runUntil(file, lineNo);
1227 void DebuggerMainWnd::slotExecAttach()
1229 #ifdef PS_COMMAND
1230 ProcAttachPS dlg(this);
1231 // seed filter with executable name
1232 QFileInfo fi = m_debugger->executable();
1233 dlg.filterEdit->setText(fi.fileName());
1234 #else
1235 ProcAttach dlg(this);
1236 dlg.setText(m_debugger->attachedPid());
1237 #endif
1238 if (dlg.exec()) {
1239 m_debugger->attachProgram(dlg.text());
1243 void DebuggerMainWnd::slotExecArgs()
1245 if (m_debugger != 0) {
1246 m_debugger->programArgs(this);
1250 void DebuggerMainWnd::slotConfigureKeys()
1252 KKeyDialog::configure(actionCollection(), this);
1255 #include "dbgmainwnd.moc"