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.
7 #include <kapplication.h>
8 #include <klocale.h> /* i18n */
9 #include <kmessagebox.h>
11 #include <kstatusbar.h>
12 #include <kiconloader.h>
13 #include <kstdaccel.h>
14 #include <kstdaction.h>
16 #include <kpopupmenu.h>
17 #include <kfiledialog.h>
19 #include <kkeydialog.h>
20 #include <kanimwidget.h>
23 #include <qfileinfo.h>
24 #include "dbgmainwnd.h"
26 #include "commandids.h"
29 #include "threadlist.h"
30 #include "memwindow.h"
32 #include "procattach.h"
33 #include "dbgdriver.h"
38 #ifdef HAVE_SYS_STAT_H
39 #include <sys/stat.h> /* mknod(2) */
42 #include <unistd.h> /* getpid */
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(),
52 m_ttyLevel(-1), /* no tty yet */
53 m_statusActive(i18n("active"))
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
);
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);
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
&)));
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
&)));
128 connect(m_debugger
, SIGNAL(programStopped()), SLOT(slotProgramStopped()));
129 connect(&m_backTimer
, SIGNAL(timeout()), SLOT(slotBackTimer()));
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
*)));
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());
166 m_bpTable
->updateUI();
169 DebuggerMainWnd::~DebuggerMainWnd()
171 saveSettings(kapp
->config());
172 // must delete m_debugger early since it references our windows
176 delete m_memoryWindow
;
182 delete m_localVariables
;
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()
197 KAction
* open
= KStdAction::open(this, SLOT(slotFileOpen()),
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(),
204 (void)new KAction(i18n("&Executable..."), "execopen", 0, this,
205 SLOT(slotFileExe()), actionCollection(),
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());
215 (void)new KAction(i18n("This &Program..."), 0, this,
216 SLOT(slotFileProgSettings()), actionCollection(),
218 (void)new KAction(i18n("&Global Options..."), 0, this,
219 SLOT(slotFileGlobalSettings()), actionCollection(),
221 KStdAction::keyBindings(this, SLOT(slotConfigureKeys()), actionCollection());
222 KStdAction::showStatusbar(this, SLOT(slotViewStatusbar()), actionCollection());
225 (void)new KToggleAction(i18n("&Find"), "find", CTRL
+Key_F
, m_filesWindow
,
226 SLOT(slotViewFind()), actionCollection(),
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
);
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(),
256 connect(a
, SIGNAL(activated()), this, SLOT(intoBackground()));
257 a
= new KAction(i18n("Step &over"), "pgmnext", Key_F10
, m_debugger
,
258 SLOT(programNext()), actionCollection(),
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(),
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(),
283 (void)new KAction(i18n("&Kill"), 0, m_debugger
,
284 SLOT(programKill()), actionCollection(),
286 (void)new KAction(i18n("Re&start"), 0, m_debugger
,
287 SLOT(programRunAgain()), actionCollection(),
289 (void)new KAction(i18n("A&ttach..."), 0, this,
290 SLOT(slotExecAttach()), actionCollection(),
292 (void)new KAction(i18n("&Arguments..."), 0, this,
293 SLOT(slotExecArgs()), actionCollection(),
297 (void)new KAction(i18n("Set/Clear &breakpoint"), "brkpt", Key_F9
,
298 m_filesWindow
, SLOT(slotBrkptSet()), actionCollection(),
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(),
311 (void)new KAction(i18n("Edit Value"), Key_F2
, this,
312 SLOT(slotEditValue()), actionCollection(),
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()),
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
344 bool DebuggerMainWnd::queryClose()
346 if (m_debugger
!= 0) {
347 m_debugger
->shutdown();
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
);
450 m_recentExecAction
->loadEntries(config
, RecentExecutables
);
452 KConfigGroupSaver
g2(config
, LastSession
);
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());
527 KAnimWidget
* w
= toolBar("mainToolBar")->animatedWidget(ID_STATUS_BUSY
);
528 if (m_debugger
->isIdle()) {
531 m_animRunning
= false;
534 if (!m_animRunning
) {
536 m_animRunning
= true;
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
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
);
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
))
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
)
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
645 bool success
= fi
.isFile();
648 QString msg
= i18n("`%1' is not a file or does not exist");
649 KMessageBox::sorry(this, msg
.arg(exe
));
653 success
= DebuggerMainWndBase::debugProgram(fi
.absFilePath(), lang
, this);
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();
670 m_recentExecAction
->removeURL(KURL(fi
.absFilePath()));
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 */
698 if (m_ttyLevel
== m_debugger
->ttyLevel())
701 // shut down terminal emulations we will not need
702 switch (m_ttyLevel
) {
703 case KDebugger::ttySimpleOutputOnly
:
704 m_ttyWindow
->deactivate();
706 case KDebugger::ttyFull
:
707 if (m_outputTermProc
!= 0) {
708 m_outputTermProc
->kill();
709 // will be deleted in slot
715 m_ttyLevel
= m_debugger
->ttyLevel();
718 switch (m_ttyLevel
) {
719 case KDebugger::ttySimpleOutputOnly
:
720 ttyName
= m_ttyWindow
->activate();
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");
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
758 fifoName
.sprintf("/tmp/kdbgttywin%05d", ::getpid());
760 // create a fifo that will pass in the tty name
761 QFile::remove(fifoName
); // remove remnants
763 if (::mkfifo(fifoName
.local8Bit(), S_IRUSR
|S_IWUSR
) < 0) {
765 TRACE("mkfifo " + fifoName
+ " failed");
769 if (::mknod(fifoName
.local8Bit(), S_IFIFO
| S_IRUSR
|S_IWUSR
, 0) < 0) {
771 TRACE("mknod " + fifoName
+ " failed");
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
[] =
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
789 if (!m_outputTermKeepScript
.isEmpty()) {
790 shellScript
= m_outputTermKeepScript
;
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:
812 { "%C", shellScript
}
815 for (QStringList::iterator i
= cmdParts
.begin(); i
!= cmdParts
.end(); ++i
)
818 for (int j
= sizeof(substitute
)/sizeof(substitute
[0])-1; j
>= 0; j
--) {
819 int pos
= str
.find(substitute
[j
].seq
);
821 str
.replace(pos
, 2, substitute
[j
].replace
);
822 break; /* substitute only one sequence */
825 *m_outputTermProc
<< str
;
830 if (m_outputTermProc
->start())
832 // read the ttyname from the fifo
834 if (f
.open(IO_ReadOnly
))
836 QByteArray t
= f
.readAll();
837 tty
= QString::fromLocal8Bit(t
, t
.size());
843 tty
= tty
.stripWhiteSpace();
846 connect(m_outputTermProc
, SIGNAL(processExited(KProcess
*)),
847 SLOT(slotTermEmuExited()));
851 // error, could not start xterm
852 TRACE("fork failed for fifo " + fifoName
);
853 QFile::remove(fifoName
);
854 shutdownTermWindow();
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());
882 void DebuggerMainWnd::intoBackground()
884 if (m_popForeground
) {
885 m_backTimer
.start(m_backTimeout
, true); /* single-shot */
889 void DebuggerMainWnd::slotBackTimer()
894 void DebuggerMainWnd::slotRecentExec(const KURL
& url
)
896 QString exe
= url
.path();
897 debugProgram(exe
, "");
900 QString
DebuggerMainWnd::makeSourceFilter()
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");
911 * Pop up the context menu in the locals window
913 void DebuggerMainWnd::slotLocalsPopup(QListViewItem
*, const QPoint
& pt
)
916 static_cast<QPopupMenu
*>(factory()->container("popup_locals", this));
920 if (popup
->isVisible()) {
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();
948 if (f
== m_localVariables
) {
949 wnd
= m_localVariables
;
950 } else if (f
== m_watches
->watchVariables()) {
951 wnd
= m_watches
->watchVariables();
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())
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
,
978 KFileDialog
dlg(dir
, filter
, parent
, "filedialog", true);
980 dlg
.setCaption(caption
);
982 if (dlg
.exec() == QDialog::Accepted
)
983 filename
= dlg
.selectedFile();
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
);
999 fileName
= myGetFileName(i18n("Open"),
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())
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();
1050 statusBar()->show();
1054 void DebuggerMainWnd::slotExecUntil()
1056 if (m_debugger
!= 0)
1060 if (m_filesWindow
->activeLine(file
, lineNo
))
1061 m_debugger
->runUntil(file
, lineNo
);
1065 void DebuggerMainWnd::slotExecAttach()
1068 ProcAttachPS
dlg(this);
1069 // seed filter with executable name
1070 QFileInfo fi
= m_debugger
->executable();
1071 dlg
.filterEdit
->setText(fi
.fileName());
1073 ProcAttach
dlg(this);
1074 dlg
.setText(m_debugger
->attachedPid());
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"