1 /*
2 SPDX-FileCopyrightText: 2011 Aaron Seigo <aseigo@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "debug.h"
8 #include "panelshadows_p.h"
9
10 #include <KWindowShadow>
11
12 class PanelShadows::Private
13 {
14 public:
Private(PanelShadows * shadows)15 Private(PanelShadows *shadows)
16 : q(shadows)
17 {
18 }
19
~Private()20 ~Private()
21 {
22 }
23
24 void clearTiles();
25 void setupTiles();
26 void initTile(const QString &element);
27 void updateShadow(QWindow *window, Plasma::FrameSvg::EnabledBorders);
28 void clearShadow(QWindow *window);
29 void updateShadows();
30 bool hasShadows() const;
31
32 PanelShadows *q;
33
34 QHash<QWindow *, Plasma::FrameSvg::EnabledBorders> m_windows;
35 QHash<QWindow *, KWindowShadow *> m_shadows;
36 QVector<KWindowShadowTile::Ptr> m_tiles;
37 };
38
39 class PanelShadowsSingleton
40 {
41 public:
PanelShadowsSingleton()42 PanelShadowsSingleton()
43 {
44 }
45
46 PanelShadows self;
47 };
48
Q_GLOBAL_STATIC(PanelShadowsSingleton,privatePanelShadowsSelf)49 Q_GLOBAL_STATIC(PanelShadowsSingleton, privatePanelShadowsSelf)
50
51 PanelShadows::PanelShadows(QObject *parent, const QString &prefix)
52 : Plasma::Svg(parent)
53 , d(new Private(this))
54 {
55 setImagePath(prefix);
56 connect(this, &Plasma::Svg::repaintNeeded, this, [this]() {
57 d->updateShadows();
58 });
59 }
60
~PanelShadows()61 PanelShadows::~PanelShadows()
62 {
63 delete d;
64 }
65
self()66 PanelShadows *PanelShadows::self()
67 {
68 return &privatePanelShadowsSelf->self;
69 }
70
addWindow(QWindow * window,Plasma::FrameSvg::EnabledBorders enabledBorders)71 void PanelShadows::addWindow(QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders)
72 {
73 if (!window) {
74 return;
75 }
76
77 d->m_windows[window] = enabledBorders;
78 d->updateShadow(window, enabledBorders);
79 connect(window, &QObject::destroyed, this, [this, window]() {
80 d->m_windows.remove(window);
81 d->clearShadow(window);
82 if (d->m_windows.isEmpty()) {
83 d->clearTiles();
84 }
85 });
86 }
87
removeWindow(QWindow * window)88 void PanelShadows::removeWindow(QWindow *window)
89 {
90 if (!d->m_windows.contains(window)) {
91 return;
92 }
93
94 d->m_windows.remove(window);
95 disconnect(window, nullptr, this, nullptr);
96 d->clearShadow(window);
97
98 if (d->m_windows.isEmpty()) {
99 d->clearTiles();
100 }
101 }
102
setEnabledBorders(QWindow * window,Plasma::FrameSvg::EnabledBorders enabledBorders)103 void PanelShadows::setEnabledBorders(QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders)
104 {
105 if (!window || !d->m_windows.contains(window)) {
106 return;
107 }
108
109 d->m_windows[window] = enabledBorders;
110 d->updateShadow(window, enabledBorders);
111 }
112
updateShadows()113 void PanelShadows::Private::updateShadows()
114 {
115 const bool hadShadowsBefore = !m_tiles.isEmpty();
116
117 // has shadows now?
118 if (hasShadows()) {
119 if (hadShadowsBefore) {
120 clearTiles();
121 }
122 for (auto i = m_windows.constBegin(); i != m_windows.constEnd(); ++i) {
123 updateShadow(i.key(), i.value());
124 }
125 } else {
126 if (hadShadowsBefore) {
127 for (auto i = m_windows.constBegin(); i != m_windows.constEnd(); ++i) {
128 clearShadow(i.key());
129 }
130 clearTiles();
131 }
132 }
133 }
134
initTile(const QString & element)135 void PanelShadows::Private::initTile(const QString &element)
136 {
137 const QImage image = q->pixmap(element).toImage();
138
139 KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create();
140 tile->setImage(image);
141
142 m_tiles << tile;
143 }
144
setupTiles()145 void PanelShadows::Private::setupTiles()
146 {
147 clearTiles();
148
149 initTile(QStringLiteral("shadow-top"));
150 initTile(QStringLiteral("shadow-topright"));
151 initTile(QStringLiteral("shadow-right"));
152 initTile(QStringLiteral("shadow-bottomright"));
153 initTile(QStringLiteral("shadow-bottom"));
154 initTile(QStringLiteral("shadow-bottomleft"));
155 initTile(QStringLiteral("shadow-left"));
156 initTile(QStringLiteral("shadow-topleft"));
157 }
158
clearTiles()159 void PanelShadows::Private::clearTiles()
160 {
161 m_tiles.clear();
162 }
163
updateShadow(QWindow * window,Plasma::FrameSvg::EnabledBorders enabledBorders)164 void PanelShadows::Private::updateShadow(QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders)
165 {
166 if (!hasShadows()) {
167 return;
168 }
169
170 if (m_tiles.isEmpty()) {
171 setupTiles();
172 }
173
174 KWindowShadow *&shadow = m_shadows[window];
175
176 if (!shadow) {
177 shadow = new KWindowShadow(q);
178 }
179
180 if (shadow->isCreated()) {
181 shadow->destroy();
182 }
183
184 if (enabledBorders & Plasma::FrameSvg::TopBorder) {
185 shadow->setTopTile(m_tiles.at(0));
186 } else {
187 shadow->setTopTile(nullptr);
188 }
189
190 if (enabledBorders & Plasma::FrameSvg::TopBorder && enabledBorders & Plasma::FrameSvg::RightBorder) {
191 shadow->setTopRightTile(m_tiles.at(1));
192 } else {
193 shadow->setTopRightTile(nullptr);
194 }
195
196 if (enabledBorders & Plasma::FrameSvg::RightBorder) {
197 shadow->setRightTile(m_tiles.at(2));
198 } else {
199 shadow->setRightTile(nullptr);
200 }
201
202 if (enabledBorders & Plasma::FrameSvg::BottomBorder && enabledBorders & Plasma::FrameSvg::RightBorder) {
203 shadow->setBottomRightTile(m_tiles.at(3));
204 } else {
205 shadow->setBottomRightTile(nullptr);
206 }
207
208 if (enabledBorders & Plasma::FrameSvg::BottomBorder) {
209 shadow->setBottomTile(m_tiles.at(4));
210 } else {
211 shadow->setBottomTile(nullptr);
212 }
213
214 if (enabledBorders & Plasma::FrameSvg::BottomBorder && enabledBorders & Plasma::FrameSvg::LeftBorder) {
215 shadow->setBottomLeftTile(m_tiles.at(5));
216 } else {
217 shadow->setBottomLeftTile(nullptr);
218 }
219
220 if (enabledBorders & Plasma::FrameSvg::LeftBorder) {
221 shadow->setLeftTile(m_tiles.at(6));
222 } else {
223 shadow->setLeftTile(nullptr);
224 }
225
226 if (enabledBorders & Plasma::FrameSvg::TopBorder && enabledBorders & Plasma::FrameSvg::LeftBorder) {
227 shadow->setTopLeftTile(m_tiles.at(7));
228 } else {
229 shadow->setTopLeftTile(nullptr);
230 }
231
232 QMargins padding;
233
234 if (enabledBorders & Plasma::FrameSvg::TopBorder) {
235 const QSize marginHint = q->elementSize(QStringLiteral("shadow-hint-top-margin"));
236 if (marginHint.isValid()) {
237 padding.setTop(marginHint.height());
238 } else {
239 padding.setTop(m_tiles[0]->image().height());
240 }
241 }
242
243 if (enabledBorders & Plasma::FrameSvg::RightBorder) {
244 const QSize marginHint = q->elementSize(QStringLiteral("shadow-hint-right-margin"));
245 if (marginHint.isValid()) {
246 padding.setRight(marginHint.width());
247 } else {
248 padding.setRight(m_tiles[2]->image().width());
249 }
250 }
251
252 if (enabledBorders & Plasma::FrameSvg::BottomBorder) {
253 const QSize marginHint = q->elementSize(QStringLiteral("shadow-hint-bottom-margin"));
254 if (marginHint.isValid()) {
255 padding.setBottom(marginHint.height());
256 } else {
257 padding.setBottom(m_tiles[4]->image().height());
258 }
259 }
260
261 if (enabledBorders & Plasma::FrameSvg::LeftBorder) {
262 const QSize marginHint = q->elementSize(QStringLiteral("shadow-hint-left-margin"));
263 if (marginHint.isValid()) {
264 padding.setLeft(marginHint.width());
265 } else {
266 padding.setLeft(m_tiles[6]->image().width());
267 }
268 }
269
270 shadow->setPadding(padding);
271 shadow->setWindow(window);
272
273 if (!shadow->create()) {
274 qCWarning(PLASMASHELL) << "Couldn't create KWindowShadow for" << window;
275 }
276 }
277
clearShadow(QWindow * window)278 void PanelShadows::Private::clearShadow(QWindow *window)
279 {
280 delete m_shadows.take(window);
281 }
282
hasShadows() const283 bool PanelShadows::Private::hasShadows() const
284 {
285 return q->hasElement(QStringLiteral("shadow-left"));
286 }
287
288 #include "moc_panelshadows_p.cpp"
289