changed some stuff of active/inactive detection
[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 print "got active: ", res
77 for cb in self.gotActiveCallback:
78 cb(status, param)
79 else:
80 print "got inactive: ", res
81 for cb in self.gotInactiveCallback:
82 cb(status, param)
83 except:
84 pass
85
86 return True
87
88
89
90 def contents_changed(self, term):
91 assert( self.getHistoryLen()>0 )
92
93 c,r = term.get_cursor_position()
94 text = self.get_text_range(self.lastr,self.lastc,r,c-1,lambda *w:True)
95 self.lastc, self.lastr = c,r
96
97 #Remove annoying \n at the end
98 assert(text[-1] == "\n")
99 text = text[:-1]
100 #Get the lines and remove empty lines
101 lines = string.split(text, "\n")
102
103 #Remove the incomplete line
104 len = max(0,self.getHistoryLen())
105 self.history[-1] += lines[0]
106 self.history += lines[1:]
107
108
109 #Check if activity status has been changed
110 for i in range(len, self.getHistoryLen()):
111 line = self.history[i]
112
113 res = self.testForInactivity(i)
114 if res != None:
115 while self.activityChanged != None:
116 print "wait for pending activity"
117 gtk.main_iteration()
118
119 self.setActive(False)
120 self.activityChanged = res
121
122 res = self.testForActivity(i)
123 if res != None:
124 while self.activityChanged != None:
125 print "wait for pending activity"
126 gtk.main_iteration()
127
128 self.setActive(True)
129 self.activityChanged = res
130
131
132
133
134 def waitForNewline(self):
135 l = self.getHistoryLen()
136 while not self.getHistoryLen() > l:
137 gtk.main_iteration()
138
139 def getHistoryLen(self):
140 return len(self.history)
141
142 def waitForRx(self, rx, start):
143 curr = start
144 while True:
145 assert( curr>=start )
146 for no in range(curr, self.getHistoryLen()):
147 line = self.history[no]
148 if rx.search(line):
149 return no, line
150
151 #Do not forget the last line
152 curr = max(start,self.getHistoryLen()-1)
153 gtk.main_iteration()
154
155
156 def getCommand(self):
157 return self.getArgv()[0];
158
159 def getArgv(self):
160 raise NotImplementedError()
161
162 def setPty(self, pty):
163 raise NotImplementedError()
164
165 def setRun(self):
166 raise NotImplementedError()
167
168 def setContinue(self):
169 raise NotImplementedError()
170
171 def setStepover(self):
172 raise NotImplementedError()
173
174 def setStepin(self):
175 raise NotImplementedError()
176
177 def setQuit(self):
178 raise NotImplementedError()
179
180 def setBreakpoint(self, file, lineno, condition=False):
181 raise NotImplementedError()
182
183 def delBreakpoint(self, breakpoint):
184 raise NotImplementedError()
185
186 def getExpression(self, expr):
187 raise NotImplementedError()
188
189 def waitForActivation(self, his):
190 raise NotImplementedError()
191
192 def testForActivity(self, his):
193 raise NotImplementedError()
194
195 def testForInactivity(self, his):
196 raise NotImplementedError()
197
198 def setActive(self, isactive):
199 self.isactive = isactive
200
201 def isActive(self):
202 return self.isactive
203
204
205
206 def quitHandler(*w):
207 try:
208 gtk.main_quit()
209 except:
210 pass
211
212
213
214 class DbgWindow (gtk.Window):
215
216 clientIOWnd = None
217
218
219 def __init__(self, terminal):
220
221 #Set up some members
222 self.terminal = terminal
223
224 #Set up GTK stuff
225 gtk.Window.__init__(self)
226 self.connect("destroy", quitHandler)
227
228 #Set title and add terminal
229 self.set_title("Debugger I/O")
230 self.terminal.history = []
231 self.terminal.history_length = 5
232 self.add(self.terminal)
233
234 #Show the window
235 self.show_all()
236
237 def toggleClientIOWindow(self):
238 if not self.clientIOWnd:
239 self.clientIOWnd = ClientIOTerminal.ClientIOWindow(self, \
240 self.terminal.client_ptymaster)
241 else:
242 self.clientIOWnd.destroy()
243 self.clientIOWnd = None
244
245 def isClientIOWindowExisting(self):
246 return self.clientIOWnd != None
247
248
249