CPP minimal
Minimal CPP est un exemple qui montre comment écrire un compositeur Wayland en C++.
Minimal CPP est un exemple minimaliste de compositeur mettant en œuvre une « Qt Wayland Compositor » complète à l’aide de C++. L’API C++ de QtWaylandCompositor est de bas niveau et destinée à des applications spécialisées, telles que la prise en charge de fonctionnalités matérielles, ou lorsque l’ Qt Quick n’est pas disponible. L’API QML offre davantage de commodité et de fonctionnalités. À titre de comparaison, l’exemple Minimal QML implémente davantage de fonctionnalités en 30 lignes de QML que cet exemple en plus de 300 lignes.

Cet exemple est divisé en deux parties. La logique Wayland est contenue dans la classe ` Compositor `, et l’interface utilisateur se trouve dans la classe ` Window `.
Fenêtre
La classe ` Window ` est assez simple. Pour afficher les surfaces Wayland, elle parcourt les vues du compositeur et les affiche à l'écran à l'aide de ` 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();
}Tous les événements clavier et souris sont transmis au compositeur. Par exemple :
void Window::mousePressEvent(QMouseEvent *event)
{
m_compositor->handleMousePress(event->position().toPoint(), event->button());
}Compositeur
La classe ` Compositor ` est plus complexe, car elle doit implémenter une grande partie de la logique qui serait gérée par ` WaylandCompositor ` et ` WaylandQuickItem ` dans un compositeur basé sur QML.
La fonction ` create ` configure le compositeur à l’aide de l’extension ` IviApplication`, qui est l’extension de shell la plus basique. Cette fonction est appelée après l’initialisation du contexte 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);
}Toute la logique relative aux événements de souris et au focus clavier doit être implémentée manuellement, y compris les « mouse grabs » implicites (qui consistent à envoyer tous les mouvements de souris vers la surface ayant reçu le clic initial). Notez que les événements de clic dans le protocole Wayland ne contiennent pas la position de la souris ; nous devons donc toujours envoyer un mouvement de souris lorsque nous recevons un clic :
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);
}Lors d’un relâchement de la souris, nous mettons fin à la capture implicite et informons la surface de la position actuelle de la souris :
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);
}Lorsque nous sommes informés de l’existence d’une nouvelle surface, nous créons un objet ` View ` pour en assurer le suivi, et nous connectons les signaux afin de pouvoir gérer les mises à jour.
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 classe ` View ` hérite de ` QWaylandView`, qui représente une vue spécifique d’une surface. La fonction ` advance ` met à jour le tampon actuel de la vue et renvoie `true` s’il y a du nouveau contenu. La fonction ` getTexture ` rend le contenu du tampon disponible sous forme de texture OpenGL à l’intention de la classe ` 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.