File indexing completed on 2024-11-10 04:57:11
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2007 Lubos Lunak <l.lunak@kde.org> 0006 SPDX-FileCopyrightText: 2007 Christian Nitschkowski <christian.nitschkowski@kdemail.net> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "thumbnailaside.h" 0012 #include "core/renderviewport.h" 0013 #include "effect/effecthandler.h" 0014 // KConfigSkeleton 0015 #include "thumbnailasideconfig.h" 0016 0017 #include <KGlobalAccel> 0018 #include <KLocalizedString> 0019 0020 #include <QAction> 0021 #include <QMatrix4x4> 0022 0023 namespace KWin 0024 { 0025 0026 ThumbnailAsideEffect::ThumbnailAsideEffect() 0027 { 0028 ThumbnailAsideConfig::instance(effects->config()); 0029 QAction *a = new QAction(this); 0030 a->setObjectName(QStringLiteral("ToggleCurrentThumbnail")); 0031 a->setText(i18n("Toggle Thumbnail for Current Window")); 0032 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::CTRL | Qt::Key_T)); 0033 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::CTRL | Qt::Key_T)); 0034 connect(a, &QAction::triggered, this, &ThumbnailAsideEffect::toggleCurrentThumbnail); 0035 0036 connect(effects, &EffectsHandler::windowAdded, this, &ThumbnailAsideEffect::slotWindowAdded); 0037 connect(effects, &EffectsHandler::windowClosed, this, &ThumbnailAsideEffect::slotWindowClosed); 0038 connect(effects, &EffectsHandler::screenLockingChanged, this, &ThumbnailAsideEffect::repaintAll); 0039 0040 const auto windows = effects->stackingOrder(); 0041 for (EffectWindow *window : windows) { 0042 slotWindowAdded(window); 0043 } 0044 0045 reconfigure(ReconfigureAll); 0046 } 0047 0048 void ThumbnailAsideEffect::reconfigure(ReconfigureFlags) 0049 { 0050 ThumbnailAsideConfig::self()->read(); 0051 maxwidth = ThumbnailAsideConfig::maxWidth(); 0052 spacing = ThumbnailAsideConfig::spacing(); 0053 opacity = ThumbnailAsideConfig::opacity() / 100.0; 0054 screen = ThumbnailAsideConfig::screen(); // Xinerama screen TODO add gui option 0055 arrange(); 0056 } 0057 0058 void ThumbnailAsideEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, Output *screen) 0059 { 0060 painted = QRegion(); 0061 effects->paintScreen(renderTarget, viewport, mask, region, screen); 0062 0063 for (const Data &d : std::as_const(windows)) { 0064 if (painted.intersects(d.rect)) { 0065 WindowPaintData data(viewport.projectionMatrix()); 0066 data.multiplyOpacity(opacity); 0067 QRect region; 0068 setPositionTransformations(data, region, d.window, d.rect, Qt::KeepAspectRatio); 0069 effects->drawWindow(renderTarget, viewport, d.window, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_TRANSFORMED, region, data); 0070 } 0071 } 0072 } 0073 0074 void ThumbnailAsideEffect::paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, QRegion region, WindowPaintData &data) 0075 { 0076 effects->paintWindow(renderTarget, viewport, w, mask, region, data); 0077 painted += region; 0078 } 0079 0080 void ThumbnailAsideEffect::slotWindowDamaged(EffectWindow *w) 0081 { 0082 for (const Data &d : std::as_const(windows)) { 0083 if (d.window == w) { 0084 effects->addRepaint(d.rect); 0085 } 0086 } 0087 } 0088 0089 void ThumbnailAsideEffect::slotWindowFrameGeometryChanged(EffectWindow *w, const QRectF &old) 0090 { 0091 for (const Data &d : std::as_const(windows)) { 0092 if (d.window == w) { 0093 if (w->size() == old.size()) { 0094 effects->addRepaint(d.rect); 0095 } else { 0096 arrange(); 0097 } 0098 return; 0099 } 0100 } 0101 } 0102 0103 void ThumbnailAsideEffect::slotWindowAdded(EffectWindow *w) 0104 { 0105 connect(w, &EffectWindow::windowFrameGeometryChanged, this, &ThumbnailAsideEffect::slotWindowFrameGeometryChanged); 0106 connect(w, &EffectWindow::windowDamaged, this, &ThumbnailAsideEffect::slotWindowDamaged); 0107 } 0108 0109 void ThumbnailAsideEffect::slotWindowClosed(EffectWindow *w) 0110 { 0111 removeThumbnail(w); 0112 } 0113 0114 void ThumbnailAsideEffect::toggleCurrentThumbnail() 0115 { 0116 EffectWindow *active = effects->activeWindow(); 0117 if (active == nullptr) { 0118 return; 0119 } 0120 if (windows.contains(active)) { 0121 removeThumbnail(active); 0122 } else { 0123 addThumbnail(active); 0124 } 0125 } 0126 0127 void ThumbnailAsideEffect::addThumbnail(EffectWindow *w) 0128 { 0129 repaintAll(); // repaint old areas 0130 Data d; 0131 d.window = w; 0132 d.index = windows.count(); 0133 windows[w] = d; 0134 arrange(); 0135 } 0136 0137 void ThumbnailAsideEffect::removeThumbnail(EffectWindow *w) 0138 { 0139 if (!windows.contains(w)) { 0140 return; 0141 } 0142 repaintAll(); // repaint old areas 0143 int index = windows[w].index; 0144 windows.remove(w); 0145 for (QHash<EffectWindow *, Data>::Iterator it = windows.begin(); 0146 it != windows.end(); 0147 ++it) { 0148 Data &d = *it; 0149 if (d.index > index) { 0150 --d.index; 0151 } 0152 } 0153 arrange(); 0154 } 0155 0156 void ThumbnailAsideEffect::arrange() 0157 { 0158 if (windows.size() == 0) { 0159 return; 0160 } 0161 int height = 0; 0162 QList<int> pos(windows.size()); 0163 qreal mwidth = 0; 0164 for (const Data &d : std::as_const(windows)) { 0165 height += d.window->height(); 0166 mwidth = std::max(mwidth, d.window->width()); 0167 pos[d.index] = d.window->height(); 0168 } 0169 Output *effectiveScreen = effects->findScreen(screen); 0170 if (!effectiveScreen) { 0171 effectiveScreen = effects->activeScreen(); 0172 } 0173 QRectF area = effects->clientArea(MaximizeArea, effectiveScreen, effects->currentDesktop()); 0174 double scale = area.height() / double(height); 0175 scale = std::min(scale, maxwidth / double(mwidth)); // don't be wider than maxwidth pixels 0176 int add = 0; 0177 for (int i = 0; 0178 i < windows.size(); 0179 ++i) { 0180 pos[i] = int(pos[i] * scale); 0181 pos[i] += spacing + add; // compute offset of each item 0182 add = pos[i]; 0183 } 0184 for (QHash<EffectWindow *, Data>::Iterator it = windows.begin(); 0185 it != windows.end(); 0186 ++it) { 0187 Data &d = *it; 0188 int width = int(d.window->width() * scale); 0189 d.rect = QRect(area.right() - width, area.bottom() - pos[d.index], width, int(d.window->height() * scale)); 0190 } 0191 repaintAll(); 0192 } 0193 0194 void ThumbnailAsideEffect::repaintAll() 0195 { 0196 for (const Data &d : std::as_const(windows)) { 0197 effects->addRepaint(d.rect); 0198 } 0199 } 0200 0201 bool ThumbnailAsideEffect::isActive() const 0202 { 0203 return !windows.isEmpty() && !effects->isScreenLocked(); 0204 } 0205 0206 } // namespace 0207 0208 #include "moc_thumbnailaside.cpp"