KWin
Loading...
Searching...
No Matches
fallapart.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2007 Lubos Lunak <l.lunak@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "fallapart.h"
12// KConfigSkeleton
13#include "fallapartconfig.h"
14
15#include <QEasingCurve>
16
17#include <cmath>
18
19Q_LOGGING_CATEGORY(KWIN_FALLAPART, "kwin_effect_fallapart", QtWarningMsg)
20
21static const QSet<QString> s_blacklist{
22 // Spectacle needs to be blacklisted in order to stay out of its own screenshots.
23 QStringLiteral("spectacle spectacle"), // x11
24 QStringLiteral("spectacle org.kde.spectacle"), // wayland
25};
26
27namespace KWin
28{
29
34
42
43void FallApartEffect::reconfigure(ReconfigureFlags)
44{
45 FallApartConfig::self()->read();
46 blockSize = FallApartConfig::blockSize();
47}
48
49void FallApartEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
50{
51 if (!windows.isEmpty()) {
53 }
54 effects->prePaintScreen(data, presentTime);
55}
56
57void FallApartEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime)
58{
59 auto animationIt = windows.find(w);
60 if (animationIt != windows.end() && isRealWindow(w)) {
61 int time = 0;
62 if (animationIt->lastPresentTime.count()) {
63 time = (presentTime - animationIt->lastPresentTime).count();
64 }
65 animationIt->lastPresentTime = presentTime;
66
67 animationIt->progress += time / animationTime(1000.);
68 data.setTransformed();
69 }
70 effects->prePaintWindow(w, data, presentTime);
71}
72
74{
75 auto animationIt = windows.constFind(w);
76 if (animationIt != windows.constEnd() && isRealWindow(w)) {
77 QEasingCurve easing(QEasingCurve::InCubic);
78 const qreal t = easing.valueForProgress(animationIt->progress);
79 // Request the window to be divided into cells
80 quads = quads.makeGrid(blockSize);
81 int cnt = 0;
82 for (WindowQuad &quad : quads) {
83 // make fragments move in various directions, based on where
84 // they are (left pieces generally move to the left, etc.)
85 QPointF p1(quad[0].x(), quad[0].y());
86 double xdiff = 0;
87 if (p1.x() < w->width() / 2) {
88 xdiff = -(w->width() / 2 - p1.x()) / w->width() * 100;
89 }
90 if (p1.x() > w->width() / 2) {
91 xdiff = (p1.x() - w->width() / 2) / w->width() * 100;
92 }
93 double ydiff = 0;
94 if (p1.y() < w->height() / 2) {
95 ydiff = -(w->height() / 2 - p1.y()) / w->height() * 100;
96 }
97 if (p1.y() > w->height() / 2) {
98 ydiff = (p1.y() - w->height() / 2) / w->height() * 100;
99 }
100 double modif = t * 64;
101 srandom(cnt); // change direction randomly but consistently
102 xdiff += (rand() % 21 - 10);
103 ydiff += (rand() % 21 - 10);
104 for (int j = 0;
105 j < 4;
106 ++j) {
107 quad[j].move(quad[j].x() + xdiff * modif, quad[j].y() + ydiff * modif);
108 }
109 // also make the fragments rotate around their center
110 QPointF center((quad[0].x() + quad[1].x() + quad[2].x() + quad[3].x()) / 4,
111 (quad[0].y() + quad[1].y() + quad[2].y() + quad[3].y()) / 4);
112 double adiff = (rand() % 720 - 360) / 360. * 2 * M_PI; // spin randomly
113 for (int j = 0;
114 j < 4;
115 ++j) {
116 double x = quad[j].x() - center.x();
117 double y = quad[j].y() - center.y();
118 double angle = atan2(y, x);
119 angle += animationIt->progress * adiff;
120 double dist = sqrt(x * x + y * y);
121 x = dist * cos(angle);
122 y = dist * sin(angle);
123 quad[j].move(center.x() + x, center.y() + y);
124 }
125 ++cnt;
126 }
127 data.multiplyOpacity(interpolate(1.0, 0.0, t));
128 }
129}
130
132{
133 for (auto it = windows.begin(); it != windows.end();) {
134 if (it->progress < 1) {
135 ++it;
136 } else {
137 unredirect(it.key());
138 it = windows.erase(it);
139 }
140 }
141
144}
145
146bool FallApartEffect::isRealWindow(EffectWindow *w)
147{
148 // TODO: isSpecialWindow is rather generic, maybe tell windowtypes separately?
149 /*
150 qCDebug(KWIN_FALLAPART) << "--" << w->caption() << "--------------------------------";
151 qCDebug(KWIN_FALLAPART) << "Tooltip:" << w->isTooltip();
152 qCDebug(KWIN_FALLAPART) << "Toolbar:" << w->isToolbar();
153 qCDebug(KWIN_FALLAPART) << "Desktop:" << w->isDesktop();
154 qCDebug(KWIN_FALLAPART) << "Special:" << w->isSpecialWindow();
155 qCDebug(KWIN_FALLAPART) << "TopMenu:" << w->isTopMenu();
156 qCDebug(KWIN_FALLAPART) << "Notific:" << w->isNotification();
157 qCDebug(KWIN_FALLAPART) << "Splash:" << w->isSplash();
158 qCDebug(KWIN_FALLAPART) << "Normal:" << w->isNormalWindow();
159 */
160 if (w->isPopupWindow()) {
161 return false;
162 }
163 if (w->isX11Client() && !w->isManaged()) {
164 return false;
165 }
166 if (!w->isNormalWindow()) {
167 return false;
168 }
169 return true;
170}
171
173{
175 return;
176 }
177 if (!isRealWindow(c)) {
178 return;
179 }
180 if (!c->isVisible()) {
181 return;
182 }
183 if (s_blacklist.contains(c->windowClass())) {
184 return;
185 }
186 const void *e = c->data(WindowClosedGrabRole).value<void *>();
187 if (e && e != this) {
188 return;
189 }
190 c->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast<void *>(this)));
191
192 FallApartAnimation &animation = windows[c];
193 animation.progress = 0;
194 animation.deletedRef = EffectWindowDeletedRef(c);
195
196 redirect(c);
197}
198
200{
201 if (role != WindowClosedGrabRole) {
202 return;
203 }
204
205 if (w->data(role).value<void *>() == this) {
206 return;
207 }
208
209 auto it = windows.find(w);
210 if (it != windows.end()) {
211 unredirect(it.key());
212 windows.erase(it);
213 }
214}
215
217{
218 return !windows.isEmpty();
219}
220
221} // namespace
222
223#include "moc_fallapart.cpp"
Representation of a window used by/for Effect classes.
bool isX11Client() const
bool isManaged() const
bool isNormalWindow() const
bool isVisible() const
Q_SCRIPTABLE void setData(int role, const QVariant &data)
Q_SCRIPTABLE QVariant data(int role) const
bool isPopupWindow() const
bool animationsSupported() const
void windowClosed(KWin::EffectWindow *w)
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime)
KSharedConfigPtr config() const
Q_SCRIPTABLE void addRepaintFull()
Effect * activeFullScreenEffect() const
void windowDataChanged(KWin::EffectWindow *w, int role)
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override
Definition fallapart.cpp:49
bool isActive() const override
static bool supported()
Definition fallapart.cpp:30
void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override
Definition fallapart.cpp:57
void apply(EffectWindow *w, int mask, WindowPaintData &data, WindowQuadList &quads) override
Definition fallapart.cpp:73
void slotWindowClosed(KWin::EffectWindow *c)
void reconfigure(ReconfigureFlags) override
Definition fallapart.cpp:43
void postPaintScreen() override
void slotWindowDataChanged(KWin::EffectWindow *w, int role)
void unredirect(EffectWindow *window)
void redirect(EffectWindow *window)
Class representing one area of a window.
WindowQuadList makeGrid(int maxquadsize) const
qreal multiplyOpacity(qreal factor)
Definition effect.cpp:309
static double interpolate(double x, double y, double a)
Definition effect.h:910
static double animationTime(const KConfigGroup &cfg, const QString &key, int defaultTime)
Definition effect.cpp:483
@ PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS
Definition effect.h:567
@ ReconfigureAll
Definition effect.h:601
@ WindowClosedGrabRole
EffectsHandler * effects
EffectWindowDeletedRef deletedRef
Definition fallapart.h:20
#define dist(a, b)
Definition xcursor.c:384