26950a65a6
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.
185 lines
5.6 KiB
C++
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 ®ion, 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
|
|
|