Remove DebuggerMainWndBase: terminal window handling.
[kdbg.git] / kdbg / dbgmainwnd.cpp
blob9a72649022d2db709cf14f9ddd18a42401d6926b
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 <qlistbox.h>
23 #include <qfileinfo.h>
24 #include "dbgmainwnd.h"
25 #include "debugger.h"
26 #include "commandids.h"
27 #include "winstack.h"
28 #include "brkpt.h"
29 #include "threadlist.h"
30 #include "memwindow.h"
31 #include "ttywnd.h"
32 #include "procattach.h"
33 #include "dbgdriver.h"
34 #include "mydebug.h"
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 #ifdef HAVE_SYS_STAT_H
39 #include <sys/stat.h> /* mknod(2) */
40 #endif
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h> /* getpid */
43 #endif
46 static const char defaultTermCmdStr[] = "xterm -name kdbgio -title %T -e sh -c %C";
48 DebuggerMainWnd::DebuggerMainWnd(const char* name) :
49 KDockMainWindow(0, name),
50 DebuggerMainWndBase(),
51 m_outputTermProc(0),
52 m_ttyLevel(-1), /* no tty yet */
53 m_statusActive(i18n("active"))
55 QPixmap p;
57 KDockWidget* dw0 = createDockWidget("Source", p, 0, i18n("Source"));
58 m_filesWindow = new WinStack(dw0, "files");
59 dw0->setWidget(m_filesWindow);
60 dw0->setDockSite(KDockWidget::DockCorner);
61 dw0->setEnableDocking(KDockWidget::DockNone);
62 setView(dw0);
63 setMainDockWidget(dw0);
65 KDockWidget* dw1 = createDockWidget("Stack", p, 0, i18n("Stack"));
66 m_btWindow = new QListBox(dw1, "backtrace");
67 dw1->setWidget(m_btWindow);
68 KDockWidget* dw2 = createDockWidget("Locals", p, 0, i18n("Locals"));
69 m_localVariables = new ExprWnd(dw2, i18n("Variable"), "locals");
70 dw2->setWidget(m_localVariables);
71 KDockWidget* dw3 = createDockWidget("Watches", p, 0, i18n("Watches"));
72 m_watches = new WatchWindow(dw3, "watches");
73 dw3->setWidget(m_watches);
74 KDockWidget* dw4 = createDockWidget("Registers", p, 0, i18n("Registers"));
75 m_registers = new RegisterView(dw4, "registers");
76 dw4->setWidget(m_registers);
77 KDockWidget* dw5 = createDockWidget("Breakpoints", p, 0, i18n("Breakpoints"));
78 m_bpTable = new BreakpointTable(dw5, "breakpoints");
79 dw5->setWidget(m_bpTable);
80 KDockWidget* dw6 = createDockWidget("Output", p, 0, i18n("Output"));
81 m_ttyWindow = new TTYWindow(dw6, "output");
82 dw6->setWidget(m_ttyWindow);
83 KDockWidget* dw7 = createDockWidget("Threads", p, 0, i18n("Threads"));
84 m_threads = new ThreadList(dw7, "threads");
85 dw7->setWidget(m_threads);
86 KDockWidget* dw8 = createDockWidget("Memory", p, 0, i18n("Memory"));
87 m_memoryWindow = new MemoryWindow(dw8, "memory");
88 dw8->setWidget(m_memoryWindow);
90 setupDebugger(this, m_localVariables, m_watches->watchVariables(), m_btWindow);
91 m_bpTable->setDebugger(m_debugger);
92 m_memoryWindow->setDebugger(m_debugger);
94 setStandardToolBarMenuEnabled(true);
95 initKAction();
96 initToolbar(); // kind of obsolete?
98 connect(m_watches, SIGNAL(addWatch()), SLOT(slotAddWatch()));
99 connect(m_watches, SIGNAL(deleteWatch()), m_debugger, SLOT(slotDeleteWatch()));
100 connect(m_watches, SIGNAL(textDropped(const QString&)), SLOT(slotAddWatch(const QString&)));
102 connect(&m_filesWindow->m_findDlg, SIGNAL(closed()), SLOT(updateUI()));
103 connect(m_filesWindow, SIGNAL(newFileLoaded()),
104 SLOT(slotNewFileLoaded()));
105 connect(m_filesWindow, SIGNAL(toggleBreak(const QString&,int,const DbgAddr&,bool)),
106 this, SLOT(slotToggleBreak(const QString&,int,const DbgAddr&,bool)));
107 connect(m_filesWindow, SIGNAL(enadisBreak(const QString&,int,const DbgAddr&)),
108 this, SLOT(slotEnaDisBreak(const QString&,int,const DbgAddr&)));
109 connect(m_debugger, SIGNAL(activateFileLine(const QString&,int,const DbgAddr&)),
110 m_filesWindow, SLOT(activate(const QString&,int,const DbgAddr&)));
111 connect(m_debugger, SIGNAL(executableUpdated()),
112 m_filesWindow, SLOT(reloadAllFiles()));
113 connect(m_debugger, SIGNAL(updatePC(const QString&,int,const DbgAddr&,int)),
114 m_filesWindow, SLOT(updatePC(const QString&,int,const DbgAddr&,int)));
115 // value popup communication
116 connect(m_filesWindow, SIGNAL(initiateValuePopup(const QString&)),
117 m_debugger, SLOT(slotValuePopup(const QString&)));
118 connect(m_debugger, SIGNAL(valuePopup(const QString&)),
119 m_filesWindow, SLOT(slotShowValueTip(const QString&)));
120 // disassembling
121 connect(m_filesWindow, SIGNAL(disassemble(const QString&, int)),
122 m_debugger, SLOT(slotDisassemble(const QString&, int)));
123 connect(m_debugger, SIGNAL(disassembled(const QString&,int,const std::list<DisassembledCode>&)),
124 m_filesWindow, SLOT(slotDisassembled(const QString&,int,const std::list<DisassembledCode>&)));
125 connect(m_filesWindow, SIGNAL(moveProgramCounter(const QString&,int,const DbgAddr&)),
126 m_debugger, SLOT(setProgramCounter(const QString&,int,const DbgAddr&)));
127 // program stopped
128 connect(m_debugger, SIGNAL(programStopped()), SLOT(slotProgramStopped()));
129 connect(&m_backTimer, SIGNAL(timeout()), SLOT(slotBackTimer()));
130 // tab width
131 connect(this, SIGNAL(setTabWidth(int)), m_filesWindow, SIGNAL(setTabWidth(int)));
133 // connect breakpoint table
134 connect(m_bpTable, SIGNAL(activateFileLine(const QString&,int,const DbgAddr&)),
135 m_filesWindow, SLOT(activate(const QString&,int,const DbgAddr&)));
136 connect(m_debugger, SIGNAL(updateUI()), m_bpTable, SLOT(updateUI()));
137 connect(m_debugger, SIGNAL(breakpointsChanged()), m_bpTable, SLOT(updateBreakList()));
138 connect(m_debugger, SIGNAL(breakpointsChanged()), m_bpTable, SLOT(updateUI()));
140 connect(m_debugger, SIGNAL(registersChanged(const std::list<RegisterInfo>&)),
141 m_registers, SLOT(updateRegisters(const std::list<RegisterInfo>&)));
143 connect(m_debugger, SIGNAL(memoryDumpChanged(const QString&, const std::list<MemoryDump>&)),
144 m_memoryWindow, SLOT(slotNewMemoryDump(const QString&, const std::list<MemoryDump>&)));
145 connect(m_debugger, SIGNAL(saveProgramSpecific(KConfigBase*)),
146 m_memoryWindow, SLOT(saveProgramSpecific(KConfigBase*)));
147 connect(m_debugger, SIGNAL(restoreProgramSpecific(KConfigBase*)),
148 m_memoryWindow, SLOT(restoreProgramSpecific(KConfigBase*)));
150 // thread window
151 connect(m_debugger, SIGNAL(threadsChanged(const std::list<ThreadInfo>&)),
152 m_threads, SLOT(updateThreads(const std::list<ThreadInfo>&)));
153 connect(m_threads, SIGNAL(setThread(int)),
154 m_debugger, SLOT(setThread(int)));
156 // view menu changes when docking state changes
157 connect(dockManager, SIGNAL(change()), SLOT(updateUI()));
159 // popup menu of the local variables window
160 connect(m_localVariables, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
161 this, SLOT(slotLocalsPopup(QListViewItem*, const QPoint&)));
163 restoreSettings(kapp->config());
165 updateUI();
166 m_bpTable->updateUI();
169 DebuggerMainWnd::~DebuggerMainWnd()
171 saveSettings(kapp->config());
172 // must delete m_debugger early since it references our windows
173 delete m_debugger;
174 m_debugger = 0;
176 delete m_memoryWindow;
177 delete m_threads;
178 delete m_ttyWindow;
179 delete m_bpTable;
180 delete m_registers;
181 delete m_watches;
182 delete m_localVariables;
183 delete m_btWindow;
184 delete m_filesWindow;
186 // if the output window is open, close it
187 if (m_outputTermProc != 0) {
188 m_outputTermProc->disconnect(); /* ignore signals */
189 m_outputTermProc->kill();
190 shutdownTermWindow();
194 void DebuggerMainWnd::initKAction()
196 // file menu
197 KAction* open = KStdAction::open(this, SLOT(slotFileOpen()),
198 actionCollection());
199 open->setText(i18n("&Open Source..."));
200 KStdAction::close(m_filesWindow, SLOT(slotClose()), actionCollection());
201 (void)new KAction(i18n("&Reload Source"), "reload", 0, m_filesWindow,
202 SLOT(slotFileReload()), actionCollection(),
203 "file_reload");
204 (void)new KAction(i18n("&Executable..."), "execopen", 0, this,
205 SLOT(slotFileExe()), actionCollection(),
206 "file_executable");
207 m_recentExecAction = new KRecentFilesAction(i18n("Recent E&xecutables"), 0,
208 this, SLOT(slotRecentExec(const KURL&)),
209 actionCollection(), "file_executable_recent");
210 (void)new KAction(i18n("&Core dump..."), 0, this, SLOT(slotFileCore()),
211 actionCollection(), "file_core_dump");
212 KStdAction::quit(kapp, SLOT(closeAllWindows()), actionCollection());
214 // settings menu
215 (void)new KAction(i18n("This &Program..."), 0, this,
216 SLOT(slotFileProgSettings()), actionCollection(),
217 "settings_program");
218 (void)new KAction(i18n("&Global Options..."), 0, this,
219 SLOT(slotFileGlobalSettings()), actionCollection(),
220 "settings_global");
221 KStdAction::keyBindings(this, SLOT(slotConfigureKeys()), actionCollection());
222 KStdAction::showStatusbar(this, SLOT(slotViewStatusbar()), actionCollection());
224 // view menu
225 (void)new KToggleAction(i18n("&Find"), "find", CTRL+Key_F, m_filesWindow,
226 SLOT(slotViewFind()), actionCollection(),
227 "view_find");
228 (void)KStdAction::findNext(m_filesWindow, SLOT(slotFindForward()), actionCollection(), "view_findnext");
229 (void)KStdAction::findPrev(m_filesWindow, SLOT(slotFindBackward()), actionCollection(), "view_findprev");
231 i18n("Source &code");
232 struct { QString text; QWidget* w; QString id; } dw[] = {
233 { i18n("Stac&k"), m_btWindow, "view_stack"},
234 { i18n("&Locals"), m_localVariables, "view_locals"},
235 { i18n("&Watched expressions"), m_watches, "view_watched_expressions"},
236 { i18n("&Registers"), m_registers, "view_registers"},
237 { i18n("&Breakpoints"), m_bpTable, "view_breakpoints"},
238 { i18n("T&hreads"), m_threads, "view_threads"},
239 { i18n("&Output"), m_ttyWindow, "view_output"},
240 { i18n("&Memory"), m_memoryWindow, "view_memory"}
242 for (unsigned i = 0; i < sizeof(dw)/sizeof(dw[0]); i++) {
243 KDockWidget* d = dockParent(dw[i].w);
244 (void)new KToggleAction(dw[i].text, 0, d, SLOT(changeHideShowState()),
245 actionCollection(), dw[i].id);
249 // execution menu
250 KAction* a = new KAction(i18n("&Run"), "pgmrun", Key_F5, m_debugger,
251 SLOT(programRun()), actionCollection(), "exec_run");
252 connect(a, SIGNAL(activated()), this, SLOT(intoBackground()));
253 a = new KAction(i18n("Step &into"), "pgmstep", Key_F8, m_debugger,
254 SLOT(programStep()), actionCollection(),
255 "exec_step_into");
256 connect(a, SIGNAL(activated()), this, SLOT(intoBackground()));
257 a = new KAction(i18n("Step &over"), "pgmnext", Key_F10, m_debugger,
258 SLOT(programNext()), actionCollection(),
259 "exec_step_over");
260 connect(a, SIGNAL(activated()), this, SLOT(intoBackground()));
261 a = new KAction(i18n("Step o&ut"), "pgmfinish", Key_F6, m_debugger,
262 SLOT(programFinish()), actionCollection(),
263 "exec_step_out");
264 connect(a, SIGNAL(activated()), this, SLOT(intoBackground()));
265 a = new KAction(i18n("Run to &cursor"), Key_F7, this,
266 SLOT(slotExecUntil()), actionCollection(),
267 "exec_run_to_cursor");
268 connect(a, SIGNAL(activated()), this, SLOT(intoBackground()));
269 a = new KAction(i18n("Step i&nto by instruction"), "pgmstepi",
270 SHIFT+Key_F8, m_debugger, SLOT(programStepi()),
271 actionCollection(), "exec_step_into_by_insn");
272 connect(a, SIGNAL(activated()), this, SLOT(intoBackground()));
273 a = new KAction(i18n("Step o&ver by instruction"), "pgmnexti",
274 SHIFT+Key_F10, m_debugger, SLOT(programNexti()),
275 actionCollection(), "exec_step_over_by_insn");
276 connect(a, SIGNAL(activated()), this, SLOT(intoBackground()));
277 (void)new KAction(i18n("&Program counter to current line"), 0,
278 m_filesWindow, SLOT(slotMoveProgramCounter()),
279 actionCollection(), "exec_movepc");
280 (void)new KAction(i18n("&Break"), 0, m_debugger,
281 SLOT(programBreak()), actionCollection(),
282 "exec_break");
283 (void)new KAction(i18n("&Kill"), 0, m_debugger,
284 SLOT(programKill()), actionCollection(),
285 "exec_kill");
286 (void)new KAction(i18n("Re&start"), 0, m_debugger,
287 SLOT(programRunAgain()), actionCollection(),
288 "exec_restart");
289 (void)new KAction(i18n("A&ttach..."), 0, this,
290 SLOT(slotExecAttach()), actionCollection(),
291 "exec_attach");
292 (void)new KAction(i18n("&Arguments..."), 0, this,
293 SLOT(slotExecArgs()), actionCollection(),
294 "exec_arguments");
296 // breakpoint menu
297 (void)new KAction(i18n("Set/Clear &breakpoint"), "brkpt", Key_F9,
298 m_filesWindow, SLOT(slotBrkptSet()), actionCollection(),
299 "breakpoint_set");
300 (void)new KAction(i18n("Set &temporary breakpoint"), SHIFT+Key_F9,
301 m_filesWindow, SLOT(slotBrkptSetTemp()), actionCollection(),
302 "breakpoint_set_temporary");
303 (void)new KAction(i18n("&Enable/Disable breakpoint"), CTRL+Key_F9,
304 m_filesWindow, SLOT(slotBrkptEnable()), actionCollection(),
305 "breakpoint_enable");
307 // only in popup menus
308 (void)new KAction(i18n("Watch Expression"), 0, this,
309 SLOT(slotLocalsToWatch()), actionCollection(),
310 "watch_expression");
311 (void)new KAction(i18n("Edit Value"), Key_F2, this,
312 SLOT(slotEditValue()), actionCollection(),
313 "edit_value");
315 // all actions force an UI update
316 QValueList<KAction*> actions = actionCollection()->actions();
317 QValueList<KAction*>::Iterator it = actions.begin();
318 for (; it != actions.end(); ++it) {
319 connect(*it, SIGNAL(activated()), this, SLOT(updateUI()));
322 createGUI("kdbgui.rc");
325 void DebuggerMainWnd::initToolbar()
327 KToolBar* toolbar = toolBar("mainToolBar");
328 toolbar->insertAnimatedWidget(ID_STATUS_BUSY,
329 actionCollection()->action("exec_break"), SLOT(activate()),
330 "pulse", -1);
331 toolbar->alignItemRight(ID_STATUS_BUSY, true);
332 m_animRunning = false;
334 KStatusBar* statusbar = statusBar();
335 statusbar->insertItem(m_statusActive, ID_STATUS_ACTIVE);
336 m_lastActiveStatusText = m_statusActive;
337 statusbar->insertItem("", ID_STATUS_MSG); /* message pane */
339 // reserve some translations
340 i18n("Restart");
341 i18n("Core dump");
344 bool DebuggerMainWnd::queryClose()
346 if (m_debugger != 0) {
347 m_debugger->shutdown();
349 return true;
353 // instance properties
354 void DebuggerMainWnd::saveProperties(KConfig* config)
356 // session management
357 QString executable = "";
358 if (m_debugger != 0) {
359 executable = m_debugger->executable();
361 config->writeEntry("executable", executable);
364 void DebuggerMainWnd::readProperties(KConfig* config)
366 // session management
367 QString execName = config->readEntry("executable");
369 TRACE("readProperties: executable=" + execName);
370 if (!execName.isEmpty()) {
371 debugProgram(execName, "");
375 static const char WindowGroup[] = "Windows";
376 static const char RecentExecutables[] = "RecentExecutables";
377 static const char LastSession[] = "LastSession";
378 static const char OutputWindowGroup[] = "OutputWindow";
379 static const char TermCmdStr[] = "TermCmdStr";
380 static const char KeepScript[] = "KeepScript";
381 static const char DebuggerGroup[] = "Debugger";
382 static const char DebuggerCmdStr[] = "DebuggerCmdStr";
383 static const char PreferencesGroup[] = "Preferences";
384 static const char PopForeground[] = "PopForeground";
385 static const char BackTimeout[] = "BackTimeout";
386 static const char TabWidth[] = "TabWidth";
387 static const char SourceFileFilter[] = "SourceFileFilter";
388 static const char HeaderFileFilter[] = "HeaderFileFilter";
390 void DebuggerMainWnd::saveSettings(KConfig* config)
392 KConfigGroupSaver g(config, WindowGroup);
394 writeDockConfig(config);
395 fixDockConfig(config, false); // downgrade
397 m_recentExecAction->saveEntries(config, RecentExecutables);
399 KConfigGroupSaver g2(config, LastSession);
400 config->writeEntry("Width0Locals", m_localVariables->columnWidth(0));
401 config->writeEntry("Width0Watches", m_watches->columnWidth(0));
403 if (m_debugger != 0) {
404 m_debugger->saveSettings(config);
407 KConfigGroupSaver g3(config, OutputWindowGroup);
408 config->writeEntry(TermCmdStr, m_outputTermCmdStr);
410 config->setGroup(DebuggerGroup);
411 config->writeEntry(DebuggerCmdStr, m_debuggerCmdStr);
413 config->setGroup(PreferencesGroup);
414 config->writeEntry(PopForeground, m_popForeground);
415 config->writeEntry(BackTimeout, m_backTimeout);
416 config->writeEntry(TabWidth, m_tabWidth);
417 config->writeEntry(SourceFileFilter, m_sourceFilter);
418 config->writeEntry(HeaderFileFilter, m_headerFilter);
421 void DebuggerMainWnd::restoreSettings(KConfig* config)
423 KConfigGroupSaver g(config, WindowGroup);
425 fixDockConfig(config, true); // upgrade
426 readDockConfig(config);
428 // Workaround bug #87787: KDockManager stores the titles of the KDockWidgets
429 // in the config files, although they are localized:
430 // If the user changes the language, the titles remain in the previous language.
431 struct { QString text; QWidget* w; } dw[] = {
432 { i18n("Stack"), m_btWindow },
433 { i18n("Locals"), m_localVariables },
434 { i18n("Watches"), m_watches },
435 { i18n("Registers"), m_registers },
436 { i18n("Breakpoints"), m_bpTable },
437 { i18n("Threads"), m_threads },
438 { i18n("Output"), m_ttyWindow },
439 { i18n("Memory"), m_memoryWindow }
441 for (int i = 0; i < int(sizeof(dw)/sizeof(dw[0])); i++)
443 KDockWidget* w = dockParent(dw[i].w);
444 w->setTabPageLabel(dw[i].text);
445 // this actually changes the captions in the tabs:
446 QEvent ev(QEvent::CaptionChange);
447 w->event(&ev);
450 m_recentExecAction->loadEntries(config, RecentExecutables);
452 KConfigGroupSaver g2(config, LastSession);
453 int w;
454 w = config->readNumEntry("Width0Locals", -1);
455 if (w >= 0 && w < 30000)
456 m_localVariables->setColumnWidth(0, w);
457 w = config->readNumEntry("Width0Watches", -1);
458 if (w >= 0 && w < 30000)
459 m_watches->setColumnWidth(0, w);
461 if (m_debugger != 0) {
462 m_debugger->restoreSettings(config);
465 KConfigGroupSaver g3(config, OutputWindowGroup);
467 * For debugging and emergency purposes, let the config file override
468 * the shell script that is used to keep the output window open. This
469 * string must have EXACTLY 1 %s sequence in it.
471 setTerminalCmd(config->readEntry(TermCmdStr, defaultTermCmdStr));
472 m_outputTermKeepScript = config->readEntry(KeepScript);
474 config->setGroup(DebuggerGroup);
475 setDebuggerCmdStr(config->readEntry(DebuggerCmdStr));
477 config->setGroup(PreferencesGroup);
478 m_popForeground = config->readBoolEntry(PopForeground, false);
479 m_backTimeout = config->readNumEntry(BackTimeout, 1000);
480 m_tabWidth = config->readNumEntry(TabWidth, 0);
481 m_sourceFilter = config->readEntry(SourceFileFilter, m_sourceFilter);
482 m_headerFilter = config->readEntry(HeaderFileFilter, m_headerFilter);
484 emit setTabWidth(m_tabWidth);
487 void DebuggerMainWnd::updateUI()
489 KToggleAction* viewFind =
490 static_cast<KToggleAction*>(actionCollection()->action("view_find"));
491 viewFind->setChecked(m_filesWindow->m_findDlg.isVisible());
492 viewFind->setEnabled(m_filesWindow->hasWindows());
493 actionCollection()->action("breakpoint_set")->setEnabled(m_debugger->canChangeBreakpoints());
494 actionCollection()->action("breakpoint_set_temporary")->setEnabled(m_debugger->canChangeBreakpoints());
495 actionCollection()->action("breakpoint_enable")->setEnabled(m_debugger->canChangeBreakpoints());
496 dockUpdateHelper("view_breakpoints", m_bpTable);
497 dockUpdateHelper("view_stack", m_btWindow);
498 dockUpdateHelper("view_locals", m_localVariables);
499 dockUpdateHelper("view_watched_expressions", m_watches);
500 dockUpdateHelper("view_registers", m_registers);
501 dockUpdateHelper("view_threads", m_threads);
502 dockUpdateHelper("view_memory", m_memoryWindow);
503 dockUpdateHelper("view_output", m_ttyWindow);
505 // AB: maybe in mainwndbase.cpp?
506 actionCollection()->action("file_executable")->setEnabled(m_debugger->isIdle());
507 actionCollection()->action("settings_program")->setEnabled(m_debugger->haveExecutable());
508 actionCollection()->action("file_core_dump")->setEnabled(m_debugger->canStart());
509 actionCollection()->action("file_close")->setEnabled(m_filesWindow->hasWindows());
510 actionCollection()->action("file_reload")->setEnabled(m_filesWindow->hasWindows());
511 actionCollection()->action("exec_step_into")->setEnabled(m_debugger->canSingleStep());
512 actionCollection()->action("exec_step_into_by_insn")->setEnabled(m_debugger->canSingleStep());
513 actionCollection()->action("exec_step_over")->setEnabled(m_debugger->canSingleStep());
514 actionCollection()->action("exec_step_over_by_insn")->setEnabled(m_debugger->canSingleStep());
515 actionCollection()->action("exec_step_out")->setEnabled(m_debugger->canSingleStep());
516 actionCollection()->action("exec_run_to_cursor")->setEnabled(m_debugger->canSingleStep());
517 actionCollection()->action("exec_movepc")->setEnabled(m_debugger->canSingleStep());
518 actionCollection()->action("exec_restart")->setEnabled(m_debugger->canSingleStep());
519 actionCollection()->action("exec_attach")->setEnabled(m_debugger->isReady());
520 actionCollection()->action("exec_run")->setEnabled(m_debugger->canStart() || m_debugger->canSingleStep());
521 actionCollection()->action("exec_kill")->setEnabled(m_debugger->haveExecutable() && m_debugger->isProgramActive());
522 actionCollection()->action("exec_break")->setEnabled(m_debugger->isProgramRunning());
523 actionCollection()->action("exec_arguments")->setEnabled(m_debugger->haveExecutable());
524 actionCollection()->action("edit_value")->setEnabled(m_debugger->canSingleStep());
526 // animation
527 KAnimWidget* w = toolBar("mainToolBar")->animatedWidget(ID_STATUS_BUSY);
528 if (m_debugger->isIdle()) {
529 if (m_animRunning) {
530 w->stop();
531 m_animRunning = false;
533 } else {
534 if (!m_animRunning) {
535 w->start();
536 m_animRunning = true;
540 // update statusbar
541 QString newStatus;
542 if (m_debugger->isProgramActive())
543 newStatus = m_statusActive;
544 if (newStatus != m_lastActiveStatusText) {
545 statusBar()->changeItem(newStatus, ID_STATUS_ACTIVE);
546 m_lastActiveStatusText = newStatus;
550 void DebuggerMainWnd::dockUpdateHelper(QString action, QWidget* w)
552 KToggleAction* item =
553 static_cast<KToggleAction*>(actionCollection()->action(action));
554 bool canChange = canChangeDockVisibility(w);
555 item->setEnabled(canChange);
556 item->setChecked(canChange && isDockVisible(w));
559 void DebuggerMainWnd::updateLineItems()
561 m_filesWindow->updateLineItems(m_debugger);
564 void DebuggerMainWnd::slotAddWatch()
566 if (m_debugger != 0) {
567 QString t = m_watches->watchText();
568 m_debugger->addWatch(t);
572 void DebuggerMainWnd::slotAddWatch(const QString& text)
574 if (m_debugger != 0) {
575 m_debugger->addWatch(text);
579 void DebuggerMainWnd::slotNewFileLoaded()
581 // updates program counter in the new file
582 if (m_debugger != 0)
583 m_filesWindow->updateLineItems(m_debugger);
586 KDockWidget* DebuggerMainWnd::dockParent(QWidget* w)
588 while ((w = w->parentWidget()) != 0) {
589 if (w->isA("KDockWidget"))
590 return static_cast<KDockWidget*>(w);
592 return 0;
595 bool DebuggerMainWnd::isDockVisible(QWidget* w)
597 KDockWidget* d = dockParent(w);
598 return d != 0 && d->mayBeHide();
601 bool DebuggerMainWnd::canChangeDockVisibility(QWidget* w)
603 KDockWidget* d = dockParent(w);
604 return d != 0 && (d->mayBeHide() || d->mayBeShow());
607 // upgrades the entries from version 0.0.4 to 0.0.5 and back
608 void DebuggerMainWnd::fixDockConfig(KConfig* c, bool upgrade)
610 static const char dockGroup[] = "dock_setting_default";
611 if (!c->hasGroup(dockGroup))
612 return;
614 static const char oldVersion[] = "0.0.4";
615 static const char newVersion[] = "0.0.5";
616 const char* from = upgrade ? oldVersion : newVersion;
617 const char* to = upgrade ? newVersion : oldVersion;
618 QMap<QString,QString> e = c->entryMap(dockGroup);
619 if (e["Version"] != from)
620 return;
622 KConfigGroupSaver g(c, dockGroup);
623 c->writeEntry("Version", to);
624 TRACE(upgrade ? "upgrading dockconfig" : "downgrading dockconfig");
626 // turn all orientation entries from 0 to 1 and from 1 to 0
627 QMap<QString,QString>::Iterator i;
628 for (i = e.begin(); i != e.end(); ++i)
630 if (i.key().right(12) == ":orientation") {
631 TRACE("upgrading " + i.key() + " old value: " + *i);
632 int orientation = c->readNumEntry(i.key(), -1);
633 if (orientation >= 0) { // paranoia
634 c->writeEntry(i.key(), 1 - orientation);
640 bool DebuggerMainWnd::debugProgram(const QString& exe, const QString& lang)
642 // check the file name
643 QFileInfo fi(exe);
645 bool success = fi.isFile();
646 if (!success)
648 QString msg = i18n("`%1' is not a file or does not exist");
649 KMessageBox::sorry(this, msg.arg(exe));
651 else
653 success = DebuggerMainWndBase::debugProgram(fi.absFilePath(), lang, this);
656 if (success)
658 m_recentExecAction->addURL(KURL(fi.absFilePath()));
660 // keep the directory
661 m_lastDirectory = fi.dirPath(true);
662 m_filesWindow->setExtraDirectory(m_lastDirectory);
664 // set caption to basename part of executable
665 QString caption = fi.fileName();
666 setCaption(caption);
668 else
670 m_recentExecAction->removeURL(KURL(fi.absFilePath()));
673 return success;
676 void DebuggerMainWnd::slotNewStatusMsg()
678 QString msg = m_debugger->statusMessage();
679 statusBar()->changeItem(msg, ID_STATUS_MSG);
682 void DebuggerMainWnd::slotFileGlobalSettings()
684 int oldTabWidth = m_tabWidth;
686 doGlobalOptions(this);
688 if (m_tabWidth != oldTabWidth) {
689 emit setTabWidth(m_tabWidth);
693 void DebuggerMainWnd::slotDebuggerStarting()
695 if (m_debugger == 0) /* paranoia check */
696 return;
698 if (m_ttyLevel == m_debugger->ttyLevel())
699 return;
701 // shut down terminal emulations we will not need
702 switch (m_ttyLevel) {
703 case KDebugger::ttySimpleOutputOnly:
704 m_ttyWindow->deactivate();
705 break;
706 case KDebugger::ttyFull:
707 if (m_outputTermProc != 0) {
708 m_outputTermProc->kill();
709 // will be deleted in slot
711 break;
712 default: break;
715 m_ttyLevel = m_debugger->ttyLevel();
717 QString ttyName;
718 switch (m_ttyLevel) {
719 case KDebugger::ttySimpleOutputOnly:
720 ttyName = m_ttyWindow->activate();
721 break;
722 case KDebugger::ttyFull:
723 if (m_outputTermProc == 0) {
724 // create an output window
725 ttyName = createOutputWindow();
726 TRACE(ttyName.isEmpty() ?
727 "createOuputWindow failed" : "successfully created output window");
729 break;
730 default: break;
733 m_debugger->setTerminal(ttyName);
736 void DebuggerMainWnd::slotToggleBreak(const QString& fileName, int lineNo,
737 const DbgAddr& address, bool temp)
739 // lineNo is zero-based
740 if (m_debugger != 0) {
741 m_debugger->setBreakpoint(fileName, lineNo, address, temp);
745 void DebuggerMainWnd::slotEnaDisBreak(const QString& fileName, int lineNo,
746 const DbgAddr& address)
748 // lineNo is zero-based
749 if (m_debugger != 0) {
750 m_debugger->enableDisableBreakpoint(fileName, lineNo, address);
754 QString DebuggerMainWnd::createOutputWindow()
756 // create a name for a fifo
757 QString fifoName;
758 fifoName.sprintf("/tmp/kdbgttywin%05d", ::getpid());
760 // create a fifo that will pass in the tty name
761 QFile::remove(fifoName); // remove remnants
762 #ifdef HAVE_MKFIFO
763 if (::mkfifo(fifoName.local8Bit(), S_IRUSR|S_IWUSR) < 0) {
764 // failed
765 TRACE("mkfifo " + fifoName + " failed");
766 return QString();
768 #else
769 if (::mknod(fifoName.local8Bit(), S_IFIFO | S_IRUSR|S_IWUSR, 0) < 0) {
770 // failed
771 TRACE("mknod " + fifoName + " failed");
772 return QString();
774 #endif
776 m_outputTermProc = new KProcess;
779 * Spawn an xterm that in turn runs a shell script that passes us
780 * back the terminal name and then only sits and waits.
782 static const char shellScriptFmt[] =
783 "tty>%s;"
784 "trap \"\" INT QUIT TSTP;" /* ignore various signals */
785 "exec<&-;exec>&-;" /* close stdin and stdout */
786 "while :;do sleep 3600;done";
787 // let config file override this script
788 QString shellScript;
789 if (!m_outputTermKeepScript.isEmpty()) {
790 shellScript = m_outputTermKeepScript;
791 } else {
792 shellScript = shellScriptFmt;
795 shellScript.replace("%s", fifoName);
796 TRACE("output window script is " + shellScript);
798 QString title = kapp->caption();
799 title += i18n(": Program output");
801 // parse the command line specified in the preferences
802 QStringList cmdParts = QStringList::split(' ', m_outputTermCmdStr);
805 * Build the argv array. Thereby substitute special sequences:
807 struct {
808 char seq[4];
809 QString replace;
810 } substitute[] = {
811 { "%T", title },
812 { "%C", shellScript }
815 for (QStringList::iterator i = cmdParts.begin(); i != cmdParts.end(); ++i)
817 QString& str = *i;
818 for (int j = sizeof(substitute)/sizeof(substitute[0])-1; j >= 0; j--) {
819 int pos = str.find(substitute[j].seq);
820 if (pos >= 0) {
821 str.replace(pos, 2, substitute[j].replace);
822 break; /* substitute only one sequence */
825 *m_outputTermProc << str;
828 QString tty;
830 if (m_outputTermProc->start())
832 // read the ttyname from the fifo
833 QFile f(fifoName);
834 if (f.open(IO_ReadOnly))
836 QByteArray t = f.readAll();
837 tty = QString::fromLocal8Bit(t, t.size());
838 f.close();
840 f.remove();
842 // remove whitespace
843 tty = tty.stripWhiteSpace();
844 TRACE("tty=" + tty);
846 connect(m_outputTermProc, SIGNAL(processExited(KProcess*)),
847 SLOT(slotTermEmuExited()));
849 else
851 // error, could not start xterm
852 TRACE("fork failed for fifo " + fifoName);
853 QFile::remove(fifoName);
854 shutdownTermWindow();
857 return tty;
860 void DebuggerMainWnd::slotTermEmuExited()
862 shutdownTermWindow();
865 void DebuggerMainWnd::shutdownTermWindow()
867 delete m_outputTermProc;
868 m_outputTermProc = 0;
871 void DebuggerMainWnd::slotProgramStopped()
873 // when the program stopped, move the window to the foreground
874 if (m_popForeground) {
875 // unfortunately, this requires quite some force to work :-(
876 KWin::raiseWindow(winId());
877 KWin::forceActiveWindow(winId());
879 m_backTimer.stop();
882 void DebuggerMainWnd::intoBackground()
884 if (m_popForeground) {
885 m_backTimer.start(m_backTimeout, true); /* single-shot */
889 void DebuggerMainWnd::slotBackTimer()
891 lower();
894 void DebuggerMainWnd::slotRecentExec(const KURL& url)
896 QString exe = url.path();
897 debugProgram(exe, "");
900 QString DebuggerMainWnd::makeSourceFilter()
902 QString f;
903 f = m_sourceFilter + " " + m_headerFilter + i18n("|All source files\n");
904 f += m_sourceFilter + i18n("|Source files\n");
905 f += m_headerFilter + i18n("|Header files\n");
906 f += i18n("*|All files");
907 return f;
911 * Pop up the context menu in the locals window
913 void DebuggerMainWnd::slotLocalsPopup(QListViewItem*, const QPoint& pt)
915 QPopupMenu* popup =
916 static_cast<QPopupMenu*>(factory()->container("popup_locals", this));
917 if (popup == 0) {
918 return;
920 if (popup->isVisible()) {
921 popup->hide();
922 } else {
923 popup->popup(pt);
928 * Copies the currently selected item to the watch window.
930 void DebuggerMainWnd::slotLocalsToWatch()
932 VarTree* item = m_localVariables->selectedItem();
934 if (item != 0 && m_debugger != 0) {
935 QString text = item->computeExpr();
936 m_debugger->addWatch(text);
941 * Starts editing a value in a value display
943 void DebuggerMainWnd::slotEditValue()
945 // does one of the value trees have the focus
946 QWidget* f = kapp->focusWidget();
947 ExprWnd* wnd;
948 if (f == m_localVariables) {
949 wnd = m_localVariables;
950 } else if (f == m_watches->watchVariables()) {
951 wnd = m_watches->watchVariables();
952 } else {
953 return;
956 if (m_localVariables->isEditing() ||
957 m_watches->watchVariables()->isEditing())
959 return; /* don't edit twice */
962 VarTree* expr = wnd->currentItem();
963 if (expr != 0 && m_debugger != 0 && m_debugger->canSingleStep())
965 TRACE("edit value");
966 // determine the text to edit
967 QString text = m_debugger->driver()->editableValue(expr);
968 wnd->editValue(expr, text);
972 // helper that gets a file name (it only differs in the caption of the dialog)
973 static QString myGetFileName(QString caption,
974 QString dir, QString filter,
975 QWidget* parent)
977 QString filename;
978 KFileDialog dlg(dir, filter, parent, "filedialog", true);
980 dlg.setCaption(caption);
982 if (dlg.exec() == QDialog::Accepted)
983 filename = dlg.selectedFile();
985 return filename;
988 void DebuggerMainWnd::slotFileOpen()
990 // start browsing in the active file's directory
991 // fall back to last used directory (executable)
992 QString dir = m_lastDirectory;
993 QString fileName = m_filesWindow->activeFileName();
994 if (!fileName.isEmpty()) {
995 QFileInfo fi(fileName);
996 dir = fi.dirPath();
999 fileName = myGetFileName(i18n("Open"),
1000 dir,
1001 makeSourceFilter(), this);
1003 if (!fileName.isEmpty())
1005 QFileInfo fi(fileName);
1006 m_lastDirectory = fi.dirPath();
1007 m_filesWindow->setExtraDirectory(m_lastDirectory);
1008 m_filesWindow->activateFile(fileName);
1012 void DebuggerMainWnd::slotFileExe()
1014 if (m_debugger->isIdle())
1016 // open a new executable
1017 QString executable = myGetFileName(i18n("Select the executable to debug"),
1018 m_lastDirectory, 0, this);
1019 if (executable.isEmpty())
1020 return;
1022 debugProgram(executable, "");
1026 void DebuggerMainWnd::slotFileCore()
1028 if (m_debugger->canStart())
1030 QString corefile = myGetFileName(i18n("Select core dump"),
1031 m_lastDirectory, 0, this);
1032 if (!corefile.isEmpty()) {
1033 m_debugger->useCoreFile(corefile, false);
1038 void DebuggerMainWnd::slotFileProgSettings()
1040 if (m_debugger != 0) {
1041 m_debugger->programSettings(this);
1045 void DebuggerMainWnd::slotViewStatusbar()
1047 if (statusBar()->isVisible())
1048 statusBar()->hide();
1049 else
1050 statusBar()->show();
1051 setSettingsDirty();
1054 void DebuggerMainWnd::slotExecUntil()
1056 if (m_debugger != 0)
1058 QString file;
1059 int lineNo;
1060 if (m_filesWindow->activeLine(file, lineNo))
1061 m_debugger->runUntil(file, lineNo);
1065 void DebuggerMainWnd::slotExecAttach()
1067 #ifdef PS_COMMAND
1068 ProcAttachPS dlg(this);
1069 // seed filter with executable name
1070 QFileInfo fi = m_debugger->executable();
1071 dlg.filterEdit->setText(fi.fileName());
1072 #else
1073 ProcAttach dlg(this);
1074 dlg.setText(m_debugger->attachedPid());
1075 #endif
1076 if (dlg.exec()) {
1077 m_debugger->attachProgram(dlg.text());
1081 void DebuggerMainWnd::slotExecArgs()
1083 if (m_debugger != 0) {
1084 m_debugger->programArgs(this);
1088 void DebuggerMainWnd::slotConfigureKeys()
1090 KKeyDialog::configure(actionCollection(), this);
1093 #include "dbgmainwnd.moc"