Changeset View
Changeset View
Standalone View
Standalone View
effects/sheet/sheet.cpp
1 | /******************************************************************** | 1 | /******************************************************************** | ||
---|---|---|---|---|---|
2 | KWin - the KDE window manager | 2 | KWin - the KDE window manager | ||
3 | This file is part of the KDE project. | 3 | This file is part of the KDE project. | ||
4 | 4 | | |||
5 | Copyright (C) 2007 Philip Falkner <philip.falkner@gmail.com> | 5 | Copyright (C) 2007 Philip Falkner <philip.falkner@gmail.com> | ||
6 | Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org> | 6 | Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org> | ||
7 | Copyright (C) 2018 Vlad Zagorodniy <vladzzag@gmail.com> | ||||
7 | 8 | | |||
8 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | 11 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | 12 | (at your option) any later version. | ||
12 | 13 | | |||
13 | This program is distributed in the hope that it will be useful, | 14 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | 17 | GNU General Public License for more details. | ||
17 | 18 | | |||
18 | You should have received a copy of the GNU General Public License | 19 | You should have received a copy of the GNU General Public License | ||
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 20 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | *********************************************************************/ | 21 | *********************************************************************/ | ||
21 | 22 | | |||
23 | // own | ||||
22 | #include "sheet.h" | 24 | #include "sheet.h" | ||
23 | #include "sheetconfig.h" | | |||
24 | | ||||
25 | #include <QTimeLine> | | |||
26 | #include <QGraphicsRotation> | | |||
27 | #include <QVector3D> | | |||
28 | 25 | | |||
29 | // Effect is based on fade effect by Philip Falkner | 26 | // KConfigSkeleton | ||
27 | #include "sheetconfig.h" | ||||
30 | 28 | | |||
31 | namespace KWin | 29 | namespace KWin | ||
32 | { | 30 | { | ||
33 | 31 | | |||
34 | SheetEffect::SheetEffect() | 32 | SheetEffect::SheetEffect() | ||
35 | { | 33 | { | ||
36 | initConfig<SheetConfig>(); | 34 | initConfig<SheetConfig>(); | ||
37 | reconfigure(ReconfigureAll); | 35 | reconfigure(ReconfigureAll); | ||
38 | connect(effects, SIGNAL(windowAdded(KWin::EffectWindow*)), this, SLOT(slotWindowAdded(KWin::EffectWindow*))); | | |||
39 | connect(effects, SIGNAL(windowClosed(KWin::EffectWindow*)), this, SLOT(slotWindowClosed(KWin::EffectWindow*))); | | |||
40 | connect(effects, SIGNAL(windowDeleted(KWin::EffectWindow*)), this, SLOT(slotWindowDeleted(KWin::EffectWindow*))); | | |||
41 | } | | |||
42 | 36 | | |||
43 | bool SheetEffect::supported() | 37 | connect(effects, &EffectsHandler::windowAdded, this, &SheetEffect::slotWindowAdded); | ||
44 | { | 38 | connect(effects, &EffectsHandler::windowClosed, this, &SheetEffect::slotWindowClosed); | ||
45 | return effects->isOpenGLCompositing() && effects->animationsSupported(); | 39 | connect(effects, &EffectsHandler::windowDeleted, this, &SheetEffect::slotWindowDeleted); | ||
46 | } | 40 | } | ||
47 | 41 | | |||
48 | void SheetEffect::reconfigure(ReconfigureFlags) | 42 | void SheetEffect::reconfigure(ReconfigureFlags flags) | ||
49 | { | 43 | { | ||
44 | Q_UNUSED(flags) | ||||
45 | | ||||
50 | SheetConfig::self()->read(); | 46 | SheetConfig::self()->read(); | ||
51 | duration = animationTime(SheetConfig::animationTime() != 0 ? SheetConfig::animationTime() : 500); | 47 | | ||
48 | // TODO: Rename AnimationTime config key to Duration. | ||||
49 | const int d = animationTime(SheetConfig::animationTime() != 0 | ||||
50 | ? SheetConfig::animationTime() | ||||
51 | : 500); | ||||
52 | m_duration = std::chrono::milliseconds(static_cast<int>(d)); | ||||
52 | } | 53 | } | ||
53 | 54 | | |||
54 | void SheetEffect::prePaintScreen(ScreenPrePaintData& data, int time) | 55 | void SheetEffect::prePaintScreen(ScreenPrePaintData &data, int time) | ||
55 | { | 56 | { | ||
56 | if (!windows.isEmpty()) { | 57 | const std::chrono::milliseconds delta(time); | ||
57 | data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; | 58 | | ||
58 | screenTime = time; | 59 | auto animationIt = m_animations.begin(); | ||
60 | while (animationIt != m_animations.end()) { | ||||
61 | (*animationIt).timeLine.update(delta); | ||||
62 | ++animationIt; | ||||
59 | } | 63 | } | ||
64 | | ||||
65 | data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; | ||||
66 | | ||||
60 | effects->prePaintScreen(data, time); | 67 | effects->prePaintScreen(data, time); | ||
61 | } | 68 | } | ||
62 | 69 | | |||
63 | void SheetEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) | 70 | void SheetEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) | ||
64 | { | 71 | { | ||
65 | InfoMap::iterator info = windows.find(w); | 72 | if (m_animations.contains(w)) { | ||
66 | if (info != windows.end()) { | | |||
67 | data.setTransformed(); | 73 | data.setTransformed(); | ||
68 | if (info->added) | | |||
69 | info->timeLine->setCurrentTime(info->timeLine->currentTime() + screenTime); | | |||
70 | else if (info->closed) { | | |||
71 | info->timeLine->setCurrentTime(info->timeLine->currentTime() - screenTime); | | |||
72 | if (info->deleted) | | |||
73 | w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); | 74 | w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); | ||
74 | } | 75 | } | ||
75 | } | | |||
76 | 76 | | |||
77 | effects->prePaintWindow(w, data, time); | 77 | effects->prePaintWindow(w, data, time); | ||
78 | | ||||
79 | // if the window isn't to be painted, then let's make sure | | |||
80 | // to track its progress | | |||
81 | if (info != windows.end() && !w->isPaintingEnabled() && !effects->activeFullScreenEffect()) | | |||
82 | w->addRepaintFull(); | | |||
83 | } | 78 | } | ||
84 | 79 | | |||
85 | void SheetEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) | 80 | void SheetEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) | ||
86 | { | 81 | { | ||
87 | InfoMap::const_iterator info = windows.constFind(w); | 82 | auto animationIt = m_animations.constFind(w); | ||
88 | if (info != windows.constEnd()) { | 83 | if (animationIt != m_animations.constEnd()) { | ||
89 | const double progress = info->timeLine->currentValue(); | 84 | const qreal t = (*animationIt).timeLine.value(); | ||
90 | QGraphicsRotation rot; | | |||
91 | data.setRotationAxis(Qt::XAxis); | 85 | data.setRotationAxis(Qt::XAxis); | ||
92 | data.setRotationAngle(60.0 * (1.0 - progress)); | 86 | data.setRotationAngle(interpolate(60.0, 0.0, t)); | ||
93 | data *= QVector3D(1.0, progress, progress); | 87 | data *= QVector3D(1.0, t, t); | ||
94 | data.translate(0.0, - (w->y() - info->parentY) * (1.0 - progress)); | 88 | data.translate(0.0, -interpolate(w->y() - (*animationIt).parentY, 0.0, t)); | ||
95 | } | 89 | } | ||
90 | | ||||
96 | effects->paintWindow(w, mask, region, data); | 91 | effects->paintWindow(w, mask, region, data); | ||
97 | } | 92 | } | ||
98 | 93 | | |||
99 | void SheetEffect::postPaintWindow(EffectWindow* w) | 94 | void SheetEffect::postPaintWindow(EffectWindow *w) | ||
100 | { | 95 | { | ||
101 | InfoMap::iterator info = windows.find(w); | 96 | auto animationIt = m_animations.begin(); | ||
102 | if (info != windows.end()) { | 97 | while (animationIt != m_animations.end()) { | ||
103 | if (info->added && info->timeLine->currentValue() == 1.0) { | 98 | EffectWindow *w = animationIt.key(); | ||
104 | windows.remove(w); | 99 | w->addRepaintFull(); | ||
105 | effects->addRepaintFull(); | 100 | if ((*animationIt).timeLine.done()) { | ||
106 | } else if (info->closed && info->timeLine->currentValue() == 0.0) { | 101 | if (w->isDeleted()) { | ||
107 | info->closed = false; | | |||
108 | if (info->deleted) { | | |||
109 | windows.remove(w); | | |||
110 | w->unrefWindow(); | 102 | w->unrefWindow(); | ||
111 | } | 103 | } | ||
112 | effects->addRepaintFull(); | 104 | animationIt = m_animations.erase(animationIt); | ||
105 | } else { | ||||
106 | ++animationIt; | ||||
113 | } | 107 | } | ||
114 | if (info->added || info->closed) | | |||
115 | w->addRepaintFull(); | | |||
116 | } | 108 | } | ||
109 | | ||||
110 | if (m_animations.isEmpty()) { | ||||
111 | effects->addRepaintFull(); | ||||
112 | } | ||||
113 | | ||||
117 | effects->postPaintWindow(w); | 114 | effects->postPaintWindow(w); | ||
118 | } | 115 | } | ||
119 | 116 | | |||
117 | bool SheetEffect::isActive() const | ||||
118 | { | ||||
119 | return !m_animations.isEmpty(); | ||||
120 | } | ||||
121 | | ||||
122 | bool SheetEffect::supported() | ||||
123 | { | ||||
124 | return effects->isOpenGLCompositing() | ||||
125 | && effects->animationsSupported(); | ||||
126 | } | ||||
127 | | ||||
120 | void SheetEffect::slotWindowAdded(EffectWindow* w) | 128 | void SheetEffect::slotWindowAdded(EffectWindow *w) | ||
121 | { | 129 | { | ||
122 | if (!isSheetWindow(w)) | 130 | if (effects->activeFullScreenEffect()) { | ||
123 | return; | 131 | return; | ||
132 | } | ||||
124 | 133 | | |||
125 | InfoMap::iterator it = windows.find(w); | 134 | if (!isSheetWindow(w)) { | ||
126 | WindowInfo *info = (it == windows.end()) ? &windows[w] : &it.value(); | 135 | return; | ||
127 | info->added = true; | | |||
128 | info->closed = false; | | |||
129 | info->deleted = false; | | |||
130 | delete info->timeLine; | | |||
131 | info->timeLine = new QTimeLine(duration); | | |||
132 | const EffectWindowList stack = effects->stackingOrder(); | | |||
133 | // find parent | | |||
134 | foreach (EffectWindow * window, stack) { | | |||
135 | if (window->findModal() == w) { | | |||
136 | info->parentY = window->y(); | | |||
137 | break; | | |||
138 | } | 136 | } | ||
137 | | ||||
138 | Animation &animation = m_animations[w]; | ||||
139 | animation.parentY = 0; | ||||
140 | animation.timeLine.reset(); | ||||
141 | animation.timeLine.setDuration(m_duration); | ||||
142 | animation.timeLine.setDirection(TimeLine::Forward); | ||||
143 | animation.timeLine.setEasingCurve(QEasingCurve::Linear); | ||||
144 | | ||||
145 | const auto windows = effects->stackingOrder(); | ||||
146 | auto parentIt = std::find_if(windows.constBegin(), windows.constEnd(), | ||||
147 | [w](EffectWindow *p) { | ||||
148 | return p->findModal() == w; | ||||
149 | }); | ||||
150 | if (parentIt != windows.constEnd()) { | ||||
151 | animation.parentY = (*parentIt)->y(); | ||||
139 | } | 152 | } | ||
140 | 153 | | |||
141 | w->setData(WindowAddedGrabRole, QVariant::fromValue(static_cast<void*>(this))); | 154 | w->setData(WindowAddedGrabRole, QVariant::fromValue(static_cast<void*>(this))); | ||
142 | 155 | | |||
143 | w->addRepaintFull(); | 156 | w->addRepaintFull(); | ||
144 | } | 157 | } | ||
145 | 158 | | |||
146 | void SheetEffect::slotWindowClosed(EffectWindow* w) | 159 | void SheetEffect::slotWindowClosed(EffectWindow *w) | ||
147 | { | 160 | { | ||
148 | if (!isSheetWindow(w)) | 161 | if (effects->activeFullScreenEffect()) { | ||
162 | return; | ||||
163 | } | ||||
164 | | ||||
165 | if (!isSheetWindow(w)) { | ||||
149 | return; | 166 | return; | ||
167 | } | ||||
150 | 168 | | |||
151 | w->refWindow(); | 169 | w->refWindow(); | ||
152 | 170 | | |||
153 | InfoMap::iterator it = windows.find(w); | 171 | Animation &animation = m_animations[w]; | ||
154 | WindowInfo *info = (it == windows.end()) ? &windows[w] : &it.value(); | 172 | | ||
155 | info->added = false; | 173 | animation.timeLine.reset(); | ||
156 | info->closed = true; | 174 | animation.parentY = 0; | ||
157 | info->deleted = true; | 175 | animation.timeLine.setDuration(m_duration); | ||
158 | delete info->timeLine; | 176 | animation.timeLine.setDirection(TimeLine::Backward); | ||
159 | info->timeLine = new QTimeLine(duration); | 177 | animation.timeLine.setEasingCurve(QEasingCurve::Linear); | ||
160 | info->timeLine->setCurrentTime(duration); | 178 | | ||
161 | 179 | const auto windows = effects->stackingOrder(); | |||
162 | bool found = false; | 180 | auto parentIt = std::find_if(windows.constBegin(), windows.constEnd(), | ||
163 | // find parent | 181 | [w](EffectWindow *p) { | ||
164 | const EffectWindowList stack = effects->stackingOrder(); | 182 | return p->findModal() == w; | ||
165 | foreach (EffectWindow * window, stack) { | 183 | }); | ||
166 | if (window->findModal() == w) { | 184 | if (parentIt != windows.constEnd()) { | ||
167 | info->parentY = window->y(); | 185 | animation.parentY = (*parentIt)->y(); | ||
168 | found = true; | | |||
169 | break; | | |||
170 | } | | |||
171 | } | 186 | } | ||
172 | if (!found) | | |||
173 | info->parentY = 0; | | |||
174 | 187 | | |||
175 | w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast<void*>(this))); | 188 | w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast<void*>(this))); | ||
176 | 189 | | |||
177 | w->addRepaintFull(); | 190 | w->addRepaintFull(); | ||
178 | } | 191 | } | ||
179 | 192 | | |||
180 | void SheetEffect::slotWindowDeleted(EffectWindow* w) | 193 | void SheetEffect::slotWindowDeleted(EffectWindow *w) | ||
181 | { | 194 | { | ||
182 | windows.remove(w); | 195 | m_animations.remove(w); | ||
183 | } | 196 | } | ||
184 | 197 | | |||
185 | bool SheetEffect::isSheetWindow(EffectWindow* w) | 198 | bool SheetEffect::isSheetWindow(EffectWindow *w) const | ||
186 | { | 199 | { | ||
187 | return w->isModal(); | 200 | return w->isModal(); | ||
188 | } | 201 | } | ||
189 | 202 | | |||
190 | bool SheetEffect::isActive() const | 203 | } // namespace KWin | ||
191 | { | | |||
192 | return !windows.isEmpty(); | | |||
193 | } | | |||
194 | | ||||
195 | SheetEffect::WindowInfo::WindowInfo() | | |||
196 | : deleted(false) | | |||
197 | , added(false) | | |||
198 | , closed(false) | | |||
199 | , timeLine(0) | | |||
200 | , parentY(0) | | |||
201 | { | | |||
202 | } | | |||
203 | | ||||
204 | SheetEffect::WindowInfo::~WindowInfo() | | |||
205 | { | | |||
206 | delete timeLine; | | |||
207 | } | | |||
208 | | ||||
209 | } // namespace | |