I tried to enhanced this code The code embeds a terminal into a pyqt tab and sends command remotely with a button. I tried to make it so that a new tab with another embedded terminal instance is added when pressing a button. I successfully implemented this but the embedded terminal in the new tab isn't placed inside.
This is the code.
import time
from gi.repository import Wnck, Gdk
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import gi
import uuid
gi.require_version('Wnck', '3.0')
class Container(QtWidgets.QTabWidget):
def __init__(self):
QtWidgets.QTabWidget.__init__(self)
self.sess_count = 0
self.embed('xterm')
def embed(self, command, *args):
self.name_session = uuid.uuid4().hex
print ("SESSION {0} ID: {1}".format(self.sess_count,self.name_session))
proc = QtCore.QProcess()
proc.setProgram(command)
proc.setArguments(args)
started, procId = QtCore.QProcess.startDetached(
"xterm", ["-e", "tmux", "new", "-s", self.name_session], "."
)
if not started:
QtWidgets.QMessageBox.critical(
self, 'Command "{}" not started!'.format(command), "Eh")
return
attempts = 0
while attempts < 10:
screen = Wnck.Screen.get_default()
screen.force_update()
# do a bit of sleep, else window is not really found
time.sleep(0.1)
# this is required to ensure that newly mapped window get listed.
while Gdk.events_pending():
Gdk.event_get()
for w in screen.get_windows():
print(attempts, w.get_pid(), procId, w.get_pid() == procId)
if w.get_pid() == procId:
#self.window = QtGui.QWindow.fromWinId(w.get_xid())
proc.setParent(self)
win32w = QtGui.QWindow.fromWinId(w.get_xid())
win32w.setFlags(QtCore.Qt.FramelessWindowHint)
widg = QtWidgets.QWidget.createWindowContainer(win32w)
self.addTab(widg, command)
#self.insertTab(self.sess_count, widg, command)
#widg.setFocusPolicy(QtCore.Qt.StrongFocus)
#self.currentIndex(self.sess_count)
self.resize(500, 400) # set initial size of window
# self.setFocus()
# self.update()
return
attempts += 1
QtWidgets.QMessageBox.critical(
self, 'Window not found', 'Process started but window not found')
def stop(self):
QtCore.QProcess.execute(
"tmux", ["kill-session", "-t", self.name_session])
def send_command(self, command):
QtCore.QProcess.execute(
"tmux", ["send-keys", "-t", self.name_session, command, "Enter"]
)
def add_terminal(self):
self.sess_count +=1
self.embed('xterm')
#self.addTab(EmbTerminal(),"")
#self.currentIndex(self.sess_count)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.ifconfig_btn = QtWidgets.QPushButton("ifconfig")
self.ping_btn = QtWidgets.QPushButton("ping")
self.add_term_btn = QtWidgets.QPushButton("add terminal")
self.terminal = Container()
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QGridLayout(central_widget)
lay.addWidget(self.ifconfig_btn, 0, 0)
lay.addWidget(self.ping_btn, 0, 1)
lay.addWidget(self.add_term_btn, 1, 0, 1, 2)
lay.addWidget(self.terminal, 2, 0, 2, 2)
self.resize(640, 480)
self.ifconfig_btn.clicked.connect(self.launch_ifconfig)
self.ping_btn.clicked.connect(self.launch_ping)
self.add_term_btn.clicked.connect(self.terminal.add_terminal)
def launch_ifconfig(self):
self.terminal.send_command("ifconfig")
def launch_ping(self):
self.terminal.send_command("ping 8.8.8.8")
def closeEvent(self, event):
self.terminal.stop()
super().closeEvent(event)
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Also, I found a workaround to fix this, Video Link on the workaround, but as you can see, it involves interacting the GUI, not by code. I want to fix this via code.
When clicking the Add Terminal Button, the embedded terminal should be inside the new tab.