Improve thumbnail item integration
Currently, thumbnail items are rendered by kwin. This means that qtquick code cannot do things such as applying shader effects to window thumbnails or simply draw custom controls on top of thumbnails. With this change, task switchers and qml extensions will be able to place their own contents on top of thumbnails and apply custom effects to them. In order to integrate window thumbnails, a window is rendered on kwin side using its own opengl context. A fence is inserted in the command stream to ensure that the qtquick machinery doesn't start using the offscreen texture while there are still rendering commands being executed. Thumbnails are rendered into offscreen textures as we don't have full control over when qtquick windows render their contents and to work around the fact that things such as VAOs can't be shared across OpenGL contexts. WindowThumbnailItem and DesktopThumbnailItem act as texture providers.
This commit is contained in:
parent
172c541cad
commit
3427143017
11 changed files with 592 additions and 541 deletions
|
@ -105,6 +105,7 @@ set(kwin_SRCS
|
|||
scripting/scripting_logging.cpp
|
||||
scripting/scripting_model.cpp
|
||||
scripting/scriptingutils.cpp
|
||||
scripting/thumbnailitem.cpp
|
||||
scripting/workspace_wrapper.cpp
|
||||
session.cpp
|
||||
session_consolekit.cpp
|
||||
|
@ -120,7 +121,6 @@ set(kwin_SRCS
|
|||
surfaceitem_x11.cpp
|
||||
syncalarmx11filter.cpp
|
||||
tablet_input.cpp
|
||||
thumbnailitem.cpp
|
||||
toplevel.cpp
|
||||
touch_hide_cursor_spy.cpp
|
||||
touch_input.cpp
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "scripting/scriptedeffect.h"
|
||||
#include "screens.h"
|
||||
#include "screenlockerwatcher.h"
|
||||
#include "thumbnailitem.h"
|
||||
#include "virtualdesktops.h"
|
||||
#include "window_property_notify_x11_filter.h"
|
||||
#include "workspace.h"
|
||||
|
@ -39,6 +38,8 @@
|
|||
#include "kwineffectquickview.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMouseEvent>
|
||||
#include <QWheelEvent>
|
||||
|
||||
#include <Plasma/Theme>
|
||||
|
||||
|
@ -2098,47 +2099,6 @@ void EffectWindowImpl::elevate(bool elevate)
|
|||
effects->setElevatedWindow(this, elevate);
|
||||
}
|
||||
|
||||
void EffectWindowImpl::registerThumbnail(AbstractThumbnailItem *item)
|
||||
{
|
||||
if (WindowThumbnailItem *thumb = qobject_cast<WindowThumbnailItem*>(item)) {
|
||||
insertThumbnail(thumb);
|
||||
connect(thumb, &QObject::destroyed, this, &EffectWindowImpl::thumbnailDestroyed);
|
||||
connect(thumb, &WindowThumbnailItem::wIdChanged, this, &EffectWindowImpl::thumbnailTargetChanged);
|
||||
} else if (DesktopThumbnailItem *desktopThumb = qobject_cast<DesktopThumbnailItem*>(item)) {
|
||||
m_desktopThumbnails.append(desktopThumb);
|
||||
connect(desktopThumb, &QObject::destroyed, this, &EffectWindowImpl::desktopThumbnailDestroyed);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectWindowImpl::thumbnailDestroyed(QObject *object)
|
||||
{
|
||||
// we know it is a ThumbnailItem
|
||||
m_thumbnails.remove(static_cast<WindowThumbnailItem*>(object));
|
||||
}
|
||||
|
||||
void EffectWindowImpl::thumbnailTargetChanged()
|
||||
{
|
||||
if (WindowThumbnailItem *item = qobject_cast<WindowThumbnailItem*>(sender())) {
|
||||
insertThumbnail(item);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectWindowImpl::insertThumbnail(WindowThumbnailItem *item)
|
||||
{
|
||||
EffectWindow *w = effects->findWindow(item->wId());
|
||||
if (w) {
|
||||
m_thumbnails.insert(item, QPointer<EffectWindowImpl>(static_cast<EffectWindowImpl*>(w)));
|
||||
} else {
|
||||
m_thumbnails.insert(item, QPointer<EffectWindowImpl>());
|
||||
}
|
||||
}
|
||||
|
||||
void EffectWindowImpl::desktopThumbnailDestroyed(QObject *object)
|
||||
{
|
||||
// we know it is a DesktopThumbnailItem
|
||||
m_desktopThumbnails.removeAll(static_cast<DesktopThumbnailItem*>(object));
|
||||
}
|
||||
|
||||
void EffectWindowImpl::minimize()
|
||||
{
|
||||
if (auto client = qobject_cast<AbstractClient *>(toplevel)) {
|
||||
|
|
|
@ -35,11 +35,6 @@ class QDBusServiceWatcher;
|
|||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class AbstractThumbnailItem;
|
||||
class DesktopThumbnailItem;
|
||||
class WindowThumbnailItem;
|
||||
|
||||
class AbstractClient;
|
||||
class Compositor;
|
||||
class Deleted;
|
||||
|
@ -508,25 +503,10 @@ public:
|
|||
void setData(int role, const QVariant &data) override;
|
||||
QVariant data(int role) const override;
|
||||
|
||||
void registerThumbnail(AbstractThumbnailItem *item);
|
||||
QHash<WindowThumbnailItem*, QPointer<EffectWindowImpl> > const &thumbnails() const {
|
||||
return m_thumbnails;
|
||||
}
|
||||
QList<DesktopThumbnailItem*> const &desktopThumbnails() const {
|
||||
return m_desktopThumbnails;
|
||||
}
|
||||
|
||||
private Q_SLOTS:
|
||||
void thumbnailDestroyed(QObject *object);
|
||||
void thumbnailTargetChanged();
|
||||
void desktopThumbnailDestroyed(QObject *object);
|
||||
private:
|
||||
void insertThumbnail(WindowThumbnailItem *item);
|
||||
Toplevel* toplevel;
|
||||
Scene::Window* sw; // This one is used only during paint pass.
|
||||
QHash<int, QVariant> dataMap;
|
||||
QHash<WindowThumbnailItem*, QPointer<EffectWindowImpl> > m_thumbnails;
|
||||
QList<DesktopThumbnailItem*> m_desktopThumbnails;
|
||||
bool managed = false;
|
||||
bool waylandClient;
|
||||
bool x11Client;
|
||||
|
|
124
src/scene.cpp
124
src/scene.cpp
|
@ -74,7 +74,6 @@
|
|||
#include "screens.h"
|
||||
#include "shadow.h"
|
||||
#include "wayland_server.h"
|
||||
#include "thumbnailitem.h"
|
||||
#include "composite.h"
|
||||
|
||||
namespace KWin
|
||||
|
@ -484,8 +483,6 @@ void Scene::clearStackingOrder()
|
|||
stacking_order.clear();
|
||||
}
|
||||
|
||||
static Scene::Window *s_recursionCheck = nullptr;
|
||||
|
||||
void Scene::paintWindow(Window* w, int mask, const QRegion &_region)
|
||||
{
|
||||
// no painting outside visible screen (and no transformations)
|
||||
|
@ -497,129 +494,8 @@ void Scene::paintWindow(Window* w, int mask, const QRegion &_region)
|
|||
return;
|
||||
}
|
||||
|
||||
if (s_recursionCheck == w) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowPaintData data(w->window()->effectWindow(), screenProjectionMatrix());
|
||||
effects->paintWindow(effectWindow(w), mask, region, data);
|
||||
// paint thumbnails on top of window
|
||||
paintWindowThumbnails(w, region, data.opacity(), data.brightness(), data.saturation());
|
||||
// and desktop thumbnails
|
||||
paintDesktopThumbnails(w);
|
||||
}
|
||||
|
||||
static void adjustClipRegion(AbstractThumbnailItem *item, QRegion &clippingRegion)
|
||||
{
|
||||
if (item->clip() && item->clipTo()) {
|
||||
// the x/y positions of the parent item are not correct. The margins are added, though the size seems fine
|
||||
// that's why we have to get the offset by inspecting the anchors properties
|
||||
QQuickItem *parentItem = item->clipTo();
|
||||
QPointF offset;
|
||||
QVariant anchors = parentItem->property("anchors");
|
||||
if (anchors.isValid()) {
|
||||
if (QObject *anchorsObject = anchors.value<QObject*>()) {
|
||||
offset.setX(anchorsObject->property("leftMargin").toReal());
|
||||
offset.setY(anchorsObject->property("topMargin").toReal());
|
||||
}
|
||||
}
|
||||
QRectF rect = QRectF(parentItem->position() - offset, QSizeF(parentItem->width(), parentItem->height()));
|
||||
if (QQuickItem *p = parentItem->parentItem()) {
|
||||
rect = p->mapRectToScene(rect);
|
||||
}
|
||||
clippingRegion &= rect.adjusted(0,0,-1,-1).translated(item->window()->position()).toRect();
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::paintWindowThumbnails(Scene::Window *w, const QRegion ®ion, qreal opacity, qreal brightness, qreal saturation)
|
||||
{
|
||||
EffectWindowImpl *wImpl = static_cast<EffectWindowImpl*>(effectWindow(w));
|
||||
for (QHash<WindowThumbnailItem*, QPointer<EffectWindowImpl> >::const_iterator it = wImpl->thumbnails().constBegin();
|
||||
it != wImpl->thumbnails().constEnd();
|
||||
++it) {
|
||||
if (it.value().isNull()) {
|
||||
continue;
|
||||
}
|
||||
WindowThumbnailItem *item = it.key();
|
||||
if (!item->isVisible()) {
|
||||
continue;
|
||||
}
|
||||
EffectWindowImpl *thumb = it.value().data();
|
||||
WindowPaintData thumbData(thumb, screenProjectionMatrix());
|
||||
thumbData.setOpacity(opacity);
|
||||
thumbData.setBrightness(brightness * item->brightness());
|
||||
thumbData.setSaturation(saturation * item->saturation());
|
||||
|
||||
const QRect visualThumbRect(thumb->expandedGeometry());
|
||||
|
||||
QSizeF size = QSizeF(visualThumbRect.size());
|
||||
size.scale(QSizeF(item->width(), item->height()), Qt::KeepAspectRatio);
|
||||
if (size.width() > visualThumbRect.width() || size.height() > visualThumbRect.height()) {
|
||||
size = QSizeF(visualThumbRect.size());
|
||||
}
|
||||
thumbData.setXScale(size.width() / static_cast<qreal>(visualThumbRect.width()));
|
||||
thumbData.setYScale(size.height() / static_cast<qreal>(visualThumbRect.height()));
|
||||
|
||||
if (!item->window()) {
|
||||
continue;
|
||||
}
|
||||
const QPointF point = item->mapToScene(QPointF(0,0));
|
||||
qreal x = point.x() + w->x() + (item->width() - size.width())/2;
|
||||
qreal y = point.y() + w->y() + (item->height() - size.height()) / 2;
|
||||
x -= thumb->x();
|
||||
y -= thumb->y();
|
||||
// compensate shadow topleft padding
|
||||
x += (thumb->x()-visualThumbRect.x())*thumbData.xScale();
|
||||
y += (thumb->y()-visualThumbRect.y())*thumbData.yScale();
|
||||
thumbData.setXTranslation(x);
|
||||
thumbData.setYTranslation(y);
|
||||
int thumbMask = PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_LANCZOS;
|
||||
if (thumbData.opacity() == 1.0) {
|
||||
thumbMask |= PAINT_WINDOW_OPAQUE;
|
||||
} else {
|
||||
thumbMask |= PAINT_WINDOW_TRANSLUCENT;
|
||||
}
|
||||
QRegion clippingRegion = region;
|
||||
clippingRegion &= QRegion(wImpl->x(), wImpl->y(), wImpl->width(), wImpl->height());
|
||||
adjustClipRegion(item, clippingRegion);
|
||||
effects->drawWindow(thumb, thumbMask, clippingRegion, thumbData);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::paintDesktopThumbnails(Scene::Window *w)
|
||||
{
|
||||
EffectWindowImpl *wImpl = static_cast<EffectWindowImpl*>(effectWindow(w));
|
||||
for (QList<DesktopThumbnailItem*>::const_iterator it = wImpl->desktopThumbnails().constBegin();
|
||||
it != wImpl->desktopThumbnails().constEnd();
|
||||
++it) {
|
||||
DesktopThumbnailItem *item = *it;
|
||||
if (!item->isVisible()) {
|
||||
continue;
|
||||
}
|
||||
if (!item->window()) {
|
||||
continue;
|
||||
}
|
||||
s_recursionCheck = w;
|
||||
|
||||
ScreenPaintData data;
|
||||
const QSize &screenSize = screens()->size();
|
||||
QSize size = screenSize;
|
||||
|
||||
size.scale(item->width(), item->height(), Qt::KeepAspectRatio);
|
||||
data *= QVector2D(size.width() / double(screenSize.width()),
|
||||
size.height() / double(screenSize.height()));
|
||||
const QPointF point = item->mapToScene(item->position());
|
||||
const qreal x = point.x() + w->x() + (item->width() - size.width())/2;
|
||||
const qreal y = point.y() + w->y() + (item->height() - size.height()) / 2;
|
||||
const QRect region = QRect(x, y, item->width(), item->height());
|
||||
QRegion clippingRegion = region;
|
||||
clippingRegion &= QRegion(wImpl->x(), wImpl->y(), wImpl->width(), wImpl->height());
|
||||
adjustClipRegion(item, clippingRegion);
|
||||
data += QPointF(x, y);
|
||||
const int desktopMask = PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST;
|
||||
paintDesktop(item->desktop(), desktopMask, clippingRegion, data);
|
||||
s_recursionCheck = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data)
|
||||
|
|
|
@ -26,7 +26,6 @@ class DecoratedClientImpl;
|
|||
}
|
||||
|
||||
class AbstractOutput;
|
||||
class AbstractThumbnailItem;
|
||||
class DecorationRenderer;
|
||||
class Deleted;
|
||||
class EffectFrameImpl;
|
||||
|
@ -193,6 +192,8 @@ public:
|
|||
virtual PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap);
|
||||
virtual PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap);
|
||||
|
||||
virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data);
|
||||
|
||||
Q_SIGNALS:
|
||||
void frameRendered();
|
||||
void resetCompositing();
|
||||
|
@ -236,7 +237,6 @@ protected:
|
|||
// let the scene decide whether it's better to paint more of the screen, eg. in order to allow a buffer swap
|
||||
// the default is NOOP
|
||||
virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen);
|
||||
virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data);
|
||||
|
||||
virtual void paintEffectQuickView(EffectQuickView *w) = 0;
|
||||
|
||||
|
@ -263,8 +263,6 @@ protected:
|
|||
// windows in their stacking order
|
||||
QVector< Window* > stacking_order;
|
||||
private:
|
||||
void paintWindowThumbnails(Scene::Window *w, const QRegion ®ion, qreal opacity, qreal brightness, qreal saturation);
|
||||
void paintDesktopThumbnails(Scene::Window *w);
|
||||
std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero();
|
||||
void reallocRepaints();
|
||||
QHash< Toplevel*, Window* > m_windows;
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
#include "screenedgeitem.h"
|
||||
#include "scripting_model.h"
|
||||
#include "scripting_logging.h"
|
||||
#include "thumbnailitem.h"
|
||||
|
||||
#include "options.h"
|
||||
#include "screenedge.h"
|
||||
#include "thumbnailitem.h"
|
||||
#include "workspace.h"
|
||||
#include "x11client.h"
|
||||
// KDE
|
||||
|
|
446
src/scripting/thumbnailitem.cpp
Normal file
446
src/scripting/thumbnailitem.cpp
Normal file
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "thumbnailitem.h"
|
||||
#include "abstract_client.h"
|
||||
#include "composite.h"
|
||||
#include "effects.h"
|
||||
#include "scene.h"
|
||||
#include "screens.h"
|
||||
#include "scripting_logging.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include <kwingltexture.h>
|
||||
#include <kwinglutils.h>
|
||||
|
||||
#include <QSGImageNode>
|
||||
#include <QRunnable>
|
||||
#include <QQuickWindow>
|
||||
#include <QSGTextureProvider>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class ThumbnailTextureProvider : public QSGTextureProvider
|
||||
{
|
||||
public:
|
||||
explicit ThumbnailTextureProvider(QQuickWindow *window);
|
||||
|
||||
QSGTexture *texture() const override;
|
||||
void setTexture(const QSharedPointer<GLTexture> &nativeTexture);
|
||||
void setTexture(QSGTexture *texture);
|
||||
|
||||
private:
|
||||
QQuickWindow *m_window;
|
||||
QSharedPointer<GLTexture> m_nativeTexture;
|
||||
QScopedPointer<QSGTexture> m_texture;
|
||||
};
|
||||
|
||||
ThumbnailTextureProvider::ThumbnailTextureProvider(QQuickWindow *window)
|
||||
: m_window(window)
|
||||
{
|
||||
}
|
||||
|
||||
QSGTexture *ThumbnailTextureProvider::texture() const
|
||||
{
|
||||
return m_texture.data();
|
||||
}
|
||||
|
||||
void ThumbnailTextureProvider::setTexture(const QSharedPointer<GLTexture> &nativeTexture)
|
||||
{
|
||||
if (m_nativeTexture != nativeTexture) {
|
||||
const GLuint textureId = nativeTexture->texture();
|
||||
m_nativeTexture = nativeTexture;
|
||||
m_texture.reset(m_window->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture,
|
||||
&textureId, 0,
|
||||
nativeTexture->size(),
|
||||
QQuickWindow::TextureHasAlphaChannel));
|
||||
m_texture->setFiltering(QSGTexture::Linear);
|
||||
m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
|
||||
m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);
|
||||
}
|
||||
|
||||
// The textureChanged signal must be emitted also if only texture data changes.
|
||||
Q_EMIT textureChanged();
|
||||
}
|
||||
|
||||
void ThumbnailTextureProvider::setTexture(QSGTexture *texture)
|
||||
{
|
||||
m_nativeTexture = nullptr;
|
||||
m_texture.reset(texture);
|
||||
Q_EMIT textureChanged();
|
||||
}
|
||||
|
||||
class ThumbnailTextureProviderCleanupJob : public QRunnable
|
||||
{
|
||||
public:
|
||||
explicit ThumbnailTextureProviderCleanupJob(ThumbnailTextureProvider *provider)
|
||||
: m_provider(provider)
|
||||
{
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
m_provider.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
QScopedPointer<ThumbnailTextureProvider> m_provider;
|
||||
};
|
||||
|
||||
ThumbnailItemBase::ThumbnailItemBase(QQuickItem *parent)
|
||||
: QQuickItem(parent)
|
||||
{
|
||||
setFlag(ItemHasContents);
|
||||
handleCompositingToggled();
|
||||
|
||||
connect(Compositor::self(), &Compositor::aboutToToggleCompositing,
|
||||
this, &ThumbnailItemBase::destroyOffscreenTexture);
|
||||
connect(Compositor::self(), &Compositor::compositingToggled,
|
||||
this, &ThumbnailItemBase::handleCompositingToggled);
|
||||
}
|
||||
|
||||
ThumbnailItemBase::~ThumbnailItemBase()
|
||||
{
|
||||
destroyOffscreenTexture();
|
||||
|
||||
if (m_provider) {
|
||||
if (window()) {
|
||||
window()->scheduleRenderJob(new ThumbnailTextureProviderCleanupJob(m_provider),
|
||||
QQuickWindow::AfterSynchronizingStage);
|
||||
} else {
|
||||
qCCritical(KWIN_SCRIPTING) << "Can't destroy thumbnail texture provider because window is null";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThumbnailItemBase::releaseResources()
|
||||
{
|
||||
if (m_provider) {
|
||||
window()->scheduleRenderJob(new ThumbnailTextureProviderCleanupJob(m_provider),
|
||||
QQuickWindow::AfterSynchronizingStage);
|
||||
m_provider = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ThumbnailItemBase::isTextureProvider() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QSGTextureProvider *ThumbnailItemBase::textureProvider() const
|
||||
{
|
||||
if (QQuickItem::isTextureProvider()) {
|
||||
return QQuickItem::textureProvider();
|
||||
}
|
||||
if (!m_provider) {
|
||||
m_provider = new ThumbnailTextureProvider(window());
|
||||
}
|
||||
return m_provider;
|
||||
}
|
||||
|
||||
void ThumbnailItemBase::handleCompositingToggled()
|
||||
{
|
||||
Scene *scene = Compositor::self()->scene();
|
||||
if (scene && scene->compositingType() == OpenGLCompositing) {
|
||||
connect(scene, &Scene::frameRendered, this, &ThumbnailItemBase::updateOffscreenTexture);
|
||||
}
|
||||
}
|
||||
|
||||
QSize ThumbnailItemBase::sourceSize() const
|
||||
{
|
||||
return m_sourceSize;
|
||||
}
|
||||
|
||||
void ThumbnailItemBase::setSourceSize(const QSize &sourceSize)
|
||||
{
|
||||
if (m_sourceSize != sourceSize) {
|
||||
m_sourceSize = sourceSize;
|
||||
invalidateOffscreenTexture();
|
||||
Q_EMIT sourceSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ThumbnailItemBase::destroyOffscreenTexture()
|
||||
{
|
||||
Scene *scene = Compositor::self()->scene();
|
||||
if (!scene || scene->compositingType() != OpenGLCompositing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_offscreenTexture) {
|
||||
scene->makeOpenGLContextCurrent();
|
||||
m_offscreenTarget.reset();
|
||||
m_offscreenTexture.reset();
|
||||
|
||||
if (m_acquireFence) {
|
||||
glDeleteSync(m_acquireFence);
|
||||
m_acquireFence = 0;
|
||||
}
|
||||
scene->doneOpenGLContextCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
QSGNode *ThumbnailItemBase::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
|
||||
{
|
||||
if (Compositor::compositing() && !m_offscreenTexture) {
|
||||
return oldNode;
|
||||
}
|
||||
|
||||
// Wait for rendering commands to the offscreen texture complete if there are any.
|
||||
if (m_acquireFence) {
|
||||
glClientWaitSync(m_acquireFence, GL_SYNC_FLUSH_COMMANDS_BIT, 5000);
|
||||
glDeleteSync(m_acquireFence);
|
||||
m_acquireFence = 0;
|
||||
}
|
||||
|
||||
if (!m_provider) {
|
||||
m_provider = new ThumbnailTextureProvider(window());
|
||||
}
|
||||
|
||||
if (m_offscreenTexture) {
|
||||
m_provider->setTexture(m_offscreenTexture);
|
||||
} else {
|
||||
m_provider->setTexture(window()->createTextureFromImage(fallbackImage()));
|
||||
}
|
||||
|
||||
QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
|
||||
if (!node) {
|
||||
node = window()->createImageNode();
|
||||
}
|
||||
node->setTexture(m_provider->texture());
|
||||
|
||||
if (m_offscreenTexture && m_offscreenTexture->isYInverted()) {
|
||||
node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically);
|
||||
} else {
|
||||
node->setTextureCoordinatesTransform(QSGImageNode::NoTransform);
|
||||
}
|
||||
|
||||
const QSizeF size = QSizeF(node->texture()->textureSize())
|
||||
.scaled(boundingRect().size(), Qt::KeepAspectRatio);
|
||||
const qreal x = boundingRect().x() + (boundingRect().width() - size.width()) / 2;
|
||||
const qreal y = boundingRect().y() + (boundingRect().height() - size.height()) / 2;
|
||||
node->setRect(QRectF(QPointF(x, y), size));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void ThumbnailItemBase::setSaturation(qreal saturation)
|
||||
{
|
||||
Q_UNUSED(saturation)
|
||||
qCWarning(KWIN_SCRIPTING) << "ThumbnailItem.saturation is removed. Use a shader effect to change saturation";
|
||||
}
|
||||
|
||||
void ThumbnailItemBase::setBrightness(qreal brightness)
|
||||
{
|
||||
Q_UNUSED(brightness)
|
||||
qCWarning(KWIN_SCRIPTING) << "ThumbnailItem.brightness is removed. Use a shader effect to change brightness";
|
||||
}
|
||||
|
||||
void ThumbnailItemBase::setClipTo(QQuickItem *clip)
|
||||
{
|
||||
Q_UNUSED(clip)
|
||||
qCWarning(KWIN_SCRIPTING) << "ThumbnailItem.clipTo is removed and it has no replacements";
|
||||
}
|
||||
|
||||
WindowThumbnailItem::WindowThumbnailItem(QQuickItem *parent)
|
||||
: ThumbnailItemBase(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QUuid WindowThumbnailItem::wId() const
|
||||
{
|
||||
return m_wId;
|
||||
}
|
||||
|
||||
void WindowThumbnailItem::setWId(const QUuid &wId)
|
||||
{
|
||||
if (m_wId == wId) {
|
||||
return;
|
||||
}
|
||||
m_wId = wId;
|
||||
if (!m_wId.isNull()) {
|
||||
setClient(workspace()->findAbstractClient(wId));
|
||||
} else if (m_client) {
|
||||
m_client = nullptr;
|
||||
Q_EMIT clientChanged();
|
||||
}
|
||||
Q_EMIT wIdChanged();
|
||||
}
|
||||
|
||||
AbstractClient *WindowThumbnailItem::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
void WindowThumbnailItem::setClient(AbstractClient *client)
|
||||
{
|
||||
if (m_client == client) {
|
||||
return;
|
||||
}
|
||||
if (m_client) {
|
||||
disconnect(m_client, &AbstractClient::frameGeometryChanged,
|
||||
this, &WindowThumbnailItem::invalidateOffscreenTexture);
|
||||
disconnect(m_client, &AbstractClient::damaged,
|
||||
this, &WindowThumbnailItem::invalidateOffscreenTexture);
|
||||
}
|
||||
m_client = client;
|
||||
if (m_client) {
|
||||
connect(m_client, &AbstractClient::frameGeometryChanged,
|
||||
this, &WindowThumbnailItem::invalidateOffscreenTexture);
|
||||
connect(m_client, &AbstractClient::damaged,
|
||||
this, &WindowThumbnailItem::invalidateOffscreenTexture);
|
||||
setWId(m_client->internalId());
|
||||
} else {
|
||||
setWId(QUuid());
|
||||
}
|
||||
invalidateOffscreenTexture();
|
||||
Q_EMIT clientChanged();
|
||||
}
|
||||
|
||||
QImage WindowThumbnailItem::fallbackImage() const
|
||||
{
|
||||
if (m_client) {
|
||||
return m_client->icon().pixmap(boundingRect().size().toSize()).toImage();
|
||||
}
|
||||
return QImage();
|
||||
}
|
||||
|
||||
void WindowThumbnailItem::invalidateOffscreenTexture()
|
||||
{
|
||||
m_dirty = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void WindowThumbnailItem::updateOffscreenTexture()
|
||||
{
|
||||
if (m_acquireFence || !m_dirty || !m_client) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QRect geometry = m_client->frameGeometry();
|
||||
QSize textureSize = geometry.size();
|
||||
if (sourceSize().width() > 0) {
|
||||
textureSize.setWidth(sourceSize().width());
|
||||
}
|
||||
if (sourceSize().height() > 0) {
|
||||
textureSize.setHeight(sourceSize().height());
|
||||
}
|
||||
|
||||
if (!m_offscreenTexture || m_offscreenTexture->size() != textureSize) {
|
||||
m_offscreenTexture.reset(new GLTexture(GL_RGBA8, textureSize));
|
||||
m_offscreenTexture->setFilter(GL_LINEAR);
|
||||
m_offscreenTexture->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||
m_offscreenTarget.reset(new GLRenderTarget(*m_offscreenTexture));
|
||||
}
|
||||
|
||||
GLRenderTarget::pushRenderTarget(m_offscreenTarget.data());
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
QMatrix4x4 projectionMatrix;
|
||||
projectionMatrix.ortho(geometry.x(), geometry.x() + geometry.width(),
|
||||
geometry.y(), geometry.y() + geometry.height(), -1, 1);
|
||||
|
||||
EffectWindowImpl *effectWindow = m_client->effectWindow();
|
||||
WindowPaintData data(effectWindow);
|
||||
data.setProjectionMatrix(projectionMatrix);
|
||||
|
||||
// The thumbnail must be rendered using kwin's opengl context as VAOs are not
|
||||
// shared across contexts. Unfortunately, this also introduces a latency of 1
|
||||
// frame, which is not ideal, but it is acceptable for things such as thumbnails.
|
||||
const int mask = Scene::PAINT_WINDOW_TRANSFORMED;
|
||||
effectWindow->sceneWindow()->performPaint(mask, infiniteRegion(), data);
|
||||
GLRenderTarget::popRenderTarget();
|
||||
|
||||
// The fence is needed to avoid the case where qtquick renderer starts using
|
||||
// the texture while all rendering commands to it haven't completed yet.
|
||||
m_dirty = false;
|
||||
m_acquireFence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
// We know that the texture has changed, so schedule an item update.
|
||||
update();
|
||||
}
|
||||
|
||||
DesktopThumbnailItem::DesktopThumbnailItem(QQuickItem *parent)
|
||||
: ThumbnailItemBase(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int DesktopThumbnailItem::desktop() const
|
||||
{
|
||||
return m_desktop;
|
||||
}
|
||||
|
||||
void DesktopThumbnailItem::setDesktop(int desktop)
|
||||
{
|
||||
desktop = qBound<int>(1, desktop, VirtualDesktopManager::self()->count());
|
||||
if (m_desktop != desktop) {
|
||||
m_desktop = desktop;
|
||||
invalidateOffscreenTexture();
|
||||
Q_EMIT desktopChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QImage DesktopThumbnailItem::fallbackImage() const
|
||||
{
|
||||
return QImage();
|
||||
}
|
||||
|
||||
void DesktopThumbnailItem::invalidateOffscreenTexture()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void DesktopThumbnailItem::updateOffscreenTexture()
|
||||
{
|
||||
if (m_acquireFence) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QRect geometry = screens()->geometry();
|
||||
QSize textureSize = geometry.size();
|
||||
if (sourceSize().width() > 0) {
|
||||
textureSize.setWidth(sourceSize().width());
|
||||
}
|
||||
if (sourceSize().height() > 0) {
|
||||
textureSize.setHeight(sourceSize().height());
|
||||
}
|
||||
|
||||
if (!m_offscreenTexture || m_offscreenTexture->size() != textureSize) {
|
||||
m_offscreenTexture.reset(new GLTexture(GL_RGBA8, textureSize));
|
||||
m_offscreenTexture->setFilter(GL_LINEAR);
|
||||
m_offscreenTexture->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||
m_offscreenTexture->setYInverted(true);
|
||||
m_offscreenTarget.reset(new GLRenderTarget(*m_offscreenTexture));
|
||||
}
|
||||
|
||||
GLRenderTarget::pushRenderTarget(m_offscreenTarget.data());
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
QMatrix4x4 projectionMatrix;
|
||||
projectionMatrix.ortho(geometry);
|
||||
ScreenPaintData data(projectionMatrix);
|
||||
|
||||
// The thumbnail must be rendered using kwin's opengl context as VAOs are not
|
||||
// shared across contexts. Unfortunately, this also introduces a latency of 1
|
||||
// frame, which is not ideal, but it is acceptable for things such as thumbnails.
|
||||
const int mask = Scene::PAINT_WINDOW_TRANSFORMED | Scene::PAINT_SCREEN_TRANSFORMED;
|
||||
Scene *scene = Compositor::self()->scene();
|
||||
scene->paintDesktop(m_desktop, mask, infiniteRegion(), data);
|
||||
GLRenderTarget::popRenderTarget();
|
||||
|
||||
// The fence is needed to avoid the case where qtquick renderer starts using
|
||||
// the texture while all rendering commands to it haven't completed yet.
|
||||
m_acquireFence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
// We know that the texture has changed, so schedule an item update.
|
||||
update();
|
||||
}
|
||||
|
||||
} // namespace KWin
|
140
src/scripting/thumbnailitem.h
Normal file
140
src/scripting/thumbnailitem.h
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QUuid>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class AbstractClient;
|
||||
class GLRenderTarget;
|
||||
class GLTexture;
|
||||
class ThumbnailTextureProvider;
|
||||
|
||||
class ThumbnailItemBase : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize NOTIFY sourceSizeChanged)
|
||||
/**
|
||||
* TODO Plasma 6: Remove.
|
||||
* @deprecated use a shader effect to change the brightness
|
||||
*/
|
||||
Q_PROPERTY(qreal brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged)
|
||||
/**
|
||||
* TODO Plasma 6: Remove.
|
||||
* @deprecated use a shader effect to change color saturation
|
||||
*/
|
||||
Q_PROPERTY(qreal saturation READ saturation WRITE setSaturation NOTIFY saturationChanged)
|
||||
/**
|
||||
* TODO Plasma 6: Remove.
|
||||
* @deprecated clipTo has no replacement
|
||||
*/
|
||||
Q_PROPERTY(QQuickItem *clipTo READ clipTo WRITE setClipTo NOTIFY clipToChanged)
|
||||
|
||||
public:
|
||||
explicit ThumbnailItemBase(QQuickItem *parent = nullptr);
|
||||
~ThumbnailItemBase() override;
|
||||
|
||||
qreal brightness() const { return 1; }
|
||||
void setBrightness(qreal brightness);
|
||||
|
||||
qreal saturation() const { return 1; }
|
||||
void setSaturation(qreal saturation);
|
||||
|
||||
QQuickItem *clipTo() const { return nullptr; }
|
||||
void setClipTo(QQuickItem *clip);
|
||||
|
||||
QSize sourceSize() const;
|
||||
void setSourceSize(const QSize &sourceSize);
|
||||
|
||||
QSGTextureProvider *textureProvider() const override;
|
||||
bool isTextureProvider() const override;
|
||||
QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void brightnessChanged();
|
||||
void saturationChanged();
|
||||
void clipToChanged();
|
||||
void sourceSizeChanged();
|
||||
|
||||
protected:
|
||||
void releaseResources() override;
|
||||
|
||||
virtual QImage fallbackImage() const = 0;
|
||||
virtual void invalidateOffscreenTexture() = 0;
|
||||
virtual void updateOffscreenTexture() = 0;
|
||||
void destroyOffscreenTexture();
|
||||
|
||||
mutable ThumbnailTextureProvider *m_provider = nullptr;
|
||||
QSharedPointer<GLTexture> m_offscreenTexture;
|
||||
QScopedPointer<GLRenderTarget> m_offscreenTarget;
|
||||
GLsync m_acquireFence = 0;
|
||||
|
||||
private:
|
||||
void handleCompositingToggled();
|
||||
|
||||
QSize m_sourceSize;
|
||||
};
|
||||
|
||||
class WindowThumbnailItem : public ThumbnailItemBase
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUuid wId READ wId WRITE setWId NOTIFY wIdChanged)
|
||||
Q_PROPERTY(KWin::AbstractClient *client READ client WRITE setClient NOTIFY clientChanged)
|
||||
|
||||
public:
|
||||
explicit WindowThumbnailItem(QQuickItem *parent = nullptr);
|
||||
|
||||
QUuid wId() const;
|
||||
void setWId(const QUuid &wId);
|
||||
|
||||
AbstractClient *client() const;
|
||||
void setClient(AbstractClient *client);
|
||||
|
||||
Q_SIGNALS:
|
||||
void wIdChanged();
|
||||
void clientChanged();
|
||||
|
||||
protected:
|
||||
QImage fallbackImage() const override;
|
||||
void invalidateOffscreenTexture() override;
|
||||
void updateOffscreenTexture() override;
|
||||
|
||||
private:
|
||||
QUuid m_wId;
|
||||
QPointer<AbstractClient> m_client;
|
||||
bool m_dirty = false;
|
||||
};
|
||||
|
||||
class DesktopThumbnailItem : public ThumbnailItemBase
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int desktop READ desktop WRITE setDesktop NOTIFY desktopChanged)
|
||||
|
||||
public:
|
||||
explicit DesktopThumbnailItem(QQuickItem *parent = nullptr);
|
||||
|
||||
int desktop() const;
|
||||
void setDesktop(int desktop);
|
||||
|
||||
Q_SIGNALS:
|
||||
void desktopChanged();
|
||||
|
||||
protected:
|
||||
QImage fallbackImage() const override;
|
||||
void invalidateOffscreenTexture() override;
|
||||
void updateOffscreenTexture() override;
|
||||
|
||||
private:
|
||||
int m_desktop = 1;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
|
@ -15,7 +15,6 @@
|
|||
// tabbox
|
||||
#include "clientmodel.h"
|
||||
#include "desktopmodel.h"
|
||||
#include "thumbnailitem.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "switcheritem.h"
|
||||
#include "tabbox_logging.h"
|
||||
|
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "thumbnailitem.h"
|
||||
// KWin
|
||||
#include "x11client.h"
|
||||
#include "composite.h"
|
||||
#include "effects.h"
|
||||
#include "workspace.h"
|
||||
#include "wayland_server.h"
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QQuickWindow>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
AbstractThumbnailItem::AbstractThumbnailItem(QQuickItem *parent)
|
||||
: QQuickPaintedItem(parent)
|
||||
, m_brightness(1.0)
|
||||
, m_saturation(1.0)
|
||||
, m_clipToItem()
|
||||
{
|
||||
connect(Compositor::self(), &Compositor::compositingToggled, this, &AbstractThumbnailItem::compositingToggled);
|
||||
compositingToggled();
|
||||
QTimer::singleShot(0, this, &AbstractThumbnailItem::init);
|
||||
}
|
||||
|
||||
AbstractThumbnailItem::~AbstractThumbnailItem()
|
||||
{
|
||||
}
|
||||
|
||||
void AbstractThumbnailItem::compositingToggled()
|
||||
{
|
||||
m_parent.clear();
|
||||
if (effects) {
|
||||
connect(effects, &EffectsHandler::windowAdded, this, &AbstractThumbnailItem::effectWindowAdded);
|
||||
connect(effects, &EffectsHandler::windowDamaged, this, &AbstractThumbnailItem::repaint);
|
||||
effectWindowAdded();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractThumbnailItem::init()
|
||||
{
|
||||
findParentEffectWindow();
|
||||
if (m_parent) {
|
||||
m_parent->registerThumbnail(this);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractThumbnailItem::findParentEffectWindow()
|
||||
{
|
||||
if (effects) {
|
||||
QQuickWindow *qw = window();
|
||||
if (!qw) {
|
||||
qCDebug(KWIN_CORE) << "No QQuickWindow assigned yet";
|
||||
return;
|
||||
}
|
||||
if (auto *w = static_cast<EffectWindowImpl*>(effects->findWindow(qw))) {
|
||||
m_parent = QPointer<EffectWindowImpl>(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractThumbnailItem::effectWindowAdded()
|
||||
{
|
||||
// the window might be added before the EffectWindow is created
|
||||
// by using this slot we can register the thumbnail when it is finally created
|
||||
if (m_parent.isNull()) {
|
||||
findParentEffectWindow();
|
||||
if (m_parent) {
|
||||
m_parent->registerThumbnail(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractThumbnailItem::setBrightness(qreal brightness)
|
||||
{
|
||||
if (qFuzzyCompare(brightness, m_brightness)) {
|
||||
return;
|
||||
}
|
||||
m_brightness = brightness;
|
||||
update();
|
||||
Q_EMIT brightnessChanged();
|
||||
}
|
||||
|
||||
void AbstractThumbnailItem::setSaturation(qreal saturation)
|
||||
{
|
||||
if (qFuzzyCompare(saturation, m_saturation)) {
|
||||
return;
|
||||
}
|
||||
m_saturation = saturation;
|
||||
update();
|
||||
Q_EMIT saturationChanged();
|
||||
}
|
||||
|
||||
void AbstractThumbnailItem::setClipTo(QQuickItem *clip)
|
||||
{
|
||||
m_clipToItem = QPointer<QQuickItem>(clip);
|
||||
Q_EMIT clipToChanged();
|
||||
}
|
||||
|
||||
WindowThumbnailItem::WindowThumbnailItem(QQuickItem* parent)
|
||||
: AbstractThumbnailItem(parent)
|
||||
, m_wId(nullptr)
|
||||
, m_client(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
WindowThumbnailItem::~WindowThumbnailItem()
|
||||
{
|
||||
}
|
||||
|
||||
void WindowThumbnailItem::setWId(const QUuid &wId)
|
||||
{
|
||||
if (m_wId == wId) {
|
||||
return;
|
||||
}
|
||||
m_wId = wId;
|
||||
if (m_wId != nullptr) {
|
||||
setClient(workspace()->findAbstractClient([this] (const AbstractClient *c) { return c->internalId() == m_wId; }));
|
||||
} else if (m_client) {
|
||||
m_client = nullptr;
|
||||
Q_EMIT clientChanged();
|
||||
}
|
||||
Q_EMIT wIdChanged(wId);
|
||||
}
|
||||
|
||||
void WindowThumbnailItem::setClient(AbstractClient *client)
|
||||
{
|
||||
if (m_client == client) {
|
||||
return;
|
||||
}
|
||||
m_client = client;
|
||||
if (m_client) {
|
||||
setWId(m_client->internalId());
|
||||
} else {
|
||||
setWId({});
|
||||
}
|
||||
Q_EMIT clientChanged();
|
||||
}
|
||||
|
||||
void WindowThumbnailItem::paint(QPainter *painter)
|
||||
{
|
||||
if (effects) {
|
||||
return;
|
||||
}
|
||||
auto client = workspace()->findAbstractClient([this] (const AbstractClient *c) { return c->internalId() == m_wId; });
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
QPixmap pixmap = client->icon().pixmap(boundingRect().size().toSize());
|
||||
const QSize size(boundingRect().size().toSize() - pixmap.size());
|
||||
painter->drawPixmap(boundingRect().adjusted(size.width()/2.0, size.height()/2.0, -size.width()/2.0, -size.height()/2.0).toRect(),
|
||||
pixmap);
|
||||
}
|
||||
|
||||
void WindowThumbnailItem::repaint(KWin::EffectWindow *w)
|
||||
{
|
||||
if (static_cast<KWin::EffectWindowImpl*>(w)->window()->internalId() == m_wId) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
DesktopThumbnailItem::DesktopThumbnailItem(QQuickItem *parent)
|
||||
: AbstractThumbnailItem(parent)
|
||||
, m_desktop(0)
|
||||
{
|
||||
}
|
||||
|
||||
DesktopThumbnailItem::~DesktopThumbnailItem()
|
||||
{
|
||||
}
|
||||
|
||||
void DesktopThumbnailItem::setDesktop(int desktop)
|
||||
{
|
||||
desktop = qBound<int>(1, desktop, VirtualDesktopManager::self()->count());
|
||||
if (desktop == m_desktop) {
|
||||
return;
|
||||
}
|
||||
m_desktop = desktop;
|
||||
update();
|
||||
Q_EMIT desktopChanged(m_desktop);
|
||||
}
|
||||
|
||||
void DesktopThumbnailItem::paint(QPainter *painter)
|
||||
{
|
||||
Q_UNUSED(painter)
|
||||
if (effects) {
|
||||
return;
|
||||
}
|
||||
// TODO: render icon
|
||||
}
|
||||
|
||||
void DesktopThumbnailItem::repaint(EffectWindow *w)
|
||||
{
|
||||
if (w->isOnDesktop(m_desktop)) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace KWin
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KWIN_THUMBNAILITEM_H
|
||||
#define KWIN_THUMBNAILITEM_H
|
||||
|
||||
#include <QPointer>
|
||||
#include <QUuid>
|
||||
#include <QWeakPointer>
|
||||
#include <QQuickPaintedItem>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class AbstractClient;
|
||||
class EffectWindow;
|
||||
class EffectWindowImpl;
|
||||
|
||||
class AbstractThumbnailItem : public QQuickPaintedItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qreal brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged)
|
||||
Q_PROPERTY(qreal saturation READ saturation WRITE setSaturation NOTIFY saturationChanged)
|
||||
Q_PROPERTY(QQuickItem *clipTo READ clipTo WRITE setClipTo NOTIFY clipToChanged)
|
||||
public:
|
||||
~AbstractThumbnailItem() override;
|
||||
qreal brightness() const;
|
||||
qreal saturation() const;
|
||||
QQuickItem *clipTo() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setBrightness(qreal brightness);
|
||||
void setSaturation(qreal saturation);
|
||||
void setClipTo(QQuickItem *clip);
|
||||
|
||||
Q_SIGNALS:
|
||||
void brightnessChanged();
|
||||
void saturationChanged();
|
||||
void clipToChanged();
|
||||
|
||||
protected:
|
||||
explicit AbstractThumbnailItem(QQuickItem *parent = nullptr);
|
||||
|
||||
protected Q_SLOTS:
|
||||
virtual void repaint(KWin::EffectWindow* w) = 0;
|
||||
|
||||
private Q_SLOTS:
|
||||
void init();
|
||||
void effectWindowAdded();
|
||||
void compositingToggled();
|
||||
|
||||
private:
|
||||
void findParentEffectWindow();
|
||||
QPointer<EffectWindowImpl> m_parent;
|
||||
qreal m_brightness;
|
||||
qreal m_saturation;
|
||||
QPointer<QQuickItem> m_clipToItem;
|
||||
};
|
||||
|
||||
class WindowThumbnailItem : public AbstractThumbnailItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUuid wId READ wId WRITE setWId NOTIFY wIdChanged SCRIPTABLE true)
|
||||
Q_PROPERTY(KWin::AbstractClient *client READ client WRITE setClient NOTIFY clientChanged)
|
||||
public:
|
||||
explicit WindowThumbnailItem(QQuickItem *parent = nullptr);
|
||||
~WindowThumbnailItem() override;
|
||||
|
||||
QUuid wId() const {
|
||||
return m_wId;
|
||||
}
|
||||
void setWId(const QUuid &wId);
|
||||
AbstractClient *client() const;
|
||||
void setClient(AbstractClient *client);
|
||||
void paint(QPainter *painter) override;
|
||||
Q_SIGNALS:
|
||||
void wIdChanged(const QUuid &wid);
|
||||
void clientChanged();
|
||||
protected Q_SLOTS:
|
||||
void repaint(KWin::EffectWindow* w) override;
|
||||
private:
|
||||
QUuid m_wId;
|
||||
AbstractClient *m_client;
|
||||
};
|
||||
|
||||
class DesktopThumbnailItem : public AbstractThumbnailItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int desktop READ desktop WRITE setDesktop NOTIFY desktopChanged)
|
||||
public:
|
||||
DesktopThumbnailItem(QQuickItem *parent = nullptr);
|
||||
~DesktopThumbnailItem() override;
|
||||
|
||||
int desktop() const {
|
||||
return m_desktop;
|
||||
}
|
||||
void setDesktop(int desktop);
|
||||
void paint(QPainter *painter) override;
|
||||
Q_SIGNALS:
|
||||
void desktopChanged(int desktop);
|
||||
protected Q_SLOTS:
|
||||
void repaint(KWin::EffectWindow* w) override;
|
||||
private:
|
||||
int m_desktop;
|
||||
};
|
||||
|
||||
inline
|
||||
qreal AbstractThumbnailItem::brightness() const
|
||||
{
|
||||
return m_brightness;
|
||||
}
|
||||
|
||||
inline
|
||||
qreal AbstractThumbnailItem::saturation() const
|
||||
{
|
||||
return m_saturation;
|
||||
}
|
||||
|
||||
inline
|
||||
QQuickItem* AbstractThumbnailItem::clipTo() const
|
||||
{
|
||||
return m_clipToItem.data();
|
||||
}
|
||||
|
||||
inline
|
||||
AbstractClient *WindowThumbnailItem::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // KWin
|
||||
|
||||
#endif // KWIN_THUMBNAILITEM_H
|
Loading…
Reference in a new issue