forked from quickshell/quickshell
wayland/screencopy: apply output transform to wlr screencopy
Note that this only fixes output copies, and not toplevel copies. Toplevel copies are harder because a toplevel can be on more than one output. Hopefully we'll all be using image-copy-capture before this one comes up. Fixes #75
This commit is contained in:
parent
27f97c3283
commit
d949f91347
4 changed files with 103 additions and 8 deletions
|
@ -40,6 +40,7 @@ struct WlBufferTransform {
|
||||||
|
|
||||||
[[nodiscard]] int degrees() const { return 90 * (this->transform & 0b11111011); }
|
[[nodiscard]] int degrees() const { return 90 * (this->transform & 0b11111011); }
|
||||||
[[nodiscard]] bool flip() const { return this->transform & 0b00000100; }
|
[[nodiscard]] bool flip() const { return this->transform & 0b00000100; }
|
||||||
|
[[nodiscard]] bool flipSize() const { return this->transform & 0b00000001; }
|
||||||
|
|
||||||
void apply(QMatrix4x4& matrix) const {
|
void apply(QMatrix4x4& matrix) const {
|
||||||
matrix.rotate(this->flip() ? 180 : 0, 0, 1, 0);
|
matrix.rotate(this->flip() ? 180 : 0, 0, 1, 0);
|
||||||
|
|
|
@ -120,8 +120,14 @@ void ScreencopyView::captureFrame() {
|
||||||
void ScreencopyView::onFrameCaptured() {
|
void ScreencopyView::onFrameCaptured() {
|
||||||
this->setFlag(QQuickItem::ItemHasContents);
|
this->setFlag(QQuickItem::ItemHasContents);
|
||||||
this->update();
|
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->bHasContent = true;
|
||||||
this->bSourceSize = this->context->swapchain().frontbuffer()->size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreencopyView::componentComplete() {
|
void ScreencopyView::componentComplete() {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
#include "wlr_screencopy.hpp"
|
#include "wlr_screencopy.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <private/qwaylanddisplay_p.h>
|
||||||
#include <private/qwaylandscreen_p.h>
|
#include <private/qwaylandscreen_p.h>
|
||||||
#include <qlogging.h>
|
#include <qlogging.h>
|
||||||
#include <qloggingcategory.h>
|
#include <qloggingcategory.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qscreen.h>
|
#include <qscreen.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
|
#include <qtypes.h>
|
||||||
#include <qwaylandclientextension.h>
|
#include <qwaylandclientextension.h>
|
||||||
#include <wayland-wlr-screencopy-unstable-v1-client-protocol.h>
|
#include <wayland-wlr-screencopy-unstable-v1-client-protocol.h>
|
||||||
|
|
||||||
|
@ -45,6 +47,7 @@ WlrScreencopyContext::WlrScreencopyContext(
|
||||||
, screen(dynamic_cast<QtWaylandClient::QWaylandScreen*>(screen->handle()))
|
, screen(dynamic_cast<QtWaylandClient::QWaylandScreen*>(screen->handle()))
|
||||||
, paintCursors(paintCursors)
|
, paintCursors(paintCursors)
|
||||||
, region(region) {
|
, region(region) {
|
||||||
|
this->transform.setScreen(this->screen);
|
||||||
QObject::connect(screen, &QObject::destroyed, this, &WlrScreencopyContext::onScreenDestroyed);
|
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) {
|
void WlrScreencopyContext::zwlr_screencopy_frame_v1_flags(uint32_t flags) {
|
||||||
if (flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT) {
|
this->yInvert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
|
||||||
this->mSwapchain.backbuffer()->transform = buffer::WlBufferTransform::Flipped180;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WlrScreencopyContext::zwlr_screencopy_frame_v1_buffer_done() {
|
void WlrScreencopyContext::zwlr_screencopy_frame_v1_buffer_done() {
|
||||||
|
@ -119,10 +120,7 @@ void WlrScreencopyContext::zwlr_screencopy_frame_v1_ready(
|
||||||
uint32_t /*tvSecLo*/,
|
uint32_t /*tvSecLo*/,
|
||||||
uint32_t /*tvNsec*/
|
uint32_t /*tvNsec*/
|
||||||
) {
|
) {
|
||||||
this->destroy();
|
this->submitFrame();
|
||||||
this->copiedFirstFrame = true;
|
|
||||||
this->mSwapchain.swapBuffers();
|
|
||||||
emit this->frameCaptured();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WlrScreencopyContext::zwlr_screencopy_frame_v1_failed() {
|
void WlrScreencopyContext::zwlr_screencopy_frame_v1_failed() {
|
||||||
|
@ -130,4 +128,61 @@ void WlrScreencopyContext::zwlr_screencopy_frame_v1_failed() {
|
||||||
emit this->stopped();
|
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<QWaylandScreenReflector*>(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
|
} // namespace qs::wayland::screencopy::wlr
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <private/qwayland-wayland.h>
|
||||||
#include <private/qwaylandscreen_p.h>
|
#include <private/qwaylandscreen_p.h>
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
#include <qtclasshelpermacros.h>
|
#include <qtclasshelpermacros.h>
|
||||||
|
#include <qtypes.h>
|
||||||
#include <qwayland-wlr-screencopy-unstable-v1.h>
|
#include <qwayland-wlr-screencopy-unstable-v1.h>
|
||||||
|
|
||||||
#include "../manager.hpp"
|
#include "../manager.hpp"
|
||||||
|
@ -24,6 +27,7 @@ public:
|
||||||
Q_DISABLE_COPY_MOVE(WlrScreencopyContext);
|
Q_DISABLE_COPY_MOVE(WlrScreencopyContext);
|
||||||
|
|
||||||
void captureFrame() override;
|
void captureFrame() override;
|
||||||
|
void updateTransform(bool previouslyUnset);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -39,9 +43,38 @@ private slots:
|
||||||
void onScreenDestroyed();
|
void onScreenDestroyed();
|
||||||
|
|
||||||
private:
|
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;
|
WlrScreencopyManager* manager;
|
||||||
buffer::WlBufferRequest request;
|
buffer::WlBufferRequest request;
|
||||||
bool copiedFirstFrame = false;
|
bool copiedFirstFrame = false;
|
||||||
|
OutputTransformQuery transform {this};
|
||||||
|
bool yInvert = false;
|
||||||
|
|
||||||
QtWaylandClient::QWaylandScreen* screen;
|
QtWaylandClient::QWaylandScreen* screen;
|
||||||
bool paintCursors;
|
bool paintCursors;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue