Minimaler CPP
Minimal CPP ist ein Beispiel, das zeigt, wie man einen Wayland-Compositor in C++ schreibt.
Minimal CPP ist ein minimalistisches Compositor-Beispiel, das eine vollständige Qt Wayland Compositor mit C++ implementiert. Die C++-API von QtWaylandCompositor ist auf niedriger Ebene angesiedelt und für spezialisierte Anwendungen gedacht, z. B. für die Unterstützung von Hardware-Funktionen, oder wenn Qt Quick nicht verfügbar ist. Die QML-API bietet mehr Komfort und Funktionalität. Zum Vergleich: Das Minimal-QML-Beispiel implementiert mit 30 Zeilen QML mehr Funktionalität als dieses Beispiel mit über 300 Zeilen.
Dieses Beispiel ist in zwei Teile aufgeteilt. Die Wayland-Logik ist in der Klasse Compositor
enthalten, und die Benutzeroberfläche befindet sich in der Klasse Window
.
Fenster
Die Klasse Window
ist ziemlich einfach. Um die Wayland-Oberflächen anzuzeigen, durchläuft sie die Ansichten des Compositors und rendert sie mit QOpenGLTextureBlitter auf dem Bildschirm:
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(); }
Alle Tastatur- und Mausereignisse werden an den Compositor weitergeleitet. Zum Beispiel:
void Window::mousePressEvent(QMouseEvent *event) { m_compositor->handleMousePress(event->position().toPoint(), event->button()); }
Compositor
Die Klasse Compositor
ist komplexer, da sie einen Großteil der Logik implementieren muss, die in einem QML-basierten Compositor von WaylandCompositor und WaylandQuickItem abgewickelt werden würde.
Die Funktion create
richtet den Compositor unter Verwendung der IviApplication ein, die die einfachste Shell-Erweiterung darstellt. Die Funktion wird aufgerufen, nachdem der OpenGL-Kontext initialisiert worden ist:
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); }
Die gesamte Logik für Mausereignisse und Tastaturfokus muss manuell implementiert werden, einschließlich impliziter Mausgrabs (Senden aller Mausbewegungen an die Oberfläche, die den ersten Mausdruck erhalten hat). Beachten Sie, dass Mausdruckereignisse im Wayland-Protokoll nicht die Mausposition enthalten, so dass wir immer eine Mausbewegung senden müssen, wenn wir einen Mausdruck erhalten:
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); }
Wenn die Maus losgelassen wird, beenden wir das implizite Greifen und benachrichtigen die Oberfläche an der aktuellen Mausposition:
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); }
Wenn wir über eine neue Oberfläche informiert werden, erstellen wir eine View
, um sie zu verfolgen, und verbinden Signale, damit wir Aktualisierungen verarbeiten können.
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); }
Die Klasse View
ist eine Unterklasse von QWaylandView, die eine bestimmte Ansicht einer Oberfläche darstellt. Die Funktion advance aktualisiert den aktuellen Puffer der Ansicht und gibt true zurück, wenn es neue Inhalte gibt. Die Funktion getTexture
macht den Pufferinhalt als OpenGL-Textur für die Klasse Window
verfügbar:
QOpenGLTexture *View::getTexture() { if (advance()) m_texture = currentBuffer().toOpenGLTexture(); return m_texture; }
© 2025 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.