blob: 0b59daacbf4051881d3272dcd6e1bd7d7ba32503 [file] [log] [blame]
Guido van Rossum630112e1995-01-10 17:08:10 +00001import os
2import sys
3import string
4from Tkinter import *
5from ScrolledText import ScrolledText
6from Dialog import Dialog
7import signal
8
Guido van Rossum630112e1995-01-10 17:08:10 +00009BUFSIZE = 512
10
11class ShellWindow(ScrolledText):
12
Guido van Rossum89cb67b1996-07-30 18:57:18 +000013 def __init__(self, master=None, shell=None, **cnf):
14 if not shell:
Guido van Rossum630112e1995-01-10 17:08:10 +000015 try:
16 shell = os.environ['SHELL']
17 except KeyError:
18 shell = '/bin/sh'
19 shell = shell + ' -i'
20 args = string.split(shell)
21 shell = args[0]
22
Guido van Rossum89cb67b1996-07-30 18:57:18 +000023 apply(ScrolledText.__init__, (self, master), cnf)
Guido van Rossum630112e1995-01-10 17:08:10 +000024 self.pos = '1.0'
25 self.bind('<Return>', self.inputhandler)
26 self.bind('<Control-c>', self.sigint)
27 self.bind('<Control-t>', self.sigterm)
28 self.bind('<Control-k>', self.sigkill)
29 self.bind('<Control-d>', self.sendeof)
30
31 self.pid, self.fromchild, self.tochild = spawn(shell, args)
Guido van Rossum89cb67b1996-07-30 18:57:18 +000032 self.tk.createfilehandler(self.fromchild, READABLE,
Guido van Rossum630112e1995-01-10 17:08:10 +000033 self.outputhandler)
34
35 def outputhandler(self, file, mask):
36 data = os.read(file, BUFSIZE)
37 if not data:
38 self.tk.deletefilehandler(file)
39 pid, sts = os.waitpid(self.pid, 0)
40 print 'pid', pid, 'status', sts
41 self.pid = None
42 detail = sts>>8
43 cause = sts & 0xff
44 if cause == 0:
45 msg = "exit status %d" % detail
46 else:
47 msg = "killed by signal %d" % (cause & 0x7f)
48 if cause & 0x80:
49 msg = msg + " -- core dumped"
Guido van Rossum89cb67b1996-07-30 18:57:18 +000050 Dialog(self.master,
51 text=msg,
52 title="Exit status",
53 bitmap='warning',
54 default=0,
55 strings=('OK',))
Guido van Rossum630112e1995-01-10 17:08:10 +000056 return
Guido van Rossum89cb67b1996-07-30 18:57:18 +000057 self.insert(END, data)
58 self.pos = self.index("end - 1 char")
59 self.yview_pickplace(END)
Guido van Rossum630112e1995-01-10 17:08:10 +000060
61 def inputhandler(self, *args):
62 if not self.pid:
Guido van Rossum89cb67b1996-07-30 18:57:18 +000063 self.no_process()
64 return "break"
65 self.insert(END, "\n")
66 line = self.get(self.pos, "end - 1 char")
67 self.pos = self.index(END)
Guido van Rossum630112e1995-01-10 17:08:10 +000068 os.write(self.tochild, line)
Guido van Rossum89cb67b1996-07-30 18:57:18 +000069 return "break"
Guido van Rossum630112e1995-01-10 17:08:10 +000070
71 def sendeof(self, *args):
72 if not self.pid:
Guido van Rossum89cb67b1996-07-30 18:57:18 +000073 self.no_process()
74 return "break"
Guido van Rossum630112e1995-01-10 17:08:10 +000075 os.close(self.tochild)
Guido van Rossum89cb67b1996-07-30 18:57:18 +000076 return "break"
Guido van Rossum630112e1995-01-10 17:08:10 +000077
78 def sendsig(self, sig):
79 if not self.pid:
Guido van Rossum89cb67b1996-07-30 18:57:18 +000080 self.no_process()
81 return "break"
Guido van Rossum630112e1995-01-10 17:08:10 +000082 os.kill(self.pid, sig)
Guido van Rossum89cb67b1996-07-30 18:57:18 +000083 return "break"
Guido van Rossum630112e1995-01-10 17:08:10 +000084
85 def sigint(self, *args):
Guido van Rossum89cb67b1996-07-30 18:57:18 +000086 return self.sendsig(signal.SIGINT)
Guido van Rossum630112e1995-01-10 17:08:10 +000087
88 def sigquit(self, *args):
Guido van Rossum89cb67b1996-07-30 18:57:18 +000089 return self.sendsig(signal.SIGQUIT)
Guido van Rossum630112e1995-01-10 17:08:10 +000090
91 def sigterm(self, *args):
Guido van Rossum89cb67b1996-07-30 18:57:18 +000092 return self.sendsig(signal.SIGTERM)
Guido van Rossum630112e1995-01-10 17:08:10 +000093
94 def sigkill(self, *args):
Guido van Rossum89cb67b1996-07-30 18:57:18 +000095 return self.sendsig(signal.SIGKILL)
96
97 def no_process(self):
98 Dialog(self.master,
99 text="No active process",
100 title="No process",
101 bitmap='error',
102 default=0,
103 strings=('OK',))
Guido van Rossum630112e1995-01-10 17:08:10 +0000104
105MAXFD = 100 # Max number of file descriptors (os.getdtablesize()???)
106
107def spawn(prog, args):
108 p2cread, p2cwrite = os.pipe()
109 c2pread, c2pwrite = os.pipe()
110 pid = os.fork()
111 if pid == 0:
112 # Child
113 os.close(0)
114 os.close(1)
115 os.close(2)
116 if os.dup(p2cread) <> 0:
117 sys.stderr.write('popen2: bad read dup\n')
118 if os.dup(c2pwrite) <> 1:
119 sys.stderr.write('popen2: bad write dup\n')
120 if os.dup(c2pwrite) <> 2:
121 sys.stderr.write('popen2: bad write dup\n')
122 for i in range(3, MAXFD):
123 try:
124 os.close(i)
125 except:
126 pass
127 try:
128 os.execvp(prog, args)
129 finally:
Guido van Rossum89cb67b1996-07-30 18:57:18 +0000130 sys.stderr.write('execvp failed\n')
Guido van Rossum630112e1995-01-10 17:08:10 +0000131 os._exit(1)
132 os.close(p2cread)
133 os.close(c2pwrite)
134 return pid, c2pread, p2cwrite
135
136def test():
137 shell = string.join(sys.argv[1:])
Guido van Rossum630112e1995-01-10 17:08:10 +0000138 root = Tk()
139 root.minsize(1, 1)
Guido van Rossum89cb67b1996-07-30 18:57:18 +0000140 if shell:
141 w = ShellWindow(root, shell=shell)
142 else:
143 w = ShellWindow(root)
144 w.pack(expand=1, fill=BOTH)
Guido van Rossum630112e1995-01-10 17:08:10 +0000145 w.focus_set()
146 w.tk.mainloop()
147
148if __name__ == '__main__':
149 test()