CPP mínimo
Minimal CPP es un ejemplo que demuestra cómo escribir un compositor Wayland en C++.
Minimal CPP es un ejemplo de compositor minimalista que implementa un Qt Wayland Compositor completo usando C++. La API C++ de QtWaylandCompositor es de bajo nivel y está pensada para aplicaciones especializadas, como el soporte de características de hardware, o si Qt Quick no está disponible. La API QML ofrece más comodidad y funcionalidad. A modo de comparación, el ejemplo Minimal QML implementa más funcionalidad con 30 líneas de QML que este ejemplo en más de 300 líneas.

Este ejemplo está dividido en dos partes. La lógica Wayland está contenida en la clase Compositor, y la interfaz de usuario está en la clase Window.
Ventana
La clase Window es bastante sencilla. Para mostrar las superficies Wayland, itera a través de las vistas del compositor y las renderiza en la pantalla usando 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(); }
Todos los eventos de teclado y ratón se envían al compositor. Por ejemplo
void Window::mousePressEvent(QMouseEvent *event) { m_compositor->handleMousePress(event->position().toPoint(), event->button()); }
Compositor
La clase Compositor es más compleja, ya que tiene que implementar gran parte de la lógica que sería manejada por WaylandCompositor y WaylandQuickItem en un compositor basado en QML.
La función create configura el compositor, utilizando IviApplication, que es la extensión de shell más básica. La función es llamada después de que el contexto OpenGL haya sido inicializado:
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); }
Toda la lógica para los eventos del ratón y el foco del teclado tiene que ser implementada manualmente, incluyendo los agarres implícitos del ratón (enviando todos los movimientos del ratón a la superficie que recibió la pulsación inicial del ratón). Ten en cuenta que los eventos de pulsación del ratón en el protocolo Wayland no contienen la posición del ratón, por lo que siempre tenemos que enviar un movimiento del ratón cuando recibimos una pulsación del ratón:
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); }
Para una liberación del ratón, terminamos el agarre implícito y notificamos a la superficie en la posición actual del ratón:
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); }
Cuando recibimos la notificación de una nueva superficie, creamos un View para seguirla, y conectamos señales para poder manejar las actualizaciones.
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); }
La clase View subclase QWaylandView, que representa una vista específica de una superficie. La función advance actualiza el búfer actual de la vista y devuelve true si hay nuevo contenido. La función getTexture hace que el contenido del buffer esté disponible como una textura OpenGL para el beneficio de la clase Window:
QOpenGLTexture *View::getTexture() { if (advance()) m_texture = currentBuffer().toOpenGLTexture(); return m_texture; }
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.