plugins/screencast: Hide cursor if another window covers screencasted window

BUG: 487294
This commit is contained in:
Vlad Zahorodnii 2024-06-19 14:40:23 +03:00
parent 8cb7e0a26b
commit b452a5a5fb
10 changed files with 97 additions and 29 deletions

View file

@ -10,6 +10,7 @@
#include "compositor.h"
#include "core/output.h"
#include "core/renderloop.h"
#include "cursor.h"
#include "opengl/gltexture.h"
#include "opengl/glutils.h"
#include "scene/workspacescene.h"
@ -115,6 +116,25 @@ void OutputScreenCastSource::pause()
m_active = false;
}
bool OutputScreenCastSource::includesCursor(Cursor *cursor) const
{
if (Cursors::self()->isCursorHidden()) {
return false;
}
return cursor->isOnOutput(m_output);
}
QPointF OutputScreenCastSource::mapFromGlobal(const QPointF &point) const
{
return m_output->mapFromGlobal(point);
}
QRectF OutputScreenCastSource::mapFromGlobal(const QRectF &rect) const
{
return m_output->mapFromGlobal(rect);
}
} // namespace KWin
#include "moc_outputscreencastsource.cpp"

View file

@ -34,6 +34,11 @@ public:
void resume() override;
void pause() override;
bool includesCursor(Cursor *cursor) const override;
QPointF mapFromGlobal(const QPointF &point) const override;
QRectF mapFromGlobal(const QRectF &rect) const override;
private:
void report(const QRegion &damage);

View file

@ -7,6 +7,7 @@
#include "regionscreencastsource.h"
#include "screencastutils.h"
#include "cursor.h"
#include "opengl/gltexture.h"
#include "opengl/glutils.h"
#include <compositor.h>
@ -206,6 +207,25 @@ void RegionScreenCastSource::resume()
m_active = true;
}
bool RegionScreenCastSource::includesCursor(Cursor *cursor) const
{
if (Cursors::self()->isCursorHidden()) {
return false;
}
return cursor->geometry().intersects(m_region);
}
QPointF RegionScreenCastSource::mapFromGlobal(const QPointF &point) const
{
return point - m_region.topLeft();
}
QRectF RegionScreenCastSource::mapFromGlobal(const QRectF &rect) const
{
return rect.translated(-m_region.topLeft());
}
} // namespace KWin
#include "moc_regionscreencastsource.cpp"

View file

@ -50,6 +50,11 @@ public:
void pause() override;
void resume() override;
bool includesCursor(Cursor *cursor) const override;
QPointF mapFromGlobal(const QPointF &point) const override;
QRectF mapFromGlobal(const QRectF &rect) const override;
private:
void blit(Output *output);
void ensureTexture();

View file

@ -48,13 +48,7 @@ void ScreencastManager::streamWindow(ScreencastStreamV1Interface *waylandStream,
auto stream = new ScreenCastStream(new WindowScreenCastSource(window), getPipewireConnection(), this);
stream->setObjectName(window->desktopFileName());
stream->setCursorMode(mode, 1, window->clientGeometry());
if (mode != ScreencastV1Interface::CursorMode::Hidden) {
connect(window, &Window::clientGeometryChanged, stream, [window, stream, mode]() {
stream->setCursorMode(mode, 1, window->clientGeometry().toRect());
});
}
stream->setCursorMode(mode, 1);
integrateStreams(waylandStream, stream);
}
@ -90,10 +84,10 @@ void ScreencastManager::streamOutput(ScreencastStreamV1Interface *waylandStream,
auto stream = new ScreenCastStream(new OutputScreenCastSource(streamOutput), getPipewireConnection(), this);
stream->setObjectName(streamOutput->name());
stream->setCursorMode(mode, streamOutput->scale(), streamOutput->geometry());
stream->setCursorMode(mode, streamOutput->scale());
connect(streamOutput, &Output::changed, stream, [streamOutput, stream, mode]() {
stream->setCursorMode(mode, streamOutput->scale(), streamOutput->geometry());
stream->setCursorMode(mode, streamOutput->scale());
});
integrateStreams(waylandStream, stream);
@ -114,7 +108,7 @@ void ScreencastManager::streamRegion(ScreencastStreamV1Interface *waylandStream,
auto source = new RegionScreenCastSource(geometry, scale);
auto stream = new ScreenCastStream(source, getPipewireConnection(), this);
stream->setObjectName(rectToString(geometry));
stream->setCursorMode(mode, scale, geometry);
stream->setCursorMode(mode, scale);
integrateStreams(waylandStream, stream);
}

View file

@ -13,6 +13,7 @@ class QImage;
namespace KWin
{
class Cursor;
class GLFramebuffer;
class GLTexture;
@ -34,6 +35,11 @@ public:
virtual void resume() = 0;
virtual void pause() = 0;
virtual bool includesCursor(Cursor *cursor) const = 0;
virtual QPointF mapFromGlobal(const QPointF &point) const = 0;
virtual QRectF mapFromGlobal(const QRectF &rect) const = 0;
Q_SIGNALS:
void frame(const QRegion &damage);
void closed();

View file

@ -468,7 +468,7 @@ void ScreenCastStream::scheduleRecord(const QRegion &damage, Contents contents)
}
if (contents == Content::Cursor) {
if (!m_cursor.visible && !includesCursor(Cursors::self()->currentCursor())) {
if (!m_cursor.visible && !m_source->includesCursor(Cursors::self()->currentCursor())) {
return;
}
}
@ -703,14 +703,6 @@ spa_pod *ScreenCastStream::buildFormat(struct spa_pod_builder *b, enum spa_video
return (spa_pod *)spa_pod_builder_pop(b, &f[0]);
}
bool ScreenCastStream::includesCursor(Cursor *cursor) const
{
if (Cursors::self()->isCursorHidden()) {
return false;
}
return m_cursor.viewport.intersects(cursor->geometry());
}
void ScreenCastStream::addCursorMetadata(spa_buffer *spaBuffer, Cursor *cursor)
{
if (!cursor) {
@ -722,13 +714,13 @@ void ScreenCastStream::addCursorMetadata(spa_buffer *spaBuffer, Cursor *cursor)
return;
}
if (!includesCursor(cursor)) {
if (!m_source->includesCursor(cursor)) {
spaMetaCursor->id = 0;
m_cursor.visible = false;
return;
}
m_cursor.visible = true;
const auto position = (cursor->pos() - m_cursor.viewport.topLeft()) * m_cursor.scale;
const auto position = m_source->mapFromGlobal(cursor->pos()) * m_cursor.scale;
spaMetaCursor->id = 1;
spaMetaCursor->position.x = position.x();
@ -772,17 +764,17 @@ void ScreenCastStream::addCursorMetadata(spa_buffer *spaBuffer, Cursor *cursor)
QRegion ScreenCastStream::addCursorEmbedded(ScreenCastBuffer *buffer, Cursor *cursor)
{
if (!includesCursor(cursor)) {
if (!m_source->includesCursor(cursor)) {
const QRegion damage = m_cursor.lastRect.toAlignedRect();
m_cursor.visible = false;
m_cursor.lastRect = QRectF();
return damage;
}
const QRectF cursorRect = scaledRect(cursor->geometry().translated(-m_cursor.viewport.topLeft()), m_cursor.scale);
const QRectF cursorRect = scaledRect(m_source->mapFromGlobal(cursor->geometry()), m_cursor.scale);
if (auto memfd = dynamic_cast<MemFdScreenCastBuffer *>(buffer)) {
QPainter painter(memfd->view.image());
const auto position = (cursor->pos() - m_cursor.viewport.topLeft() - cursor->hotspot()) * m_cursor.scale;
const auto position = m_source->mapFromGlobal(cursor->pos() - cursor->hotspot()) * m_cursor.scale;
const PlatformCursorImage cursorImage = kwinApp()->cursorImage();
painter.drawImage(QRect{position.toPoint(), cursorImage.image().size()}, cursorImage.image());
} else if (auto dmabuf = dynamic_cast<DmaBufScreenCastBuffer *>(buffer)) {
@ -824,11 +816,10 @@ QRegion ScreenCastStream::addCursorEmbedded(ScreenCastBuffer *buffer, Cursor *cu
return damage;
}
void ScreenCastStream::setCursorMode(ScreencastV1Interface::CursorMode mode, qreal scale, const QRectF &viewport)
void ScreenCastStream::setCursorMode(ScreencastV1Interface::CursorMode mode, qreal scale)
{
m_cursor.mode = mode;
m_cursor.scale = scale;
m_cursor.viewport = viewport;
}
std::optional<ScreenCastDmaBufTextureParams> ScreenCastStream::testCreateDmaBuf(const QSize &size, quint32 format, const QList<uint64_t> &modifiers)

View file

@ -68,11 +68,10 @@ public:
void scheduleRecord(const QRegion &damage, Contents contents = Content::Video);
void setCursorMode(ScreencastV1Interface::CursorMode mode, qreal scale, const QRectF &viewport);
void setCursorMode(ScreencastV1Interface::CursorMode mode, qreal scale);
public Q_SLOTS:
void invalidateCursor();
bool includesCursor(Cursor *cursor) const;
Q_SIGNALS:
void ready(quint32 nodeId);
@ -123,7 +122,6 @@ private:
ScreencastV1Interface::CursorMode mode = ScreencastV1Interface::Hidden;
const QSize bitmapSize = QSize(256, 256);
qreal scale = 1;
QRectF viewport;
QRectF lastRect;
std::unique_ptr<GLTexture> texture;
bool visible = false;

View file

@ -13,6 +13,7 @@
#include "core/rendertarget.h"
#include "core/renderviewport.h"
#include "effect/effect.h"
#include "input.h"
#include "opengl/gltexture.h"
#include "opengl/glutils.h"
#include "scene/itemrenderer.h"
@ -118,6 +119,29 @@ void WindowScreenCastSource::resume()
m_active = true;
}
bool WindowScreenCastSource::includesCursor(Cursor *cursor) const
{
if (Cursors::self()->isCursorHidden()) {
return false;
}
if (!m_window->clientGeometry().intersects(cursor->geometry())) {
return false;
}
return input()->findToplevel(cursor->pos()) == m_window;
}
QPointF WindowScreenCastSource::mapFromGlobal(const QPointF &point) const
{
return point - m_window->clientGeometry().topLeft();
}
QRectF WindowScreenCastSource::mapFromGlobal(const QRectF &rect) const
{
return rect.translated(-m_window->clientGeometry().topLeft());
}
} // namespace KWin
#include "moc_windowscreencastsource.cpp"

View file

@ -34,6 +34,11 @@ public:
void resume() override;
void pause() override;
bool includesCursor(Cursor *cursor) const override;
QPointF mapFromGlobal(const QPointF &point) const override;
QRectF mapFromGlobal(const QRectF &rect) const override;
private:
void report();