File indexing completed on 2024-11-10 04:57:08
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2007 Philip Falkner <philip.falkner@gmail.com> 0006 SPDX-FileCopyrightText: 2009 Martin Gräßlin <mgraesslin@kde.org> 0007 SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 // own 0013 #include "sheet.h" 0014 0015 // KConfigSkeleton 0016 #include "sheetconfig.h" 0017 0018 #include "core/renderviewport.h" 0019 #include "effect/effecthandler.h" 0020 0021 // Qt 0022 #include <QMatrix4x4> 0023 #include <qmath.h> 0024 0025 namespace KWin 0026 { 0027 0028 static QMatrix4x4 createPerspectiveMatrix(const QRectF &rect, const qreal scale) 0029 { 0030 QMatrix4x4 ret; 0031 0032 const float fovY = std::tan(qDegreesToRadians(60.0f) / 2); 0033 const float aspect = 1.0f; 0034 const float zNear = 0.1f; 0035 const float zFar = 100.0f; 0036 0037 const float yMax = zNear * fovY; 0038 const float yMin = -yMax; 0039 const float xMin = yMin * aspect; 0040 const float xMax = yMax * aspect; 0041 0042 ret.frustum(xMin, xMax, yMin, yMax, zNear, zFar); 0043 0044 const auto deviceRect = scaledRect(rect, scale); 0045 0046 const float scaleFactor = 1.1 * fovY / yMax; 0047 ret.translate(xMin * scaleFactor, yMax * scaleFactor, -1.1); 0048 ret.scale((xMax - xMin) * scaleFactor / deviceRect.width(), 0049 -(yMax - yMin) * scaleFactor / deviceRect.height(), 0050 0.001); 0051 ret.translate(-deviceRect.x(), -deviceRect.y()); 0052 0053 return ret; 0054 } 0055 0056 SheetEffect::SheetEffect() 0057 { 0058 SheetConfig::instance(effects->config()); 0059 reconfigure(ReconfigureAll); 0060 0061 connect(effects, &EffectsHandler::windowAdded, this, &SheetEffect::slotWindowAdded); 0062 connect(effects, &EffectsHandler::windowClosed, this, &SheetEffect::slotWindowClosed); 0063 } 0064 0065 void SheetEffect::reconfigure(ReconfigureFlags flags) 0066 { 0067 SheetConfig::self()->read(); 0068 0069 // TODO: Rename AnimationTime config key to Duration. 0070 const int d = animationTime(SheetConfig::animationTime() != 0 0071 ? SheetConfig::animationTime() 0072 : 300); 0073 m_duration = std::chrono::milliseconds(static_cast<int>(d)); 0074 } 0075 0076 void SheetEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) 0077 { 0078 data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; 0079 0080 effects->prePaintScreen(data, presentTime); 0081 } 0082 0083 void SheetEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) 0084 { 0085 auto animationIt = m_animations.find(w); 0086 if (animationIt != m_animations.end()) { 0087 (*animationIt).timeLine.advance(presentTime); 0088 data.setTransformed(); 0089 } 0090 0091 effects->prePaintWindow(w, data, presentTime); 0092 } 0093 0094 void SheetEffect::paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, QRegion region, WindowPaintData &data) 0095 { 0096 auto animationIt = m_animations.constFind(w); 0097 if (animationIt == m_animations.constEnd()) { 0098 effects->paintWindow(renderTarget, viewport, w, mask, region, data); 0099 return; 0100 } 0101 0102 // Perspective projection distorts objects near edges of the viewport 0103 // in undesired way. To fix this, the center of the window will be 0104 // moved to the origin, after applying perspective projection, the 0105 // center is moved back to its "original" projected position. Overall, 0106 // this is how the window will be transformed: 0107 // [move to the origin] -> [scale] -> [rotate] -> [translate] -> 0108 // -> [perspective projection] -> [reverse "move to the origin"] 0109 const QMatrix4x4 oldProjMatrix = createPerspectiveMatrix(viewport.renderRect(), viewport.scale()); 0110 const QRectF windowGeo = w->frameGeometry(); 0111 const QVector3D invOffset = oldProjMatrix.map(QVector3D(windowGeo.center())); 0112 QMatrix4x4 invOffsetMatrix; 0113 invOffsetMatrix.translate(invOffset.x(), invOffset.y()); 0114 data.setProjectionMatrix(invOffsetMatrix * oldProjMatrix); 0115 0116 // Move the center of the window to the origin. 0117 const QRectF screenGeo = effects->virtualScreenGeometry(); 0118 const QPointF offset = screenGeo.center() - windowGeo.center(); 0119 data.translate(offset.x(), offset.y()); 0120 0121 const qreal t = (*animationIt).timeLine.value(); 0122 data.setRotationAxis(Qt::XAxis); 0123 data.setRotationAngle(interpolate(60.0, 0.0, t)); 0124 data *= QVector3D(1.0, t, t); 0125 data.translate(0.0, -interpolate(w->y() - (*animationIt).parentY, 0.0, t)); 0126 0127 data.multiplyOpacity(t); 0128 0129 effects->paintWindow(renderTarget, viewport, w, mask, region, data); 0130 } 0131 0132 void SheetEffect::postPaintWindow(EffectWindow *w) 0133 { 0134 auto animationIt = m_animations.begin(); 0135 while (animationIt != m_animations.end()) { 0136 EffectWindow *w = animationIt.key(); 0137 w->addRepaintFull(); 0138 if ((*animationIt).timeLine.done()) { 0139 animationIt = m_animations.erase(animationIt); 0140 } else { 0141 ++animationIt; 0142 } 0143 } 0144 0145 if (m_animations.isEmpty()) { 0146 effects->addRepaintFull(); 0147 } 0148 0149 effects->postPaintWindow(w); 0150 } 0151 0152 bool SheetEffect::isActive() const 0153 { 0154 return !m_animations.isEmpty(); 0155 } 0156 0157 bool SheetEffect::supported() 0158 { 0159 return effects->isOpenGLCompositing() 0160 && effects->animationsSupported(); 0161 } 0162 0163 void SheetEffect::slotWindowAdded(EffectWindow *w) 0164 { 0165 if (effects->activeFullScreenEffect()) { 0166 return; 0167 } 0168 0169 if (!isSheetWindow(w)) { 0170 return; 0171 } 0172 0173 Animation &animation = m_animations[w]; 0174 animation.parentY = 0; 0175 animation.timeLine.reset(); 0176 animation.timeLine.setDuration(m_duration); 0177 animation.timeLine.setDirection(TimeLine::Forward); 0178 animation.timeLine.setEasingCurve(QEasingCurve::Linear); 0179 0180 const auto windows = effects->stackingOrder(); 0181 auto parentIt = std::find_if(windows.constBegin(), windows.constEnd(), 0182 [w](EffectWindow *p) { 0183 return p->findModal() == w; 0184 }); 0185 if (parentIt != windows.constEnd()) { 0186 animation.parentY = (*parentIt)->y(); 0187 } 0188 0189 w->setData(WindowAddedGrabRole, QVariant::fromValue(static_cast<void *>(this))); 0190 0191 w->addRepaintFull(); 0192 } 0193 0194 void SheetEffect::slotWindowClosed(EffectWindow *w) 0195 { 0196 if (effects->activeFullScreenEffect()) { 0197 return; 0198 } 0199 0200 if (!isSheetWindow(w) || w->skipsCloseAnimation()) { 0201 return; 0202 } 0203 0204 Animation &animation = m_animations[w]; 0205 animation.deletedRef = EffectWindowDeletedRef(w); 0206 animation.timeLine.reset(); 0207 animation.parentY = 0; 0208 animation.timeLine.setDuration(m_duration); 0209 animation.timeLine.setDirection(TimeLine::Backward); 0210 animation.timeLine.setEasingCurve(QEasingCurve::Linear); 0211 0212 const auto windows = effects->stackingOrder(); 0213 auto parentIt = std::find_if(windows.constBegin(), windows.constEnd(), 0214 [w](EffectWindow *p) { 0215 return p->findModal() == w; 0216 }); 0217 if (parentIt != windows.constEnd()) { 0218 animation.parentY = (*parentIt)->y(); 0219 } 0220 0221 w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast<void *>(this))); 0222 0223 w->addRepaintFull(); 0224 } 0225 0226 bool SheetEffect::isSheetWindow(EffectWindow *w) const 0227 { 0228 return w->isModal(); 0229 } 0230 0231 } // namespace KWin 0232 0233 #include "moc_sheet.cpp"