From 0296b6d5afe20a15764842873917bf1d6aa34b77 Mon Sep 17 00:00:00 2001 From: Stefan Huber Date: Wed, 11 Jun 2008 09:43:58 +0200 Subject: [PATCH] MAJOR CHANGE! - moved to event detection in DbgTerminal: DbgTerminal detects by output if state is active or not, if breakpoint has been hit or not... - Introduced a position frame source listing is still missing. --- BreakpointsFrame.py | 8 ++-- DbgTerminal.py | 54 ++++++++++++++++++++++--- GdbTerminal.py | 52 ++++++++++++++++++------ MainControlWindow.py | 26 ++---------- PositionFrame.py | 94 ++++++++++++++++++++++++++++++++++++++++++++ StatusWindow.py | 72 +++++++++++---------------------- WatchesFrame.py | 10 +++-- pygdb.py | 2 +- 8 files changed, 222 insertions(+), 96 deletions(-) create mode 100644 PositionFrame.py diff --git a/BreakpointsFrame.py b/BreakpointsFrame.py index 0d3bcf2..9f1fe98 100644 --- a/BreakpointsFrame.py +++ b/BreakpointsFrame.py @@ -22,6 +22,8 @@ class BreakpointsFrame (StatusFrame.StatusFrame): StatusFrame.StatusFrame.__init__(self, debugger) self.set_label("Breakpoints") + debugger.gotActiveCallback += [self.updateValues] + vbox = gtk.VBox(False, 5) self.add(vbox) @@ -115,7 +117,7 @@ class BreakpointsFrame (StatusFrame.StatusFrame): def applyConfiguration(self, conf): for b in conf.breakpoints: self.addBreakpoint(b["file"], b["lineno"], b["cond"]) - self.updateValues(None) + self.updateValues(None, None) def fillConfiguration(self, conf): iter = self.model.get_iter_first() @@ -204,10 +206,10 @@ class BreakpointsFrame (StatusFrame.StatusFrame): if not self.debugger.isActive(): return - self.updateValues(None) + self.updateValues(None, None) - def updateValues(self, pos): + def updateValues(self, status, param): bpnts = self.debugger.getBreakpoints() diff --git a/DbgTerminal.py b/DbgTerminal.py index 0f0eb07..005661c 100644 --- a/DbgTerminal.py +++ b/DbgTerminal.py @@ -4,6 +4,7 @@ __author__ = "shuber" +import gobject import gtk import os import pango @@ -29,6 +30,9 @@ class DbgTerminal (vte.Terminal): self.history = [""] self.isactive = True self.lastc, self.lastr = 0,0 + self.gotActiveCallback = [] + self.gotInactiveCallback = [] + self.activityChanged = None #Start debugger self.clientCmd = clientCmd @@ -38,6 +42,7 @@ class DbgTerminal (vte.Terminal): #Set up terminal window and initialize debugger self.connect("cursor-moved", self.contents_changed) self.connect("child-exited", quitHandler) + gobject.timeout_add(50, self.checkActivityChanged) #font description fontdesc = pango.FontDescription("monospace 9") @@ -56,6 +61,28 @@ class DbgTerminal (vte.Terminal): os.kill(self.childpid, 15); self.childpid = None + def checkActivityChanged(self): + + try: + + #There was activity + if self.activityChanged != None: + + res = self.activityChanged + self.activityChanged = None + + status, param = res + if self.isActive(): + for cb in self.gotActiveCallback: + cb(status, param) + else: + for cb in self.gotInactiveCallback: + cb(status, param) + except: + pass + + return True + def contents_changed(self, term): @@ -68,18 +95,29 @@ class DbgTerminal (vte.Terminal): #Remove annoying \n at the end assert(text[-1] == "\n") text = text[:-1] - #Get the lines and remove empty lines lines = string.split(text, "\n") - #Remove the incomplete line - len = self.getHistoryLen() + len = max(0,self.getHistoryLen()-1) self.history[-1] += lines[0] self.history += lines[1:] - for l in self.history[len:]: - pass + + #Check if activity status has been changed + for i in range(len, self.getHistoryLen()): + line = self.history[i] + + res = self.testForActivity(i) + if res != None and not self.isActive(): + self.setActive(True) + self.activityChanged = res + + res = self.testForInactivity(i) + if res != None and self.isActive(): + self.setActive(False) + self.activityChanged = res + def waitForNewline(self): @@ -140,6 +178,12 @@ class DbgTerminal (vte.Terminal): def waitForActivation(self, his): raise NotImplementedError() + def testForActivity(self, his): + raise NotImplementedError() + + def testForInactivity(self, his): + raise NotImplementedError() + def setActive(self, isactive): self.isactive = isactive diff --git a/GdbTerminal.py b/GdbTerminal.py index f468f89..8600c90 100755 --- a/GdbTerminal.py +++ b/GdbTerminal.py @@ -25,30 +25,20 @@ class GdbTerminal (DbgTerminal.DbgTerminal): def setPty(self, pty): ttyname = os.ttyname(pty) - his = self.getHistoryLen() self.feed_child("set inferior-tty %s\n" % (ttyname,)) - self.waitForActivation(his) def setRun(self): - his = self.getHistoryLen() argv = string.join(string.split(self.clientCmd)[1:]) self.feed_child("run " + argv + "\n") - return self.waitForActivation(his) def setContinue(self): - his = self.getHistoryLen() self.feed_child("cont\n"); - return self.waitForActivation(his) def setStepover(self): - his = self.getHistoryLen() self.feed_child("next\n"); - return self.waitForActivation(his) def setStepin(self): - his = self.getHistoryLen() self.feed_child("step\n"); - return self.waitForActivation(his) def setQuit(self): self.feed_child("quit\n") @@ -155,7 +145,7 @@ class GdbTerminal (DbgTerminal.DbgTerminal): for his in reversed(range(starthis+1,endhis)): if self.history[his][0:2]=="\x1a\x1a": tuples = string.split(self.history[his][2:], ":") - return tuples[0:2] + return tuples[0], int(tuples[1]) return None @@ -165,6 +155,46 @@ class GdbTerminal (DbgTerminal.DbgTerminal): return self.waitForRx(rx,his) + def testForActivity(self, his): + """Test whether debugger got active again""" + rx = re.compile("^\(gdb\) ") + + #Aha! There is a prompt... + if rx.search(self.history[his]): + line = self.history[his-1] + + if line[0:2]=="\x1a\x1a": + tuples = string.split(line[2:], ":") + tuples[1] = int(tuples[1]) + return "break", [tuples[0], int(tuples[1])] + + if string.find(line, "Program exited") == 0: + code = string.split(line)[-1] + code = code[:-1] + return "exited", code + + return None + + + def testForInactivity(self, his): + """Test whether debugger got inactive""" + line = self.history[his] + rxcont = re.compile("^\(gdb\)\s+(cont|step|next|stepi|nexti)") + + if string.find(line, "Starting program:") == 0: + prog = string.join( string.split(line)[1:]) + return "started", prog + + if rxcont.search(line): + return "continued", None + + return None + + + + + + if __name__ == "__main__": diff --git a/MainControlWindow.py b/MainControlWindow.py index c8706d9..0b5c3f1 100644 --- a/MainControlWindow.py +++ b/MainControlWindow.py @@ -22,8 +22,8 @@ class MainControlWindow (gtk.Window): gtk.Window.__init__(self) self.connect("destroy", DbgTerminal.quitHandler ) - #Callbacks for new positions - self.newPosCbs = [] + dbgterm.gotActiveCallback += [self.enableButtons] + dbgterm.gotInactiveCallback += [self.disableButtons] #Set terminals self.dbgterm = dbgterm @@ -76,49 +76,31 @@ class MainControlWindow (gtk.Window): def runBtnClicked(self, btn): - self.disableButtons() pos = self.dbgterm.setRun() - self.newSourcePosition(pos) - self.enableButtons() def continueBtnClicked(self, btn): - self.disableButtons() pos = self.dbgterm.setContinue() - self.newSourcePosition(pos) - self.enableButtons() def stepoverBtnClicked(self, btn): - self.disableButtons() pos = self.dbgterm.setStepover() - self.newSourcePosition(pos) - self.enableButtons() def stepinBtnClicked(self, btn): - self.disableButtons() pos = self.dbgterm.setStepin() - self.newSourcePosition(pos) - self.enableButtons() def quitBtnClicked(self, btn): self.dbgterm.setQuit() - def disableButtons(self): + def disableButtons(self, *w): self.runBtn.handler_block(self.runBtnHandler) self.continueBtn.handler_block(self.continueBtnHandler) self.stepoverBtn.handler_block(self.stepoverBtnHandler) self.stepinBtn.handler_block(self.stepinBtnHandler) self.quitBtn.handler_block(self.quitBtnHandler) - def enableButtons(self): + def enableButtons(self, *w): self.runBtn.handler_unblock(self.runBtnHandler) self.continueBtn.handler_unblock(self.continueBtnHandler) self.stepoverBtn.handler_unblock(self.stepoverBtnHandler) self.stepinBtn.handler_unblock(self.stepinBtnHandler) self.quitBtn.handler_unblock(self.quitBtnHandler) - def newSourcePosition(self, pos): - #Call the callbacks - for cb in self.newPosCbs: - cb(pos) - - diff --git a/PositionFrame.py b/PositionFrame.py new file mode 100644 index 0000000..a752163 --- /dev/null +++ b/PositionFrame.py @@ -0,0 +1,94 @@ +#!/usr/bin/python +#shuber, 2008-06-04 + +__author__ = "shuber" + + +import gobject +import gtk +import re +import os +import string +import vte + +import DbgTerminal +import StatusFrame + + +class PositionFrame (StatusFrame.StatusFrame): + + + def __init__(self, debugger): + + StatusFrame.StatusFrame.__init__(self, debugger) + self.set_label("Position") + + debugger.gotActiveCallback += [self.updateValues] + debugger.gotInactiveCallback += [self.updateValues] + + self.file = None + self.lineno = 0 + + vbox = gtk.VBox(False, 5) + self.add(vbox) + + hbox = gtk.HBox(False, 4) + vbox.pack_start(hbox, False, False) + self.openBtn = gtk.Button(":e") + hbox.pack_start(self.openBtn, False, False) + self.positionLabel = gtk.Label() + hbox.pack_start(self.positionLabel, False, False) + + sw = gtk.ScrolledWindow() + sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + vbox.add(sw) + + self.srcview = gtk.TextView() + sw.add(self.srcview) + + self.openBtn.connect("clicked", self.openBtnClicked) + + + def openBtnClicked(self, btn): + + if not self.debugger.isActive(): + return + + if self.file!=None: + try: + cmd = 'gvim -R -c ":%d" %s' % (self.lineno, self.file) + os.system(cmd) + except OSError: + dialog = gtk.MessageDialog(None, \ + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, \ + gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, \ + "Error calling editor with '%s'." % cmd) + dialog.run() + dialog.destroy() + + + def updateValues(self, status, param): + + if status == "break": + self.file, self.lineno = param + self.positionLabel.set_label("%s:%d" % (self.file, self.lineno)) + else: + self.file, self.lineno = None, 0 + + if status == "exited": + self.positionLabel.set_label("Exited.") + elif status == "started": + self.positionLabel.set_label("Started.") + elif status == "continued": + self.positionLabel.set_label("Continued.") + else: + self.positionLabel.set_label(status) + + + def applyConfiguration(self, conf): + pass + + def fillConfiguration(self, conf): + pass + diff --git a/StatusWindow.py b/StatusWindow.py index e021fed..3209fed 100644 --- a/StatusWindow.py +++ b/StatusWindow.py @@ -12,15 +12,16 @@ import vte import DbgTerminal import BreakpointsFrame +import PositionFrame import WatchesFrame class StatusWindow (gtk.Window): - def __init__(self, mainctrlwnd, debugger): - + def __init__(self, debugger): gtk.Window.__init__(self) + self.debugger = debugger self.set_border_width(5) @@ -28,31 +29,29 @@ class StatusWindow (gtk.Window): self.set_default_size(400,600) self.connect("destroy", DbgTerminal.quitHandler) + + #Vbox container of frames vbox = gtk.VBox(False, 5) self.add(vbox) - hbox = gtk.HBox(False, 5) - vbox.pack_start(hbox, False, False) + + #Adding the frames + self.frames = [] + self.frames += [PositionFrame.PositionFrame(debugger), \ + WatchesFrame.WatchesFrame(debugger), \ + BreakpointsFrame.BreakpointsFrame(debugger) ] - self.viewBtn = gtk.Button("View") - self.viewBtn.connect("clicked", self.viewBtnClicked) - hbox.pack_start(self.viewBtn, False, False) - self.status = gtk.Label("Not Running") - hbox.pack_start(self.status, False, False) + #First paned window self.paned1 = gtk.VPaned() vbox.add(self.paned1) + #Second one + self.paned2 = gtk.VPaned() + self.paned1.add2(self.paned2) - #Adding the frames - self.frames = [] - self.frames += [WatchesFrame.WatchesFrame(debugger)] - self.frames += [BreakpointsFrame.BreakpointsFrame(debugger)] - self.paned1.add1(self.frames[0]) - self.paned1.add2(self.frames[1]) - - #Register callback function for new positions - #and update the values - mainctrlwnd.newPosCbs += [self.updateValues] + self.paned1.add1(self.frames[1]) + self.paned2.add1(self.frames[2]) + self.paned2.add2(self.frames[0]) self.show_all() @@ -62,11 +61,14 @@ class StatusWindow (gtk.Window): w = conf.findInt("statuswnd-width") h = conf.findInt("statuswnd-height") paned1 = conf.findInt("statuswnd-paned1") + paned2 = conf.findInt("statuswnd-paned2") if w!=None and h!=None: self.resize(w,h) if paned1!=None: self.paned1.set_position(paned1) + if paned2!=None: + self.paned2.set_position(paned2) while not self.debugger.isActive(): @@ -81,38 +83,8 @@ class StatusWindow (gtk.Window): conf.addInt("statuswnd-width", self.get_size()[0]) conf.addInt("statuswnd-height", self.get_size()[1]) conf.addInt("statuswnd-paned1", self.paned1.get_position()) + conf.addInt("statuswnd-paned2", self.paned2.get_position()) for f in self.frames: f.fillConfiguration(conf) - - def updateValues(self, pos): - - if pos == None: - self.status.set_text("Exited") - else: - file, lineno = pos - self.status.set_text("%s:%s" % (file, lineno)) - - for f in self.frames: - f.updateValues(pos) - - - def viewBtnClicked(self, btn): - - status = self.status.get_label().strip() - rx = re.compile("\S+:\d+") - - #It is a path - if rx.search(status): - try: - [file,lineno] = string.split(status,":") - lineno = int(lineno) - - os.system('gvim -R -c ":%d" %s' % (lineno,file)) - - except OSError: - pass - - - diff --git a/WatchesFrame.py b/WatchesFrame.py index cfcd14a..0ee6623 100644 --- a/WatchesFrame.py +++ b/WatchesFrame.py @@ -20,6 +20,8 @@ class WatchesFrame (StatusFrame.StatusFrame): StatusFrame.StatusFrame.__init__(self, debugger) self.set_label("Watches") + debugger.gotActiveCallback += [self.updateValues] + vbox = gtk.VBox(False, 5) self.add(vbox) @@ -92,7 +94,7 @@ class WatchesFrame (StatusFrame.StatusFrame): for w in conf.watches: iter = self.model.append() self.model.set(iter, 0, w["expr"], 1, "", 2, True) - self.updateValues(None) + self.updateValues(None, None) def fillConfiguration(self, conf): @@ -116,12 +118,12 @@ class WatchesFrame (StatusFrame.StatusFrame): iter = model.get_iter(path) model.remove(iter) - def updateValues(self, pos): + def updateValues(self, status, param): iter = self.model.get_iter_first() while iter != None: expr, = self.model.get(iter, 0) - res = self.debugger.getExpression(expr) - self.model.set(iter, 1, res) + res = self.debugger.getExpression(expr) + self.model.set(iter, 1, res) iter = self.model.iter_next(iter) diff --git a/pygdb.py b/pygdb.py index 6b6f5d3..422f83a 100755 --- a/pygdb.py +++ b/pygdb.py @@ -21,7 +21,7 @@ def launchDebugger(clientCmd): #Create windows mainCtrlWnd = MainControlWindow.MainControlWindow(dbgterm) - statusWnd = StatusWindow.StatusWindow(mainCtrlWnd, dbgterm) + statusWnd = StatusWindow.StatusWindow(dbgterm) dbgterm.initialize() #Load configuration -- 2.30.2