diff --git a/plugins/scenes/qpainter/scene_qpainter.cpp b/plugins/scenes/qpainter/scene_qpainter.cpp --- a/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/plugins/scenes/qpainter/scene_qpainter.cpp @@ -287,14 +287,29 @@ renderWindowDecorations(painter); // render content - QRect source; - QRect target; + QRectF source; + QRectF target; + QRectF viewportRectangle; + if (toplevel->surface()) { + viewportRectangle = toplevel->surface()->sourceRectangle(); + } if (toplevel->isClient()) { // special case for XWayland windows - source = QRect(toplevel->clientPos(), toplevel->clientSize()); + if (viewportRectangle.isValid()) { + source = viewportRectangle; + source.translate(toplevel->clientPos()); + } else { + source = QRect(toplevel->clientPos(), toplevel->clientSize()); + } target = source; } else { - source = pixmap->image().rect(); + if (viewportRectangle.isValid()) { + const qreal imageScale = toplevel->bufferScale(); + source = QRectF(viewportRectangle.topLeft() * imageScale, + viewportRectangle.bottomRight() * imageScale); + } else { + source = pixmap->image().rect(); + } target = toplevel->bufferGeometry().translated(-pos()); } painter->drawImage(target, pixmap->image(), source); diff --git a/scene.cpp b/scene.cpp --- a/scene.cpp +++ b/scene.cpp @@ -959,25 +959,56 @@ WindowQuadList quads; quads.reserve(contentsRegion.rectCount()); - for (const QRectF &rect : contentsRegion) { + auto createQuad = [geometryOffset](const QRectF &rect, const QRectF &sourceRect) { WindowQuad quad(WindowQuadContents); const qreal x0 = rect.left() + geometryOffset.x(); const qreal y0 = rect.top() + geometryOffset.y(); const qreal x1 = rect.right() + geometryOffset.x(); const qreal y1 = rect.bottom() + geometryOffset.y(); - const qreal u0 = rect.left() * textureScale; - const qreal v0 = rect.top() * textureScale; - const qreal u1 = rect.right() * textureScale; - const qreal v1 = rect.bottom() * textureScale; + const qreal u0 = sourceRect.left(); + const qreal v0 = sourceRect.top(); + const qreal u1 = sourceRect.right(); + const qreal v1 = sourceRect.bottom(); quad[0] = WindowVertex(QPointF(x0, y0), QPointF(u0, v0)); quad[1] = WindowVertex(QPointF(x1, y0), QPointF(u1, v0)); quad[2] = WindowVertex(QPointF(x1, y1), QPointF(u1, v1)); quad[3] = WindowVertex(QPointF(x0, y1), QPointF(u0, v1)); + return quad; + }; - quads << quad; + // Check for viewport being set. We only allow specifying the viewport at the moment for + // non-shape windows. + if (contentsRegion.rectCount() < 2) { + const QRectF contentsRect = *contentsRegion.begin(); + QRectF sourceRect(contentsRect.topLeft() * textureScale, + contentsRect.bottomRight() * textureScale); + + if (const auto *surface = toplevel->surface()) { + const QRectF rect = surface->sourceRectangle(); + if (rect.isValid()) { + sourceRect = QRectF(rect.topLeft() * textureScale, + rect.bottomRight() * textureScale); + } else if (auto *buffer = surface->buffer()) { + // Try to get the source rectangle from the buffer size, what defines the source + // size without respect to destination size. + const auto origin = contentsRect.topLeft(); + const QRectF rect = QRectF(origin, buffer->size() - QSize(origin.x(), origin.y())); + // Make sure a buffer was set already. + if (rect.isValid()) { + sourceRect = rect; + } + } + } + quads << createQuad(contentsRect, sourceRect); + } else { + for (const QRectF &contentsRect : contentsRegion) { + const QRectF sourceRect(contentsRect.topLeft() * textureScale, + contentsRect.bottomRight() * textureScale); + quads << createQuad(contentsRect, sourceRect); + } } return quads; diff --git a/wayland_server.h b/wayland_server.h --- a/wayland_server.h +++ b/wayland_server.h @@ -69,6 +69,7 @@ class KeyStateInterface; class LinuxDmabufUnstableV1Interface; class LinuxDmabufUnstableV1Buffer; +class ViewporterInterface; } } @@ -120,6 +121,9 @@ KWayland::Server::XdgOutputManagerInterface *xdgOutputManager() const { return m_xdgOutputManager; } + KWayland::Server::ViewporterInterface *viewporter() const { + return m_viewporter; + } KWayland::Server::LinuxDmabufUnstableV1Interface *linuxDmabuf(); QList clients() const { @@ -258,6 +262,7 @@ KWayland::Server::ServerSideDecorationPaletteManagerInterface *m_paletteManager = nullptr; KWayland::Server::IdleInterface *m_idle = nullptr; KWayland::Server::XdgOutputManagerInterface *m_xdgOutputManager = nullptr; + KWayland::Server::ViewporterInterface *m_viewporter = nullptr; KWayland::Server::XdgDecorationManagerInterface *m_xdgDecorationManager = nullptr; KWayland::Server::LinuxDmabufUnstableV1Interface *m_linuxDmabuf = nullptr; QSet m_linuxDmabufBuffers; diff --git a/wayland_server.cpp b/wayland_server.cpp --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -66,6 +66,7 @@ #include #include #include +#include // KF #include @@ -451,6 +452,9 @@ m_keyState = m_display->createKeyStateInterface(m_display); m_keyState->create(); + m_viewporter = m_display->createViewporterInterface(m_display); + m_viewporter->create(); + return true; }