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