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