MAJOR CHANGE!
authorStefan Huber <shuber2@gmail.com>
Wed, 11 Jun 2008 07:43:58 +0000 (09:43 +0200)
committerStefan Huber <shuber2@gmail.com>
Wed, 11 Jun 2008 07:43:58 +0000 (09:43 +0200)
  - 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
DbgTerminal.py
GdbTerminal.py
MainControlWindow.py
PositionFrame.py [new file with mode: 0644]
StatusWindow.py
WatchesFrame.py
pygdb.py

index 0d3bcf2cf8f5204a04d601242cf9ba5db7692610..9f1fe98c53e931c2927796ff4d035fab48ecf55c 100644 (file)
@@ -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()
 
index 0f0eb07f77a4ded1a1917f0e37965c1b6656234c..005661ce3e4aeff79f2bcea9461a8389555e7929 100644 (file)
@@ -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
 
index f468f89fe1f718fb99e870bf3b21abe0b10ff2b9..8600c90d0a94e4e7f1f1733f15a1bf70f8551727 100755 (executable)
@@ -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__":
index c8706d9b0368717d579f457c0a4e511cf31cd48b..0b5c3f11413e36067c55c373fbb625a63d20d8ca 100644 (file)
@@ -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 (file)
index 0000000..a752163
--- /dev/null
@@ -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
+
index e021fed1a18b2f4c1b26d901ffbca4ac5e1786d2..3209fed5b94e69141518965cfc87363c7dc938e1 100644 (file)
@@ -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
-
-
-
index cfcd14a916cc700f16082ae5dca212d4c94ac10b..0ee6623645fa9bd285dc1f3192d7adac0e18de75 100644 (file)
@@ -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, "<unkown>", 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)
 
index 6b6f5d3d2953a45b2ec603e2d4eef31ffc850b9d..422f83a812b10d15476f98d017b5f64fc1ee08ea 100755 (executable)
--- 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