0

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.

The error that I was trying to fix

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.

0 Answers0