Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 70 additions & 21 deletions src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include <qobject.h>
#include <qscreen.h>
#include <qtmetamacros.h>
#include <qtypes.h>
#include <qwaylandclientextension.h>
#include <wayland-client-protocol.h>
#include <wayland-wlr-screencopy-unstable-v1-client-protocol.h>

#include "../../../core/logcat.hpp"
Expand Down Expand Up @@ -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(
Expand All @@ -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<QWaylandScreenReflector*>(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<OutputTransformQuery*>(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
43 changes: 28 additions & 15 deletions src/wayland/screencopy/wlr_screencopy/wlr_screencopy_p.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <qtclasshelpermacros.h>
#include <qtypes.h>
#include <qwayland-wlr-screencopy-unstable-v1.h>
#include <wayland-client-protocol.h>

#include "../manager.hpp"

Expand Down Expand Up @@ -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;
Expand Down
Loading