【Wayland】QtWayland启动流程分析

news2024/11/16 15:36:24

QtWayland启动流程分析

QtWayland版本:6.4.0
QtWayland的服务端(CompositorServer)入口点是QWaylandCompositor这个类,可以参考官网提供的example,其路径为:examples\wayland\minimal-cpp

下面基于minimal-cpp这个例子,进行分析。

启动流程分析

  • examples\wayland\minimal-cpp\main.cpp
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include <QGuiApplication>
#include "window.h"
#include "compositor.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    Window window;
    window.resize(800,600);
    // 这里启动了Compositor Server
    Compositor compositor(&window);
    window.show();

    return app.exec();
}

上面的代码中,使用QGuiApplication 创建了一个App实例,并使用Window类(其父类为QOpenGLWindow),创建了一个WIndow对象。这里重点关注的是Compositor类,通过创建Compositor类实际上启动了 QtWayland Compositor Server。

  • examples\wayland\minimal-cpp\compositor.h
class Compositor : public QWaylandCompositor
{
    //省略
}

Compositor::Compositor(Window *window)
    : m_window(window)
{
    window->setCompositor(this);
    connect(window, &Window::glReady, this, [this] { create(); });
}

Compositor::~Compositor()
{
}

void Compositor::create()
{
    QWaylandOutput *output = new QWaylandOutput(this, m_window);
    QWaylandOutputMode mode(m_window->size(), 60000);
    output->addMode(mode, true);
    QWaylandCompositor::create();
    output->setCurrentMode(mode);

    m_iviApplication = new QWaylandIviApplication(this);
    connect(m_iviApplication, &QWaylandIviApplication::iviSurfaceCreated, this, &Compositor::onIviSurfaceCreated);
}

分析一下上面Compositor类的代码
Compositor的父类是QWaylandCompositor,因此创建Compositor时会调用父类的构造函数。

QWaylandCompositor(QObject *parent = nullptr);

QWaylandCompositor::QWaylandCompositor(QObject *parent)
    : QWaylandObject(*new QWaylandCompositorPrivate(this), parent)
{
}

上面的代码创建了QWaylandCompositorPrivate这个类。我们看一下这个类的定义。

// 父类有
// QtWaylandServer::wl_compositor
// QtWaylandServer::wl_subcompositor
// QObjectPrivate
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandCompositorPrivate : public QObjectPrivate, public QtWaylandServer::wl_compositor, public QtWaylandServer::wl_subcompositor
{
}

QWaylandCompositorPrivate::QWaylandCompositorPrivate(QWaylandCompositor *compositor)
{
    if (QGuiApplication::platformNativeInterface())
        display = static_cast<wl_display*>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("server_wl_display"));

    if (!display) {
    	// 创建了全局Display对象
        display = wl_display_create();
        ownsDisplay = true;
    }
   // 省略
}

QWaylandCompositorPrivate这个类的父类比较多,主要包括 QtWaylandServer::wl_compositor和QtWaylandServer::wl_subcompositor这两个,这两个类是QtWayland根据 Wayland.xml 这个协议生成的,利用这两个类可以初始化wl_compositor和wl_subcompositor两个协议对象。在QWaylandCompositorPrivate的构造函数中调用了wl_display_create,通过该函数创建了全局的Display对象。

  • 让我们回到上面代码中Compositor这个类的构造函数中。
Compositor::Compositor(Window *window)
    : m_window(window)
{
    window->setCompositor(this);
    connect(window, &Window::glReady, this, [this] { create(); });

父类的构造函数执行后,会执行当前类的构造函数。上面代码中,只关注connect这段。该段代码将 Window::glReady这个信息和Compositor类的create函数绑定。glReady这个信号会在WIndow(父类为QOpenGLWindow)自身初始化中,被调用。本文只关住 create这个函数。

  • examples\wayland\minimal-cpp\compositor.cpp
void Compositor::create()
{
    QWaylandOutput *output = new QWaylandOutput(this, m_window);
    QWaylandOutputMode mode(m_window->size(), 60000);
    output->addMode(mode, true);
    QWaylandCompositor::create();
    output->setCurrentMode(mode);
    // 省略
}
  • 上面的代码中创建了QWaylandOutput,这个类最终会初始化wl_output这个Wayland协议。代码中调用了QWaylandCompositor::create()
  • src\compositor\compositor_api\qwaylandcompositor.cpp
/*!
 * 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->preInit();
    d->init();
}

void QWaylandCompositorPrivate::preInit()
{
    Q_Q(QWaylandCompositor);

    if (preInitialized)
        return;

    if (seats.empty())
        seats.append(q->createSeat());

    preInitialized = true;
}

void QWaylandCompositorPrivate::init()
{
    Q_Q(QWaylandCompositor);
    QStringList arguments = QCoreApplication::instance()->arguments();
	 
	 // 设置Socket名字
    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_compoisotor和wl_subcompositor这两个协议
    wl_compositor::init(display, 4);
    wl_subcompositor::init(display, 1);
    // 省略
    // 初始化shm
    wl_display_init_shm(display);
	
	// 创建socket,socket用于Compositor server与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);
    }

    // 省略
    // 获取loop,并使用QSocketNotifier,监听fd产生可读的event,当有可读的event时,调用processWaylandEvents这个函数
    loop = wl_display_get_event_loop(display);
    int fd = wl_event_loop_get_fd(loop);
    QSocketNotifier *sockNot = new QSocketNotifier(fd, QSocketNotifier::Read, q);
    QObject::connect(sockNot, SIGNAL(activated(QSocketDescriptor)), q, SLOT(processWaylandEvents()));
    // 省略
    // 标记已经初始化了
    initialized = true;
}

void QWaylandCompositor::processWaylandEvents()
{
    Q_D(QWaylandCompositor);
    int ret = wl_event_loop_dispatch(d->loop, 0);
    if (ret)
        fprintf(stderr, "wl_event_loop_dispatch error: %d\n", ret);
}
  • 上面的代码,创建了CompositorServer与Client端通信使用的sockect,并且监听了event loop的fd,当fd可读时触发绑定的事件函数。到这里Compoositor server端主要的启动流程便完事了。
  • 启动时序图:
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/134210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

详解 Redis 中的 AOF 日志

AOF&#xff08;Append Only File&#xff09;追加写&#xff0c; AOF 日志它是写后日志&#xff0c;“写后”的意思是 Redis 是先执行命令&#xff0c;把数据写入内存&#xff0c;然后才记录日志&#xff0c;如下图所示&#xff1a; 后写日志有什么好处呢&#xff1f; Redis …

FPGA知识汇集-串行 RapidIO: 高性能嵌入式互连技术

本文摘自&#xff1a;德州仪器网站 串行RapidIO: 高性能嵌入式互连技术 | 德州仪器 (http://ti.com.cn) 串行RapidIO针对高性能嵌入式系统芯片间和板间互连而设计&#xff0c;它将是未来十几年中嵌入式系统互连的最佳选择。 本文比较RapidIO和传统互连技术的优点&#xff1b…

Windows内核--GUI显示原理(6.1)

传统的Windows图形处理 在Vista之前&#xff0c;图形子系统内核部分win32k.sys 通过DDI接口操作显示驱动&#xff0c; 显示驱动通过ENG接口调用win32k.sys. From: Windows 2000 显示体系结构 显示驱动程序的作用 不同显示驱动程序负责对于不同显示设备的优化。GDI仅负责标准位图…

使用python的parser.add_argument()在卷积神经网络中如何预定义参数?

在训练卷积神经网络时&#xff0c;需要预定义很多参数&#xff0c;例如batchsizebatch_sizebatchs​ize,backbone,dataset,datasetrootbackbone,dataset,dataset_rootbackbone,dataset,datasetr​oot等等&#xff0c;这些参数多而且特别零散&#xff0c;如果我们最初不把这些参…

我国制造行业 工业控制系统安全控制措施建设思考总结

声明 本文是学习GB-T 32919-2016 信息安全技术 工业控制系统安全控制应用指南. 下载地址 http://github5.com/view/585而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 工业控制系统安全控制概述 从概念上来说&#xff0c;工业控制系统的安全与其它领域…

【网络】网络发展,网络协议,网络传输流程,地址管理

目录 1.计算机网络背景 1.1网络发展 局域网和广域网 1.2 协议 2.网络协议初识 2.1协议分层 2.2OSI七层模型 2.3 TCP/IP 五层&#xff08;或四层&#xff09;模型 网络和操作系统之间的关系 2.4重谈协议 -- 计算机的视角&#xff0c;如何看待协议&#xff1f; 2.5 网…

python带你采集淘/苏/唯/考四大电商平台商品数据

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 环境介绍: python 3.8 越稳定越好 pycharm 2021专业版 一、苏宁 模块使用: selenium >>> pip install selenium 3.141.0 Python当中的模块 操作 浏览器的驱动 Chrome浏览器 Chromedr…

2023北京国际残疾人用品展览会|福祉博览会

全 称&#xff1a;2023中国国际福祉博览会暨中国国际康复博览会 英 文&#xff1a;Care & Rehabilitation Expo China 2023 时 间&#xff1a;2023年5月21-23日 地 点&#xff1a;北京首钢会展中心&#xff08;1-3号馆&#xff09; 主 办&#xff1a;中国残疾人联合会 承 办…

visdrone数据集转化为MOT数据集(用作MOTR模型训练)

文章目录visdrone数据集转化为MOT数据集MOT17 数据集格式traindet.txtgt.txtseqinfo.initestdet.txtvisdrone——Task 4_ Multi-Object Tracking配置seqinfo.ini文件代码如下Linuxvisdrone数据集转化为MOT数据集 MOT17 数据集格式 ├── MOT17 │ ├── images │ ├─…

YOLO学习记录之模型修改

我们在做实验时&#xff0c;不免需要对模型结构进行修改来检测自己的改进性能&#xff0c;对于一般模型而言&#xff0c;我们只需要简单的在代码中添加网络层即可&#xff0c;但对于一些预训练好的模型&#xff0c;我们则需要进行较为复杂的修改。以我们的YOLOV7模型为例&#…

[Linux]----守护进程

文章目录前言一、什么是守护进程?二、会话和进程组会话进程组三、守护进程的编程流程总结前言 这节课我来给大家讲解在Linux下如何让进程守护化,运行在后台,处理我们的任务. 正文开始! 一、什么是守护进程? 守护进程也称为精灵进程(Daemon),是运行在后台的一种特殊进程.它…

Mybatis-Plus快速使用相关知识点1

Mybatis-Plus的mapper、service 基本CURD BaseMapper BaseMapper是MyBatis-Plus提供的模板mapper&#xff0c;其中包含了基本的CRUD方法&#xff0c;泛型为操作的实体类型&#xff0c;Mapper 继承该接口后&#xff0c;无需编写 mapper.xml 文件&#xff0c;即可获得CRUD功能…

JavaScript刷LeetCode拿offer-链表篇

一、链表 链表&#xff08;Linked List&#xff09;是一种常见的基础数据结构&#xff0c;也是线性表的一种。 一个线性表是 n 个具有相同特性的数据元素的有限序列&#xff0c;线性表的存储结构分为两类&#xff1a;顺序表&#xff08;数组&#xff09;和链表。 链表相比较顺…

站得高,望得远

1、站得高&#xff0c;望的远 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。 这句话几乎概括了计算机系统软件体系结构的设计要点 &#xff0c;整个体系结构从上到下都是按照严格的层次结构设计的。不仅是计算机系统软件整个体系是这样的&#xff0c;体系里…

884. 两句话中的不常见单词 map与stringstream

目录 力扣884. 两句话中的不常见单词 【解法一】&#xff1a;最后写出了一坨屎&#xff0c;虽然它是一坨屎&#xff0c;但是它能动&#xff0c;虽然它是一坨屎&#xff0c;但起码这是我自己拉的 【大佬解法】 stringstream的使用 以及 map的使用 884. 两句话中的不常见单词 句…

python实现bib文件中参考文献的题目每个单词首字母大写

文章目录前言实现思路前言 由于毕业论文格式要求英文参考文献的题目的每个单词&#xff08;除了介词&#xff09;的首字母都要大写&#xff0c;如果一条条地自己修改费时费力&#xff0c;这里就想着简单地用python操作字符串的方式实现。 实现思路 观察bib参考文献格式&#x…

20230102单独编译Toybrick的TB-RK3588X开发板的Android12的内核

20230102单独编译Toybrick的TB-RK3588X开发板的Android12的内核 2023/1/2 17:40 《RK3588_Android12_SDK_Developer_Guide_CN.pdf》 原厂的开发板rk3588-evb1-lp4-v10单独编译内核的方式&#xff1a; cd kernel-5.10 export PATH../prebuilts/clang/host/linux-x86/clang-r4161…

【数据结构】C语言实现链表(单链表部分)

目录 前言 链表 链表的分类 1.单向或者双向 2.带头或者不带头 3.循环或者非循环 单链表实现 定义节点 接口函数实现 创建节点 打印链表 尾插节点 尾删节点 头插节点 头删节点 单链表查找 删除指定位置后的节点 指定位置后插入节点 删除指定位置 指定位置插入节点…

Linux-7 文本编辑vivim

Linux-7 文本编辑vi/vim vim介绍 什么是vim&#xff1f; vi和vim是Linux下的一个文本编辑工具。&#xff08;可以李姐为Windows的记事本或word文档&#xff09; 为什么要使用vim&#xff1f; 因为Linux系统一切皆为文件&#xff0c;而我们工作最多的就是修改某个服务的配置&a…

一名七年老安卓的 2022 总结

大家好&#xff0c;我是 shixin。一转眼到了 2022 的最后一天&#xff0c;今年发生了很多事&#xff0c;这篇文章来总结一下。长短期目标达成情况和去年一样&#xff0c;我的长期目标是成为具备创业能力的人&#xff0c;包括商业思维和全栈技术能力。总的来说&#xff0c;今年是…