【Wayland】QtWayland框架分析
创始人
2024-02-03 19:00:37
0

QtWayland框架分析

QtWayland概念介绍

QtWayland是Qt官方基于Wayland开发的一款Toolbox,根据其官网介绍

The QtWayland module consists of two parts:
Wayland platform plugin:
Enables Qt applications to be run as Wayland clients.
QtWaylandCompositor API:
Enables the creation of Wayland compositors using Qt and QtQuick.

可以将QtWayland的功能归纳为两点:

  1. 基于Qt/QtQuick,使用QtWayland可以写出一套 Compositor(Wayland Compositor)
  2. Qt应用可以作为Wayland的Client端运行。
  • 下图摘自Qt官网,对于Qt与Wayland关系的介绍。
    在这里插入图片描述 如何运行QtWayland?
  • Qtwayland是基于Qt编译的,可以参考QtWayland官网提供的编译手顺。并且QtWayland在其源码中,提供了一些Compositor的例子,在运行例子前只需要设置 如“QT_WAYLAND_HARDWARE_INTEGRATION”,“XDG_RUNTIME_DIR ”等环境变量即可(这里不在详细描述)

QtWayland源码分析

本文基于QtWayland 6.4的源码,对其模块框架及Compositor启动流程进行分析。

模块框架

请添加图片描述

  • ClientApi:Qtwayland提供给Client端使用的API。这些Api大部分是对于Wayland协议的封装。这样做的好处,是将Wayland协议与Client端进行了隔离。
  • ServerApi:QtWayland提供给你Server端(即Compositor)使用的API。这些API也是对Wayland协议的封装。你可以基于这些API,写出一个Compositor。
  • Plugins:插件模块。从Shell角度考虑,存在多种Shell,比如xdg-shell、ivi-shell、wl-shell、fullscreen-shell,Plugins实现了多种Shell(Client端),Qt应用只需要在启动前设定 Shell有关的环境变量,在启动Qt应用时就会根据环境变量使用不同的Shell。除了Shell外,还包括HardWareIntegration,这是Server端和Client端使用的Buffer,也是根据设定的 环境变量进行加载。
  • Platform:除了QtWayland,QtBase中实现了一个叫 eglfs的platform使用的渲染方式。
  • Common:协议文件、Scanner(根据协议文件生成源代码的工具。)

Compositor启动(Server)

  • QWaylandCompositor是启动的入口
// src\compositor\compositor_api\qwaylandcompositor.h
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandCompositor : public QWaylandObject
{Q_OBJECT// 对应类 QWaylandCompositorPrivate Q_DECLARE_PRIVATE(QWaylandCompositor)// ...
public:QWaylandCompositor(QObject *parent = nullptr);~QWaylandCompositor() override;
}// src\compositor\compositor_api\qwaylandcompositor_p.h
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandCompositorPrivate : public QObjectPrivate, public QtWaylandServer::wl_compositor, public QtWaylandServer::wl_subcompositor
{
public:QWaylandCompositorPrivate(QWaylandCompositor *compositor);~QWaylandCompositorPrivate() override; 
}
  • 创建QWaylandCompositor,调用其构造函数
// new QWaylandCompositor(),因为它提供默认参数,所以可以不传参数
QWaylandCompositor::QWaylandCompositor(QObject *parent): QWaylandObject(*new QWaylandCompositorPrivate(this), parent)
{
}
// new QWaylandCompositorPrivate
QWaylandCompositorPrivate::QWaylandCompositorPrivate(QWaylandCompositor *compositor)
{// ...// 创建Display(全局Display)if (!display) {display = wl_display_create();ownsDisplay = true;}// ...
}
  • 到这步,创建了全局的Display对象。上面的代码中可以看到 wl_compositor 这个对象。
  • 写Compositor(Server)时,创建QWaylandCompositor后,需要调用其create方式,进行Server端的初始化。
/** Initializes the QWaylandCompositor.* If you override this function in your subclass, be sure to call the base class implementation.*/
void QWaylandCompositor::create()
{Q_D(QWaylandCompositor);// d 是QWaylandCompositorPrivate// 大部分初始化是在 QWaylandCompositorPrivate::init中实现d->preInit();d->init();
}void QWaylandCompositorPrivate::init()
{// 设置Server端Socket名字// Socket用来跟Client端进行协议通讯if (socket_name.isEmpty()) {const int socketArg = arguments.indexOf(QLatin1String("--wayland-socket-name"));if (socketArg != -1 && socketArg + 1 < arguments.size())socket_name = arguments.at(socketArg + 1).toLocal8Bit();}// 这里初始化了wl_compositor/wl_subcompositor协议// 这里会调用到wl_global_create,将全局对象发布到display上wl_compositor::init(display, 4);wl_subcompositor::init(display, 1);// 初始化shmwl_display_init_shm(display);// 创建Server端Socket// Socket用于跟Client端通信if (!socket_name.isEmpty()) {if (wl_display_add_socket(display, socket_name.constData()))qFatal("Fatal: Failed to open server socket: \"%s\". XDG_RUNTIME_DIR is: \"%s\"\n", socket_name.constData(), getenv("XDG_RUNTIME_DIR"));} else {const char *autoSocketName = wl_display_add_socket_auto(display);if (!autoSocketName)qFatal("Fatal: Failed to open default server socket. XDG_RUNTIME_DIR is: \"%s\"\n", getenv("XDG_RUNTIME_DIR"));socket_name = autoSocketName;emit q->socketNameChanged(socket_name);}// 拿到looploop = wl_display_get_event_loop(display);int fd = wl_event_loop_get_fd(loop);// 通过Qt的QSocketNotifier 监听fd,当有读事件时触发回调processWaylandEventsQSocketNotifier *sockNot = new QSocketNotifier(fd, QSocketNotifier::Read, q);QObject::connect(sockNot, SIGNAL(activated(QSocketDescriptor)), q, SLOT(processWaylandEvents()));QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;QObject::connect(dispatcher, SIGNAL(aboutToBlock()), q, SLOT(processWaylandEvents()));}
  • 上述部分,完成了全局Display创建、Socket创建、wl_compositor这个重要协议的初始化,监听Socket的事件并绑定事件处理函数。Compositor端初始化的主要工作到这里完成。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...