1 /*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
6 SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "effects.h"
12
13 #include "abstract_output.h"
14 #include "effectsadaptor.h"
15 #include "effectloader.h"
16 #ifdef KWIN_BUILD_ACTIVITIES
17 #include "activities.h"
18 #endif
19 #include "deleted.h"
20 #include "x11client.h"
21 #include "cursor.h"
22 #include "group.h"
23 #include "internal_client.h"
24 #include "osd.h"
25 #include "pointer_input.h"
26 #include "unmanaged.h"
27 #ifdef KWIN_BUILD_TABBOX
28 #include "tabbox.h"
29 #endif
30 #include "screenedge.h"
31 #include "scripting/scriptedeffect.h"
32 #include "screens.h"
33 #include "screenlockerwatcher.h"
34 #include "virtualdesktops.h"
35 #include "window_property_notify_x11_filter.h"
36 #include "workspace.h"
37 #include "kwinglutils.h"
38 #include "kwineffectquickview.h"
39
40 #include <QDebug>
41 #include <QMouseEvent>
42 #include <QWheelEvent>
43
44 #include <Plasma/Theme>
45
46 #include "composite.h"
47 #include "xcbutils.h"
48 #include "platform.h"
49 #include "waylandclient.h"
50 #include "wayland_server.h"
51
52 #include "decorations/decorationbridge.h"
53 #include <KDecoration2/DecorationSettings>
54
55 namespace KWin
56 {
57 //---------------------
58 // Static
59
readWindowProperty(xcb_window_t win,xcb_atom_t atom,xcb_atom_t type,int format)60 static QByteArray readWindowProperty(xcb_window_t win, xcb_atom_t atom, xcb_atom_t type, int format)
61 {
62 if (win == XCB_WINDOW_NONE) {
63 return QByteArray();
64 }
65 uint32_t len = 32768;
66 for (;;) {
67 Xcb::Property prop(false, win, atom, XCB_ATOM_ANY, 0, len);
68 if (prop.isNull()) {
69 // get property failed
70 return QByteArray();
71 }
72 if (prop->bytes_after > 0) {
73 len *= 2;
74 continue;
75 }
76 return prop.toByteArray(format, type);
77 }
78 }
79
deleteWindowProperty(xcb_window_t win,long int atom)80 static void deleteWindowProperty(xcb_window_t win, long int atom)
81 {
82 if (win == XCB_WINDOW_NONE) {
83 return;
84 }
85 xcb_delete_property(kwinApp()->x11Connection(), win, atom);
86 }
87
registerSupportProperty(const QByteArray & propertyName)88 static xcb_atom_t registerSupportProperty(const QByteArray &propertyName)
89 {
90 auto c = kwinApp()->x11Connection();
91 if (!c) {
92 return XCB_ATOM_NONE;
93 }
94 // get the atom for the propertyName
95 ScopedCPointer<xcb_intern_atom_reply_t> atomReply(xcb_intern_atom_reply(c,
96 xcb_intern_atom_unchecked(c, false, propertyName.size(), propertyName.constData()),
97 nullptr));
98 if (atomReply.isNull()) {
99 return XCB_ATOM_NONE;
100 }
101 // announce property on root window
102 unsigned char dummy = 0;
103 xcb_change_property(c, XCB_PROP_MODE_REPLACE, kwinApp()->x11RootWindow(), atomReply->atom, atomReply->atom, 8, 1, &dummy);
104 // TODO: add to _NET_SUPPORTED
105 return atomReply->atom;
106 }
107
108 //---------------------
109
EffectsHandlerImpl(Compositor * compositor,Scene * scene)110 EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
111 : EffectsHandler(scene->compositingType())
112 , keyboard_grab_effect(nullptr)
113 , fullscreen_effect(nullptr)
114 , m_compositor(compositor)
115 , m_scene(scene)
116 , m_desktopRendering(false)
117 , m_currentRenderedDesktop(0)
118 , m_effectLoader(new EffectLoader(this))
119 , m_trackingCursorChanges(0)
120 {
121 qRegisterMetaType<QVector<KWin::EffectWindow*>>();
122 connect(m_effectLoader, &AbstractEffectLoader::effectLoaded, this,
123 [this](Effect *effect, const QString &name) {
124 effect_order.insert(effect->requestedEffectChainPosition(), EffectPair(name, effect));
125 loaded_effects << EffectPair(name, effect);
126 effectsChanged();
127 }
128 );
129 m_effectLoader->setConfig(kwinApp()->config());
130 new EffectsAdaptor(this);
131 QDBusConnection dbus = QDBusConnection::sessionBus();
132 dbus.registerObject(QStringLiteral("/Effects"), this);
133
134 Workspace *ws = Workspace::self();
135 VirtualDesktopManager *vds = VirtualDesktopManager::self();
136 connect(ws, &Workspace::showingDesktopChanged,
137 this, &EffectsHandlerImpl::showingDesktopChanged);
138 connect(ws, &Workspace::currentDesktopChanged, this,
139 [this](int old, AbstractClient *c) {
140 const int newDesktop = VirtualDesktopManager::self()->current();
141 if (old != 0 && newDesktop != old) {
142 Q_EMIT desktopChanged(old, newDesktop, c ? c->effectWindow() : nullptr);
143 // TODO: remove in 4.10
144 Q_EMIT desktopChanged(old, newDesktop);
145 }
146 }
147 );
148 connect(ws, &Workspace::desktopPresenceChanged, this,
149 [this](AbstractClient *c, int old) {
150 if (!c->effectWindow()) {
151 return;
152 }
153 Q_EMIT desktopPresenceChanged(c->effectWindow(), old, c->desktop());
154 }
155 );
156 connect(ws, &Workspace::clientAdded, this,
157 [this](AbstractClient *c) {
158 if (c->readyForPainting())
159 slotClientShown(c);
160 else
161 connect(c, &Toplevel::windowShown, this, &EffectsHandlerImpl::slotClientShown);
162 }
163 );
164 connect(ws, &Workspace::unmanagedAdded, this,
165 [this](Unmanaged *u) {
166 // it's never initially ready but has synthetic 50ms delay
167 connect(u, &Toplevel::windowShown, this, &EffectsHandlerImpl::slotUnmanagedShown);
168 }
169 );
170 connect(ws, &Workspace::internalClientAdded, this,
171 [this](InternalClient *client) {
172 setupClientConnections(client);
173 Q_EMIT windowAdded(client->effectWindow());
174 }
175 );
176 connect(ws, &Workspace::clientActivated, this,
177 [this](KWin::AbstractClient *c) {
178 Q_EMIT windowActivated(c ? c->effectWindow() : nullptr);
179 }
180 );
181 connect(ws, &Workspace::deletedRemoved, this,
182 [this](KWin::Deleted *d) {
183 Q_EMIT windowDeleted(d->effectWindow());
184 elevated_windows.removeAll(d->effectWindow());
185 }
186 );
187 connect(ws->sessionManager(), &SessionManager::stateChanged, this,
188 &KWin::EffectsHandler::sessionStateChanged);
189 connect(vds, &VirtualDesktopManager::countChanged, this, &EffectsHandler::numberDesktopsChanged);
190 connect(Cursors::self()->mouse(), &Cursor::mouseChanged, this, &EffectsHandler::mouseChanged);
191 connect(Screens::self(), &Screens::countChanged, this, &EffectsHandler::numberScreensChanged);
192 connect(Screens::self(), &Screens::sizeChanged, this, &EffectsHandler::virtualScreenSizeChanged);
193 connect(Screens::self(), &Screens::geometryChanged, this, &EffectsHandler::virtualScreenGeometryChanged);
194 #ifdef KWIN_BUILD_ACTIVITIES
195 if (Activities *activities = Activities::self()) {
196 connect(activities, &Activities::added, this, &EffectsHandler::activityAdded);
197 connect(activities, &Activities::removed, this, &EffectsHandler::activityRemoved);
198 connect(activities, &Activities::currentChanged, this, &EffectsHandler::currentActivityChanged);
199 }
200 #endif
201 connect(ws, &Workspace::stackingOrderChanged, this, &EffectsHandler::stackingOrderChanged);
202 #ifdef KWIN_BUILD_TABBOX
203 TabBox::TabBox *tabBox = TabBox::TabBox::self();
204 connect(tabBox, &TabBox::TabBox::tabBoxAdded, this, &EffectsHandler::tabBoxAdded);
205 connect(tabBox, &TabBox::TabBox::tabBoxUpdated, this, &EffectsHandler::tabBoxUpdated);
206 connect(tabBox, &TabBox::TabBox::tabBoxClosed, this, &EffectsHandler::tabBoxClosed);
207 connect(tabBox, &TabBox::TabBox::tabBoxKeyEvent, this, &EffectsHandler::tabBoxKeyEvent);
208 #endif
209 connect(ScreenEdges::self(), &ScreenEdges::approaching, this, &EffectsHandler::screenEdgeApproaching);
210 connect(ScreenLockerWatcher::self(), &ScreenLockerWatcher::locked, this, &EffectsHandler::screenLockingChanged);
211 connect(ScreenLockerWatcher::self(), &ScreenLockerWatcher::aboutToLock, this, &EffectsHandler::screenAboutToLock);
212
213 connect(kwinApp(), &Application::x11ConnectionChanged, this,
214 [this] {
215 registered_atoms.clear();
216 for (auto it = m_propertiesForEffects.keyBegin(); it != m_propertiesForEffects.keyEnd(); it++) {
217 const auto atom = registerSupportProperty(*it);
218 if (atom == XCB_ATOM_NONE) {
219 continue;
220 }
221 m_compositor->keepSupportProperty(atom);
222 m_managedProperties.insert(*it, atom);
223 registerPropertyType(atom, true);
224 }
225 if (kwinApp()->x11Connection()) {
226 m_x11WindowPropertyNotify = std::make_unique<WindowPropertyNotifyX11Filter>(this);
227 } else {
228 m_x11WindowPropertyNotify.reset();
229 }
230 Q_EMIT xcbConnectionChanged();
231 }
232 );
233
234 if (kwinApp()->x11Connection()) {
235 m_x11WindowPropertyNotify = std::make_unique<WindowPropertyNotifyX11Filter>(this);
236 }
237
238 // connect all clients
239 for (AbstractClient *client : ws->allClientList()) {
240 if (client->readyForPainting()) {
241 setupClientConnections(client);
242 } else {
243 connect(client, &Toplevel::windowShown, this, &EffectsHandlerImpl::slotClientShown);
244 }
245 }
246 for (Unmanaged *u : ws->unmanagedList()) {
247 setupUnmanagedConnections(u);
248 }
249 for (InternalClient *client : ws->internalClients()) {
250 setupClientConnections(client);
251 }
252
253 connect(kwinApp()->platform(), &Platform::outputEnabled, this, &EffectsHandlerImpl::slotOutputEnabled);
254 connect(kwinApp()->platform(), &Platform::outputDisabled, this, &EffectsHandlerImpl::slotOutputDisabled);
255
256 const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
257 for (AbstractOutput *output : outputs) {
258 slotOutputEnabled(output);
259 }
260
261 reconfigure();
262 }
263
~EffectsHandlerImpl()264 EffectsHandlerImpl::~EffectsHandlerImpl()
265 {
266 unloadAllEffects();
267 }
268
unloadAllEffects()269 void EffectsHandlerImpl::unloadAllEffects()
270 {
271 for (const EffectPair &pair : qAsConst(loaded_effects)) {
272 destroyEffect(pair.second);
273 }
274
275 effect_order.clear();
276 m_effectLoader->clear();
277
278 effectsChanged();
279 }
280
setupClientConnections(AbstractClient * c)281 void EffectsHandlerImpl::setupClientConnections(AbstractClient* c)
282 {
283 connect(c, &AbstractClient::windowClosed, this, &EffectsHandlerImpl::slotWindowClosed);
284 connect(c, static_cast<void (AbstractClient::*)(KWin::AbstractClient*, MaximizeMode)>(&AbstractClient::clientMaximizedStateChanged),
285 this, &EffectsHandlerImpl::slotClientMaximized);
286 connect(c, &AbstractClient::clientStartUserMovedResized, this,
287 [this](AbstractClient *c) {
288 Q_EMIT windowStartUserMovedResized(c->effectWindow());
289 }
290 );
291 connect(c, &AbstractClient::clientStepUserMovedResized, this,
292 [this](AbstractClient *c, const QRect &geometry) {
293 Q_EMIT windowStepUserMovedResized(c->effectWindow(), geometry);
294 }
295 );
296 connect(c, &AbstractClient::clientFinishUserMovedResized, this,
297 [this](AbstractClient *c) {
298 Q_EMIT windowFinishUserMovedResized(c->effectWindow());
299 }
300 );
301 connect(c, &AbstractClient::opacityChanged, this, &EffectsHandlerImpl::slotOpacityChanged);
302 connect(c, &AbstractClient::clientMinimized, this,
303 [this](AbstractClient *c, bool animate) {
304 // TODO: notify effects even if it should not animate?
305 if (animate) {
306 Q_EMIT windowMinimized(c->effectWindow());
307 }
308 }
309 );
310 connect(c, &AbstractClient::clientUnminimized, this,
311 [this](AbstractClient* c, bool animate) {
312 // TODO: notify effects even if it should not animate?
313 if (animate) {
314 Q_EMIT windowUnminimized(c->effectWindow());
315 }
316 }
317 );
318 connect(c, &AbstractClient::modalChanged, this, &EffectsHandlerImpl::slotClientModalityChanged);
319 connect(c, &AbstractClient::geometryShapeChanged, this, &EffectsHandlerImpl::slotGeometryShapeChanged);
320 connect(c, &AbstractClient::frameGeometryChanged, this, &EffectsHandlerImpl::slotFrameGeometryChanged);
321 connect(c, &AbstractClient::damaged, this, &EffectsHandlerImpl::slotWindowDamaged);
322 connect(c, &AbstractClient::unresponsiveChanged, this,
323 [this, c](bool unresponsive) {
324 Q_EMIT windowUnresponsiveChanged(c->effectWindow(), unresponsive);
325 }
326 );
327 connect(c, &AbstractClient::windowShown, this,
328 [this](Toplevel *c) {
329 Q_EMIT windowShown(c->effectWindow());
330 }
331 );
332 connect(c, &AbstractClient::windowHidden, this,
333 [this](Toplevel *c) {
334 Q_EMIT windowHidden(c->effectWindow());
335 }
336 );
337 connect(c, &AbstractClient::keepAboveChanged, this,
338 [this, c](bool above) {
339 Q_UNUSED(above)
340 Q_EMIT windowKeepAboveChanged(c->effectWindow());
341 }
342 );
343 connect(c, &AbstractClient::keepBelowChanged, this,
344 [this, c](bool below) {
345 Q_UNUSED(below)
346 Q_EMIT windowKeepBelowChanged(c->effectWindow());
347 }
348 );
349 connect(c, &AbstractClient::fullScreenChanged, this,
350 [this, c]() {
351 Q_EMIT windowFullScreenChanged(c->effectWindow());
352 }
353 );
354 connect(c, &AbstractClient::visibleGeometryChanged, this, [this, c]() {
355 Q_EMIT windowExpandedGeometryChanged(c->effectWindow());
356 });
357 }
358
setupUnmanagedConnections(Unmanaged * u)359 void EffectsHandlerImpl::setupUnmanagedConnections(Unmanaged* u)
360 {
361 connect(u, &Unmanaged::windowClosed, this, &EffectsHandlerImpl::slotWindowClosed);
362 connect(u, &Unmanaged::opacityChanged, this, &EffectsHandlerImpl::slotOpacityChanged);
363 connect(u, &Unmanaged::geometryShapeChanged, this, &EffectsHandlerImpl::slotGeometryShapeChanged);
364 connect(u, &Unmanaged::frameGeometryChanged, this, &EffectsHandlerImpl::slotFrameGeometryChanged);
365 connect(u, &Unmanaged::damaged, this, &EffectsHandlerImpl::slotWindowDamaged);
366 connect(u, &Unmanaged::visibleGeometryChanged, this, [this, u]() {
367 Q_EMIT windowExpandedGeometryChanged(u->effectWindow());
368 });
369 }
370
reconfigure()371 void EffectsHandlerImpl::reconfigure()
372 {
373 m_effectLoader->queryAndLoadAll();
374 }
375
376 // the idea is that effects call this function again which calls the next one
prePaintScreen(ScreenPrePaintData & data,std::chrono::milliseconds presentTime)377 void EffectsHandlerImpl::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime)
378 {
379 if (m_currentPaintScreenIterator != m_activeEffects.constEnd()) {
380 (*m_currentPaintScreenIterator++)->prePaintScreen(data, presentTime);
381 --m_currentPaintScreenIterator;
382 }
383 // no special final code
384 }
385
paintScreen(int mask,const QRegion & region,ScreenPaintData & data)386 void EffectsHandlerImpl::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data)
387 {
388 if (m_currentPaintScreenIterator != m_activeEffects.constEnd()) {
389 (*m_currentPaintScreenIterator++)->paintScreen(mask, region, data);
390 --m_currentPaintScreenIterator;
391 } else
392 m_scene->finalPaintScreen(mask, region, data);
393 }
394
paintDesktop(int desktop,int mask,QRegion region,ScreenPaintData & data)395 void EffectsHandlerImpl::paintDesktop(int desktop, int mask, QRegion region, ScreenPaintData &data)
396 {
397 if (desktop < 1 || desktop > numberOfDesktops()) {
398 return;
399 }
400 m_currentRenderedDesktop = desktop;
401 m_desktopRendering = true;
402 // save the paint screen iterator
403 EffectsIterator savedIterator = m_currentPaintScreenIterator;
404 m_currentPaintScreenIterator = m_activeEffects.constBegin();
405 effects->paintScreen(mask, region, data);
406 // restore the saved iterator
407 m_currentPaintScreenIterator = savedIterator;
408 m_desktopRendering = false;
409 }
410
postPaintScreen()411 void EffectsHandlerImpl::postPaintScreen()
412 {
413 if (m_currentPaintScreenIterator != m_activeEffects.constEnd()) {
414 (*m_currentPaintScreenIterator++)->postPaintScreen();
415 --m_currentPaintScreenIterator;
416 }
417 // no special final code
418 }
419
prePaintWindow(EffectWindow * w,WindowPrePaintData & data,std::chrono::milliseconds presentTime)420 void EffectsHandlerImpl::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime)
421 {
422 if (m_currentPaintWindowIterator != m_activeEffects.constEnd()) {
423 (*m_currentPaintWindowIterator++)->prePaintWindow(w, data, presentTime);
424 --m_currentPaintWindowIterator;
425 }
426 // no special final code
427 }
428
paintWindow(EffectWindow * w,int mask,const QRegion & region,WindowPaintData & data)429 void EffectsHandlerImpl::paintWindow(EffectWindow* w, int mask, const QRegion ®ion, WindowPaintData& data)
430 {
431 if (m_currentPaintWindowIterator != m_activeEffects.constEnd()) {
432 (*m_currentPaintWindowIterator++)->paintWindow(w, mask, region, data);
433 --m_currentPaintWindowIterator;
434 } else
435 m_scene->finalPaintWindow(static_cast<EffectWindowImpl*>(w), mask, region, data);
436 }
437
paintEffectFrame(EffectFrame * frame,const QRegion & region,double opacity,double frameOpacity)438 void EffectsHandlerImpl::paintEffectFrame(EffectFrame* frame, const QRegion ®ion, double opacity, double frameOpacity)
439 {
440 if (m_currentPaintEffectFrameIterator != m_activeEffects.constEnd()) {
441 (*m_currentPaintEffectFrameIterator++)->paintEffectFrame(frame, region, opacity, frameOpacity);
442 --m_currentPaintEffectFrameIterator;
443 } else {
444 const EffectFrameImpl* frameImpl = static_cast<const EffectFrameImpl*>(frame);
445 frameImpl->finalRender(region, opacity, frameOpacity);
446 }
447 }
448
postPaintWindow(EffectWindow * w)449 void EffectsHandlerImpl::postPaintWindow(EffectWindow* w)
450 {
451 if (m_currentPaintWindowIterator != m_activeEffects.constEnd()) {
452 (*m_currentPaintWindowIterator++)->postPaintWindow(w);
453 --m_currentPaintWindowIterator;
454 }
455 // no special final code
456 }
457
provides(Effect::Feature ef)458 Effect *EffectsHandlerImpl::provides(Effect::Feature ef)
459 {
460 for (int i = 0; i < loaded_effects.size(); ++i)
461 if (loaded_effects.at(i).second->provides(ef))
462 return loaded_effects.at(i).second;
463 return nullptr;
464 }
465
drawWindow(EffectWindow * w,int mask,const QRegion & region,WindowPaintData & data)466 void EffectsHandlerImpl::drawWindow(EffectWindow* w, int mask, const QRegion ®ion, WindowPaintData& data)
467 {
468 if (m_currentDrawWindowIterator != m_activeEffects.constEnd()) {
469 (*m_currentDrawWindowIterator++)->drawWindow(w, mask, region, data);
470 --m_currentDrawWindowIterator;
471 } else
472 m_scene->finalDrawWindow(static_cast<EffectWindowImpl*>(w), mask, region, data);
473 }
474
hasDecorationShadows() const475 bool EffectsHandlerImpl::hasDecorationShadows() const
476 {
477 return false;
478 }
479
decorationsHaveAlpha() const480 bool EffectsHandlerImpl::decorationsHaveAlpha() const
481 {
482 return true;
483 }
484
decorationSupportsBlurBehind() const485 bool EffectsHandlerImpl::decorationSupportsBlurBehind() const
486 {
487 return Decoration::DecorationBridge::self()->needsBlur();
488 }
489
490 // start another painting pass
startPaint()491 void EffectsHandlerImpl::startPaint()
492 {
493 m_activeEffects.clear();
494 m_activeEffects.reserve(loaded_effects.count());
495 for(QVector< KWin::EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
496 if (it->second->isActive()) {
497 m_activeEffects << it->second;
498 }
499 }
500 m_currentDrawWindowIterator = m_activeEffects.constBegin();
501 m_currentPaintWindowIterator = m_activeEffects.constBegin();
502 m_currentPaintScreenIterator = m_activeEffects.constBegin();
503 m_currentPaintEffectFrameIterator = m_activeEffects.constBegin();
504 }
505
slotClientMaximized(KWin::AbstractClient * c,MaximizeMode maxMode)506 void EffectsHandlerImpl::slotClientMaximized(KWin::AbstractClient *c, MaximizeMode maxMode)
507 {
508 bool horizontal = false;
509 bool vertical = false;
510 switch (maxMode) {
511 case MaximizeHorizontal:
512 horizontal = true;
513 break;
514 case MaximizeVertical:
515 vertical = true;
516 break;
517 case MaximizeFull:
518 horizontal = true;
519 vertical = true;
520 break;
521 case MaximizeRestore: // fall through
522 default:
523 // default - nothing to do
524 break;
525 }
526 if (EffectWindowImpl *w = c->effectWindow()) {
527 Q_EMIT windowMaximizedStateChanged(w, horizontal, vertical);
528 }
529 }
530
slotOpacityChanged(Toplevel * t,qreal oldOpacity)531 void EffectsHandlerImpl::slotOpacityChanged(Toplevel *t, qreal oldOpacity)
532 {
533 if (t->opacity() == oldOpacity || !t->effectWindow()) {
534 return;
535 }
536 Q_EMIT windowOpacityChanged(t->effectWindow(), oldOpacity, (qreal)t->opacity());
537 }
538
slotClientShown(KWin::Toplevel * t)539 void EffectsHandlerImpl::slotClientShown(KWin::Toplevel *t)
540 {
541 Q_ASSERT(qobject_cast<AbstractClient *>(t));
542 AbstractClient *c = static_cast<AbstractClient *>(t);
543 disconnect(c, &Toplevel::windowShown, this, &EffectsHandlerImpl::slotClientShown);
544 setupClientConnections(c);
545 Q_EMIT windowAdded(c->effectWindow());
546 }
547
slotUnmanagedShown(KWin::Toplevel * t)548 void EffectsHandlerImpl::slotUnmanagedShown(KWin::Toplevel *t)
549 { // regardless, unmanaged windows are -yet?- not synced anyway
550 Q_ASSERT(qobject_cast<Unmanaged *>(t));
551 Unmanaged *u = static_cast<Unmanaged*>(t);
552 setupUnmanagedConnections(u);
553 Q_EMIT windowAdded(u->effectWindow());
554 }
555
slotWindowClosed(KWin::Toplevel * c,KWin::Deleted * d)556 void EffectsHandlerImpl::slotWindowClosed(KWin::Toplevel *c, KWin::Deleted *d)
557 {
558 c->disconnect(this);
559 if (d) {
560 Q_EMIT windowClosed(c->effectWindow());
561 }
562 }
563
slotClientModalityChanged()564 void EffectsHandlerImpl::slotClientModalityChanged()
565 {
566 Q_EMIT windowModalityChanged(static_cast<X11Client *>(sender())->effectWindow());
567 }
568
slotCurrentTabAboutToChange(EffectWindow * from,EffectWindow * to)569 void EffectsHandlerImpl::slotCurrentTabAboutToChange(EffectWindow *from, EffectWindow *to)
570 {
571 Q_EMIT currentTabAboutToChange(from, to);
572 }
573
slotTabAdded(EffectWindow * w,EffectWindow * to)574 void EffectsHandlerImpl::slotTabAdded(EffectWindow* w, EffectWindow* to)
575 {
576 Q_EMIT tabAdded(w, to);
577 }
578
slotTabRemoved(EffectWindow * w,EffectWindow * leaderOfFormerGroup)579 void EffectsHandlerImpl::slotTabRemoved(EffectWindow *w, EffectWindow* leaderOfFormerGroup)
580 {
581 Q_EMIT tabRemoved(w, leaderOfFormerGroup);
582 }
583
slotWindowDamaged(Toplevel * t,const QRegion & r)584 void EffectsHandlerImpl::slotWindowDamaged(Toplevel* t, const QRegion& r)
585 {
586 if (!t->effectWindow()) {
587 // can happen during tear down of window
588 return;
589 }
590 Q_EMIT windowDamaged(t->effectWindow(), r);
591 }
592
slotGeometryShapeChanged(Toplevel * t,const QRect & old)593 void EffectsHandlerImpl::slotGeometryShapeChanged(Toplevel* t, const QRect& old)
594 {
595 // during late cleanup effectWindow() may be already NULL
596 // in some functions that may still call this
597 if (t == nullptr || t->effectWindow() == nullptr)
598 return;
599 Q_EMIT windowGeometryShapeChanged(t->effectWindow(), old);
600 }
601
slotFrameGeometryChanged(Toplevel * toplevel,const QRect & oldGeometry)602 void EffectsHandlerImpl::slotFrameGeometryChanged(Toplevel *toplevel, const QRect &oldGeometry)
603 {
604 // effectWindow() might be nullptr during tear down of the client.
605 if (toplevel->effectWindow()) {
606 Q_EMIT windowFrameGeometryChanged(toplevel->effectWindow(), oldGeometry);
607 }
608 }
609
setActiveFullScreenEffect(Effect * e)610 void EffectsHandlerImpl::setActiveFullScreenEffect(Effect* e)
611 {
612 if (fullscreen_effect == e) {
613 return;
614 }
615 const bool activeChanged = (e == nullptr || fullscreen_effect == nullptr);
616 fullscreen_effect = e;
617 Q_EMIT activeFullScreenEffectChanged();
618 if (activeChanged) {
619 Q_EMIT hasActiveFullScreenEffectChanged();
620 }
621 }
622
activeFullScreenEffect() const623 Effect* EffectsHandlerImpl::activeFullScreenEffect() const
624 {
625 return fullscreen_effect;
626 }
627
hasActiveFullScreenEffect() const628 bool EffectsHandlerImpl::hasActiveFullScreenEffect() const
629 {
630 return fullscreen_effect;
631 }
632
grabKeyboard(Effect * effect)633 bool EffectsHandlerImpl::grabKeyboard(Effect* effect)
634 {
635 if (keyboard_grab_effect != nullptr)
636 return false;
637 if (!doGrabKeyboard()) {
638 return false;
639 }
640 keyboard_grab_effect = effect;
641 return true;
642 }
643
doGrabKeyboard()644 bool EffectsHandlerImpl::doGrabKeyboard()
645 {
646 return true;
647 }
648
ungrabKeyboard()649 void EffectsHandlerImpl::ungrabKeyboard()
650 {
651 Q_ASSERT(keyboard_grab_effect != nullptr);
652 doUngrabKeyboard();
653 keyboard_grab_effect = nullptr;
654 }
655
doUngrabKeyboard()656 void EffectsHandlerImpl::doUngrabKeyboard()
657 {
658 }
659
grabbedKeyboardEvent(QKeyEvent * e)660 void EffectsHandlerImpl::grabbedKeyboardEvent(QKeyEvent* e)
661 {
662 if (keyboard_grab_effect != nullptr)
663 keyboard_grab_effect->grabbedKeyboardEvent(e);
664 }
665
startMouseInterception(Effect * effect,Qt::CursorShape shape)666 void EffectsHandlerImpl::startMouseInterception(Effect *effect, Qt::CursorShape shape)
667 {
668 if (m_grabbedMouseEffects.contains(effect)) {
669 return;
670 }
671 m_grabbedMouseEffects.append(effect);
672 if (m_grabbedMouseEffects.size() != 1) {
673 return;
674 }
675 doStartMouseInterception(shape);
676 }
677
doStartMouseInterception(Qt::CursorShape shape)678 void EffectsHandlerImpl::doStartMouseInterception(Qt::CursorShape shape)
679 {
680 input()->pointer()->setEffectsOverrideCursor(shape);
681 }
682
stopMouseInterception(Effect * effect)683 void EffectsHandlerImpl::stopMouseInterception(Effect *effect)
684 {
685 if (!m_grabbedMouseEffects.contains(effect)) {
686 return;
687 }
688 m_grabbedMouseEffects.removeAll(effect);
689 if (m_grabbedMouseEffects.isEmpty()) {
690 doStopMouseInterception();
691 }
692 }
693
doStopMouseInterception()694 void EffectsHandlerImpl::doStopMouseInterception()
695 {
696 input()->pointer()->removeEffectsOverrideCursor();
697 }
698
isMouseInterception() const699 bool EffectsHandlerImpl::isMouseInterception() const
700 {
701 return m_grabbedMouseEffects.count() > 0;
702 }
703
704
touchDown(qint32 id,const QPointF & pos,quint32 time)705 bool EffectsHandlerImpl::touchDown(qint32 id, const QPointF &pos, quint32 time)
706 {
707 // TODO: reverse call order?
708 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
709 if (it->second->touchDown(id, pos, time)) {
710 return true;
711 }
712 }
713 return false;
714 }
715
touchMotion(qint32 id,const QPointF & pos,quint32 time)716 bool EffectsHandlerImpl::touchMotion(qint32 id, const QPointF &pos, quint32 time)
717 {
718 // TODO: reverse call order?
719 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
720 if (it->second->touchMotion(id, pos, time)) {
721 return true;
722 }
723 }
724 return false;
725 }
726
touchUp(qint32 id,quint32 time)727 bool EffectsHandlerImpl::touchUp(qint32 id, quint32 time)
728 {
729 // TODO: reverse call order?
730 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
731 if (it->second->touchUp(id, time)) {
732 return true;
733 }
734 }
735 return false;
736 }
737
registerGlobalShortcut(const QKeySequence & shortcut,QAction * action)738 void EffectsHandlerImpl::registerGlobalShortcut(const QKeySequence &shortcut, QAction *action)
739 {
740 input()->registerShortcut(shortcut, action);
741 }
742
registerPointerShortcut(Qt::KeyboardModifiers modifiers,Qt::MouseButton pointerButtons,QAction * action)743 void EffectsHandlerImpl::registerPointerShortcut(Qt::KeyboardModifiers modifiers, Qt::MouseButton pointerButtons, QAction *action)
744 {
745 input()->registerPointerShortcut(modifiers, pointerButtons, action);
746 }
747
registerAxisShortcut(Qt::KeyboardModifiers modifiers,PointerAxisDirection axis,QAction * action)748 void EffectsHandlerImpl::registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action)
749 {
750 input()->registerAxisShortcut(modifiers, axis, action);
751 }
752
registerRealtimeTouchpadSwipeShortcut(SwipeDirection dir,QAction * onUp,std::function<void (qreal)> progressCallback)753 void EffectsHandlerImpl::registerRealtimeTouchpadSwipeShortcut(SwipeDirection dir, QAction* onUp, std::function<void(qreal)> progressCallback)
754 {
755 input()->registerRealtimeTouchpadSwipeShortcut(dir, onUp, progressCallback);
756 }
757
registerTouchpadSwipeShortcut(SwipeDirection direction,QAction * action)758 void EffectsHandlerImpl::registerTouchpadSwipeShortcut(SwipeDirection direction, QAction *action)
759 {
760 input()->registerTouchpadSwipeShortcut(direction, action);
761 }
762
getProxy(QString name)763 void* EffectsHandlerImpl::getProxy(QString name)
764 {
765 for (QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it)
766 if ((*it).first == name)
767 return (*it).second->proxy();
768
769 return nullptr;
770 }
771
startMousePolling()772 void EffectsHandlerImpl::startMousePolling()
773 {
774 if (Cursors::self()->mouse())
775 Cursors::self()->mouse()->startMousePolling();
776 }
777
stopMousePolling()778 void EffectsHandlerImpl::stopMousePolling()
779 {
780 if (Cursors::self()->mouse())
781 Cursors::self()->mouse()->stopMousePolling();
782 }
783
hasKeyboardGrab() const784 bool EffectsHandlerImpl::hasKeyboardGrab() const
785 {
786 return keyboard_grab_effect != nullptr;
787 }
788
registerPropertyType(long atom,bool reg)789 void EffectsHandlerImpl::registerPropertyType(long atom, bool reg)
790 {
791 if (reg)
792 ++registered_atoms[ atom ]; // initialized to 0 if not present yet
793 else {
794 if (--registered_atoms[ atom ] == 0)
795 registered_atoms.remove(atom);
796 }
797 }
798
announceSupportProperty(const QByteArray & propertyName,Effect * effect)799 xcb_atom_t EffectsHandlerImpl::announceSupportProperty(const QByteArray &propertyName, Effect *effect)
800 {
801 PropertyEffectMap::iterator it = m_propertiesForEffects.find(propertyName);
802 if (it != m_propertiesForEffects.end()) {
803 // property has already been registered for an effect
804 // just append Effect and return the atom stored in m_managedProperties
805 if (!it.value().contains(effect)) {
806 it.value().append(effect);
807 }
808 return m_managedProperties.value(propertyName, XCB_ATOM_NONE);
809 }
810 m_propertiesForEffects.insert(propertyName, QList<Effect*>() << effect);
811 const auto atom = registerSupportProperty(propertyName);
812 if (atom == XCB_ATOM_NONE) {
813 return atom;
814 }
815 m_compositor->keepSupportProperty(atom);
816 m_managedProperties.insert(propertyName, atom);
817 registerPropertyType(atom, true);
818 return atom;
819 }
820
removeSupportProperty(const QByteArray & propertyName,Effect * effect)821 void EffectsHandlerImpl::removeSupportProperty(const QByteArray &propertyName, Effect *effect)
822 {
823 PropertyEffectMap::iterator it = m_propertiesForEffects.find(propertyName);
824 if (it == m_propertiesForEffects.end()) {
825 // property is not registered - nothing to do
826 return;
827 }
828 if (!it.value().contains(effect)) {
829 // property is not registered for given effect - nothing to do
830 return;
831 }
832 it.value().removeAll(effect);
833 if (!it.value().isEmpty()) {
834 // property still registered for another effect - nothing further to do
835 return;
836 }
837 const xcb_atom_t atom = m_managedProperties.take(propertyName);
838 registerPropertyType(atom, false);
839 m_propertiesForEffects.remove(propertyName);
840 m_compositor->removeSupportProperty(atom); // delayed removal
841 }
842
readRootProperty(long atom,long type,int format) const843 QByteArray EffectsHandlerImpl::readRootProperty(long atom, long type, int format) const
844 {
845 if (!kwinApp()->x11Connection()) {
846 return QByteArray();
847 }
848 return readWindowProperty(kwinApp()->x11RootWindow(), atom, type, format);
849 }
850
activateWindow(EffectWindow * c)851 void EffectsHandlerImpl::activateWindow(EffectWindow* c)
852 {
853 if (auto cl = qobject_cast<AbstractClient *>(static_cast<EffectWindowImpl *>(c)->window())) {
854 Workspace::self()->activateClient(cl, true);
855 }
856 }
857
activeWindow() const858 EffectWindow* EffectsHandlerImpl::activeWindow() const
859 {
860 return Workspace::self()->activeClient() ? Workspace::self()->activeClient()->effectWindow() : nullptr;
861 }
862
moveWindow(EffectWindow * w,const QPoint & pos,bool snap,double snapAdjust)863 void EffectsHandlerImpl::moveWindow(EffectWindow* w, const QPoint& pos, bool snap, double snapAdjust)
864 {
865 auto cl = qobject_cast<AbstractClient *>(static_cast<EffectWindowImpl *>(w)->window());
866 if (!cl || !cl->isMovable())
867 return;
868
869 if (snap)
870 cl->move(Workspace::self()->adjustClientPosition(cl, pos, true, snapAdjust));
871 else
872 cl->move(pos);
873 }
874
windowToDesktop(EffectWindow * w,int desktop)875 void EffectsHandlerImpl::windowToDesktop(EffectWindow* w, int desktop)
876 {
877 auto cl = qobject_cast<AbstractClient *>(static_cast<EffectWindowImpl *>(w)->window());
878 if (cl && !cl->isDesktop() && !cl->isDock()) {
879 Workspace::self()->sendClientToDesktop(cl, desktop, true);
880 }
881 }
882
windowToDesktops(EffectWindow * w,const QVector<uint> & desktopIds)883 void EffectsHandlerImpl::windowToDesktops(EffectWindow *w, const QVector<uint> &desktopIds)
884 {
885 AbstractClient* cl = qobject_cast< AbstractClient* >(static_cast<EffectWindowImpl*>(w)->window());
886 if (!cl || cl->isDesktop() || cl->isDock()) {
887 return;
888 }
889 QVector<VirtualDesktop*> desktops;
890 desktops.reserve(desktopIds.count());
891 for (uint x11Id: desktopIds) {
892 if (x11Id > VirtualDesktopManager::self()->count()) {
893 continue;
894 }
895 VirtualDesktop *d = VirtualDesktopManager::self()->desktopForX11Id(x11Id);
896 Q_ASSERT(d);
897 if (desktops.contains(d)) {
898 continue;
899 }
900 desktops << d;
901 }
902 cl->setDesktops(desktops);
903 }
904
windowToScreen(EffectWindow * w,int screen)905 void EffectsHandlerImpl::windowToScreen(EffectWindow* w, int screen)
906 {
907 AbstractOutput *output = kwinApp()->platform()->findOutput(screen);
908 if (!output) {
909 return;
910 }
911 auto cl = qobject_cast<AbstractClient *>(static_cast<EffectWindowImpl *>(w)->window());
912 if (cl && !cl->isDesktop() && !cl->isDock()) {
913 Workspace::self()->sendClientToOutput(cl, output);
914 }
915 }
916
setShowingDesktop(bool showing)917 void EffectsHandlerImpl::setShowingDesktop(bool showing)
918 {
919 Workspace::self()->setShowingDesktop(showing);
920 }
921
currentActivity() const922 QString EffectsHandlerImpl::currentActivity() const
923 {
924 #ifdef KWIN_BUILD_ACTIVITIES
925 if (!Activities::self()) {
926 return QString();
927 }
928 return Activities::self()->current();
929 #else
930 return QString();
931 #endif
932 }
933
currentDesktop() const934 int EffectsHandlerImpl::currentDesktop() const
935 {
936 return VirtualDesktopManager::self()->current();
937 }
938
numberOfDesktops() const939 int EffectsHandlerImpl::numberOfDesktops() const
940 {
941 return VirtualDesktopManager::self()->count();
942 }
943
setCurrentDesktop(int desktop)944 void EffectsHandlerImpl::setCurrentDesktop(int desktop)
945 {
946 VirtualDesktopManager::self()->setCurrent(desktop);
947 }
948
setNumberOfDesktops(int desktops)949 void EffectsHandlerImpl::setNumberOfDesktops(int desktops)
950 {
951 VirtualDesktopManager::self()->setCount(desktops);
952 }
953
desktopGridSize() const954 QSize EffectsHandlerImpl::desktopGridSize() const
955 {
956 return VirtualDesktopManager::self()->grid().size();
957 }
958
desktopGridWidth() const959 int EffectsHandlerImpl::desktopGridWidth() const
960 {
961 return desktopGridSize().width();
962 }
963
desktopGridHeight() const964 int EffectsHandlerImpl::desktopGridHeight() const
965 {
966 return desktopGridSize().height();
967 }
968
workspaceWidth() const969 int EffectsHandlerImpl::workspaceWidth() const
970 {
971 return desktopGridWidth() * Screens::self()->size().width();
972 }
973
workspaceHeight() const974 int EffectsHandlerImpl::workspaceHeight() const
975 {
976 return desktopGridHeight() * Screens::self()->size().height();
977 }
978
desktopAtCoords(QPoint coords) const979 int EffectsHandlerImpl::desktopAtCoords(QPoint coords) const
980 {
981 if (auto vd = VirtualDesktopManager::self()->grid().at(coords)) {
982 return vd->x11DesktopNumber();
983 }
984 return 0;
985 }
986
desktopGridCoords(int id) const987 QPoint EffectsHandlerImpl::desktopGridCoords(int id) const
988 {
989 return VirtualDesktopManager::self()->grid().gridCoords(id);
990 }
991
desktopCoords(int id) const992 QPoint EffectsHandlerImpl::desktopCoords(int id) const
993 {
994 QPoint coords = VirtualDesktopManager::self()->grid().gridCoords(id);
995 if (coords.x() == -1)
996 return QPoint(-1, -1);
997 const QSize displaySize = Screens::self()->size();
998 return QPoint(coords.x() * displaySize.width(), coords.y() * displaySize.height());
999 }
1000
desktopAbove(int desktop,bool wrap) const1001 int EffectsHandlerImpl::desktopAbove(int desktop, bool wrap) const
1002 {
1003 return getDesktop<DesktopAbove>(desktop, wrap);
1004 }
1005
desktopToRight(int desktop,bool wrap) const1006 int EffectsHandlerImpl::desktopToRight(int desktop, bool wrap) const
1007 {
1008 return getDesktop<DesktopRight>(desktop, wrap);
1009 }
1010
desktopBelow(int desktop,bool wrap) const1011 int EffectsHandlerImpl::desktopBelow(int desktop, bool wrap) const
1012 {
1013 return getDesktop<DesktopBelow>(desktop, wrap);
1014 }
1015
desktopToLeft(int desktop,bool wrap) const1016 int EffectsHandlerImpl::desktopToLeft(int desktop, bool wrap) const
1017 {
1018 return getDesktop<DesktopLeft>(desktop, wrap);
1019 }
1020
desktopName(int desktop) const1021 QString EffectsHandlerImpl::desktopName(int desktop) const
1022 {
1023 const VirtualDesktop *vd = VirtualDesktopManager::self()->desktopForX11Id(desktop);
1024 return vd ? vd->name() : QString();
1025 }
1026
optionRollOverDesktops() const1027 bool EffectsHandlerImpl::optionRollOverDesktops() const
1028 {
1029 return options->isRollOverDesktops();
1030 }
1031
animationTimeFactor() const1032 double EffectsHandlerImpl::animationTimeFactor() const
1033 {
1034 return options->animationTimeFactor();
1035 }
1036
findWindow(WId id) const1037 EffectWindow* EffectsHandlerImpl::findWindow(WId id) const
1038 {
1039 if (X11Client *w = Workspace::self()->findClient(Predicate::WindowMatch, id))
1040 return w->effectWindow();
1041 if (Unmanaged* w = Workspace::self()->findUnmanaged(id))
1042 return w->effectWindow();
1043 return nullptr;
1044 }
1045
findWindow(KWaylandServer::SurfaceInterface * surf) const1046 EffectWindow* EffectsHandlerImpl::findWindow(KWaylandServer::SurfaceInterface *surf) const
1047 {
1048 if (waylandServer()) {
1049 if (AbstractClient *w = waylandServer()->findClient(surf)) {
1050 return w->effectWindow();
1051 }
1052 }
1053 return nullptr;
1054 }
1055
findWindow(QWindow * w) const1056 EffectWindow *EffectsHandlerImpl::findWindow(QWindow *w) const
1057 {
1058 if (Toplevel *toplevel = workspace()->findInternal(w)) {
1059 return toplevel->effectWindow();
1060 }
1061 return nullptr;
1062 }
1063
findWindow(const QUuid & id) const1064 EffectWindow *EffectsHandlerImpl::findWindow(const QUuid &id) const
1065 {
1066 if (const auto client = workspace()->findAbstractClient([&id] (const AbstractClient *c) { return c->internalId() == id; })) {
1067 return client->effectWindow();
1068 }
1069 if (const auto unmanaged = workspace()->findUnmanaged([&id] (const Unmanaged *c) { return c->internalId() == id; })) {
1070 return unmanaged->effectWindow();
1071 }
1072 return nullptr;
1073 }
1074
stackingOrder() const1075 EffectWindowList EffectsHandlerImpl::stackingOrder() const
1076 {
1077 QList<Toplevel *> list = Workspace::self()->xStackingOrder();
1078 EffectWindowList ret;
1079 for (Toplevel *t : list) {
1080 if (EffectWindow *w = effectWindow(t))
1081 ret.append(w);
1082 }
1083 return ret;
1084 }
1085
setElevatedWindow(KWin::EffectWindow * w,bool set)1086 void EffectsHandlerImpl::setElevatedWindow(KWin::EffectWindow* w, bool set)
1087 {
1088 elevated_windows.removeAll(w);
1089 if (set)
1090 elevated_windows.append(w);
1091 }
1092
setTabBoxWindow(EffectWindow * w)1093 void EffectsHandlerImpl::setTabBoxWindow(EffectWindow* w)
1094 {
1095 #ifdef KWIN_BUILD_TABBOX
1096 if (auto c = qobject_cast<AbstractClient *>(static_cast<EffectWindowImpl *>(w)->window())) {
1097 TabBox::TabBox::self()->setCurrentClient(c);
1098 }
1099 #else
1100 Q_UNUSED(w)
1101 #endif
1102 }
1103
setTabBoxDesktop(int desktop)1104 void EffectsHandlerImpl::setTabBoxDesktop(int desktop)
1105 {
1106 #ifdef KWIN_BUILD_TABBOX
1107 TabBox::TabBox::self()->setCurrentDesktop(desktop);
1108 #else
1109 Q_UNUSED(desktop)
1110 #endif
1111 }
1112
currentTabBoxWindowList() const1113 EffectWindowList EffectsHandlerImpl::currentTabBoxWindowList() const
1114 {
1115 #ifdef KWIN_BUILD_TABBOX
1116 const auto clients = TabBox::TabBox::self()->currentClientList();
1117 EffectWindowList ret;
1118 ret.reserve(clients.size());
1119 std::transform(std::cbegin(clients), std::cend(clients),
1120 std::back_inserter(ret),
1121 [](auto client) { return client->effectWindow(); });
1122 return ret;
1123 #else
1124 return EffectWindowList();
1125 #endif
1126 }
1127
refTabBox()1128 void EffectsHandlerImpl::refTabBox()
1129 {
1130 #ifdef KWIN_BUILD_TABBOX
1131 TabBox::TabBox::self()->reference();
1132 #endif
1133 }
1134
unrefTabBox()1135 void EffectsHandlerImpl::unrefTabBox()
1136 {
1137 #ifdef KWIN_BUILD_TABBOX
1138 TabBox::TabBox::self()->unreference();
1139 #endif
1140 }
1141
closeTabBox()1142 void EffectsHandlerImpl::closeTabBox()
1143 {
1144 #ifdef KWIN_BUILD_TABBOX
1145 TabBox::TabBox::self()->close();
1146 #endif
1147 }
1148
currentTabBoxDesktopList() const1149 QList< int > EffectsHandlerImpl::currentTabBoxDesktopList() const
1150 {
1151 #ifdef KWIN_BUILD_TABBOX
1152 return TabBox::TabBox::self()->currentDesktopList();
1153 #else
1154 return QList< int >();
1155 #endif
1156 }
1157
currentTabBoxDesktop() const1158 int EffectsHandlerImpl::currentTabBoxDesktop() const
1159 {
1160 #ifdef KWIN_BUILD_TABBOX
1161 return TabBox::TabBox::self()->currentDesktop();
1162 #else
1163 return -1;
1164 #endif
1165 }
1166
currentTabBoxWindow() const1167 EffectWindow* EffectsHandlerImpl::currentTabBoxWindow() const
1168 {
1169 #ifdef KWIN_BUILD_TABBOX
1170 if (auto c = TabBox::TabBox::self()->currentClient())
1171 return c->effectWindow();
1172 #endif
1173 return nullptr;
1174 }
1175
addRepaintFull()1176 void EffectsHandlerImpl::addRepaintFull()
1177 {
1178 m_compositor->addRepaintFull();
1179 }
1180
addRepaint(const QRect & r)1181 void EffectsHandlerImpl::addRepaint(const QRect& r)
1182 {
1183 m_compositor->addRepaint(r);
1184 }
1185
addRepaint(const QRegion & r)1186 void EffectsHandlerImpl::addRepaint(const QRegion& r)
1187 {
1188 m_compositor->addRepaint(r);
1189 }
1190
addRepaint(int x,int y,int w,int h)1191 void EffectsHandlerImpl::addRepaint(int x, int y, int w, int h)
1192 {
1193 m_compositor->addRepaint(x, y, w, h);
1194 }
1195
activeScreen() const1196 int EffectsHandlerImpl::activeScreen() const
1197 {
1198 return kwinApp()->platform()->enabledOutputs().indexOf(workspace()->activeOutput());
1199 }
1200
numScreens() const1201 int EffectsHandlerImpl::numScreens() const
1202 {
1203 return Screens::self()->count();
1204 }
1205
screenNumber(const QPoint & pos) const1206 int EffectsHandlerImpl::screenNumber(const QPoint& pos) const
1207 {
1208 return Screens::self()->number(pos);
1209 }
1210
clientArea(clientAreaOption opt,int screen,int desktop) const1211 QRect EffectsHandlerImpl::clientArea(clientAreaOption opt, int screen, int desktop) const
1212 {
1213 return Workspace::self()->clientArea(opt, screen, desktop);
1214 }
1215
clientArea(clientAreaOption opt,const EffectWindow * c) const1216 QRect EffectsHandlerImpl::clientArea(clientAreaOption opt, const EffectWindow* c) const
1217 {
1218 const Toplevel* t = static_cast< const EffectWindowImpl* >(c)->window();
1219 return Workspace::self()->clientArea(opt, t);
1220 }
1221
clientArea(clientAreaOption opt,const QPoint & p,int desktop) const1222 QRect EffectsHandlerImpl::clientArea(clientAreaOption opt, const QPoint& p, int desktop) const
1223 {
1224 return Workspace::self()->clientArea(opt, p, desktop);
1225 }
1226
virtualScreenGeometry() const1227 QRect EffectsHandlerImpl::virtualScreenGeometry() const
1228 {
1229 return Screens::self()->geometry();
1230 }
1231
virtualScreenSize() const1232 QSize EffectsHandlerImpl::virtualScreenSize() const
1233 {
1234 return Screens::self()->size();
1235 }
1236
defineCursor(Qt::CursorShape shape)1237 void EffectsHandlerImpl::defineCursor(Qt::CursorShape shape)
1238 {
1239 input()->pointer()->setEffectsOverrideCursor(shape);
1240 }
1241
checkInputWindowEvent(QMouseEvent * e)1242 bool EffectsHandlerImpl::checkInputWindowEvent(QMouseEvent *e)
1243 {
1244 if (m_grabbedMouseEffects.isEmpty()) {
1245 return false;
1246 }
1247 Q_FOREACH (Effect *effect, m_grabbedMouseEffects) {
1248 effect->windowInputMouseEvent(e);
1249 }
1250 return true;
1251 }
1252
checkInputWindowEvent(QWheelEvent * e)1253 bool EffectsHandlerImpl::checkInputWindowEvent(QWheelEvent *e)
1254 {
1255 if (m_grabbedMouseEffects.isEmpty()) {
1256 return false;
1257 }
1258 Q_FOREACH (Effect *effect, m_grabbedMouseEffects) {
1259 effect->windowInputMouseEvent(e);
1260 }
1261 return true;
1262 }
1263
connectNotify(const QMetaMethod & signal)1264 void EffectsHandlerImpl::connectNotify(const QMetaMethod &signal)
1265 {
1266 if (signal == QMetaMethod::fromSignal(&EffectsHandler::cursorShapeChanged)) {
1267 if (!m_trackingCursorChanges) {
1268 connect(Cursors::self()->mouse(), &Cursor::cursorChanged, this, &EffectsHandler::cursorShapeChanged);
1269 Cursors::self()->mouse()->startCursorTracking();
1270 }
1271 ++m_trackingCursorChanges;
1272 }
1273 EffectsHandler::connectNotify(signal);
1274 }
1275
disconnectNotify(const QMetaMethod & signal)1276 void EffectsHandlerImpl::disconnectNotify(const QMetaMethod &signal)
1277 {
1278 if (signal == QMetaMethod::fromSignal(&EffectsHandler::cursorShapeChanged)) {
1279 Q_ASSERT(m_trackingCursorChanges > 0);
1280 if (!--m_trackingCursorChanges) {
1281 Cursors::self()->mouse()->stopCursorTracking();
1282 disconnect(Cursors::self()->mouse(), &Cursor::cursorChanged, this, &EffectsHandler::cursorShapeChanged);
1283 }
1284 }
1285 EffectsHandler::disconnectNotify(signal);
1286 }
1287
1288
checkInputWindowStacking()1289 void EffectsHandlerImpl::checkInputWindowStacking()
1290 {
1291 if (m_grabbedMouseEffects.isEmpty()) {
1292 return;
1293 }
1294 doCheckInputWindowStacking();
1295 }
1296
doCheckInputWindowStacking()1297 void EffectsHandlerImpl::doCheckInputWindowStacking()
1298 {
1299 }
1300
cursorPos() const1301 QPoint EffectsHandlerImpl::cursorPos() const
1302 {
1303 return Cursors::self()->mouse()->pos();
1304 }
1305
reserveElectricBorder(ElectricBorder border,Effect * effect)1306 void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border, Effect *effect)
1307 {
1308 ScreenEdges::self()->reserve(border, effect, "borderActivated");
1309 }
1310
unreserveElectricBorder(ElectricBorder border,Effect * effect)1311 void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border, Effect *effect)
1312 {
1313 ScreenEdges::self()->unreserve(border, effect);
1314 }
1315
registerTouchBorder(ElectricBorder border,QAction * action)1316 void EffectsHandlerImpl::registerTouchBorder(ElectricBorder border, QAction *action)
1317 {
1318 ScreenEdges::self()->reserveTouch(border, action);
1319 }
1320
unregisterTouchBorder(ElectricBorder border,QAction * action)1321 void EffectsHandlerImpl::unregisterTouchBorder(ElectricBorder border, QAction *action)
1322 {
1323 ScreenEdges::self()->unreserveTouch(border, action);
1324 }
1325
scenePainter()1326 QPainter *EffectsHandlerImpl::scenePainter()
1327 {
1328 return m_scene->scenePainter();
1329 }
1330
toggleEffect(const QString & name)1331 void EffectsHandlerImpl::toggleEffect(const QString& name)
1332 {
1333 if (isEffectLoaded(name))
1334 unloadEffect(name);
1335 else
1336 loadEffect(name);
1337 }
1338
loadedEffects() const1339 QStringList EffectsHandlerImpl::loadedEffects() const
1340 {
1341 QStringList listModules;
1342 listModules.reserve(loaded_effects.count());
1343 std::transform(loaded_effects.constBegin(), loaded_effects.constEnd(),
1344 std::back_inserter(listModules),
1345 [](const EffectPair &pair) { return pair.first; });
1346 return listModules;
1347 }
1348
listOfEffects() const1349 QStringList EffectsHandlerImpl::listOfEffects() const
1350 {
1351 return m_effectLoader->listOfKnownEffects();
1352 }
1353
loadEffect(const QString & name)1354 bool EffectsHandlerImpl::loadEffect(const QString& name)
1355 {
1356 makeOpenGLContextCurrent();
1357 m_compositor->addRepaintFull();
1358
1359 return m_effectLoader->loadEffect(name);
1360 }
1361
unloadEffect(const QString & name)1362 void EffectsHandlerImpl::unloadEffect(const QString& name)
1363 {
1364 auto it = std::find_if(effect_order.begin(), effect_order.end(),
1365 [name](EffectPair &pair) {
1366 return pair.first == name;
1367 }
1368 );
1369 if (it == effect_order.end()) {
1370 qCDebug(KWIN_CORE) << "EffectsHandler::unloadEffect : Effect not loaded :" << name;
1371 return;
1372 }
1373
1374 qCDebug(KWIN_CORE) << "EffectsHandler::unloadEffect : Unloading Effect :" << name;
1375 destroyEffect((*it).second);
1376 effect_order.erase(it);
1377 effectsChanged();
1378
1379 m_compositor->addRepaintFull();
1380 }
1381
destroyEffect(Effect * effect)1382 void EffectsHandlerImpl::destroyEffect(Effect *effect)
1383 {
1384 makeOpenGLContextCurrent();
1385
1386 if (fullscreen_effect == effect) {
1387 setActiveFullScreenEffect(nullptr);
1388 }
1389
1390 if (keyboard_grab_effect == effect) {
1391 ungrabKeyboard();
1392 }
1393
1394 stopMouseInterception(effect);
1395
1396 const QList<QByteArray> properties = m_propertiesForEffects.keys();
1397 for (const QByteArray &property : properties) {
1398 removeSupportProperty(property, effect);
1399 }
1400
1401 delete effect;
1402 }
1403
reconfigureEffect(const QString & name)1404 void EffectsHandlerImpl::reconfigureEffect(const QString& name)
1405 {
1406 for (QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it)
1407 if ((*it).first == name) {
1408 kwinApp()->config()->reparseConfiguration();
1409 makeOpenGLContextCurrent();
1410 (*it).second->reconfigure(Effect::ReconfigureAll);
1411 return;
1412 }
1413 }
1414
isEffectLoaded(const QString & name) const1415 bool EffectsHandlerImpl::isEffectLoaded(const QString& name) const
1416 {
1417 auto it = std::find_if(loaded_effects.constBegin(), loaded_effects.constEnd(),
1418 [&name](const EffectPair &pair) { return pair.first == name; });
1419 return it != loaded_effects.constEnd();
1420 }
1421
isEffectSupported(const QString & name)1422 bool EffectsHandlerImpl::isEffectSupported(const QString &name)
1423 {
1424 // If the effect is loaded, it is obviously supported.
1425 if (isEffectLoaded(name)) {
1426 return true;
1427 }
1428
1429 // next checks might require a context
1430 makeOpenGLContextCurrent();
1431 m_compositor->addRepaintFull();
1432
1433 return m_effectLoader->isEffectSupported(name);
1434
1435 }
1436
areEffectsSupported(const QStringList & names)1437 QList<bool> EffectsHandlerImpl::areEffectsSupported(const QStringList &names)
1438 {
1439 QList<bool> retList;
1440 retList.reserve(names.count());
1441 std::transform(names.constBegin(), names.constEnd(),
1442 std::back_inserter(retList),
1443 [this](const QString &name) {
1444 return isEffectSupported(name);
1445 });
1446 return retList;
1447 }
1448
reloadEffect(Effect * effect)1449 void EffectsHandlerImpl::reloadEffect(Effect *effect)
1450 {
1451 QString effectName;
1452 for (QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
1453 if ((*it).second == effect) {
1454 effectName = (*it).first;
1455 break;
1456 }
1457 }
1458 if (!effectName.isNull()) {
1459 unloadEffect(effectName);
1460 m_effectLoader->loadEffect(effectName);
1461 }
1462 }
1463
effectsChanged()1464 void EffectsHandlerImpl::effectsChanged()
1465 {
1466 loaded_effects.clear();
1467 m_activeEffects.clear(); // it's possible to have a reconfigure and a quad rebuild between two paint cycles - bug #308201
1468
1469 loaded_effects.reserve(effect_order.count());
1470 std::copy(effect_order.constBegin(), effect_order.constEnd(),
1471 std::back_inserter(loaded_effects));
1472
1473 m_activeEffects.reserve(loaded_effects.count());
1474 }
1475
activeEffects() const1476 QStringList EffectsHandlerImpl::activeEffects() const
1477 {
1478 QStringList ret;
1479 for(QVector< KWin::EffectPair >::const_iterator it = loaded_effects.constBegin(),
1480 end = loaded_effects.constEnd(); it != end; ++it) {
1481 if (it->second->isActive()) {
1482 ret << it->first;
1483 }
1484 }
1485 return ret;
1486 }
1487
blocksDirectScanout() const1488 bool EffectsHandlerImpl::blocksDirectScanout() const
1489 {
1490 for(QVector< KWin::EffectPair >::const_iterator it = loaded_effects.constBegin(),
1491 end = loaded_effects.constEnd(); it != end; ++it) {
1492 if (it->second->isActive() && it->second->blocksDirectScanout()) {
1493 return true;
1494 }
1495 }
1496 return false;
1497 }
1498
waylandDisplay() const1499 KWaylandServer::Display *EffectsHandlerImpl::waylandDisplay() const
1500 {
1501 if (waylandServer()) {
1502 return waylandServer()->display();
1503 }
1504 return nullptr;
1505 }
1506
effectFrame(EffectFrameStyle style,bool staticSize,const QPoint & position,Qt::Alignment alignment) const1507 EffectFrame* EffectsHandlerImpl::effectFrame(EffectFrameStyle style, bool staticSize, const QPoint& position, Qt::Alignment alignment) const
1508 {
1509 return new EffectFrameImpl(style, staticSize, position, alignment);
1510 }
1511
1512
kwinOption(KWinOption kwopt)1513 QVariant EffectsHandlerImpl::kwinOption(KWinOption kwopt)
1514 {
1515 switch (kwopt) {
1516 case CloseButtonCorner: {
1517 // TODO: this could become per window and be derived from the actual position in the deco
1518 const auto settings = Decoration::DecorationBridge::self()->settings();
1519 return settings && settings->decorationButtonsLeft().contains(KDecoration2::DecorationButtonType::Close) ? Qt::TopLeftCorner : Qt::TopRightCorner;
1520 }
1521 case SwitchDesktopOnScreenEdge:
1522 return ScreenEdges::self()->isDesktopSwitching();
1523 case SwitchDesktopOnScreenEdgeMovingWindows:
1524 return ScreenEdges::self()->isDesktopSwitchingMovingClients();
1525 default:
1526 return QVariant(); // an invalid one
1527 }
1528 }
1529
supportInformation(const QString & name) const1530 QString EffectsHandlerImpl::supportInformation(const QString &name) const
1531 {
1532 auto it = std::find_if(loaded_effects.constBegin(), loaded_effects.constEnd(),
1533 [name](const EffectPair &pair) { return pair.first == name; });
1534 if (it == loaded_effects.constEnd()) {
1535 return QString();
1536 }
1537
1538 QString support((*it).first + QLatin1String(":\n"));
1539 const QMetaObject *metaOptions = (*it).second->metaObject();
1540 for (int i=0; i<metaOptions->propertyCount(); ++i) {
1541 const QMetaProperty property = metaOptions->property(i);
1542 if (qstrcmp(property.name(), "objectName") == 0) {
1543 continue;
1544 }
1545 support += QString::fromUtf8(property.name()) + QLatin1String(": ") + (*it).second->property(property.name()).toString() + QLatin1Char('\n');
1546 }
1547
1548 return support;
1549 }
1550
1551
isScreenLocked() const1552 bool EffectsHandlerImpl::isScreenLocked() const
1553 {
1554 return ScreenLockerWatcher::self()->isLocked();
1555 }
1556
debug(const QString & name,const QString & parameter) const1557 QString EffectsHandlerImpl::debug(const QString& name, const QString& parameter) const
1558 {
1559 QString internalName = name.toLower();;
1560 for (QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
1561 if ((*it).first == internalName) {
1562 return it->second->debug(parameter);
1563 }
1564 }
1565 return QString();
1566 }
1567
makeOpenGLContextCurrent()1568 bool EffectsHandlerImpl::makeOpenGLContextCurrent()
1569 {
1570 return m_scene->makeOpenGLContextCurrent();
1571 }
1572
doneOpenGLContextCurrent()1573 void EffectsHandlerImpl::doneOpenGLContextCurrent()
1574 {
1575 m_scene->doneOpenGLContextCurrent();
1576 }
1577
animationsSupported() const1578 bool EffectsHandlerImpl::animationsSupported() const
1579 {
1580 static const QByteArray forceEnvVar = qgetenv("KWIN_EFFECTS_FORCE_ANIMATIONS");
1581 if (!forceEnvVar.isEmpty()) {
1582 static const int forceValue = forceEnvVar.toInt();
1583 return forceValue == 1;
1584 }
1585 return m_scene->animationsSupported();
1586 }
1587
highlightWindows(const QVector<EffectWindow * > & windows)1588 void EffectsHandlerImpl::highlightWindows(const QVector<EffectWindow *> &windows)
1589 {
1590 Effect *e = provides(Effect::HighlightWindows);
1591 if (!e) {
1592 return;
1593 }
1594 e->perform(Effect::HighlightWindows, QVariantList{QVariant::fromValue(windows)});
1595 }
1596
cursorImage() const1597 PlatformCursorImage EffectsHandlerImpl::cursorImage() const
1598 {
1599 return kwinApp()->platform()->cursorImage();
1600 }
1601
hideCursor()1602 void EffectsHandlerImpl::hideCursor()
1603 {
1604 kwinApp()->platform()->hideCursor();
1605 }
1606
showCursor()1607 void EffectsHandlerImpl::showCursor()
1608 {
1609 kwinApp()->platform()->showCursor();
1610 }
1611
startInteractiveWindowSelection(std::function<void (KWin::EffectWindow *)> callback)1612 void EffectsHandlerImpl::startInteractiveWindowSelection(std::function<void(KWin::EffectWindow*)> callback)
1613 {
1614 kwinApp()->platform()->startInteractiveWindowSelection(
1615 [callback] (KWin::Toplevel *t) {
1616 if (t && t->effectWindow()) {
1617 callback(t->effectWindow());
1618 } else {
1619 callback(nullptr);
1620 }
1621 }
1622 );
1623 }
1624
startInteractivePositionSelection(std::function<void (const QPoint &)> callback)1625 void EffectsHandlerImpl::startInteractivePositionSelection(std::function<void(const QPoint&)> callback)
1626 {
1627 kwinApp()->platform()->startInteractivePositionSelection(callback);
1628 }
1629
showOnScreenMessage(const QString & message,const QString & iconName)1630 void EffectsHandlerImpl::showOnScreenMessage(const QString &message, const QString &iconName)
1631 {
1632 OSD::show(message, iconName);
1633 }
1634
hideOnScreenMessage(OnScreenMessageHideFlags flags)1635 void EffectsHandlerImpl::hideOnScreenMessage(OnScreenMessageHideFlags flags)
1636 {
1637 OSD::HideFlags osdFlags;
1638 if (flags.testFlag(OnScreenMessageHideFlag::SkipsCloseAnimation)) {
1639 osdFlags |= OSD::HideFlag::SkipCloseAnimation;
1640 }
1641 OSD::hide(osdFlags);
1642 }
1643
config() const1644 KSharedConfigPtr EffectsHandlerImpl::config() const
1645 {
1646 return kwinApp()->config();
1647 }
1648
inputConfig() const1649 KSharedConfigPtr EffectsHandlerImpl::inputConfig() const
1650 {
1651 return InputConfig::self()->inputConfig();
1652 }
1653
findEffect(const QString & name) const1654 Effect *EffectsHandlerImpl::findEffect(const QString &name) const
1655 {
1656 auto it = std::find_if(loaded_effects.constBegin(), loaded_effects.constEnd(),
1657 [name] (const EffectPair &pair) {
1658 return pair.first == name;
1659 }
1660 );
1661 if (it == loaded_effects.constEnd()) {
1662 return nullptr;
1663 }
1664 return (*it).second;
1665 }
1666
renderEffectQuickView(EffectQuickView * w) const1667 void EffectsHandlerImpl::renderEffectQuickView(EffectQuickView *w) const
1668 {
1669 if (!w->isVisible()) {
1670 return;
1671 }
1672 scene()->paintEffectQuickView(w);
1673 }
1674
sessionState() const1675 SessionState EffectsHandlerImpl::sessionState() const
1676 {
1677 return Workspace::self()->sessionManager()->state();
1678 }
1679
screens() const1680 QList<EffectScreen *> EffectsHandlerImpl::screens() const
1681 {
1682 return m_effectScreens;
1683 }
1684
screenAt(const QPoint & point) const1685 EffectScreen *EffectsHandlerImpl::screenAt(const QPoint &point) const
1686 {
1687 return m_effectScreens.value(screenNumber(point));
1688 }
1689
findScreen(const QString & name) const1690 EffectScreen *EffectsHandlerImpl::findScreen(const QString &name) const
1691 {
1692 for (EffectScreen *screen : qAsConst(m_effectScreens)) {
1693 if (screen->name() == name) {
1694 return screen;
1695 }
1696 }
1697 return nullptr;
1698 }
1699
findScreen(int screenId) const1700 EffectScreen *EffectsHandlerImpl::findScreen(int screenId) const
1701 {
1702 return m_effectScreens.value(screenId);
1703 }
1704
slotOutputEnabled(AbstractOutput * output)1705 void EffectsHandlerImpl::slotOutputEnabled(AbstractOutput *output)
1706 {
1707 EffectScreen *screen = new EffectScreenImpl(output, this);
1708 m_effectScreens.append(screen);
1709 Q_EMIT screenAdded(screen);
1710 }
1711
slotOutputDisabled(AbstractOutput * output)1712 void EffectsHandlerImpl::slotOutputDisabled(AbstractOutput *output)
1713 {
1714 auto it = std::find_if(m_effectScreens.begin(), m_effectScreens.end(), [&output](EffectScreen *screen) {
1715 return static_cast<EffectScreenImpl *>(screen)->platformOutput() == output;
1716 });
1717 if (it != m_effectScreens.end()) {
1718 EffectScreen *screen = *it;
1719 m_effectScreens.erase(it);
1720 Q_EMIT screenRemoved(screen);
1721 delete screen;
1722 }
1723 }
1724
renderScreen(EffectScreen * screen)1725 void EffectsHandlerImpl::renderScreen(EffectScreen *screen)
1726 {
1727 auto output = static_cast<EffectScreenImpl *>(screen)->platformOutput();
1728 scene()->paintScreen(output, Compositor::self()->windowsToRender());
1729 }
1730
1731 //****************************************
1732 // EffectScreenImpl
1733 //****************************************
1734
EffectScreenImpl(AbstractOutput * output,QObject * parent)1735 EffectScreenImpl::EffectScreenImpl(AbstractOutput *output, QObject *parent)
1736 : EffectScreen(parent)
1737 , m_platformOutput(output)
1738 {
1739 connect(output, &AbstractOutput::aboutToChange, this, &EffectScreen::aboutToChange);
1740 connect(output, &AbstractOutput::changed, this, &EffectScreen::changed);
1741 connect(output, &AbstractOutput::wakeUp, this, &EffectScreen::wakeUp);
1742 connect(output, &AbstractOutput::aboutToTurnOff, this, &EffectScreen::aboutToTurnOff);
1743 connect(output, &AbstractOutput::scaleChanged, this, &EffectScreen::devicePixelRatioChanged);
1744 connect(output, &AbstractOutput::geometryChanged, this, &EffectScreen::geometryChanged);
1745 }
1746
platformOutput() const1747 AbstractOutput *EffectScreenImpl::platformOutput() const
1748 {
1749 return m_platformOutput;
1750 }
1751
name() const1752 QString EffectScreenImpl::name() const
1753 {
1754 return m_platformOutput->name();
1755 }
1756
devicePixelRatio() const1757 qreal EffectScreenImpl::devicePixelRatio() const
1758 {
1759 return m_platformOutput->scale();
1760 }
1761
geometry() const1762 QRect EffectScreenImpl::geometry() const
1763 {
1764 return m_platformOutput->geometry();
1765 }
1766
transform() const1767 EffectScreen::Transform EffectScreenImpl::transform() const
1768 {
1769 return EffectScreen::Transform(m_platformOutput->transform());
1770 }
1771
1772 //****************************************
1773 // EffectWindowImpl
1774 //****************************************
1775
EffectWindowImpl(Toplevel * toplevel)1776 EffectWindowImpl::EffectWindowImpl(Toplevel *toplevel)
1777 : EffectWindow(toplevel)
1778 , toplevel(toplevel)
1779 , sw(nullptr)
1780 {
1781 // Deleted windows are not managed. So, when windowClosed signal is
1782 // emitted, effects can't distinguish managed windows from unmanaged
1783 // windows(e.g. combo box popups, popup menus, etc). Save value of the
1784 // managed property during construction of EffectWindow. At that time,
1785 // parent can be Client, XdgShellClient, or Unmanaged. So, later on, when
1786 // an instance of Deleted becomes parent of the EffectWindow, effects
1787 // can still figure out whether it is/was a managed window.
1788 managed = toplevel->isClient();
1789
1790 waylandClient = qobject_cast<KWin::WaylandClient *>(toplevel) != nullptr;
1791 x11Client = qobject_cast<KWin::X11Client *>(toplevel) != nullptr ||
1792 qobject_cast<KWin::Unmanaged *>(toplevel) != nullptr;
1793 }
1794
~EffectWindowImpl()1795 EffectWindowImpl::~EffectWindowImpl()
1796 {
1797 QVariant cachedTextureVariant = data(LanczosCacheRole);
1798 if (cachedTextureVariant.isValid()) {
1799 GLTexture *cachedTexture = static_cast< GLTexture*>(cachedTextureVariant.value<void*>());
1800 delete cachedTexture;
1801 }
1802 }
1803
isPaintingEnabled()1804 bool EffectWindowImpl::isPaintingEnabled()
1805 {
1806 return sceneWindow()->isPaintingEnabled();
1807 }
1808
enablePainting(int reason)1809 void EffectWindowImpl::enablePainting(int reason)
1810 {
1811 sceneWindow()->enablePainting(reason);
1812 }
1813
disablePainting(int reason)1814 void EffectWindowImpl::disablePainting(int reason)
1815 {
1816 sceneWindow()->disablePainting(reason);
1817 }
1818
addRepaint(const QRect & r)1819 void EffectWindowImpl::addRepaint(const QRect &r)
1820 {
1821 toplevel->addRepaint(r);
1822 }
1823
addRepaint(int x,int y,int w,int h)1824 void EffectWindowImpl::addRepaint(int x, int y, int w, int h)
1825 {
1826 toplevel->addRepaint(x, y, w, h);
1827 }
1828
addRepaintFull()1829 void EffectWindowImpl::addRepaintFull()
1830 {
1831 toplevel->addRepaintFull();
1832 }
1833
addLayerRepaint(const QRect & r)1834 void EffectWindowImpl::addLayerRepaint(const QRect &r)
1835 {
1836 toplevel->addLayerRepaint(r);
1837 }
1838
addLayerRepaint(int x,int y,int w,int h)1839 void EffectWindowImpl::addLayerRepaint(int x, int y, int w, int h)
1840 {
1841 toplevel->addLayerRepaint(x, y, w, h);
1842 }
1843
group() const1844 const EffectWindowGroup* EffectWindowImpl::group() const
1845 {
1846 if (auto c = qobject_cast<X11Client *>(toplevel)) {
1847 return c->group()->effectGroup();
1848 }
1849 return nullptr; // TODO
1850 }
1851
refWindow()1852 void EffectWindowImpl::refWindow()
1853 {
1854 if (auto d = qobject_cast<Deleted *>(toplevel)) {
1855 return d->refWindow();
1856 }
1857 abort(); // TODO
1858 }
1859
unrefWindow()1860 void EffectWindowImpl::unrefWindow()
1861 {
1862 if (auto d = qobject_cast<Deleted *>(toplevel)) {
1863 return d->unrefWindow(); // delays deletion in case
1864 }
1865 abort(); // TODO
1866 }
1867
1868 #define TOPLEVEL_HELPER( rettype, prototype, toplevelPrototype) \
1869 rettype EffectWindowImpl::prototype ( ) const \
1870 { \
1871 return toplevel->toplevelPrototype(); \
1872 }
1873
1874 TOPLEVEL_HELPER(double, opacity, opacity)
1875 TOPLEVEL_HELPER(bool, hasAlpha, hasAlpha)
1876 TOPLEVEL_HELPER(int, x, x)
1877 TOPLEVEL_HELPER(int, y, y)
1878 TOPLEVEL_HELPER(int, width, width)
1879 TOPLEVEL_HELPER(int, height, height)
1880 TOPLEVEL_HELPER(QPoint, pos, pos)
1881 TOPLEVEL_HELPER(QSize, size, size)
1882 TOPLEVEL_HELPER(int, screen, screen)
1883 TOPLEVEL_HELPER(QRect, geometry, frameGeometry)
1884 TOPLEVEL_HELPER(QRect, frameGeometry, frameGeometry)
1885 TOPLEVEL_HELPER(QRect, bufferGeometry, bufferGeometry)
1886 TOPLEVEL_HELPER(QRect, clientGeometry, clientGeometry)
1887 TOPLEVEL_HELPER(QRect, expandedGeometry, visibleGeometry)
1888 TOPLEVEL_HELPER(QRect, rect, rect)
1889 TOPLEVEL_HELPER(int, desktop, desktop)
1890 TOPLEVEL_HELPER(bool, isDesktop, isDesktop)
1891 TOPLEVEL_HELPER(bool, isDock, isDock)
1892 TOPLEVEL_HELPER(bool, isToolbar, isToolbar)
1893 TOPLEVEL_HELPER(bool, isMenu, isMenu)
1894 TOPLEVEL_HELPER(bool, isNormalWindow, isNormalWindow)
1895 TOPLEVEL_HELPER(bool, isDialog, isDialog)
1896 TOPLEVEL_HELPER(bool, isSplash, isSplash)
1897 TOPLEVEL_HELPER(bool, isUtility, isUtility)
1898 TOPLEVEL_HELPER(bool, isDropdownMenu, isDropdownMenu)
1899 TOPLEVEL_HELPER(bool, isPopupMenu, isPopupMenu)
1900 TOPLEVEL_HELPER(bool, isTooltip, isTooltip)
1901 TOPLEVEL_HELPER(bool, isNotification, isNotification)
1902 TOPLEVEL_HELPER(bool, isCriticalNotification, isCriticalNotification)
1903 TOPLEVEL_HELPER(bool, isOnScreenDisplay, isOnScreenDisplay)
1904 TOPLEVEL_HELPER(bool, isComboBox, isComboBox)
1905 TOPLEVEL_HELPER(bool, isDNDIcon, isDNDIcon)
1906 TOPLEVEL_HELPER(bool, isDeleted, isDeleted)
1907 TOPLEVEL_HELPER(QString, windowRole, windowRole)
1908 TOPLEVEL_HELPER(QStringList, activities, activities)
1909 TOPLEVEL_HELPER(bool, skipsCloseAnimation, skipsCloseAnimation)
1910 TOPLEVEL_HELPER(KWaylandServer::SurfaceInterface *, surface, surface)
1911 TOPLEVEL_HELPER(bool, isPopupWindow, isPopupWindow)
1912 TOPLEVEL_HELPER(bool, isOutline, isOutline)
1913 TOPLEVEL_HELPER(bool, isLockScreen, isLockScreen)
1914 TOPLEVEL_HELPER(pid_t, pid, pid)
1915 TOPLEVEL_HELPER(qlonglong, windowId, window)
1916
1917 #undef TOPLEVEL_HELPER
1918
1919 #define CLIENT_HELPER_WITH_DELETED( rettype, prototype, propertyname, defaultValue ) \
1920 rettype EffectWindowImpl::prototype ( ) const \
1921 { \
1922 auto client = qobject_cast<AbstractClient *>(toplevel); \
1923 if (client) { \
1924 return client->propertyname(); \
1925 } \
1926 auto deleted = qobject_cast<Deleted *>(toplevel); \
1927 if (deleted) { \
1928 return deleted->propertyname(); \
1929 } \
1930 return defaultValue; \
1931 }
1932
1933 CLIENT_HELPER_WITH_DELETED(bool, isMinimized, isMinimized, false)
1934 CLIENT_HELPER_WITH_DELETED(bool, isModal, isModal, false)
1935 CLIENT_HELPER_WITH_DELETED(bool, isFullScreen, isFullScreen, false)
1936 CLIENT_HELPER_WITH_DELETED(bool, keepAbove, keepAbove, false)
1937 CLIENT_HELPER_WITH_DELETED(bool, keepBelow, keepBelow, false)
1938 CLIENT_HELPER_WITH_DELETED(QString, caption, caption, QString());
1939 CLIENT_HELPER_WITH_DELETED(QVector<uint>, desktops, x11DesktopIds, QVector<uint>());
1940
1941 #undef CLIENT_HELPER_WITH_DELETED
1942
1943 // legacy from tab groups, can be removed when no effects use this any more.
isCurrentTab() const1944 bool EffectWindowImpl::isCurrentTab() const
1945 {
1946 return true;
1947 }
1948
windowClass() const1949 QString EffectWindowImpl::windowClass() const
1950 {
1951 return toplevel->resourceName() + QLatin1Char(' ') + toplevel->resourceClass();
1952 }
1953
contentsRect() const1954 QRect EffectWindowImpl::contentsRect() const
1955 {
1956 return QRect(toplevel->clientPos(), toplevel->clientSize());
1957 }
1958
windowType() const1959 NET::WindowType EffectWindowImpl::windowType() const
1960 {
1961 return toplevel->windowType();
1962 }
1963
1964 #define CLIENT_HELPER( rettype, prototype, propertyname, defaultValue ) \
1965 rettype EffectWindowImpl::prototype ( ) const \
1966 { \
1967 auto client = qobject_cast<AbstractClient *>(toplevel); \
1968 if (client) { \
1969 return client->propertyname(); \
1970 } \
1971 return defaultValue; \
1972 }
1973
CLIENT_HELPER(bool,isMovable,isMovable,false)1974 CLIENT_HELPER(bool, isMovable, isMovable, false)
1975 CLIENT_HELPER(bool, isMovableAcrossScreens, isMovableAcrossScreens, false)
1976 CLIENT_HELPER(bool, isUserMove, isInteractiveMove, false)
1977 CLIENT_HELPER(bool, isUserResize, isInteractiveResize, false)
1978 CLIENT_HELPER(QRect, iconGeometry, iconGeometry, QRect())
1979 CLIENT_HELPER(bool, isSpecialWindow, isSpecialWindow, true)
1980 CLIENT_HELPER(bool, acceptsFocus, wantsInput, true) // We don't actually know...
1981 CLIENT_HELPER(QIcon, icon, icon, QIcon())
1982 CLIENT_HELPER(bool, isSkipSwitcher, skipSwitcher, false)
1983 CLIENT_HELPER(bool, decorationHasAlpha, decorationHasAlpha, false)
1984 CLIENT_HELPER(bool, isUnresponsive, unresponsive, false)
1985
1986 #undef CLIENT_HELPER
1987
1988 QSize EffectWindowImpl::basicUnit() const
1989 {
1990 if (auto client = qobject_cast<X11Client *>(toplevel)){
1991 return client->basicUnit();
1992 }
1993 return QSize(1,1);
1994 }
1995
setWindow(Toplevel * w)1996 void EffectWindowImpl::setWindow(Toplevel* w)
1997 {
1998 toplevel = w;
1999 setParent(w);
2000 }
2001
setSceneWindow(Scene::Window * w)2002 void EffectWindowImpl::setSceneWindow(Scene::Window* w)
2003 {
2004 sw = w;
2005 }
2006
decorationInnerRect() const2007 QRect EffectWindowImpl::decorationInnerRect() const
2008 {
2009 return toplevel->rect() - toplevel->frameMargins();
2010 }
2011
readProperty(long atom,long type,int format) const2012 QByteArray EffectWindowImpl::readProperty(long atom, long type, int format) const
2013 {
2014 if (!kwinApp()->x11Connection()) {
2015 return QByteArray();
2016 }
2017 return readWindowProperty(window()->window(), atom, type, format);
2018 }
2019
deleteProperty(long int atom) const2020 void EffectWindowImpl::deleteProperty(long int atom) const
2021 {
2022 if (kwinApp()->x11Connection()) {
2023 deleteWindowProperty(window()->window(), atom);
2024 }
2025 }
2026
findModal()2027 EffectWindow* EffectWindowImpl::findModal()
2028 {
2029 auto client = qobject_cast<AbstractClient *>(toplevel);
2030 if (!client) {
2031 return nullptr;
2032 }
2033
2034 AbstractClient *modal = client->findModal();
2035 if (modal) {
2036 return modal->effectWindow();
2037 }
2038
2039 return nullptr;
2040 }
2041
transientFor()2042 EffectWindow* EffectWindowImpl::transientFor()
2043 {
2044 auto client = qobject_cast<AbstractClient *>(toplevel);
2045 if (!client) {
2046 return nullptr;
2047 }
2048
2049 AbstractClient *transientFor = client->transientFor();
2050 if (transientFor) {
2051 return transientFor->effectWindow();
2052 }
2053
2054 return nullptr;
2055 }
2056
internalWindow() const2057 QWindow *EffectWindowImpl::internalWindow() const
2058 {
2059 auto client = qobject_cast<InternalClient *>(toplevel);
2060 if (!client) {
2061 return nullptr;
2062 }
2063 return client->internalWindow();
2064 }
2065
2066 template <typename T>
getMainWindows(T * c)2067 EffectWindowList getMainWindows(T *c)
2068 {
2069 const auto mainclients = c->mainClients();
2070 EffectWindowList ret;
2071 ret.reserve(mainclients.size());
2072 std::transform(std::cbegin(mainclients), std::cend(mainclients),
2073 std::back_inserter(ret),
2074 [](auto client) { return client->effectWindow(); });
2075 return ret;
2076 }
2077
mainWindows() const2078 EffectWindowList EffectWindowImpl::mainWindows() const
2079 {
2080 if (auto client = qobject_cast<AbstractClient *>(toplevel)) {
2081 return getMainWindows(client);
2082 }
2083 if (auto deleted = qobject_cast<Deleted *>(toplevel)) {
2084 return getMainWindows(deleted);
2085 }
2086 return {};
2087 }
2088
setData(int role,const QVariant & data)2089 void EffectWindowImpl::setData(int role, const QVariant &data)
2090 {
2091 if (!data.isNull())
2092 dataMap[ role ] = data;
2093 else
2094 dataMap.remove(role);
2095 Q_EMIT effects->windowDataChanged(this, role);
2096 }
2097
data(int role) const2098 QVariant EffectWindowImpl::data(int role) const
2099 {
2100 return dataMap.value(role);
2101 }
2102
effectWindow(Toplevel * w)2103 EffectWindow* effectWindow(Toplevel* w)
2104 {
2105 EffectWindowImpl* ret = w->effectWindow();
2106 return ret;
2107 }
2108
effectWindow(Scene::Window * w)2109 EffectWindow* effectWindow(Scene::Window* w)
2110 {
2111 EffectWindowImpl* ret = w->window()->effectWindow();
2112 ret->setSceneWindow(w);
2113 return ret;
2114 }
2115
elevate(bool elevate)2116 void EffectWindowImpl::elevate(bool elevate)
2117 {
2118 effects->setElevatedWindow(this, elevate);
2119 }
2120
minimize()2121 void EffectWindowImpl::minimize()
2122 {
2123 if (auto client = qobject_cast<AbstractClient *>(toplevel)) {
2124 client->minimize();
2125 }
2126 }
2127
unminimize()2128 void EffectWindowImpl::unminimize()
2129 {
2130 if (auto client = qobject_cast<AbstractClient *>(toplevel)) {
2131 client->unminimize();
2132 }
2133 }
2134
closeWindow()2135 void EffectWindowImpl::closeWindow()
2136 {
2137 if (auto client = qobject_cast<AbstractClient *>(toplevel)) {
2138 client->closeWindow();
2139 }
2140 }
2141
referencePreviousWindowPixmap()2142 void EffectWindowImpl::referencePreviousWindowPixmap()
2143 {
2144 if (sw) {
2145 sw->referencePreviousPixmap();
2146 }
2147 }
2148
unreferencePreviousWindowPixmap()2149 void EffectWindowImpl::unreferencePreviousWindowPixmap()
2150 {
2151 if (sw) {
2152 sw->unreferencePreviousPixmap();
2153 }
2154 }
2155
isManaged() const2156 bool EffectWindowImpl::isManaged() const
2157 {
2158 return managed;
2159 }
2160
isWaylandClient() const2161 bool EffectWindowImpl::isWaylandClient() const
2162 {
2163 return waylandClient;
2164 }
2165
isX11Client() const2166 bool EffectWindowImpl::isX11Client() const
2167 {
2168 return x11Client;
2169 }
2170
2171
2172 //****************************************
2173 // EffectWindowGroupImpl
2174 //****************************************
2175
2176
members() const2177 EffectWindowList EffectWindowGroupImpl::members() const
2178 {
2179 const auto memberList = group->members();
2180 EffectWindowList ret;
2181 ret.reserve(memberList.size());
2182 std::transform(std::cbegin(memberList), std::cend(memberList),
2183 std::back_inserter(ret),
2184 [](auto toplevel) { return toplevel->effectWindow(); });
2185 return ret;
2186 }
2187
2188 //****************************************
2189 // EffectFrameImpl
2190 //****************************************
2191
EffectFrameImpl(EffectFrameStyle style,bool staticSize,QPoint position,Qt::Alignment alignment)2192 EffectFrameImpl::EffectFrameImpl(EffectFrameStyle style, bool staticSize, QPoint position, Qt::Alignment alignment)
2193 : QObject(nullptr)
2194 , EffectFrame()
2195 , m_style(style)
2196 , m_static(staticSize)
2197 , m_point(position)
2198 , m_alignment(alignment)
2199 , m_shader(nullptr)
2200 , m_theme(new Plasma::Theme(this))
2201 {
2202 if (m_style == EffectFrameStyled) {
2203 m_frame.setImagePath(QStringLiteral("widgets/background"));
2204 m_frame.setCacheAllRenderedFrames(true);
2205 connect(m_theme, &Plasma::Theme::themeChanged, this, &EffectFrameImpl::plasmaThemeChanged);
2206 }
2207 m_selection.setImagePath(QStringLiteral("widgets/viewitem"));
2208 m_selection.setElementPrefix(QStringLiteral("hover"));
2209 m_selection.setCacheAllRenderedFrames(true);
2210 m_selection.setEnabledBorders(Plasma::FrameSvg::AllBorders);
2211
2212 m_sceneFrame = Compositor::self()->scene()->createEffectFrame(this);
2213 }
2214
~EffectFrameImpl()2215 EffectFrameImpl::~EffectFrameImpl()
2216 {
2217 delete m_sceneFrame;
2218 }
2219
font() const2220 const QFont& EffectFrameImpl::font() const
2221 {
2222 return m_font;
2223 }
2224
setFont(const QFont & font)2225 void EffectFrameImpl::setFont(const QFont& font)
2226 {
2227 if (m_font == font) {
2228 return;
2229 }
2230 m_font = font;
2231 QRect oldGeom = m_geometry;
2232 if (!m_text.isEmpty()) {
2233 autoResize();
2234 }
2235 if (oldGeom == m_geometry) {
2236 // Wasn't updated in autoResize()
2237 m_sceneFrame->freeTextFrame();
2238 }
2239 }
2240
free()2241 void EffectFrameImpl::free()
2242 {
2243 m_sceneFrame->free();
2244 }
2245
geometry() const2246 const QRect& EffectFrameImpl::geometry() const
2247 {
2248 return m_geometry;
2249 }
2250
setGeometry(const QRect & geometry,bool force)2251 void EffectFrameImpl::setGeometry(const QRect& geometry, bool force)
2252 {
2253 QRect oldGeom = m_geometry;
2254 m_geometry = geometry;
2255 if (m_geometry == oldGeom && !force) {
2256 return;
2257 }
2258 effects->addRepaint(oldGeom);
2259 effects->addRepaint(m_geometry);
2260 if (m_geometry.size() == oldGeom.size() && !force) {
2261 return;
2262 }
2263
2264 if (m_style == EffectFrameStyled) {
2265 qreal left, top, right, bottom;
2266 m_frame.getMargins(left, top, right, bottom); // m_geometry is the inner geometry
2267 m_frame.resizeFrame(m_geometry.adjusted(-left, -top, right, bottom).size());
2268 }
2269
2270 free();
2271 }
2272
icon() const2273 const QIcon& EffectFrameImpl::icon() const
2274 {
2275 return m_icon;
2276 }
2277
setIcon(const QIcon & icon)2278 void EffectFrameImpl::setIcon(const QIcon& icon)
2279 {
2280 m_icon = icon;
2281 if (isCrossFade()) {
2282 m_sceneFrame->crossFadeIcon();
2283 }
2284 if (m_iconSize.isEmpty() && !m_icon.availableSizes().isEmpty()) { // Set a size if we don't already have one
2285 setIconSize(m_icon.availableSizes().constFirst());
2286 }
2287 m_sceneFrame->freeIconFrame();
2288 }
2289
iconSize() const2290 const QSize& EffectFrameImpl::iconSize() const
2291 {
2292 return m_iconSize;
2293 }
2294
setIconSize(const QSize & size)2295 void EffectFrameImpl::setIconSize(const QSize& size)
2296 {
2297 if (m_iconSize == size) {
2298 return;
2299 }
2300 m_iconSize = size;
2301 autoResize();
2302 m_sceneFrame->freeIconFrame();
2303 }
2304
plasmaThemeChanged()2305 void EffectFrameImpl::plasmaThemeChanged()
2306 {
2307 free();
2308 }
2309
render(const QRegion & region,double opacity,double frameOpacity)2310 void EffectFrameImpl::render(const QRegion ®ion, double opacity, double frameOpacity)
2311 {
2312 if (m_geometry.isEmpty()) {
2313 return; // Nothing to display
2314 }
2315 m_shader = nullptr;
2316 setScreenProjectionMatrix(static_cast<EffectsHandlerImpl*>(effects)->scene()->screenProjectionMatrix());
2317 effects->paintEffectFrame(this, region, opacity, frameOpacity);
2318 }
2319
finalRender(QRegion region,double opacity,double frameOpacity) const2320 void EffectFrameImpl::finalRender(QRegion region, double opacity, double frameOpacity) const
2321 {
2322 region = infiniteRegion(); // TODO: Old region doesn't seem to work with OpenGL
2323
2324 m_sceneFrame->render(region, opacity, frameOpacity);
2325 }
2326
alignment() const2327 Qt::Alignment EffectFrameImpl::alignment() const
2328 {
2329 return m_alignment;
2330 }
2331
2332
2333 void
align(QRect & geometry)2334 EffectFrameImpl::align(QRect &geometry)
2335 {
2336 if (m_alignment & Qt::AlignLeft)
2337 geometry.moveLeft(m_point.x());
2338 else if (m_alignment & Qt::AlignRight)
2339 geometry.moveLeft(m_point.x() - geometry.width());
2340 else
2341 geometry.moveLeft(m_point.x() - geometry.width() / 2);
2342 if (m_alignment & Qt::AlignTop)
2343 geometry.moveTop(m_point.y());
2344 else if (m_alignment & Qt::AlignBottom)
2345 geometry.moveTop(m_point.y() - geometry.height());
2346 else
2347 geometry.moveTop(m_point.y() - geometry.height() / 2);
2348 }
2349
2350
setAlignment(Qt::Alignment alignment)2351 void EffectFrameImpl::setAlignment(Qt::Alignment alignment)
2352 {
2353 m_alignment = alignment;
2354 align(m_geometry);
2355 setGeometry(m_geometry);
2356 }
2357
setPosition(const QPoint & point)2358 void EffectFrameImpl::setPosition(const QPoint& point)
2359 {
2360 m_point = point;
2361 QRect geometry = m_geometry; // this is important, setGeometry need call repaint for old & new geometry
2362 align(geometry);
2363 setGeometry(geometry);
2364 }
2365
text() const2366 const QString& EffectFrameImpl::text() const
2367 {
2368 return m_text;
2369 }
2370
setText(const QString & text)2371 void EffectFrameImpl::setText(const QString& text)
2372 {
2373 if (m_text == text) {
2374 return;
2375 }
2376 if (isCrossFade()) {
2377 m_sceneFrame->crossFadeText();
2378 }
2379 m_text = text;
2380 QRect oldGeom = m_geometry;
2381 autoResize();
2382 if (oldGeom == m_geometry) {
2383 // Wasn't updated in autoResize()
2384 m_sceneFrame->freeTextFrame();
2385 }
2386 }
2387
setSelection(const QRect & selection)2388 void EffectFrameImpl::setSelection(const QRect& selection)
2389 {
2390 if (selection == m_selectionGeometry) {
2391 return;
2392 }
2393 m_selectionGeometry = selection;
2394 if (m_selectionGeometry.size() != m_selection.frameSize().toSize()) {
2395 m_selection.resizeFrame(m_selectionGeometry.size());
2396 }
2397 // TODO; optimize to only recreate when resizing
2398 m_sceneFrame->freeSelection();
2399 }
2400
autoResize()2401 void EffectFrameImpl::autoResize()
2402 {
2403 if (m_static)
2404 return; // Not automatically resizing
2405
2406 QRect geometry;
2407 // Set size
2408 if (!m_text.isEmpty()) {
2409 QFontMetrics metrics(m_font);
2410 geometry.setSize(metrics.size(0, m_text));
2411 }
2412 if (!m_icon.isNull() && !m_iconSize.isEmpty()) {
2413 geometry.setLeft(-m_iconSize.width());
2414 if (m_iconSize.height() > geometry.height())
2415 geometry.setHeight(m_iconSize.height());
2416 }
2417
2418 align(geometry);
2419 setGeometry(geometry);
2420 }
2421
styledTextColor()2422 QColor EffectFrameImpl::styledTextColor()
2423 {
2424 return m_theme->color(Plasma::Theme::TextColor);
2425 }
2426
2427 } // namespace
2428