Linux下Qt应用嵌入外部进程窗口
Qt启动嵌入外部进程窗口Linux x11环境下Qt应用实现多进程窗口嵌入效果展示如图:实现说明启动外部进程,通过进程id获取窗口winid,然后通过QWindow::fromWinId获取QWindow,使用QWidget::createWindowContainer创建包含进程界面QWidget。embedexternalapp.cppembedexternalapp::embedextern
·
Qt启动嵌入外部进程窗口
Linux x11环境下Qt应用实现多进程窗口嵌入
效果展示
如图:
实现说明
启动外部进程,通过进程id获取窗口winid,然后通过QWindow::fromWinId获取QWindow,使用QWidget::createWindowContainer创建包含进程界面QWidget。
embedexternalapp.cpp
embedexternalapp::embedexternalapp(QWidget *parent)
: QWidget(parent)
{
QStringList programs;
programs << "/usr/bin/gedit"
<< "/usr/bin/kompare"
<< "/usr/bin/gnome-help";
foreach (QString pro, programs) {
QProcess process;
qint64 pid;
if (process.startDetached(pro, QStringList(), "", &pid)) {
pidlist.push_back(pid);
}
}
QThread::currentThread()->msleep(1500);
//等待一会,虽然进程启动但如果窗口没有显示则无法通过Pid获取窗口Id
QVBoxLayout *mainlayout = new QVBoxLayout(this);
foreach (qint64 pid, pidlist) {
unsigned long winid = get_win_id_from_pid(pid);
if (0 == winid) {
QProcess proc;
proc.execute(QString("kill -9 %1").arg(pid));
continue;
}
QWindow *window = QWindow::fromWinId(winid);
window->setFlags(Qt::FramelessWindowHint);
QWidget *widget = QWidget::createWindowContainer(window);
widget->setMinimumSize(800, 600);
mainlayout->addWidget(widget);
}
QWidget *pembedwidget = new QWidget;
pembedwidget->setLayout(mainlayout);
QScrollArea *pscroll = new QScrollArea;
pscroll->setWidget(pembedwidget);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(pscroll);
this->setLayout(layout);
}
utils.cpp
#include "utils.h"
#include <QDebug>
#include <list>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
static std::list<Window> _result;
unsigned long get_win_id_from_pid(int pid)
{
unsigned long winid = 0;
_result.clear();
// Get the PID property atom.
Display *display = XOpenDisplay(0);
Window wRoot = XDefaultRootWindow(display);
Atom _atomPID = XInternAtom(display, "_NET_WM_PID", True);
if (_atomPID == None) {
return 0;
}
search(wRoot, display, _atomPID, pid);
if (_result.size() > 0) {
winid = *_result.begin();
}
qInfo() << _result.size();
return winid;
}
void search(unsigned long w, void *display, unsigned long _atomPID, int _pid)
{
Display *_display = static_cast<Display *>(display);
// Get the PID for the current Window.
Atom type;
int format;
unsigned long nItems;
unsigned long bytesAfter;
unsigned char *propPID = 0;
if (Success == XGetWindowProperty(_display, w, _atomPID, 0, 1, False,
XA_CARDINAL, &type, &format, &nItems,
&bytesAfter, &propPID)) {
if (propPID != 0) {
// If the PID matches, add this window to the result set.
if (_pid == *((unsigned long *)propPID)) {
_result.push_back(w);
}
XFree(propPID);
}
}
// Recurse into child windows.
Window wRoot;
Window wParent;
Window *wChild;
unsigned nChildren;
if (0 != XQueryTree(_display, w, &wRoot, &wParent, &wChild, &nChildren)) {
for (unsigned i = 0; i < nChildren; i++) {
search(wChild[i], _display, _atomPID, _pid);
}
}
// XFree(propPID);
}
通过进程id获取窗口winid,一个进程窗口可能有多个子窗口因此会获取到多个winid(不是所有子窗口都是真实窗口),我们取第一个就可以了。
注意:
- 测试发现gtk应用嵌入后输入框无法支持中文输入,Qt应用嵌入后可以正常使用
- 虽然设置了frameless但有些窗口无法生效,可能是现有窗口已经是在frameless窗口上自定义添加的
更多推荐
已为社区贡献1条内容
所有评论(0)