kwin/effects/thumbnailaside/thumbnailaside.cpp
Aleix Pol 26950a65a6 Have Toplevel::damage emit a QRegion
Instead of looping through the rects in the region, emit the region at
bulk. It reduces the amount of emissions we do and allows us to pack the
response accordingly.
2020-09-22 14:45:08 +02:00

185 lines
5.6 KiB
C++

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2007 Lubos Lunak <l.lunak@kde.org>
SPDX-FileCopyrightText: 2007 Christian Nitschkowski <christian.nitschkowski@kdemail.net>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "thumbnailaside.h"
// KConfigSkeleton
#include "thumbnailasideconfig.h"
#include <KGlobalAccel>
#include <KLocalizedString>
#include <QAction>
#include <QMatrix4x4>
namespace KWin
{
ThumbnailAsideEffect::ThumbnailAsideEffect()
{
initConfig<ThumbnailAsideConfig>();
QAction* a = new QAction(this);
a->setObjectName(QStringLiteral("ToggleCurrentThumbnail"));
a->setText(i18n("Toggle Thumbnail for Current Window"));
KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << Qt::META + Qt::CTRL + Qt::Key_T);
KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << Qt::META + Qt::CTRL + Qt::Key_T);
effects->registerGlobalShortcut(Qt::META + Qt::CTRL + Qt::Key_T, a);
connect(a, &QAction::triggered, this, &ThumbnailAsideEffect::toggleCurrentThumbnail);
connect(effects, &EffectsHandler::windowClosed, this, &ThumbnailAsideEffect::slotWindowClosed);
connect(effects, &EffectsHandler::windowFrameGeometryChanged, this, &ThumbnailAsideEffect::slotWindowFrameGeometryChanged);
connect(effects, &EffectsHandler::windowDamaged, this, &ThumbnailAsideEffect::slotWindowDamaged);
connect(effects, &EffectsHandler::screenLockingChanged, this, &ThumbnailAsideEffect::repaintAll);
reconfigure(ReconfigureAll);
}
void ThumbnailAsideEffect::reconfigure(ReconfigureFlags)
{
ThumbnailAsideConfig::self()->read();
maxwidth = ThumbnailAsideConfig::maxWidth();
spacing = ThumbnailAsideConfig::spacing();
opacity = ThumbnailAsideConfig::opacity()/100.0;
screen = ThumbnailAsideConfig::screen(); // Xinerama screen TODO add gui option
arrange();
}
void ThumbnailAsideEffect::paintScreen(int mask, const QRegion &region, ScreenPaintData& data)
{
painted = QRegion();
effects->paintScreen(mask, region, data);
const QMatrix4x4 projectionMatrix = data.projectionMatrix();
foreach (const Data & d, windows) {
if (painted.intersects(d.rect)) {
WindowPaintData data(d.window, projectionMatrix);
data.multiplyOpacity(opacity);
QRect region;
setPositionTransformations(data, region, d.window, d.rect, Qt::KeepAspectRatio);
effects->drawWindow(d.window, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_LANCZOS,
region, data);
}
}
}
void ThumbnailAsideEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
{
effects->paintWindow(w, mask, region, data);
painted |= region;
}
void ThumbnailAsideEffect::slotWindowDamaged(EffectWindow* w, const QRegion&)
{
foreach (const Data & d, windows) {
if (d.window == w)
effects->addRepaint(d.rect);
}
}
void ThumbnailAsideEffect::slotWindowFrameGeometryChanged(EffectWindow* w, const QRect& old)
{
foreach (const Data & d, windows) {
if (d.window == w) {
if (w->size() == old.size())
effects->addRepaint(d.rect);
else
arrange();
return;
}
}
}
void ThumbnailAsideEffect::slotWindowClosed(EffectWindow* w)
{
removeThumbnail(w);
}
void ThumbnailAsideEffect::toggleCurrentThumbnail()
{
EffectWindow* active = effects->activeWindow();
if (active == nullptr)
return;
if (windows.contains(active))
removeThumbnail(active);
else
addThumbnail(active);
}
void ThumbnailAsideEffect::addThumbnail(EffectWindow* w)
{
repaintAll(); // repaint old areas
Data d;
d.window = w;
d.index = windows.count();
windows[ w ] = d;
arrange();
}
void ThumbnailAsideEffect::removeThumbnail(EffectWindow* w)
{
if (!windows.contains(w))
return;
repaintAll(); // repaint old areas
int index = windows[ w ].index;
windows.remove(w);
for (QHash< EffectWindow*, Data >::Iterator it = windows.begin();
it != windows.end();
++it) {
Data& d = *it;
if (d.index > index)
--d.index;
}
arrange();
}
void ThumbnailAsideEffect::arrange()
{
if (windows.size() == 0)
return;
int height = 0;
QVector< int > pos(windows.size());
int mwidth = 0;
foreach (const Data & d, windows) {
height += d.window->height();
mwidth = qMax(mwidth, d.window->width());
pos[ d.index ] = d.window->height();
}
QRect area = effects->clientArea(MaximizeArea, screen, effects->currentDesktop());
double scale = area.height() / double(height);
scale = qMin(scale, maxwidth / double(mwidth)); // don't be wider than maxwidth pixels
int add = 0;
for (int i = 0;
i < windows.size();
++i) {
pos[ i ] = int(pos[ i ] * scale);
pos[ i ] += spacing + add; // compute offset of each item
add = pos[ i ];
}
for (QHash< EffectWindow*, Data >::Iterator it = windows.begin();
it != windows.end();
++it) {
Data& d = *it;
int width = int(d.window->width() * scale);
d.rect = QRect(area.right() - width, area.bottom() - pos[ d.index ], width, int(d.window->height() * scale));
}
repaintAll();
}
void ThumbnailAsideEffect::repaintAll()
{
foreach (const Data & d, windows)
effects->addRepaint(d.rect);
}
bool ThumbnailAsideEffect::isActive() const
{
return !windows.isEmpty() && !effects->isScreenLocked();
}
} // namespace