最小化 CPP
最小化 CPP 是一个演示如何使用 C++ 编写 Wayland 合成器的示例。
最小化 CPP 是一个实现完整的 Qt Wayland 合成器的极简合成器示例。QtWaylandCompositor API 是低级别的,旨在用于特殊应用程序,例如支持硬件特性或者当 Qt Quick 不可用时。QML API 提供了更多便利和功能。为了比较,最小 QML 示例使用 30 行 QML 实现了比本示例 300 多行代码更多的功能。
此示例分为两部分。Wayland 逻辑包含在 Compositor
类中,用户界面在 Window
类中。
窗口
Window
类相当直接。要显示 Wayland 表面,它通过遍历合成器的视图并在屏幕上使用 QOpenGLTextureBlitter 进行渲染
void Window::paintGL() { m_compositor->startRender(); QOpenGLFunctions *functions = context()->functions(); functions->glClearColor(.4f, .7f, .1f, 0.5f); functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLenum currentTarget = GL_TEXTURE_2D; m_textureBlitter.bind(currentTarget); functions->glEnable(GL_BLEND); functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const auto views = m_compositor->views(); for (View *view : views) { auto texture = view->getTexture(); if (!texture) continue; if (texture->target() != currentTarget) { currentTarget = texture->target(); m_textureBlitter.bind(currentTarget); } GLuint textureId = texture->textureId(); QWaylandSurface *surface = view->surface(); if (surface && surface->hasContent()) { QSize s = surface->destinationSize(); view->initPosition(size(), s); QPointF pos = view->globalPosition(); QRectF surfaceGeometry(pos, s); QOpenGLTextureBlitter::Origin surfaceOrigin = view->currentBuffer().origin() == QWaylandSurface::OriginTopLeft ? QOpenGLTextureBlitter::OriginTopLeft : QOpenGLTextureBlitter::OriginBottomLeft; QMatrix4x4 targetTransform = QOpenGLTextureBlitter::targetTransform(surfaceGeometry, QRect(QPoint(), size())); m_textureBlitter.blit(textureId, targetTransform, surfaceOrigin); } } m_textureBlitter.release(); m_compositor->endRender(); }
所有键盘和鼠标事件都传递给合成器。例如
void Window::mousePressEvent(QMouseEvent *event) { m_compositor->handleMousePress(event->position().toPoint(), event->button()); }
合成器
由于需要实现 WaylandCompositor 和 WaylandQuickItem 在基于 QML 的合成器中处理的许多逻辑,因此 Compositor
类更为复杂。
创建函数使用 IviApplication 设置合成器,它是最基础的外壳扩展。该函数在初始化 OpenGL 上下文后调用
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); }
所有鼠标事件和键盘焦点逻辑都必须手动实现,包括隐式鼠标捕获(将所有鼠标移动发送到接收初始鼠标按下的表面)。注意,Wayland 协议中的鼠标按下事件不包含鼠标位置,因此每次接收到鼠标按下时,我们总是要发送一个鼠标移动
void Compositor::handleMousePress(const QPoint &position, Qt::MouseButton button) { if (!m_mouseView) { if ((m_mouseView = viewAt(position))) raise(m_mouseView); } auto *seat = defaultSeat(); seat->sendMouseMoveEvent(m_mouseView, mapToView(m_mouseView, position)); seat->sendMousePressEvent(button); }
对于鼠标释放,我们结束隐式捕获并向当前鼠标位置的表面发出通知
void Compositor::handleMousePress(const QPoint &position, Qt::MouseButton button) { if (!m_mouseView) { if ((m_mouseView = viewAt(position))) raise(m_mouseView); } auto *seat = defaultSeat(); seat->sendMouseMoveEvent(m_mouseView, mapToView(m_mouseView, position)); seat->sendMousePressEvent(button); }
当我们收到新表面的通知时,我们创建一个 View
来跟踪它,并连接信号以便我们可以处理更新。
void Compositor::onIviSurfaceCreated(QWaylandIviSurface *iviSurface) { View *view = new View(iviSurface->iviId()); view->setSurface(iviSurface->surface()); view->setOutput(outputFor(m_window)); m_views << view; connect(view, &QWaylandView::surfaceDestroyed, this, &Compositor::viewSurfaceDestroyed); connect(iviSurface->surface(), &QWaylandSurface::redraw, this, &Compositor::triggerRender); }
View
类是 QWaylandView 的子类,它表示表面的特定视图。advance 函数更新视图的当前缓冲区,并在有新内容时返回 true。《code translate="no">getTexture 函数使缓冲区内容可作为 OpenGL 纹理提供给《code translate="no">Window 类
QOpenGLTexture *View::getTexture() { if (advance()) m_texture = currentBuffer().toOpenGLTexture(); return m_texture; }
© 2024 Qt公司有限公司。本文件中包含的文档贡献作品均为各自所有者的版权。本文件提供的文档受GNU自由文档许可证第1.3版许可,该许可证由自由软件基金会发布。Qt及其相关标志为芬兰的Qt公司及其在世界其他国家的注册商标。所有其他商标均为各自所有者的财产。