diff --git a/src/wayland/buffer/manager.hpp b/src/wayland/buffer/manager.hpp index c84ee867..b521e89e 100644 --- a/src/wayland/buffer/manager.hpp +++ b/src/wayland/buffer/manager.hpp @@ -40,6 +40,7 @@ struct WlBufferTransform { [[nodiscard]] int degrees() const { return 90 * (this->transform & 0b11111011); } [[nodiscard]] bool flip() const { return this->transform & 0b00000100; } + [[nodiscard]] bool flipSize() const { return this->transform & 0b00000001; } void apply(QMatrix4x4& matrix) const { matrix.rotate(this->flip() ? 180 : 0, 0, 1, 0); diff --git a/src/wayland/screencopy/view.cpp b/src/wayland/screencopy/view.cpp index aeafea61..7828c98d 100644 --- a/src/wayland/screencopy/view.cpp +++ b/src/wayland/screencopy/view.cpp @@ -120,8 +120,14 @@ void ScreencopyView::captureFrame() { void ScreencopyView::onFrameCaptured() { this->setFlag(QQuickItem::ItemHasContents); this->update(); + + const auto& frontbuffer = this->context->swapchain().frontbuffer(); + + auto size = frontbuffer->size(); + if (frontbuffer->transform.flipSize()) size.transpose(); + + this->bSourceSize = size; this->bHasContent = true; - this->bSourceSize = this->context->swapchain().frontbuffer()->size(); } void ScreencopyView::componentComplete() { diff --git a/src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp b/src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp index 8cc89bca..aa21266b 100644 --- a/src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp +++ b/src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp @@ -1,12 +1,14 @@ #include "wlr_screencopy.hpp" #include +#include #include #include #include #include #include #include +#include #include #include @@ -45,6 +47,7 @@ WlrScreencopyContext::WlrScreencopyContext( , screen(dynamic_cast(screen->handle())) , paintCursors(paintCursors) , region(region) { + this->transform.setScreen(this->screen); QObject::connect(screen, &QObject::destroyed, this, &WlrScreencopyContext::onScreenDestroyed); } @@ -99,9 +102,7 @@ void WlrScreencopyContext::zwlr_screencopy_frame_v1_linux_dmabuf( } void WlrScreencopyContext::zwlr_screencopy_frame_v1_flags(uint32_t flags) { - if (flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT) { - this->mSwapchain.backbuffer()->transform = buffer::WlBufferTransform::Flipped180; - } + this->yInvert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT; } void WlrScreencopyContext::zwlr_screencopy_frame_v1_buffer_done() { @@ -119,10 +120,7 @@ void WlrScreencopyContext::zwlr_screencopy_frame_v1_ready( uint32_t /*tvSecLo*/, uint32_t /*tvNsec*/ ) { - this->destroy(); - this->copiedFirstFrame = true; - this->mSwapchain.swapBuffers(); - emit this->frameCaptured(); + this->submitFrame(); } void WlrScreencopyContext::zwlr_screencopy_frame_v1_failed() { @@ -130,4 +128,61 @@ void WlrScreencopyContext::zwlr_screencopy_frame_v1_failed() { emit this->stopped(); } +void WlrScreencopyContext::updateTransform(bool previouslyUnset) { + if (previouslyUnset && this->copiedFirstFrame) this->submitFrame(); +} + +void WlrScreencopyContext::submitFrame() { + this->copiedFirstFrame = true; + if (this->transform.transform == -1) return; + + auto flipTransform = + this->yInvert ? buffer::WlBufferTransform::Flipped180 : buffer::WlBufferTransform::Normal0; + + this->mSwapchain.backbuffer()->transform = this->transform.transform ^ flipTransform; + + this->destroy(); + this->mSwapchain.swapBuffers(); + emit this->frameCaptured(); +} + +WlrScreencopyContext::OutputTransformQuery::OutputTransformQuery(WlrScreencopyContext* context) + : context(context) {} + +WlrScreencopyContext::OutputTransformQuery::~OutputTransformQuery() { + if (this->isInitialized()) this->release(); +} + +void WlrScreencopyContext::OutputTransformQuery::setScreen(QtWaylandClient::QWaylandScreen* screen +) { + // cursed hack + class QWaylandScreenReflector: public QtWaylandClient::QWaylandScreen { + public: + [[nodiscard]] int globalId() const { return this->m_outputId; } + }; + + if (this->isInitialized()) this->release(); + + this->init( + screen->display()->wl_registry(), + static_cast(screen)->globalId(), // NOLINT + 3 + ); +} + +void WlrScreencopyContext::OutputTransformQuery::output_geometry( + qint32 /*x*/, + qint32 /*y*/, + qint32 /*width*/, + qint32 /*height*/, + qint32 /*subpixel*/, + const QString& /*make*/, + const QString& /*model*/, + qint32 transform +) { + auto newTransform = this->transform == -1; + this->transform = transform; + this->context->updateTransform(newTransform); +} + } // namespace qs::wayland::screencopy::wlr diff --git a/src/wayland/screencopy/wlr_screencopy/wlr_screencopy_p.hpp b/src/wayland/screencopy/wlr_screencopy/wlr_screencopy_p.hpp index 7bdbafb7..6e7620c5 100644 --- a/src/wayland/screencopy/wlr_screencopy/wlr_screencopy_p.hpp +++ b/src/wayland/screencopy/wlr_screencopy/wlr_screencopy_p.hpp @@ -1,7 +1,10 @@ #pragma once +#include #include +#include #include +#include #include #include "../manager.hpp" @@ -24,6 +27,7 @@ public: Q_DISABLE_COPY_MOVE(WlrScreencopyContext); void captureFrame() override; + void updateTransform(bool previouslyUnset); protected: // clang-format off @@ -39,9 +43,38 @@ private slots: void onScreenDestroyed(); private: + void submitFrame(); + + class OutputTransformQuery: public QtWayland::wl_output { + public: + OutputTransformQuery(WlrScreencopyContext* context); + ~OutputTransformQuery() override; + Q_DISABLE_COPY_MOVE(OutputTransformQuery); + + qint32 transform = -1; + void setScreen(QtWaylandClient::QWaylandScreen* screen); + + protected: + void output_geometry( + qint32 x, + qint32 y, + qint32 width, + qint32 height, + qint32 subpixel, + const QString& make, + const QString& model, + qint32 transform + ) override; + + private: + WlrScreencopyContext* context; + }; + WlrScreencopyManager* manager; buffer::WlBufferRequest request; bool copiedFirstFrame = false; + OutputTransformQuery transform {this}; + bool yInvert = false; QtWaylandClient::QWaylandScreen* screen; bool paintCursors;