我有一个启动器应用程序,当用户点击相关图标时,它将fork
和exec
一个Qt应用程序。
对于视觉反馈,我想从用户选择图标的时间开始显示等待光标,直到所请求的应用程序的主窗口显示在屏幕上。
void RocketLauncher::onItemSelect(QListWidgetItem* item)
{
QApplication::setOverrideCursor(Qt::WaitCursor);
const AppConfig& app = getAppConfig(item);
forkAndExec(app.cwd(), app.cmd(), app.args(), app.env());
// TODO: wait until app's main window is being displayed
QApplication::restoreOverrideCursor();
}
我遇到的问题是,在我的启动器应用中,我立即从fork
返回子进程的pid,但子进程仍需要一些时间{ {1}}以及显示在屏幕上的主窗口。
因此,我对exec
的调用立即执行,并且用户没有视觉提示应用程序仍在启动。
有什么方法可以让我发出孩子正在跑的信号吗?
答案 0 :(得分:3)
我可以看到两种实现方法:
通过明确的进程间通信。子应用程序可以在创建主窗口后告诉启动器应用程序,例如通过DBus调用,标准输出,共享内存或任何其他可用的IPC机制。 X11有startup notification library通过传递X消息使用显式IPC,由KDE和GNOME使用。
根据操作系统和使用过的窗口管理器,您可以向窗口管理器询问打开的窗口列表,并在创建新窗口时收到通知。我不认为有Qt API,您需要使用特定于平台的代码。对于X11,您可以执行与xwininfo程序类似的操作。此外,还有一个LGPL许可的KDE Frameworks API,名为KWindowSystem,其windowAdded
信号。我还没有检查实际实现的平台,文档建议至少使用X11和Mac OS。
答案 1 :(得分:0)
我建议您启动一个线程(使用QtConcurrentRun并使用QFutureWatcher处理),该线程负责启动子进程并等待结束显示GUI。这种机制可以使用管道来完成,你可以从子代码中的地方发送数据,你可以在那里显示GUI(catch showEvent()或MainWindow constrcutor的结尾......)。父进程中的线程必须休眠,直到在管道上接收数据才能唤醒。
在linux中有很多使用管道的例子。你也可以使用Unix套接字,共享内存或其他IPC,或者你可以在/ tmp中使用creatin测试一个文件,但这是一个坏主意。
另一个简单的想法是继续使用QProcess并从您的新程序中写入标准输出上的一些字符串,以指示GUI显示结束(以测试......):
bool Class::startExternalProgram(QString _file)
{
QtConcurrent::run(this, &Class::starting, _file);
return true;
}
bool Class::starting(QString file)
{
QProcess *p = new QProcess;
params << file;
p->start("your program", params);
if (!p->waitForStarted(5000)) {
p->close();
delete p;
crashFinish(1, QProcess::CrashExit);
return false;
}
else {
processes.push_back(p);
/*to handle crash*/
QObject::connect(p, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(crashFinish(int, QProcess::ExitStatus)));
p->waitForReadyRead(600000);/*10mn*/
... /*handle timeout here*/
return true;
}
}
void Class::crashFinish(int, QProcess::ExitStatus) {
auto p = qobject_cast<QProcess*>(QObject::sender());
...
}