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、代码逻辑有些随意,主要是用于测试。效果如下:

相关推荐
我不是立达刘宁宇7 分钟前
权限提升-前置基础-linux
linux·运维·服务器
hehelm7 分钟前
C++11 新特性
c++
IOT.FIVE.NO.19 分钟前
claude code desktop cowork报错解决和记录Workspace..The isolated Linux environment ...
linux·服务器·数据库
我不是懒洋洋10 分钟前
【数据结构】排序算法(直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序、计数排序)
c语言·数据结构·c++·经验分享·算法·排序算法
邪修king12 分钟前
UE5:C++ 实现 游戏逻辑 ↔ UI 双向联动
c++·游戏·ue5
TOWE technology12 分钟前
EN32/G2401FCI——32A大功率,24位国标输出的高密度配电方案
linux·服务器·网络·科技·数据中心·pdu·智能pdu
青梅橘子皮9 小时前
Linux---基本指令
linux·运维·服务器
REDcker9 小时前
Linux信号机制详解 POSIX语义与内核要点 sigaction与备用栈实践
linux·运维·php
汉克老师10 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
cui_ruicheng10 小时前
Linux进程间通信(三):System V IPC与共享内存
linux·运维·服务器