plugins/screencast: Hide cursor if another window covers screencasted window
BUG: 487294
This commit is contained in:
parent
8cb7e0a26b
commit
b452a5a5fb
10 changed files with 97 additions and 29 deletions
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue