PageRenderTime 264ms CodeModel.GetById 121ms app.highlight 15ms RepoModel.GetById 125ms app.codeStats 1ms

/Demo/tkinter/guido/ShellWindow.py

http://unladen-swallow.googlecode.com/
Python | 147 lines | 128 code | 18 blank | 1 comment | 20 complexity | ccb9662739f61d45ba3b01c0f47a556e MD5 | raw file
  1import os
  2import sys
  3import string
  4from Tkinter import *
  5from ScrolledText import ScrolledText
  6from Dialog import Dialog
  7import signal
  8
  9BUFSIZE = 512
 10
 11class ShellWindow(ScrolledText):
 12
 13    def __init__(self, master=None, shell=None, **cnf):
 14        if not shell:
 15            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
 23        apply(ScrolledText.__init__, (self, master), cnf)
 24        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)
 32        self.tk.createfilehandler(self.fromchild, READABLE,
 33                                  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"
 50            Dialog(self.master,
 51                   text=msg,
 52                   title="Exit status",
 53                   bitmap='warning',
 54                   default=0,
 55                   strings=('OK',))
 56            return
 57        self.insert(END, data)
 58        self.pos = self.index("end - 1 char")
 59        self.yview_pickplace(END)
 60
 61    def inputhandler(self, *args):
 62        if not self.pid:
 63            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)
 68        os.write(self.tochild, line)
 69        return "break"
 70
 71    def sendeof(self, *args):
 72        if not self.pid:
 73            self.no_process()
 74            return "break"
 75        os.close(self.tochild)
 76        return "break"
 77
 78    def sendsig(self, sig):
 79        if not self.pid:
 80            self.no_process()
 81            return "break"
 82        os.kill(self.pid, sig)
 83        return "break"
 84
 85    def sigint(self, *args):
 86        return self.sendsig(signal.SIGINT)
 87
 88    def sigquit(self, *args):
 89        return self.sendsig(signal.SIGQUIT)
 90
 91    def sigterm(self, *args):
 92        return self.sendsig(signal.SIGTERM)
 93
 94    def sigkill(self, *args):
 95        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',))
104
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        for i in 0, 1, 2:
114            try:
115                os.close(i)
116            except os.error:
117                pass
118        if os.dup(p2cread) <> 0:
119            sys.stderr.write('popen2: bad read dup\n')
120        if os.dup(c2pwrite) <> 1:
121            sys.stderr.write('popen2: bad write dup\n')
122        if os.dup(c2pwrite) <> 2:
123            sys.stderr.write('popen2: bad write dup\n')
124        os.closerange(3, MAXFD)
125        try:
126            os.execvp(prog, args)
127        finally:
128            sys.stderr.write('execvp failed\n')
129            os._exit(1)
130    os.close(p2cread)
131    os.close(c2pwrite)
132    return pid, c2pread, p2cwrite
133
134def test():
135    shell = string.join(sys.argv[1:])
136    root = Tk()
137    root.minsize(1, 1)
138    if shell:
139        w = ShellWindow(root, shell=shell)
140    else:
141        w = ShellWindow(root)
142    w.pack(expand=1, fill=BOTH)
143    w.focus_set()
144    w.tk.mainloop()
145
146if __name__ == '__main__':
147    test()