MAJOR CHANGE!
[pygdb.git] / DbgTerminal.py
1 #!/usr/bin/python
2 #shuber, 2008-06-04
3
4 __author__ = "shuber"
5
6
7 import gobject
8 import gtk
9 import os
10 import pango
11 import pty
12 import string
13 import sys
14 import time
15 import threading
16 import vte
17
18 import ClientIOTerminal
19
20
21
22 class DbgTerminal (vte.Terminal):
23
24 def __init__(self, clientCmd):
25
26 vte.Terminal.__init__(self)
27
28 #Set members
29 self.childpid = None
30 self.history = [""]
31 self.isactive = True
32 self.lastc, self.lastr = 0,0
33 self.gotActiveCallback = []
34 self.gotInactiveCallback = []
35 self.activityChanged = None
36
37 #Start debugger
38 self.clientCmd = clientCmd
39 #Open pseudo-terminal where to-be-debugged process reads/writes to
40 self.client_ptymaster, self.client_ptyslave = pty.openpty()
41
42 #Set up terminal window and initialize debugger
43 self.connect("cursor-moved", self.contents_changed)
44 self.connect("child-exited", quitHandler)
45 gobject.timeout_add(50, self.checkActivityChanged)
46
47 #font description
48 fontdesc = pango.FontDescription("monospace 9")
49 self.set_font(fontdesc)
50
51
52 def initialize(self):
53 self.childpid = self.fork_command( self.getCommand(), self.getArgv())
54 self.waitForActivation(0)
55 self.setPty(self.client_ptyslave)
56
57 def stopDbg(self):
58
59 if self.childpid != None:
60 #9=KILL, 15=TERM
61 os.kill(self.childpid, 15);
62 self.childpid = None
63
64 def checkActivityChanged(self):
65
66 try:
67
68 #There was activity
69 if self.activityChanged != None:
70
71 res = self.activityChanged
72 self.activityChanged = None
73
74 status, param = res
75 if self.isActive():
76 for cb in self.gotActiveCallback:
77 cb(status, param)
78 else:
79 for cb in self.gotInactiveCallback:
80 cb(status, param)
81 except:
82 pass
83
84 return True
85
86
87
88 def contents_changed(self, term):
89 assert( self.getHistoryLen()>0 )
90
91 c,r = term.get_cursor_position()
92 text = self.get_text_range(self.lastr,self.lastc,r,c-1,lambda *w:True)
93 self.lastc, self.lastr = c,r
94
95 #Remove annoying \n at the end
96 assert(text[-1] == "\n")
97 text = text[:-1]
98 #Get the lines and remove empty lines
99 lines = string.split(text, "\n")
100
101 #Remove the incomplete line
102 len = max(0,self.getHistoryLen()-1)
103 self.history[-1] += lines[0]
104 self.history += lines[1:]
105
106
107 #Check if activity status has been changed
108 for i in range(len, self.getHistoryLen()):
109 line = self.history[i]
110
111 res = self.testForActivity(i)
112 if res != None and not self.isActive():
113 self.setActive(True)
114 self.activityChanged = res
115
116 res = self.testForInactivity(i)
117 if res != None and self.isActive():
118 self.setActive(False)
119 self.activityChanged = res
120
121
122
123 def waitForNewline(self):
124 l = self.getHistoryLen()
125 while not self.getHistoryLen() > l:
126 gtk.main_iteration()
127
128 def getHistoryLen(self):
129 return len(self.history)
130
131 def waitForRx(self, rx, start):
132 curr = start
133 while True:
134 assert( curr>=start )
135 for no in range(curr, self.getHistoryLen()):
136 line = self.history[no]
137 if rx.search(line):
138 return no, line
139
140 #Do not forget the last line
141 curr = max(start,self.getHistoryLen()-1)
142 gtk.main_iteration()
143
144
145 def getCommand(self):
146 return self.getArgv()[0];
147
148 def getArgv(self):
149 raise NotImplementedError()
150
151 def setPty(self, pty):
152 raise NotImplementedError()
153
154 def setRun(self):
155 raise NotImplementedError()
156
157 def setContinue(self):
158 raise NotImplementedError()
159
160 def setStepover(self):
161 raise NotImplementedError()
162
163 def setStepin(self):
164 raise NotImplementedError()
165
166 def setQuit(self):
167 raise NotImplementedError()
168
169 def setBreakpoint(self, file, lineno, condition=False):
170 raise NotImplementedError()
171
172 def delBreakpoint(self, breakpoint):
173 raise NotImplementedError()
174
175 def getExpression(self, expr):
176 raise NotImplementedError()
177
178 def waitForActivation(self, his):
179 raise NotImplementedError()
180
181 def testForActivity(self, his):
182 raise NotImplementedError()
183
184 def testForInactivity(self, his):
185 raise NotImplementedError()
186
187 def setActive(self, isactive):
188 self.isactive = isactive
189
190 def isActive(self):
191 return self.isactive
192
193
194
195 def quitHandler(*w):
196 try:
197 gtk.main_quit()
198 except:
199 pass
200
201
202
203 class DbgWindow (gtk.Window):
204
205 clientIOWnd = None
206
207
208 def __init__(self, terminal):
209
210 #Set up some members
211 self.terminal = terminal
212
213 #Set up GTK stuff
214 gtk.Window.__init__(self)
215 self.connect("destroy", quitHandler)
216
217 #Set title and add terminal
218 self.set_title("Debugger I/O")
219 self.terminal.history = []
220 self.terminal.history_length = 5
221 self.add(self.terminal)
222
223 #Show the window
224 self.show_all()
225
226 def toggleClientIOWindow(self):
227 if not self.clientIOWnd:
228 self.clientIOWnd = ClientIOTerminal.ClientIOWindow(self, \
229 self.terminal.client_ptymaster)
230 else:
231 self.clientIOWnd.destroy()
232 self.clientIOWnd = None
233
234 def isClientIOWindowExisting(self):
235 return self.clientIOWnd != None
236
237
238