Assuming you really are trying to embed the GUI elements of child processes into your own process then the code you've has a few potential issues.
Firstly, it is possible that on some platforms QProcess::start
simply queues the required data. The child process won't actually fork until the event loop is entered. Thus when you have...
QProcess ps;
ps.start("sudo ./exe 1");
sleep(10);
ifstream myfile;
myfile.open("winid.txt");
WId id;
myfile >> id;
it's possible that the sleep(10)
call simply blocks everything and the process hasn't yet started when you try to read. Even if the child process does start there's no guarantee that it will have written its window id to winid.txt
by the time you read it -- far better to act on the QProcess::readyReadStandardOutput
signal instead.
Secondly, you pass a complete command line to QProcess::start
. On certain platforms that will pass the command through a shell meaning you have to be very careful about quoting/escaping special characters. Better to use the...
void QProcess::start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode = ReadWrite)
...overload instead.
Finally, the command you're actually running here is sudo
. Assuming this is on a Linux
system (or similar) then sudo
may well require a password and you haven't set up any means of providing one.
By way of an example, the following code does one of two things depending on how it's invoked.
If invoked with a single command line argument it creates/shows a QPushButton
derived widget and writes that widget's window id to standard output.
If invoked with no arguments it will act as a parent process. It starts several child processes and, when each prints its window id to stdout, captures and embeds the associated widget within its own.
#include <cstdlib>
#include <iostream>
#include <set>
#include <QApplication>
#include <QDebug>
#include <QLabel>
#include <QProcess>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QWindow>
namespace {
/*
* This is the basic QPushButton derived widget that will be created by the
* child process(es).
*/
class remote_process_widget: public QPushButton {
using super = QPushButton;
public:
explicit remote_process_widget (const QString &name, QWidget *parent = nullptr)
: super(name, parent)
{
}
};
}
int
main (int argc, char **argv)
{
try {
QApplication app(argc, argv);
std::set<QProcess *> processes;
if (argc > 1) {
/*
* This process was started with at least one command line arg so we
* assume it's a managed child process. Need to write the window id to
* stdout for the parent process to read.
*/
auto *w = new remote_process_widget(QString::fromStdString(argv[1]));
w->show();
std::cout << w->winId() << std::endl;
} else {
/*
* No command line args so start up as the parent process. Create some
* child processes and set things up to manage their widgets.
*/
auto *w = new QWidget;
auto *l = new QVBoxLayout(w);
auto *label = new QLabel("Parent process");
label->setAlignment(Qt::AlignCenter);
l->addWidget(label);
w->show();
/*
* Now create/start the child processes.
*/
for (int i = 0; i < 4; ++i) {
auto *process = new QProcess;
processes.insert(process);
/*
* Connect to the `QProcess::readyReadStandardOutput` signal of the
* child. This is where the real work is done regarding the
* capture/embedding of the child processes widgets.
*/
QObject::connect(process, &QProcess::readyReadStandardOutput,
[l, process]()
{
auto wid = QString(process->readAllStandardOutput()).toULongLong();
std::cout << "wid = " << wid << "\n";
if (auto *window = QWindow::fromWinId(wid)) {
if (auto *container = QWidget::createWindowContainer(window)) {
l->addWidget(container);
}
}
});
/*
* Start the child process.
*/
process->start(argv[0], QStringList() << QString("Remote process %1").arg(i));
}
}
app.exec();
/*
* Shut down all child processes.
*/
for (auto process: processes) {
process->terminate();
std::cout << "waiting for process " << process->processId() << " to terminate\n";
while (!process->waitForFinished())
;
}
std::cout << "done\n";
}
catch (std::exception &ex) {
qCritical() << "\n" << ex.what();
}
catch (...) {
qCritical() << "\nunrecognized exception";
}
exit(0);
}
So, while it doesn't use QML
, if you run it without any arguments it should create its own widget, create four child processes and embed the widgets associated with those child processes. Something like...
