linux桌面软件(wps)内嵌到其他窗口

程序测试环境是:slackware系统,属于linux系统,有桌面(Xface Session)。系统镜像是:slackware64-15.0-install-dvd.iso。qt、c++代码实现。

程序功能:将已经打开的wps(word、pdf等都可以)软件界面内嵌到qt窗口里。

必要条件:slackware系统里需要安装wps、qt5开发工具,本篇文章不做详述。

编译说明:上图是测试demo编译时,在编译工程里加的依赖。 以下截图的部分代码,其他代码不做描述。

form.h:

cpp 复制代码
#ifndef FORM_H
#define FORM_H

#include <QWidget>
#include <QProcess>

namespace Ui {
class Form;
}

class Form : public QWidget
{
    Q_OBJECT

public:
    explicit Form(QWidget *parent = nullptr);
    ~Form();

    void find_window_id_in_tree();

    void find_window_id_by_class();

    void add_window_in_qt(WId id);

private:
    Ui::Form *ui;
    QProcess *process;
};

#endif // FORM_H

form.cpp

cpp 复制代码
#include "form.h"
#include "ui_form.h"
#include <QWindow>
#include <QVBoxLayout>
#include <QtX11Extras/QX11Info>
#include <xcb/xcb.h>
#include <QDebug>
#include <X11/Xlib.h> 
#include <X11/Xatom.h> 
#include <iostream>  
#include <vector>  
#include <string>  
#include <sstream>  
#include <fstream>

Form::Form(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Form)
{
    ui->setupUi(this);
    find_window_id_in_tree();
    find_window_id_by_class();
}

Form::~Form()
{
    delete ui;
}

// 通过系统窗口树形结构去一层层遍历窗口(我这里没有遍历子窗口,如果找不到某个窗口,或许是因为是子窗口)
void Form::find_window_id_in_tree()
{
    Display *display = XOpenDisplay(nullptr);
    if (!display) {
        std::cerr << "Cannot open display\n";
        return;
    }
    Window root = DefaultRootWindow(display);
    Window parent, *children;
    unsigned int num_children;

    if (!XQueryTree(display, root, &root, &parent, &children, &num_children)) {
        return;
    }

    std::vector<Window> windows;
    windows.push_back(root);
    for (unsigned int i = 0; i < num_children; ++i) {
        windows.push_back(children[i]);
    }
    XFree(children);

    for (Window win : windows) {
        char* name;
        int status = XFetchName(display, win, &name);
        if (status == 1) {
            // 这里的win就是窗口的id,也是窗口的句柄值
            std::cout << "Found window name: " << name << " " << win << std::endl;
            if (std::string(name).find("wps") != std::string::npos) {
//                XFree(name);
//                return;
            }
            XFree(name);
        }

        // 递归检查子窗口(如果有的话)
        // 注意:这里为了简化示例,没有实现递归
    }
}

// 将第三方软件(wps)窗口内嵌到qt窗口里
void Form::add_window_in_qt(WId id)
{
     QWindow *win = QWindow::fromWinId(id);
     QWidget *widget = QWidget::createWindowContainer(win);
     widget->setParent(this);
     QVBoxLayout *layout = new QVBoxLayout();
     layout->addWidget(widget);
     this->setLayout(layout);
}

// 获取窗口id(句柄)(找到的另外一种比较快捷的拿到窗口句柄的方式)
void Form::find_window_id_by_class()
{
    Display* display = XOpenDisplay(NULL);
    if (!display) {
        std::cerr << "Failed to open display" << std::endl;
        return;
    }

    Atom netClientListAtom = XInternAtom(display, "_NET_CLIENT_LIST", False);
    Atom actualType;
    int format;
    unsigned long numItems, bytesAfter;
    unsigned char* data = NULL;

    int status = XGetWindowProperty(display, DefaultRootWindow(display),
                                    netClientListAtom, 0, ~0UL, False,
                                    AnyPropertyType,
                                    &actualType, &format, &numItems, &bytesAfter,
                                    &data);


    if (status == Success && actualType == XA_WINDOW) {
        Window* windows = reinterpret_cast<Window*>(data);
        for (unsigned long i = 0; i < numItems; ++i) {

            Window win = windows[i];
            Atom actualType;
            int format;
            unsigned long nitems;
            unsigned long bytes_after;
            unsigned char* prop_data = nullptr;

            // 获取WM_CLASS属性
            if (XGetWindowProperty(display, win, XInternAtom(display, "WM_CLASS", False), 0, 1024, False, XA_STRING,
                                &actualType, &format, &nitems, &bytes_after, &prop_data) == Success) {
                std::string className(reinterpret_cast<char*>(prop_data));
                if (actualType == XA_STRING && className == "wpspdf") {
                    std::cout << "Window class name for window " << win << ": " << className << std::endl;
                    XFree(prop_data);

                    add_window_in_qt(win);
                }
            }
        }
    } else {
        std::cerr << "Failed to get window list property" << std::endl;
    }

    if (data != NULL) {
        XFree(data);
    }

    XCloseDisplay(display);
}

代码需要说明的有如下几点:

1、wps在slackware 中安装好后,可以打开word、pdf、execl、ppt,他们分别对应的可执行文件是wps、wpspdf、et、wpp。

2、本次demo测试,是将pdf窗口内嵌到qt窗口。

3、代码逻辑有些随意,主要是用于测试。效果如下:

相关推荐
木子欢儿1 小时前
国内 macOS/Linux 安装 rust
linux·运维·服务器·macos·rust
say_fall1 小时前
【Linux网络编程】计算机网络基础:局域网与广域网、OSI七层模型与TCP/IP五层模型、封装解包与MAC/IP地址、端口号与socket编程接口
linux·网络·tcp/ip·计算机网络·信息与通信
青少儿编程课堂1 小时前
蓝桥杯青少组图形化 STEMA 省考(报名倒计时·11/22开考)+ 全国青少年信息素养大赛 2026—2027赛季 + 电子学会图形化考级:校园华容道大闯关
c++·python·算法·bfs·信息学竞赛
进击的荆棘2 小时前
Linux系统——线程同步与互斥
linux·运维·服务器·策略模式·同步·互斥·posix
白杨尚青2 小时前
C++进阶篇(五):红黑树——四条规则、三种插入情况与旋转变色
开发语言·数据结构·c++·stl·红黑树·平衡二叉树
橙橙笔记2 小时前
QT的学习第四部分
linux·qt·学习·音视频
.道阻且长.2 小时前
Linux基本开发工具:gdb和cgdb的使用
linux·运维·服务器·开发语言
叼烟扛炮2 小时前
Linux 学习笔记(五十四):内网穿透实战——用 frp 让外网访问你的私人电脑
linux·服务器·网络·笔记·学习
Android系统攻城狮2 小时前
Linux FFmpeg深度解析之av_guess_format调用流程与实战(三十六)
linux·运维·服务器·ffmpeg·ffmpeg音视频进阶
旖旎夜光3 小时前
【C++ 基础入门】C++ 继承(上):概念、切片、隐藏、默认成员函数与友元
c++·笔记·学习