I want to embed an xterm
into a pyqt4
widget and communicate with it. Especially I want to be able to print to it and execute commands on it (such that it returns to normal user prompt after executing the command just like a normal shell would do). Consider the following minimal example. How can I make it work?
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class embedxterm(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setMinimumWidth(900)
self.setMinimumHeight(400)
self.process = QProcess(self)
self.terminal = QWidget(self)
self.terminal.setMinimumHeight(300)
self.cmd1 = QPushButton('Command1',self)
self.cmd2 = QPushButton('Command2',self)
self.hello = QPushButton('Print Hello World',self)
layout = QVBoxLayout(self)
layoutH = QHBoxLayout(self)
layoutH.addWidget(self.cmd1)
layoutH.addWidget(self.cmd2)
layoutH.addWidget(self.hello)
layout.addLayout(layoutH)
layout.addWidget(self.terminal)
self.process.start(
'xterm',['-into', str(self.terminal.winId())])
self.cmd1.clicked.connect(self.Ccmd1)
self.cmd2.clicked.connect(self.Ccmd2)
self.hello.clicked.connect(self.Chello)
def Ccmd1(self):
self.process.write('ls -l')
# Should execute ls -l on this terminal
def Ccmd2(self):
self.process.write('ping www.google.com')
# should execute ping www.google.com on this terminal
def Chello(self):
self.process.write('Hello World')
# should just print "Hello World" on this terminal
if __name__ == "__main__":
app = QApplication(sys.argv)
main = embedxterm()
main.show()
sys.exit(app.exec_())
To embed a xterm
into one of your windows you should use:
-into windowId Given an X window identifier (a decimal integer), xterm will reparent its top-level shell widget to that window. This is used to embed xterm within other applications.
xterm
itself talks to the launched shell (bash etc). So, you have to find a way to talk to that launched shell. You can pass open filedescriptors to xterm
via the -Sccn
flag:
This option allows xterm to be used as an input and output channel for an existing program and is sometimes used in specialized applications
So, I think you have to create your instance of bash, zsh, whatever you want to send the commands to. Then connect the stdout/stderr fd of that subprocess to your instance of xterm and connect the stdin to your main program which then multiplexes the input coming from the xterm and the commands you want to send to the bash (so they will get executed and be shown in xterm).
bash ----------------------> xterm
\--< your.py <----------/
The manpage of urxvt
reveils that urxvt
has some similar switches:
-embed windowid
Tells urxvt to embed its windows into an already-existing window, which enables applications to easily embed a terminal. [ ... ] Here is a short Gtk2-perl snippet that illustrates how this option can be used (a longer example is in doc/embed):my $rxvt = new Gtk2::Socket;
$rxvt->signal_connect_after (realize => sub { my $xid = $_[0]->window->get_xid;
system "urxvt -embed $xid &";
});
and
-pty-fd file descriptor
Tells urxvt NOT to execute any commands or create a new pty/tty pair but instead use the given file descriptor as the tty master. This is useful if you want to drive urxvt as a generic terminal emulator without having to run a program within it.Here is a example in perl that illustrates how this option can be used (a longer example > is in doc/pty-fd):
use IO::Pty;
use Fcntl;my $pty = new IO::Pty;
fcntl $pty, F_SETFD, 0; # clear close-on-exec
system "urxvt -pty-fd " . (fileno $pty) . "&";
close $pty;# now communicate with rxvt
my $slave = $pty->slave;
while () { print $slave "got \n" }
To open a PTY from within python the pty
module looks promising: http://docs.python.org/2/library/pty.html
Interesting read: http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/
来源:https://stackoverflow.com/questions/14772138/embed-xterm-into-qwidget-and-communicate-with-it