CPP Minimal
Minimal CPP est un exemple qui démontre comment écrire un compositeur Wayland en C++.
Minimal CPP est un exemple de compositeur minimaliste implémentant un Qt Wayland Compositor complet en utilisant 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 caractéristiques matérielles, ou si Qt Quick n'est pas disponible. L'API QML est plus pratique et plus fonctionnelle. À titre de comparaison, l'exemple QML minimal met en œuvre plus de fonctionnalités avec 30 lignes de QML que cet exemple ne le fait 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 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 rend à l'écran en utilisant 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 du clavier et de la 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 mettre en œuvre une grande partie de la logique qui serait gérée par WaylandCompositor et WaylandQuickItem dans un compositeur basé sur QML.
La fonction create met en place le compositeur, en utilisant IviApplication, qui est l'extension shell la plus basique. La 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 des événements de la souris et du focus clavier doit être implémentée manuellement, y compris les prises de souris implicites (envoyant tous les mouvements de la souris à la surface qui a reçu la pression initiale de la souris). Notez que les événements de pression de la souris dans le protocole Wayland ne contiennent pas la position de la souris, de sorte que nous devons toujours envoyer un mouvement de souris lorsque nous recevons une pression 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); }
En cas de relâchement de la souris, nous mettons fin à la saisie 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 site View pour en assurer le suivi et nous connectons des 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 sous-classe QWaylandView, qui représente une vue spécifique d'une surface. La fonction advance met à jour le tampon actuel de la vue et renvoie un message vrai s'il y a du nouveau contenu. La fonction getTexture rend le contenu du tampon disponible en tant que texture OpenGL au profit 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.