diff --git a/src/plugins/screencast/outputscreencastsource.cpp b/src/plugins/screencast/outputscreencastsource.cpp index c6197188a5..de4b22d6cc 100644 --- a/src/plugins/screencast/outputscreencastsource.cpp +++ b/src/plugins/screencast/outputscreencastsource.cpp @@ -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" diff --git a/src/plugins/screencast/outputscreencastsource.h b/src/plugins/screencast/outputscreencastsource.h index a416e50347..79ee829d7c 100644 --- a/src/plugins/screencast/outputscreencastsource.h +++ b/src/plugins/screencast/outputscreencastsource.h @@ -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); diff --git a/src/plugins/screencast/regionscreencastsource.cpp b/src/plugins/screencast/regionscreencastsource.cpp index f6d790227a..5d5e9a0f53 100644 --- a/src/plugins/screencast/regionscreencastsource.cpp +++ b/src/plugins/screencast/regionscreencastsource.cpp @@ -7,6 +7,7 @@ #include "regionscreencastsource.h" #include "screencastutils.h" +#include "cursor.h" #include "opengl/gltexture.h" #include "opengl/glutils.h" #include @@ -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" diff --git a/src/plugins/screencast/regionscreencastsource.h b/src/plugins/screencast/regionscreencastsource.h index c081dd6b1a..32693d662f 100644 --- a/src/plugins/screencast/regionscreencastsource.h +++ b/src/plugins/screencast/regionscreencastsource.h @@ -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(); diff --git a/src/plugins/screencast/screencastmanager.cpp b/src/plugins/screencast/screencastmanager.cpp index e0b009c3b7..b4e9e97b74 100644 --- a/src/plugins/screencast/screencastmanager.cpp +++ b/src/plugins/screencast/screencastmanager.cpp @@ -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); } diff --git a/src/plugins/screencast/screencastsource.h b/src/plugins/screencast/screencastsource.h index c9627c2fb5..5da2a1d4bb 100644 --- a/src/plugins/screencast/screencastsource.h +++ b/src/plugins/screencast/screencastsource.h @@ -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(); diff --git a/src/plugins/screencast/screencaststream.cpp b/src/plugins/screencast/screencaststream.cpp index d4a180122f..86a986cde0 100644 --- a/src/plugins/screencast/screencaststream.cpp +++ b/src/plugins/screencast/screencaststream.cpp @@ -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(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(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 ScreenCastStream::testCreateDmaBuf(const QSize &size, quint32 format, const QList &modifiers) diff --git a/src/plugins/screencast/screencaststream.h b/src/plugins/screencast/screencaststream.h index 1012d32f20..4a6621e424 100644 --- a/src/plugins/screencast/screencaststream.h +++ b/src/plugins/screencast/screencaststream.h @@ -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 texture; bool visible = false; diff --git a/src/plugins/screencast/windowscreencastsource.cpp b/src/plugins/screencast/windowscreencastsource.cpp index 52ec1a1dbb..1d869a2930 100644 --- a/src/plugins/screencast/windowscreencastsource.cpp +++ b/src/plugins/screencast/windowscreencastsource.cpp @@ -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" diff --git a/src/plugins/screencast/windowscreencastsource.h b/src/plugins/screencast/windowscreencastsource.h index 7f69fd0c22..a138f3e161 100644 --- a/src/plugins/screencast/windowscreencastsource.h +++ b/src/plugins/screencast/windowscreencastsource.h @@ -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();