diff --git a/src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp b/src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp index 927da8dc4..ee8dd1adc 100644 --- a/src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp +++ b/src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp @@ -8,8 +8,8 @@ #include #include #include -#include #include +#include #include #include "../../../core/logcat.hpp" @@ -161,8 +161,12 @@ void WlrScreencopyContext::submitFrame() { WlrScreencopyContext::OutputTransformQuery::OutputTransformQuery(WlrScreencopyContext* context) : context(context) {} -WlrScreencopyContext::OutputTransformQuery::~OutputTransformQuery() { - if (this->isInitialized()) this->release(); +WlrScreencopyContext::OutputTransformQuery::~OutputTransformQuery() { this->release(); } + +void WlrScreencopyContext::OutputTransformQuery::release() { + if (this->output == nullptr) return; + wl_output_release(this->output); + this->output = nullptr; } void WlrScreencopyContext::OutputTransformQuery::setScreen( @@ -174,28 +178,73 @@ void WlrScreencopyContext::OutputTransformQuery::setScreen( [[nodiscard]] int globalId() const { return this->m_outputId; } }; - if (this->isInitialized()) this->release(); + this->release(); - this->init( + // Bound by hand, with our own listener: see the class comment. + this->output = static_cast<::wl_output*>(wl_registry_bind( screen->display()->wl_registry(), static_cast(screen)->globalId(), // NOLINT + &wl_output_interface, 3 - ); -} - -void WlrScreencopyContext::OutputTransformQuery::output_geometry( - qint32 /*x*/, - qint32 /*y*/, - qint32 /*width*/, - qint32 /*height*/, - qint32 /*subpixel*/, - const QString& /*make*/, - const QString& /*model*/, - qint32 transform + )); + + wl_output_add_listener(this->output, &LISTENER, this); +} + +const wl_output_listener WlrScreencopyContext::OutputTransformQuery::LISTENER = { + .geometry = &OutputTransformQuery::onGeometry, + .mode = &OutputTransformQuery::onMode, + .done = &OutputTransformQuery::onDone, + .scale = &OutputTransformQuery::onScale, + .name = &OutputTransformQuery::onName, + .description = &OutputTransformQuery::onDescription, +}; + +void WlrScreencopyContext::OutputTransformQuery::onGeometry( + void* data, + ::wl_output* /*output*/, + int32_t /*x*/, + int32_t /*y*/, + int32_t /*physicalWidth*/, + int32_t /*physicalHeight*/, + int32_t /*subpixel*/, + const char* /*make*/, + const char* /*model*/, + int32_t transform ) { - auto newTransform = this->transform == -1; - this->transform = transform; - this->context->updateTransform(newTransform); -} + auto* self = static_cast(data); + auto newTransform = self->transform == -1; + self->transform = transform; + self->context->updateTransform(newTransform); +} + +void WlrScreencopyContext::OutputTransformQuery::onMode( + void* /*data*/, + ::wl_output* /*output*/, + uint32_t /*flags*/, + int32_t /*width*/, + int32_t /*height*/, + int32_t /*refresh*/ +) {} + +void WlrScreencopyContext::OutputTransformQuery::onDone(void* /*data*/, ::wl_output* /*output*/) {} + +void WlrScreencopyContext::OutputTransformQuery::onScale( + void* /*data*/, + ::wl_output* /*output*/, + int32_t /*factor*/ +) {} + +void WlrScreencopyContext::OutputTransformQuery::onName( + void* /*data*/, + ::wl_output* /*output*/, + const char* /*name*/ +) {} + +void WlrScreencopyContext::OutputTransformQuery::onDescription( + void* /*data*/, + ::wl_output* /*output*/, + const char* /*description*/ +) {} } // 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 6e7620c5c..c3d41d10e 100644 --- a/src/wayland/screencopy/wlr_screencopy/wlr_screencopy_p.hpp +++ b/src/wayland/screencopy/wlr_screencopy/wlr_screencopy_p.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../manager.hpp" @@ -45,29 +46,41 @@ private slots: private: void submitFrame(); - class OutputTransformQuery: public QtWayland::wl_output { + // Learns the output transform from wl_output.geometry on a private bind. + // QtWayland does not retain it: QWaylandScreen consumes mTransform in + // updateOutputProperties() and QScreen::orientation() drops flipped variants. + // + // The proxy deliberately does not use Qt's generated QtWayland::wl_output. + // Compositors send wl_surface.enter for every wl_output resource a client + // holds, and QWaylandScreen::fromWlOutput() decides whether an output is one + // of its own screens purely by the proxy's listener - so a proxy carrying + // Qt's listener ends up in QWaylandSurface::m_screens as a fake QWaylandScreen + // and is dereferenced after this object is gone. (quickshell#1094) + class OutputTransformQuery { public: - OutputTransformQuery(WlrScreencopyContext* context); - ~OutputTransformQuery() override; + explicit OutputTransformQuery(WlrScreencopyContext* context); + ~OutputTransformQuery(); 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: + void release(); + + // clang-format off + static void onGeometry(void* data, ::wl_output* output, int32_t x, int32_t y, int32_t physicalWidth, int32_t physicalHeight, int32_t subpixel, const char* make, const char* model, int32_t transform); + static void onMode(void* data, ::wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh); + static void onDone(void* data, ::wl_output* output); + static void onScale(void* data, ::wl_output* output, int32_t factor); + static void onName(void* data, ::wl_output* output, const char* name); + static void onDescription(void* data, ::wl_output* output, const char* description); + // clang-format on + + static const wl_output_listener LISTENER; + WlrScreencopyContext* context; + ::wl_output* output = nullptr; }; WlrScreencopyManager* manager;