mirror of
https://git.outfoxxed.me/quickshell/quickshell.git
synced 2025-11-04 19:04:56 +11:00
174 lines
4.3 KiB
C++
174 lines
4.3 KiB
C++
#include "view.hpp"
|
|
|
|
#include <qnamespace.h>
|
|
#include <qobject.h>
|
|
#include <qqmlinfo.h>
|
|
#include <qquickitem.h>
|
|
#include <qsize.h>
|
|
#include <qtmetamacros.h>
|
|
|
|
#include "../buffer/manager.hpp"
|
|
#include "../buffer/qsg.hpp"
|
|
#include "manager.hpp"
|
|
|
|
namespace qs::wayland::screencopy {
|
|
|
|
ScreencopyView::ScreencopyView(QQuickItem* parent): QQuickItem(parent) {
|
|
this->bImplicitSize.setBinding([this] {
|
|
auto constraint = this->bConstraintSize.value();
|
|
auto size = this->bSourceSize.value().toSizeF();
|
|
|
|
if (constraint.width() != 0 && constraint.height() != 0) {
|
|
size.scale(constraint.width(), constraint.height(), Qt::KeepAspectRatio);
|
|
} else if (constraint.width() != 0) {
|
|
size = QSizeF(constraint.width(), size.height() / constraint.width());
|
|
} else if (constraint.height() != 0) {
|
|
size = QSizeF(size.width() / constraint.height(), constraint.height());
|
|
}
|
|
|
|
return size;
|
|
});
|
|
}
|
|
|
|
void ScreencopyView::setCaptureSource(QObject* captureSource) {
|
|
if (captureSource == this->mCaptureSource) return;
|
|
auto hadContext = this->context != nullptr;
|
|
this->destroyContext(false);
|
|
|
|
this->mCaptureSource = captureSource;
|
|
|
|
if (captureSource) {
|
|
QObject::connect(
|
|
captureSource,
|
|
&QObject::destroyed,
|
|
this,
|
|
&ScreencopyView::onCaptureSourceDestroyed
|
|
);
|
|
|
|
if (this->completed) this->createContext();
|
|
}
|
|
|
|
if (!this->context && hadContext) this->update();
|
|
emit this->captureSourceChanged();
|
|
}
|
|
|
|
void ScreencopyView::onCaptureSourceDestroyed() {
|
|
this->mCaptureSource = nullptr;
|
|
this->destroyContext();
|
|
}
|
|
|
|
void ScreencopyView::setPaintCursors(bool paintCursors) {
|
|
if (paintCursors == this->mPaintCursors) return;
|
|
this->mPaintCursors = paintCursors;
|
|
if (this->completed && this->context) this->createContext();
|
|
emit this->paintCursorsChanged();
|
|
}
|
|
|
|
void ScreencopyView::setLive(bool live) {
|
|
if (live == this->mLive) return;
|
|
|
|
if (live && !this->mLive && this->context) {
|
|
this->context->captureFrame();
|
|
}
|
|
|
|
this->mLive = live;
|
|
emit this->liveChanged();
|
|
}
|
|
|
|
void ScreencopyView::createContext() {
|
|
this->destroyContext(false);
|
|
this->context = ScreencopyManager::createContext(this->mCaptureSource, this->mPaintCursors);
|
|
|
|
if (!this->context) {
|
|
qmlWarning(this) << "Capture source set to non captureable object.";
|
|
return;
|
|
}
|
|
|
|
this->context->setParent(this);
|
|
|
|
QObject::connect(
|
|
this->context,
|
|
&ScreencopyContext::stopped,
|
|
this,
|
|
&ScreencopyView::destroyContextWithUpdate
|
|
);
|
|
|
|
QObject::connect(
|
|
this->context,
|
|
&ScreencopyContext::frameCaptured,
|
|
this,
|
|
&ScreencopyView::onFrameCaptured
|
|
);
|
|
|
|
this->context->captureFrame();
|
|
}
|
|
|
|
void ScreencopyView::destroyContext(bool update) {
|
|
auto hadContext = this->context != nullptr;
|
|
delete this->context;
|
|
this->context = nullptr;
|
|
this->bHasContent = false;
|
|
this->bSourceSize = QSize();
|
|
if (hadContext && update) this->update();
|
|
}
|
|
|
|
void ScreencopyView::captureFrame() {
|
|
if (this->context) this->context->captureFrame();
|
|
else qmlWarning(this) << "Cannot capture frame, as no recording context is ready.";
|
|
}
|
|
|
|
void ScreencopyView::onFrameCaptured() {
|
|
this->setFlag(QQuickItem::ItemHasContents);
|
|
this->update();
|
|
this->bHasContent = true;
|
|
this->bSourceSize = this->context->swapchain().frontbuffer()->size();
|
|
}
|
|
|
|
void ScreencopyView::componentComplete() {
|
|
this->QQuickItem::componentComplete();
|
|
|
|
auto* bufManager = buffer::WlBufferManager::instance();
|
|
if (!bufManager->isReady()) {
|
|
QObject::connect(
|
|
bufManager,
|
|
&buffer::WlBufferManager::ready,
|
|
this,
|
|
&ScreencopyView::onBuffersReady
|
|
);
|
|
} else {
|
|
this->onBuffersReady();
|
|
}
|
|
}
|
|
|
|
void ScreencopyView::onBuffersReady() {
|
|
this->completed = true;
|
|
if (this->mCaptureSource) this->createContext();
|
|
}
|
|
|
|
QSGNode* ScreencopyView::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* /*unused*/) {
|
|
if (!this->context || !this->bHasContent) {
|
|
delete oldNode;
|
|
this->setFlag(QQuickItem::ItemHasContents, false);
|
|
return nullptr;
|
|
}
|
|
|
|
auto* node = static_cast<buffer::WlBufferQSGDisplayNode*>(oldNode); // NOLINT
|
|
|
|
if (!node) {
|
|
node = new buffer::WlBufferQSGDisplayNode(this->window());
|
|
}
|
|
|
|
auto& swapchain = this->context->swapchain();
|
|
node->syncSwapchain(swapchain);
|
|
node->setRect(this->boundingRect());
|
|
|
|
if (this->mLive) this->context->captureFrame();
|
|
return node;
|
|
}
|
|
|
|
void ScreencopyView::updateImplicitSize() {
|
|
auto size = this->bImplicitSize.value();
|
|
this->setImplicitSize(size.width(), size.height());
|
|
}
|
|
|
|
} // namespace qs::wayland::screencopy
|