WaylandQtWayland启动流程分析

Posted 林多

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WaylandQtWayland启动流程分析相关的知识,希望对你有一定的参考价值。

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端主要的启动流程便完事了。
  • 启动时序图:

以上是关于WaylandQtWayland启动流程分析的主要内容,如果未能解决你的问题,请参考以下文章

WaylandQtWayland启动流程分析

WaylandQtWayland框架分析

WaylandQtWayland框架分析

WaylandQtWayland框架分析

SpringMVC源码分析和启动流程

linux显示启动logo源码分析以及修改显示logo