Warning, file /plasma/kwin/src/effects.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org> 0006 SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "effects.h" 0012 0013 #include <config-kwin.h> 0014 0015 #include "core/output.h" 0016 #include "effectloader.h" 0017 #include "effectsadaptor.h" 0018 #if KWIN_BUILD_ACTIVITIES 0019 #include "activities.h" 0020 #endif 0021 #include "core/renderbackend.h" 0022 #include "core/renderlayer.h" 0023 #include "cursor.h" 0024 #include "deleted.h" 0025 #include "group.h" 0026 #include "input_event.h" 0027 #include "internalwindow.h" 0028 #include "osd.h" 0029 #include "pointer_input.h" 0030 #include "scene/itemrenderer.h" 0031 #include "unmanaged.h" 0032 #include "x11window.h" 0033 #if KWIN_BUILD_TABBOX 0034 #include "tabbox.h" 0035 #endif 0036 #include "screenedge.h" 0037 #include "scripting/scriptedeffect.h" 0038 #if KWIN_BUILD_SCREENLOCKER 0039 #include "screenlockerwatcher.h" 0040 #endif 0041 #include "composite.h" 0042 #include "decorations/decorationbridge.h" 0043 #include "inputmethod.h" 0044 #include "inputpanelv1window.h" 0045 #include "kwinglutils.h" 0046 #include "scene/windowitem.h" 0047 #include "utils/xcbutils.h" 0048 #include "virtualdesktops.h" 0049 #include "wayland_server.h" 0050 #include "waylandwindow.h" 0051 #include "window_property_notify_x11_filter.h" 0052 #include "workspace.h" 0053 0054 #include <KDecoration2/Decoration> 0055 #include <KDecoration2/DecorationSettings> 0056 0057 #include <QDebug> 0058 #include <QMouseEvent> 0059 #include <QPainter> 0060 #include <QQmlEngine> 0061 #include <QQuickItem> 0062 #include <QQuickWindow> 0063 #include <QStandardPaths> 0064 #include <QWheelEvent> 0065 0066 namespace KWin 0067 { 0068 //--------------------- 0069 // Static 0070 0071 static QByteArray readWindowProperty(xcb_window_t win, xcb_atom_t atom, xcb_atom_t type, int format) 0072 { 0073 if (win == XCB_WINDOW_NONE) { 0074 return QByteArray(); 0075 } 0076 uint32_t len = 32768; 0077 for (;;) { 0078 Xcb::Property prop(false, win, atom, XCB_ATOM_ANY, 0, len); 0079 if (prop.isNull()) { 0080 // get property failed 0081 return QByteArray(); 0082 } 0083 if (prop->bytes_after > 0) { 0084 len *= 2; 0085 continue; 0086 } 0087 return prop.toByteArray(format, type); 0088 } 0089 } 0090 0091 static void deleteWindowProperty(xcb_window_t win, long int atom) 0092 { 0093 if (win == XCB_WINDOW_NONE) { 0094 return; 0095 } 0096 xcb_delete_property(kwinApp()->x11Connection(), win, atom); 0097 } 0098 0099 static xcb_atom_t registerSupportProperty(const QByteArray &propertyName) 0100 { 0101 auto c = kwinApp()->x11Connection(); 0102 if (!c) { 0103 return XCB_ATOM_NONE; 0104 } 0105 // get the atom for the propertyName 0106 UniqueCPtr<xcb_intern_atom_reply_t> atomReply(xcb_intern_atom_reply(c, 0107 xcb_intern_atom_unchecked(c, false, propertyName.size(), propertyName.constData()), 0108 nullptr)); 0109 if (!atomReply) { 0110 return XCB_ATOM_NONE; 0111 } 0112 // announce property on root window 0113 unsigned char dummy = 0; 0114 xcb_change_property(c, XCB_PROP_MODE_REPLACE, kwinApp()->x11RootWindow(), atomReply->atom, atomReply->atom, 8, 1, &dummy); 0115 // TODO: add to _NET_SUPPORTED 0116 return atomReply->atom; 0117 } 0118 0119 //--------------------- 0120 0121 EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, WorkspaceScene *scene) 0122 : EffectsHandler(Compositor::self()->backend()->compositingType()) 0123 , keyboard_grab_effect(nullptr) 0124 , fullscreen_effect(nullptr) 0125 , m_compositor(compositor) 0126 , m_scene(scene) 0127 , m_effectLoader(new EffectLoader(this)) 0128 , m_trackingCursorChanges(0) 0129 { 0130 qRegisterMetaType<QVector<KWin::EffectWindow *>>(); 0131 qRegisterMetaType<KWin::SessionState>(); 0132 connect(m_effectLoader, &AbstractEffectLoader::effectLoaded, this, [this](Effect *effect, const QString &name) { 0133 effect_order.insert(effect->requestedEffectChainPosition(), EffectPair(name, effect)); 0134 loaded_effects << EffectPair(name, effect); 0135 effectsChanged(); 0136 }); 0137 m_effectLoader->setConfig(kwinApp()->config()); 0138 new EffectsAdaptor(this); 0139 QDBusConnection dbus = QDBusConnection::sessionBus(); 0140 dbus.registerObject(QStringLiteral("/Effects"), this); 0141 0142 Workspace *ws = Workspace::self(); 0143 VirtualDesktopManager *vds = VirtualDesktopManager::self(); 0144 connect(ws, &Workspace::showingDesktopChanged, this, [this](bool showing, bool animated) { 0145 if (animated) { 0146 Q_EMIT showingDesktopChanged(showing); 0147 } 0148 }); 0149 connect(ws, &Workspace::currentDesktopChanged, this, [this](int old, Window *window) { 0150 const int newDesktop = VirtualDesktopManager::self()->current(); 0151 if (old != 0 && newDesktop != old) { 0152 Q_EMIT desktopChanged(old, newDesktop, window ? window->effectWindow() : nullptr); 0153 // TODO: remove in 4.10 0154 Q_EMIT desktopChanged(old, newDesktop); 0155 } 0156 }); 0157 connect(ws, &Workspace::currentDesktopChanging, this, [this](uint currentDesktop, QPointF offset, KWin::Window *window) { 0158 Q_EMIT desktopChanging(currentDesktop, offset, window ? window->effectWindow() : nullptr); 0159 }); 0160 connect(ws, &Workspace::currentDesktopChangingCancelled, this, [this]() { 0161 Q_EMIT desktopChangingCancelled(); 0162 }); 0163 connect(ws, &Workspace::desktopPresenceChanged, this, [this](Window *window, int old) { 0164 if (!window->effectWindow()) { 0165 return; 0166 } 0167 Q_EMIT desktopPresenceChanged(window->effectWindow(), old, window->desktop()); 0168 }); 0169 connect(ws, &Workspace::windowAdded, this, [this](Window *window) { 0170 if (window->readyForPainting()) { 0171 slotWindowShown(window); 0172 } else { 0173 connect(window, &Window::windowShown, this, &EffectsHandlerImpl::slotWindowShown); 0174 } 0175 }); 0176 connect(ws, &Workspace::unmanagedAdded, this, [this](Unmanaged *u) { 0177 // it's never initially ready but has synthetic 50ms delay 0178 connect(u, &Window::windowShown, this, &EffectsHandlerImpl::slotUnmanagedShown); 0179 }); 0180 connect(ws, &Workspace::internalWindowAdded, this, [this](InternalWindow *window) { 0181 setupWindowConnections(window); 0182 Q_EMIT windowAdded(window->effectWindow()); 0183 }); 0184 connect(ws, &Workspace::windowActivated, this, [this](Window *window) { 0185 Q_EMIT windowActivated(window ? window->effectWindow() : nullptr); 0186 }); 0187 connect(ws, &Workspace::deletedRemoved, this, [this](KWin::Deleted *d) { 0188 Q_EMIT windowDeleted(d->effectWindow()); 0189 elevated_windows.removeAll(d->effectWindow()); 0190 }); 0191 connect(ws->sessionManager(), &SessionManager::stateChanged, this, &KWin::EffectsHandler::sessionStateChanged); 0192 connect(vds, &VirtualDesktopManager::countChanged, this, &EffectsHandler::numberDesktopsChanged); 0193 connect(vds, &VirtualDesktopManager::layoutChanged, this, [this](int width, int height) { 0194 Q_EMIT desktopGridSizeChanged(QSize(width, height)); 0195 Q_EMIT desktopGridWidthChanged(width); 0196 Q_EMIT desktopGridHeightChanged(height); 0197 }); 0198 connect(Cursors::self()->mouse(), &Cursor::mouseChanged, this, &EffectsHandler::mouseChanged); 0199 connect(ws, &Workspace::geometryChanged, this, &EffectsHandler::virtualScreenSizeChanged); 0200 connect(ws, &Workspace::geometryChanged, this, &EffectsHandler::virtualScreenGeometryChanged); 0201 #if KWIN_BUILD_ACTIVITIES 0202 if (Activities *activities = Workspace::self()->activities()) { 0203 connect(activities, &Activities::added, this, &EffectsHandler::activityAdded); 0204 connect(activities, &Activities::removed, this, &EffectsHandler::activityRemoved); 0205 connect(activities, &Activities::currentChanged, this, &EffectsHandler::currentActivityChanged); 0206 } 0207 #endif 0208 connect(ws, &Workspace::stackingOrderChanged, this, &EffectsHandler::stackingOrderChanged); 0209 #if KWIN_BUILD_TABBOX 0210 TabBox::TabBox *tabBox = workspace()->tabbox(); 0211 connect(tabBox, &TabBox::TabBox::tabBoxAdded, this, &EffectsHandler::tabBoxAdded); 0212 connect(tabBox, &TabBox::TabBox::tabBoxUpdated, this, &EffectsHandler::tabBoxUpdated); 0213 connect(tabBox, &TabBox::TabBox::tabBoxClosed, this, &EffectsHandler::tabBoxClosed); 0214 connect(tabBox, &TabBox::TabBox::tabBoxKeyEvent, this, &EffectsHandler::tabBoxKeyEvent); 0215 #endif 0216 connect(workspace()->screenEdges(), &ScreenEdges::approaching, this, &EffectsHandler::screenEdgeApproaching); 0217 #if KWIN_BUILD_SCREENLOCKER 0218 connect(kwinApp()->screenLockerWatcher(), &ScreenLockerWatcher::locked, this, &EffectsHandler::screenLockingChanged); 0219 connect(kwinApp()->screenLockerWatcher(), &ScreenLockerWatcher::aboutToLock, this, &EffectsHandler::screenAboutToLock); 0220 #endif 0221 0222 connect(kwinApp(), &Application::x11ConnectionChanged, this, [this]() { 0223 registered_atoms.clear(); 0224 for (auto it = m_propertiesForEffects.keyBegin(); it != m_propertiesForEffects.keyEnd(); it++) { 0225 const auto atom = registerSupportProperty(*it); 0226 if (atom == XCB_ATOM_NONE) { 0227 continue; 0228 } 0229 m_compositor->keepSupportProperty(atom); 0230 m_managedProperties.insert(*it, atom); 0231 registerPropertyType(atom, true); 0232 } 0233 if (kwinApp()->x11Connection()) { 0234 m_x11WindowPropertyNotify = std::make_unique<WindowPropertyNotifyX11Filter>(this); 0235 } else { 0236 m_x11WindowPropertyNotify.reset(); 0237 } 0238 Q_EMIT xcbConnectionChanged(); 0239 }); 0240 0241 if (kwinApp()->x11Connection()) { 0242 m_x11WindowPropertyNotify = std::make_unique<WindowPropertyNotifyX11Filter>(this); 0243 } 0244 0245 // connect all clients 0246 for (Window *window : ws->allClientList()) { 0247 if (window->readyForPainting()) { 0248 setupWindowConnections(window); 0249 } else { 0250 connect(window, &Window::windowShown, this, &EffectsHandlerImpl::slotWindowShown); 0251 } 0252 } 0253 for (Unmanaged *u : ws->unmanagedList()) { 0254 setupUnmanagedConnections(u); 0255 } 0256 for (InternalWindow *window : ws->internalWindows()) { 0257 setupWindowConnections(window); 0258 } 0259 0260 connect(ws, &Workspace::outputAdded, this, &EffectsHandlerImpl::slotOutputAdded); 0261 connect(ws, &Workspace::outputRemoved, this, &EffectsHandlerImpl::slotOutputRemoved); 0262 0263 const QList<Output *> outputs = ws->outputs(); 0264 for (Output *output : outputs) { 0265 slotOutputAdded(output); 0266 } 0267 0268 if (auto inputMethod = kwinApp()->inputMethod()) { 0269 connect(inputMethod, &InputMethod::panelChanged, this, &EffectsHandlerImpl::inputPanelChanged); 0270 } 0271 0272 reconfigure(); 0273 } 0274 0275 EffectsHandlerImpl::~EffectsHandlerImpl() 0276 { 0277 unloadAllEffects(); 0278 } 0279 0280 void EffectsHandlerImpl::unloadAllEffects() 0281 { 0282 for (const EffectPair &pair : std::as_const(loaded_effects)) { 0283 destroyEffect(pair.second); 0284 } 0285 0286 effect_order.clear(); 0287 m_effectLoader->clear(); 0288 0289 effectsChanged(); 0290 } 0291 0292 void EffectsHandlerImpl::setupWindowConnections(Window *window) 0293 { 0294 connect(window, &Window::windowClosed, this, &EffectsHandlerImpl::slotWindowClosed); 0295 connect(window, static_cast<void (Window::*)(KWin::Window *, MaximizeMode)>(&Window::clientMaximizedStateChanged), 0296 this, &EffectsHandlerImpl::slotClientMaximized); 0297 connect(window, static_cast<void (Window::*)(KWin::Window *, MaximizeMode)>(&Window::clientMaximizedStateAboutToChange), 0298 this, [this](KWin::Window *window, MaximizeMode m) { 0299 if (EffectWindowImpl *w = window->effectWindow()) { 0300 Q_EMIT windowMaximizedStateAboutToChange(w, m & MaximizeHorizontal, m & MaximizeVertical); 0301 } 0302 }); 0303 connect(window, &Window::frameGeometryAboutToChange, 0304 this, [this](KWin::Window *window) { 0305 if (EffectWindowImpl *w = window->effectWindow()) { 0306 Q_EMIT windowFrameGeometryAboutToChange(w); 0307 } 0308 }); 0309 connect(window, &Window::clientStartUserMovedResized, this, [this](Window *window) { 0310 Q_EMIT windowStartUserMovedResized(window->effectWindow()); 0311 }); 0312 connect(window, &Window::clientStepUserMovedResized, this, [this](Window *window, const QRectF &geometry) { 0313 Q_EMIT windowStepUserMovedResized(window->effectWindow(), geometry); 0314 }); 0315 connect(window, &Window::clientFinishUserMovedResized, this, [this](Window *window) { 0316 Q_EMIT windowFinishUserMovedResized(window->effectWindow()); 0317 }); 0318 connect(window, &Window::opacityChanged, this, &EffectsHandlerImpl::slotOpacityChanged); 0319 connect(window, &Window::clientMinimized, this, [this](Window *window, bool animate) { 0320 // TODO: notify effects even if it should not animate? 0321 if (animate) { 0322 Q_EMIT windowMinimized(window->effectWindow()); 0323 } 0324 }); 0325 connect(window, &Window::clientUnminimized, this, [this](Window *window, bool animate) { 0326 // TODO: notify effects even if it should not animate? 0327 if (animate) { 0328 Q_EMIT windowUnminimized(window->effectWindow()); 0329 } 0330 }); 0331 connect(window, &Window::modalChanged, this, &EffectsHandlerImpl::slotClientModalityChanged); 0332 connect(window, &Window::geometryShapeChanged, this, &EffectsHandlerImpl::slotGeometryShapeChanged); 0333 connect(window, &Window::frameGeometryChanged, this, &EffectsHandlerImpl::slotFrameGeometryChanged); 0334 connect(window, &Window::damaged, this, &EffectsHandlerImpl::slotWindowDamaged); 0335 connect(window, &Window::unresponsiveChanged, this, [this, window](bool unresponsive) { 0336 Q_EMIT windowUnresponsiveChanged(window->effectWindow(), unresponsive); 0337 }); 0338 connect(window, &Window::windowShown, this, [this](Window *window) { 0339 Q_EMIT windowShown(window->effectWindow()); 0340 }); 0341 connect(window, &Window::windowHidden, this, [this](Window *window) { 0342 Q_EMIT windowHidden(window->effectWindow()); 0343 }); 0344 connect(window, &Window::keepAboveChanged, this, [this, window](bool above) { 0345 Q_EMIT windowKeepAboveChanged(window->effectWindow()); 0346 }); 0347 connect(window, &Window::keepBelowChanged, this, [this, window](bool below) { 0348 Q_EMIT windowKeepBelowChanged(window->effectWindow()); 0349 }); 0350 connect(window, &Window::fullScreenChanged, this, [this, window]() { 0351 Q_EMIT windowFullScreenChanged(window->effectWindow()); 0352 }); 0353 connect(window, &Window::visibleGeometryChanged, this, [this, window]() { 0354 Q_EMIT windowExpandedGeometryChanged(window->effectWindow()); 0355 }); 0356 connect(window, &Window::decorationChanged, this, [this, window]() { 0357 Q_EMIT windowDecorationChanged(window->effectWindow()); 0358 }); 0359 } 0360 0361 void EffectsHandlerImpl::setupUnmanagedConnections(Unmanaged *u) 0362 { 0363 connect(u, &Unmanaged::windowClosed, this, &EffectsHandlerImpl::slotWindowClosed); 0364 connect(u, &Unmanaged::opacityChanged, this, &EffectsHandlerImpl::slotOpacityChanged); 0365 connect(u, &Unmanaged::geometryShapeChanged, this, &EffectsHandlerImpl::slotGeometryShapeChanged); 0366 connect(u, &Unmanaged::frameGeometryChanged, this, &EffectsHandlerImpl::slotFrameGeometryChanged); 0367 connect(u, &Unmanaged::damaged, this, &EffectsHandlerImpl::slotWindowDamaged); 0368 connect(u, &Unmanaged::visibleGeometryChanged, this, [this, u]() { 0369 Q_EMIT windowExpandedGeometryChanged(u->effectWindow()); 0370 }); 0371 connect(u, &Unmanaged::frameGeometryAboutToChange, this, [this](Window *window) { 0372 if (EffectWindowImpl *w = window->effectWindow()) { 0373 Q_EMIT windowFrameGeometryAboutToChange(w); 0374 } 0375 }); 0376 } 0377 0378 void EffectsHandlerImpl::reconfigure() 0379 { 0380 m_effectLoader->queryAndLoadAll(); 0381 } 0382 0383 // the idea is that effects call this function again which calls the next one 0384 void EffectsHandlerImpl::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) 0385 { 0386 if (m_currentPaintScreenIterator != m_activeEffects.constEnd()) { 0387 (*m_currentPaintScreenIterator++)->prePaintScreen(data, presentTime); 0388 --m_currentPaintScreenIterator; 0389 } 0390 // no special final code 0391 } 0392 0393 void EffectsHandlerImpl::paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) 0394 { 0395 if (m_currentPaintScreenIterator != m_activeEffects.constEnd()) { 0396 (*m_currentPaintScreenIterator++)->paintScreen(mask, region, data); 0397 --m_currentPaintScreenIterator; 0398 } else { 0399 m_scene->finalPaintScreen(mask, region, data); 0400 } 0401 } 0402 0403 void EffectsHandlerImpl::postPaintScreen() 0404 { 0405 if (m_currentPaintScreenIterator != m_activeEffects.constEnd()) { 0406 (*m_currentPaintScreenIterator++)->postPaintScreen(); 0407 --m_currentPaintScreenIterator; 0408 } 0409 // no special final code 0410 } 0411 0412 void EffectsHandlerImpl::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) 0413 { 0414 if (m_currentPaintWindowIterator != m_activeEffects.constEnd()) { 0415 (*m_currentPaintWindowIterator++)->prePaintWindow(w, data, presentTime); 0416 --m_currentPaintWindowIterator; 0417 } 0418 // no special final code 0419 } 0420 0421 void EffectsHandlerImpl::paintWindow(EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data) 0422 { 0423 if (m_currentPaintWindowIterator != m_activeEffects.constEnd()) { 0424 (*m_currentPaintWindowIterator++)->paintWindow(w, mask, region, data); 0425 --m_currentPaintWindowIterator; 0426 } else { 0427 m_scene->finalPaintWindow(static_cast<EffectWindowImpl *>(w), mask, region, data); 0428 } 0429 } 0430 0431 void EffectsHandlerImpl::postPaintWindow(EffectWindow *w) 0432 { 0433 if (m_currentPaintWindowIterator != m_activeEffects.constEnd()) { 0434 (*m_currentPaintWindowIterator++)->postPaintWindow(w); 0435 --m_currentPaintWindowIterator; 0436 } 0437 // no special final code 0438 } 0439 0440 Effect *EffectsHandlerImpl::provides(Effect::Feature ef) 0441 { 0442 for (int i = 0; i < loaded_effects.size(); ++i) { 0443 if (loaded_effects.at(i).second->provides(ef)) { 0444 return loaded_effects.at(i).second; 0445 } 0446 } 0447 return nullptr; 0448 } 0449 0450 void EffectsHandlerImpl::drawWindow(EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data) 0451 { 0452 if (m_currentDrawWindowIterator != m_activeEffects.constEnd()) { 0453 (*m_currentDrawWindowIterator++)->drawWindow(w, mask, region, data); 0454 --m_currentDrawWindowIterator; 0455 } else { 0456 m_scene->finalDrawWindow(static_cast<EffectWindowImpl *>(w), mask, region, data); 0457 } 0458 } 0459 0460 void EffectsHandlerImpl::renderWindow(EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data) 0461 { 0462 m_scene->finalDrawWindow(static_cast<EffectWindowImpl *>(w), mask, region, data); 0463 } 0464 0465 bool EffectsHandlerImpl::hasDecorationShadows() const 0466 { 0467 return false; 0468 } 0469 0470 bool EffectsHandlerImpl::decorationsHaveAlpha() const 0471 { 0472 return true; 0473 } 0474 0475 // start another painting pass 0476 void EffectsHandlerImpl::startPaint() 0477 { 0478 m_activeEffects.clear(); 0479 m_activeEffects.reserve(loaded_effects.count()); 0480 for (QVector<KWin::EffectPair>::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0481 if (it->second->isActive()) { 0482 m_activeEffects << it->second; 0483 } 0484 } 0485 m_currentDrawWindowIterator = m_activeEffects.constBegin(); 0486 m_currentPaintWindowIterator = m_activeEffects.constBegin(); 0487 m_currentPaintScreenIterator = m_activeEffects.constBegin(); 0488 } 0489 0490 void EffectsHandlerImpl::slotClientMaximized(Window *window, MaximizeMode maxMode) 0491 { 0492 bool horizontal = false; 0493 bool vertical = false; 0494 switch (maxMode) { 0495 case MaximizeHorizontal: 0496 horizontal = true; 0497 break; 0498 case MaximizeVertical: 0499 vertical = true; 0500 break; 0501 case MaximizeFull: 0502 horizontal = true; 0503 vertical = true; 0504 break; 0505 case MaximizeRestore: // fall through 0506 default: 0507 // default - nothing to do 0508 break; 0509 } 0510 if (EffectWindowImpl *w = window->effectWindow()) { 0511 Q_EMIT windowMaximizedStateChanged(w, horizontal, vertical); 0512 } 0513 } 0514 0515 void EffectsHandlerImpl::slotOpacityChanged(Window *window, qreal oldOpacity) 0516 { 0517 if (window->opacity() == oldOpacity || !window->effectWindow()) { 0518 return; 0519 } 0520 Q_EMIT windowOpacityChanged(window->effectWindow(), oldOpacity, (qreal)window->opacity()); 0521 } 0522 0523 void EffectsHandlerImpl::slotWindowShown(Window *window) 0524 { 0525 Q_ASSERT(window->isClient()); 0526 disconnect(window, &Window::windowShown, this, &EffectsHandlerImpl::slotWindowShown); 0527 setupWindowConnections(window); 0528 Q_EMIT windowAdded(window->effectWindow()); 0529 } 0530 0531 void EffectsHandlerImpl::slotUnmanagedShown(Window *window) 0532 { // regardless, unmanaged windows are -yet?- not synced anyway 0533 Q_ASSERT(qobject_cast<Unmanaged *>(window)); 0534 Unmanaged *u = static_cast<Unmanaged *>(window); 0535 setupUnmanagedConnections(u); 0536 Q_EMIT windowAdded(u->effectWindow()); 0537 } 0538 0539 void EffectsHandlerImpl::slotWindowClosed(Window *original, Deleted *d) 0540 { 0541 original->disconnect(this); 0542 if (d) { 0543 Q_EMIT windowClosed(d->effectWindow()); 0544 } 0545 } 0546 0547 void EffectsHandlerImpl::slotClientModalityChanged() 0548 { 0549 Q_EMIT windowModalityChanged(static_cast<X11Window *>(sender())->effectWindow()); 0550 } 0551 0552 void EffectsHandlerImpl::slotCurrentTabAboutToChange(EffectWindow *from, EffectWindow *to) 0553 { 0554 Q_EMIT currentTabAboutToChange(from, to); 0555 } 0556 0557 void EffectsHandlerImpl::slotTabAdded(EffectWindow *w, EffectWindow *to) 0558 { 0559 Q_EMIT tabAdded(w, to); 0560 } 0561 0562 void EffectsHandlerImpl::slotTabRemoved(EffectWindow *w, EffectWindow *leaderOfFormerGroup) 0563 { 0564 Q_EMIT tabRemoved(w, leaderOfFormerGroup); 0565 } 0566 0567 void EffectsHandlerImpl::slotWindowDamaged(Window *window) 0568 { 0569 if (!window->effectWindow()) { 0570 // can happen during tear down of window 0571 return; 0572 } 0573 Q_EMIT windowDamaged(window->effectWindow()); 0574 } 0575 0576 void EffectsHandlerImpl::slotGeometryShapeChanged(Window *window, const QRectF &old) 0577 { 0578 // during late cleanup effectWindow() may be already NULL 0579 // in some functions that may still call this 0580 if (window == nullptr || window->effectWindow() == nullptr) { 0581 return; 0582 } 0583 Q_EMIT windowGeometryShapeChanged(window->effectWindow(), old); 0584 } 0585 0586 void EffectsHandlerImpl::slotFrameGeometryChanged(Window *window, const QRectF &oldGeometry) 0587 { 0588 // effectWindow() might be nullptr during tear down of the client. 0589 if (window->effectWindow()) { 0590 Q_EMIT windowFrameGeometryChanged(window->effectWindow(), oldGeometry); 0591 } 0592 } 0593 0594 void EffectsHandlerImpl::setActiveFullScreenEffect(Effect *e) 0595 { 0596 if (fullscreen_effect == e) { 0597 return; 0598 } 0599 const bool activeChanged = (e == nullptr || fullscreen_effect == nullptr); 0600 fullscreen_effect = e; 0601 Q_EMIT activeFullScreenEffectChanged(); 0602 if (activeChanged) { 0603 const auto delegates = m_scene->delegates(); 0604 for (SceneDelegate *delegate : delegates) { 0605 RenderLoop *loop = delegate->layer()->loop(); 0606 if (fullscreen_effect) { 0607 loop->setLatencyPolicy(LatencyPolicy::LatencyExtremelyHigh); 0608 } else { 0609 loop->resetLatencyPolicy(); 0610 } 0611 } 0612 Q_EMIT hasActiveFullScreenEffectChanged(); 0613 workspace()->screenEdges()->checkBlocking(); 0614 } 0615 } 0616 0617 Effect *EffectsHandlerImpl::activeFullScreenEffect() const 0618 { 0619 return fullscreen_effect; 0620 } 0621 0622 bool EffectsHandlerImpl::hasActiveFullScreenEffect() const 0623 { 0624 return fullscreen_effect; 0625 } 0626 0627 bool EffectsHandlerImpl::grabKeyboard(Effect *effect) 0628 { 0629 if (keyboard_grab_effect != nullptr) { 0630 return false; 0631 } 0632 if (!doGrabKeyboard()) { 0633 return false; 0634 } 0635 keyboard_grab_effect = effect; 0636 return true; 0637 } 0638 0639 bool EffectsHandlerImpl::doGrabKeyboard() 0640 { 0641 return true; 0642 } 0643 0644 void EffectsHandlerImpl::ungrabKeyboard() 0645 { 0646 Q_ASSERT(keyboard_grab_effect != nullptr); 0647 doUngrabKeyboard(); 0648 keyboard_grab_effect = nullptr; 0649 } 0650 0651 void EffectsHandlerImpl::doUngrabKeyboard() 0652 { 0653 } 0654 0655 void EffectsHandlerImpl::grabbedKeyboardEvent(QKeyEvent *e) 0656 { 0657 if (keyboard_grab_effect != nullptr) { 0658 keyboard_grab_effect->grabbedKeyboardEvent(e); 0659 } 0660 } 0661 0662 void EffectsHandlerImpl::startMouseInterception(Effect *effect, Qt::CursorShape shape) 0663 { 0664 if (m_grabbedMouseEffects.contains(effect)) { 0665 return; 0666 } 0667 m_grabbedMouseEffects.append(effect); 0668 if (m_grabbedMouseEffects.size() != 1) { 0669 return; 0670 } 0671 doStartMouseInterception(shape); 0672 } 0673 0674 void EffectsHandlerImpl::doStartMouseInterception(Qt::CursorShape shape) 0675 { 0676 input()->pointer()->setEffectsOverrideCursor(shape); 0677 0678 // We want to allow global shortcuts to be triggered when moving a 0679 // window so it is possible to pick up a window and then move it to a 0680 // different desktop by using the global shortcut to switch desktop. 0681 // However, that means that some other things can also be triggered. If 0682 // an effect that fill the screen gets triggered that way, we end up in a 0683 // weird state where the move will restart after the effect closes. So to 0684 // avoid that, abort move/resize if a full screen effect starts. 0685 if (workspace()->moveResizeWindow()) { 0686 workspace()->moveResizeWindow()->endInteractiveMoveResize(); 0687 } 0688 } 0689 0690 void EffectsHandlerImpl::stopMouseInterception(Effect *effect) 0691 { 0692 if (!m_grabbedMouseEffects.contains(effect)) { 0693 return; 0694 } 0695 m_grabbedMouseEffects.removeAll(effect); 0696 if (m_grabbedMouseEffects.isEmpty()) { 0697 doStopMouseInterception(); 0698 } 0699 } 0700 0701 void EffectsHandlerImpl::doStopMouseInterception() 0702 { 0703 input()->pointer()->removeEffectsOverrideCursor(); 0704 } 0705 0706 bool EffectsHandlerImpl::isMouseInterception() const 0707 { 0708 return m_grabbedMouseEffects.count() > 0; 0709 } 0710 0711 bool EffectsHandlerImpl::touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) 0712 { 0713 // TODO: reverse call order? 0714 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0715 if (it->second->touchDown(id, pos, time)) { 0716 return true; 0717 } 0718 } 0719 return false; 0720 } 0721 0722 bool EffectsHandlerImpl::touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) 0723 { 0724 // TODO: reverse call order? 0725 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0726 if (it->second->touchMotion(id, pos, time)) { 0727 return true; 0728 } 0729 } 0730 return false; 0731 } 0732 0733 bool EffectsHandlerImpl::touchUp(qint32 id, std::chrono::microseconds time) 0734 { 0735 // TODO: reverse call order? 0736 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0737 if (it->second->touchUp(id, time)) { 0738 return true; 0739 } 0740 } 0741 return false; 0742 } 0743 0744 bool EffectsHandlerImpl::tabletToolEvent(TabletEvent *event) 0745 { 0746 // TODO: reverse call order? 0747 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0748 if (it->second->tabletToolEvent(event)) { 0749 return true; 0750 } 0751 } 0752 return false; 0753 } 0754 0755 bool EffectsHandlerImpl::tabletToolButtonEvent(uint button, bool pressed, const TabletToolId &tabletToolId, std::chrono::microseconds time) 0756 { 0757 // TODO: reverse call order? 0758 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0759 if (it->second->tabletToolButtonEvent(button, pressed, tabletToolId.m_uniqueId)) { 0760 return true; 0761 } 0762 } 0763 return false; 0764 } 0765 0766 bool EffectsHandlerImpl::tabletPadButtonEvent(uint button, bool pressed, const TabletPadId &tabletPadId, std::chrono::microseconds time) 0767 { 0768 // TODO: reverse call order? 0769 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0770 if (it->second->tabletPadButtonEvent(button, pressed, tabletPadId.data)) { 0771 return true; 0772 } 0773 } 0774 return false; 0775 } 0776 0777 bool EffectsHandlerImpl::tabletPadStripEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time) 0778 { 0779 // TODO: reverse call order? 0780 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0781 if (it->second->tabletPadStripEvent(number, position, isFinger, tabletPadId.data)) { 0782 return true; 0783 } 0784 } 0785 return false; 0786 } 0787 0788 bool EffectsHandlerImpl::tabletPadRingEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time) 0789 { 0790 // TODO: reverse call order? 0791 for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0792 if (it->second->tabletPadRingEvent(number, position, isFinger, tabletPadId.data)) { 0793 return true; 0794 } 0795 } 0796 return false; 0797 } 0798 0799 void EffectsHandlerImpl::registerPointerShortcut(Qt::KeyboardModifiers modifiers, Qt::MouseButton pointerButtons, QAction *action) 0800 { 0801 input()->registerPointerShortcut(modifiers, pointerButtons, action); 0802 } 0803 0804 void EffectsHandlerImpl::registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action) 0805 { 0806 input()->registerAxisShortcut(modifiers, axis, action); 0807 } 0808 0809 void EffectsHandlerImpl::registerRealtimeTouchpadSwipeShortcut(SwipeDirection dir, uint fingerCount, QAction *onUp, std::function<void(qreal)> progressCallback) 0810 { 0811 input()->registerRealtimeTouchpadSwipeShortcut(dir, fingerCount, onUp, progressCallback); 0812 } 0813 0814 void EffectsHandlerImpl::registerTouchpadSwipeShortcut(SwipeDirection direction, uint fingerCount, QAction *action) 0815 { 0816 input()->registerTouchpadSwipeShortcut(direction, fingerCount, action); 0817 } 0818 0819 void EffectsHandlerImpl::registerRealtimeTouchpadPinchShortcut(PinchDirection dir, uint fingerCount, QAction *onUp, std::function<void(qreal)> progressCallback) 0820 { 0821 input()->registerRealtimeTouchpadPinchShortcut(dir, fingerCount, onUp, progressCallback); 0822 } 0823 0824 void EffectsHandlerImpl::registerTouchpadPinchShortcut(PinchDirection direction, uint fingerCount, QAction *action) 0825 { 0826 input()->registerTouchpadPinchShortcut(direction, fingerCount, action); 0827 } 0828 0829 void EffectsHandlerImpl::registerTouchscreenSwipeShortcut(SwipeDirection direction, uint fingerCount, QAction *action, std::function<void(qreal)> progressCallback) 0830 { 0831 input()->registerTouchscreenSwipeShortcut(direction, fingerCount, action, progressCallback); 0832 } 0833 0834 void *EffectsHandlerImpl::getProxy(QString name) 0835 { 0836 for (QVector<EffectPair>::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 0837 if ((*it).first == name) { 0838 return (*it).second->proxy(); 0839 } 0840 } 0841 0842 return nullptr; 0843 } 0844 0845 void EffectsHandlerImpl::startMousePolling() 0846 { 0847 if (Cursors::self()->mouse()) { 0848 Cursors::self()->mouse()->startMousePolling(); 0849 } 0850 } 0851 0852 void EffectsHandlerImpl::stopMousePolling() 0853 { 0854 if (Cursors::self()->mouse()) { 0855 Cursors::self()->mouse()->stopMousePolling(); 0856 } 0857 } 0858 0859 bool EffectsHandlerImpl::hasKeyboardGrab() const 0860 { 0861 return keyboard_grab_effect != nullptr; 0862 } 0863 0864 void EffectsHandlerImpl::registerPropertyType(long atom, bool reg) 0865 { 0866 if (reg) { 0867 ++registered_atoms[atom]; // initialized to 0 if not present yet 0868 } else { 0869 if (--registered_atoms[atom] == 0) { 0870 registered_atoms.remove(atom); 0871 } 0872 } 0873 } 0874 0875 xcb_atom_t EffectsHandlerImpl::announceSupportProperty(const QByteArray &propertyName, Effect *effect) 0876 { 0877 PropertyEffectMap::iterator it = m_propertiesForEffects.find(propertyName); 0878 if (it != m_propertiesForEffects.end()) { 0879 // property has already been registered for an effect 0880 // just append Effect and return the atom stored in m_managedProperties 0881 if (!it.value().contains(effect)) { 0882 it.value().append(effect); 0883 } 0884 return m_managedProperties.value(propertyName, XCB_ATOM_NONE); 0885 } 0886 m_propertiesForEffects.insert(propertyName, QList<Effect *>() << effect); 0887 const auto atom = registerSupportProperty(propertyName); 0888 if (atom == XCB_ATOM_NONE) { 0889 return atom; 0890 } 0891 m_compositor->keepSupportProperty(atom); 0892 m_managedProperties.insert(propertyName, atom); 0893 registerPropertyType(atom, true); 0894 return atom; 0895 } 0896 0897 void EffectsHandlerImpl::removeSupportProperty(const QByteArray &propertyName, Effect *effect) 0898 { 0899 PropertyEffectMap::iterator it = m_propertiesForEffects.find(propertyName); 0900 if (it == m_propertiesForEffects.end()) { 0901 // property is not registered - nothing to do 0902 return; 0903 } 0904 if (!it.value().contains(effect)) { 0905 // property is not registered for given effect - nothing to do 0906 return; 0907 } 0908 it.value().removeAll(effect); 0909 if (!it.value().isEmpty()) { 0910 // property still registered for another effect - nothing further to do 0911 return; 0912 } 0913 const xcb_atom_t atom = m_managedProperties.take(propertyName); 0914 registerPropertyType(atom, false); 0915 m_propertiesForEffects.remove(propertyName); 0916 m_compositor->removeSupportProperty(atom); // delayed removal 0917 } 0918 0919 QByteArray EffectsHandlerImpl::readRootProperty(long atom, long type, int format) const 0920 { 0921 if (!kwinApp()->x11Connection()) { 0922 return QByteArray(); 0923 } 0924 return readWindowProperty(kwinApp()->x11RootWindow(), atom, type, format); 0925 } 0926 0927 void EffectsHandlerImpl::activateWindow(EffectWindow *effectWindow) 0928 { 0929 auto window = static_cast<EffectWindowImpl *>(effectWindow)->window(); 0930 if (window->isClient()) { 0931 Workspace::self()->activateWindow(window, true); 0932 } 0933 } 0934 0935 EffectWindow *EffectsHandlerImpl::activeWindow() const 0936 { 0937 return Workspace::self()->activeWindow() ? Workspace::self()->activeWindow()->effectWindow() : nullptr; 0938 } 0939 0940 void EffectsHandlerImpl::moveWindow(EffectWindow *w, const QPoint &pos, bool snap, double snapAdjust) 0941 { 0942 auto window = static_cast<EffectWindowImpl *>(w)->window(); 0943 if (!window->isClient() || !window->isMovable()) { 0944 return; 0945 } 0946 0947 if (snap) { 0948 window->move(Workspace::self()->adjustWindowPosition(window, pos, true, snapAdjust)); 0949 } else { 0950 window->move(pos); 0951 } 0952 } 0953 0954 void EffectsHandlerImpl::windowToDesktop(EffectWindow *w, int desktop) 0955 { 0956 auto window = static_cast<EffectWindowImpl *>(w)->window(); 0957 if (window->isClient() && !window->isDesktop() && !window->isDock()) { 0958 Workspace::self()->sendWindowToDesktop(window, desktop, true); 0959 } 0960 } 0961 0962 void EffectsHandlerImpl::windowToDesktops(EffectWindow *w, const QVector<uint> &desktopIds) 0963 { 0964 auto window = static_cast<EffectWindowImpl *>(w)->window(); 0965 if (!window->isClient() || window->isDesktop() || window->isDock()) { 0966 return; 0967 } 0968 QVector<VirtualDesktop *> desktops; 0969 desktops.reserve(desktopIds.count()); 0970 for (uint x11Id : desktopIds) { 0971 if (x11Id > VirtualDesktopManager::self()->count()) { 0972 continue; 0973 } 0974 VirtualDesktop *d = VirtualDesktopManager::self()->desktopForX11Id(x11Id); 0975 Q_ASSERT(d); 0976 if (desktops.contains(d)) { 0977 continue; 0978 } 0979 desktops << d; 0980 } 0981 window->setDesktops(desktops); 0982 } 0983 0984 void EffectsHandlerImpl::windowToScreen(EffectWindow *w, EffectScreen *screen) 0985 { 0986 auto window = static_cast<EffectWindowImpl *>(w)->window(); 0987 if (window->isClient() && !window->isDesktop() && !window->isDock()) { 0988 EffectScreenImpl *screenImpl = static_cast<EffectScreenImpl *>(screen); 0989 Workspace::self()->sendWindowToOutput(window, screenImpl->platformOutput()); 0990 } 0991 } 0992 0993 void EffectsHandlerImpl::setShowingDesktop(bool showing) 0994 { 0995 Workspace::self()->setShowingDesktop(showing); 0996 } 0997 0998 QString EffectsHandlerImpl::currentActivity() const 0999 { 1000 #if KWIN_BUILD_ACTIVITIES 1001 if (!Workspace::self()->activities()) { 1002 return QString(); 1003 } 1004 return Workspace::self()->activities()->current(); 1005 #else 1006 return QString(); 1007 #endif 1008 } 1009 1010 int EffectsHandlerImpl::currentDesktop() const 1011 { 1012 return VirtualDesktopManager::self()->current(); 1013 } 1014 1015 int EffectsHandlerImpl::numberOfDesktops() const 1016 { 1017 return VirtualDesktopManager::self()->count(); 1018 } 1019 1020 void EffectsHandlerImpl::setCurrentDesktop(int desktop) 1021 { 1022 VirtualDesktopManager::self()->setCurrent(desktop); 1023 } 1024 1025 void EffectsHandlerImpl::setNumberOfDesktops(int desktops) 1026 { 1027 VirtualDesktopManager::self()->setCount(desktops); 1028 } 1029 1030 QSize EffectsHandlerImpl::desktopGridSize() const 1031 { 1032 return VirtualDesktopManager::self()->grid().size(); 1033 } 1034 1035 int EffectsHandlerImpl::desktopGridWidth() const 1036 { 1037 return desktopGridSize().width(); 1038 } 1039 1040 int EffectsHandlerImpl::desktopGridHeight() const 1041 { 1042 return desktopGridSize().height(); 1043 } 1044 1045 int EffectsHandlerImpl::workspaceWidth() const 1046 { 1047 return desktopGridWidth() * Workspace::self()->geometry().width(); 1048 } 1049 1050 int EffectsHandlerImpl::workspaceHeight() const 1051 { 1052 return desktopGridHeight() * Workspace::self()->geometry().height(); 1053 } 1054 1055 int EffectsHandlerImpl::desktopAtCoords(QPoint coords) const 1056 { 1057 if (auto vd = VirtualDesktopManager::self()->grid().at(coords)) { 1058 return vd->x11DesktopNumber(); 1059 } 1060 return 0; 1061 } 1062 1063 QPoint EffectsHandlerImpl::desktopGridCoords(int id) const 1064 { 1065 return VirtualDesktopManager::self()->grid().gridCoords(id); 1066 } 1067 1068 QPoint EffectsHandlerImpl::desktopCoords(int id) const 1069 { 1070 QPoint coords = VirtualDesktopManager::self()->grid().gridCoords(id); 1071 if (coords.x() == -1) { 1072 return QPoint(-1, -1); 1073 } 1074 const QSize displaySize = Workspace::self()->geometry().size(); 1075 return QPoint(coords.x() * displaySize.width(), coords.y() * displaySize.height()); 1076 } 1077 1078 int EffectsHandlerImpl::desktopAbove(int desktop, bool wrap) const 1079 { 1080 return VirtualDesktopManager::self()->inDirection(desktop, VirtualDesktopManager::Direction::Up, wrap); 1081 } 1082 1083 int EffectsHandlerImpl::desktopToRight(int desktop, bool wrap) const 1084 { 1085 return VirtualDesktopManager::self()->inDirection(desktop, VirtualDesktopManager::Direction::Right, wrap); 1086 } 1087 1088 int EffectsHandlerImpl::desktopBelow(int desktop, bool wrap) const 1089 { 1090 return VirtualDesktopManager::self()->inDirection(desktop, VirtualDesktopManager::Direction::Down, wrap); 1091 } 1092 1093 int EffectsHandlerImpl::desktopToLeft(int desktop, bool wrap) const 1094 { 1095 return VirtualDesktopManager::self()->inDirection(desktop, VirtualDesktopManager::Direction::Left, wrap); 1096 } 1097 1098 QString EffectsHandlerImpl::desktopName(int desktop) const 1099 { 1100 const VirtualDesktop *vd = VirtualDesktopManager::self()->desktopForX11Id(desktop); 1101 return vd ? vd->name() : QString(); 1102 } 1103 1104 bool EffectsHandlerImpl::optionRollOverDesktops() const 1105 { 1106 return options->isRollOverDesktops(); 1107 } 1108 1109 double EffectsHandlerImpl::animationTimeFactor() const 1110 { 1111 return options->animationTimeFactor(); 1112 } 1113 1114 EffectWindow *EffectsHandlerImpl::findWindow(WId id) const 1115 { 1116 if (X11Window *w = Workspace::self()->findClient(Predicate::WindowMatch, id)) { 1117 return w->effectWindow(); 1118 } 1119 if (Unmanaged *w = Workspace::self()->findUnmanaged(id)) { 1120 return w->effectWindow(); 1121 } 1122 return nullptr; 1123 } 1124 1125 EffectWindow *EffectsHandlerImpl::findWindow(KWaylandServer::SurfaceInterface *surf) const 1126 { 1127 if (waylandServer()) { 1128 if (Window *w = waylandServer()->findWindow(surf)) { 1129 return w->effectWindow(); 1130 } 1131 } 1132 return nullptr; 1133 } 1134 1135 EffectWindow *EffectsHandlerImpl::findWindow(QWindow *w) const 1136 { 1137 if (Window *window = workspace()->findInternal(w)) { 1138 return window->effectWindow(); 1139 } 1140 return nullptr; 1141 } 1142 1143 EffectWindow *EffectsHandlerImpl::findWindow(const QUuid &id) const 1144 { 1145 if (Window *window = workspace()->findToplevel(id)) { 1146 return window->effectWindow(); 1147 } 1148 return nullptr; 1149 } 1150 1151 EffectWindowList EffectsHandlerImpl::stackingOrder() const 1152 { 1153 QList<Window *> list = workspace()->stackingOrder(); 1154 EffectWindowList ret; 1155 for (Window *t : list) { 1156 if (EffectWindow *w = t->effectWindow()) { 1157 ret.append(w); 1158 } 1159 } 1160 return ret; 1161 } 1162 1163 void EffectsHandlerImpl::setElevatedWindow(KWin::EffectWindow *w, bool set) 1164 { 1165 elevated_windows.removeAll(w); 1166 if (set) { 1167 elevated_windows.append(w); 1168 } 1169 } 1170 1171 void EffectsHandlerImpl::setTabBoxWindow(EffectWindow *w) 1172 { 1173 #if KWIN_BUILD_TABBOX 1174 auto window = static_cast<EffectWindowImpl *>(w)->window(); 1175 if (window->isClient()) { 1176 workspace()->tabbox()->setCurrentClient(window); 1177 } 1178 #endif 1179 } 1180 1181 void EffectsHandlerImpl::setTabBoxDesktop(int desktop) 1182 { 1183 #if KWIN_BUILD_TABBOX 1184 workspace()->tabbox()->setCurrentDesktop(desktop); 1185 #endif 1186 } 1187 1188 EffectWindowList EffectsHandlerImpl::currentTabBoxWindowList() const 1189 { 1190 #if KWIN_BUILD_TABBOX 1191 const auto clients = workspace()->tabbox()->currentClientList(); 1192 EffectWindowList ret; 1193 ret.reserve(clients.size()); 1194 std::transform(std::cbegin(clients), std::cend(clients), 1195 std::back_inserter(ret), 1196 [](auto client) { 1197 return client->effectWindow(); 1198 }); 1199 return ret; 1200 #else 1201 return EffectWindowList(); 1202 #endif 1203 } 1204 1205 void EffectsHandlerImpl::refTabBox() 1206 { 1207 #if KWIN_BUILD_TABBOX 1208 workspace()->tabbox()->reference(); 1209 #endif 1210 } 1211 1212 void EffectsHandlerImpl::unrefTabBox() 1213 { 1214 #if KWIN_BUILD_TABBOX 1215 workspace()->tabbox()->unreference(); 1216 #endif 1217 } 1218 1219 void EffectsHandlerImpl::closeTabBox() 1220 { 1221 #if KWIN_BUILD_TABBOX 1222 workspace()->tabbox()->close(); 1223 #endif 1224 } 1225 1226 QList<int> EffectsHandlerImpl::currentTabBoxDesktopList() const 1227 { 1228 #if KWIN_BUILD_TABBOX 1229 return workspace()->tabbox()->currentDesktopList(); 1230 #else 1231 return QList<int>(); 1232 #endif 1233 } 1234 1235 int EffectsHandlerImpl::currentTabBoxDesktop() const 1236 { 1237 #if KWIN_BUILD_TABBOX 1238 return workspace()->tabbox()->currentDesktop(); 1239 #else 1240 return -1; 1241 #endif 1242 } 1243 1244 EffectWindow *EffectsHandlerImpl::currentTabBoxWindow() const 1245 { 1246 #if KWIN_BUILD_TABBOX 1247 if (auto c = workspace()->tabbox()->currentClient()) { 1248 return c->effectWindow(); 1249 } 1250 #endif 1251 return nullptr; 1252 } 1253 1254 void EffectsHandlerImpl::addRepaintFull() 1255 { 1256 m_compositor->scene()->addRepaintFull(); 1257 } 1258 1259 void EffectsHandlerImpl::addRepaint(const QRect &r) 1260 { 1261 m_compositor->scene()->addRepaint(r); 1262 } 1263 1264 void EffectsHandlerImpl::addRepaint(const QRectF &r) 1265 { 1266 m_compositor->scene()->addRepaint(r.toAlignedRect()); 1267 } 1268 1269 void EffectsHandlerImpl::addRepaint(const QRegion &r) 1270 { 1271 m_compositor->scene()->addRepaint(r); 1272 } 1273 1274 void EffectsHandlerImpl::addRepaint(int x, int y, int w, int h) 1275 { 1276 m_compositor->scene()->addRepaint(x, y, w, h); 1277 } 1278 1279 EffectScreen *EffectsHandlerImpl::activeScreen() const 1280 { 1281 return EffectScreenImpl::get(workspace()->activeOutput()); 1282 } 1283 1284 static VirtualDesktop *resolveVirtualDesktop(int desktopId) 1285 { 1286 if (desktopId == 0 || desktopId == -1) { 1287 return VirtualDesktopManager::self()->currentDesktop(); 1288 } else { 1289 return VirtualDesktopManager::self()->desktopForX11Id(desktopId); 1290 } 1291 } 1292 1293 QRectF EffectsHandlerImpl::clientArea(clientAreaOption opt, const EffectScreen *screen, int desktop) const 1294 { 1295 const EffectScreenImpl *screenImpl = static_cast<const EffectScreenImpl *>(screen); 1296 return Workspace::self()->clientArea(opt, screenImpl->platformOutput(), resolveVirtualDesktop(desktop)); 1297 } 1298 1299 QRectF EffectsHandlerImpl::clientArea(clientAreaOption opt, const EffectWindow *effectWindow) const 1300 { 1301 const Window *window = static_cast<const EffectWindowImpl *>(effectWindow)->window(); 1302 return Workspace::self()->clientArea(opt, window); 1303 } 1304 1305 QRectF EffectsHandlerImpl::clientArea(clientAreaOption opt, const QPoint &p, int desktop) const 1306 { 1307 const Output *output = Workspace::self()->outputAt(p); 1308 const VirtualDesktop *virtualDesktop = resolveVirtualDesktop(desktop); 1309 return Workspace::self()->clientArea(opt, output, virtualDesktop); 1310 } 1311 1312 QRect EffectsHandlerImpl::virtualScreenGeometry() const 1313 { 1314 return Workspace::self()->geometry(); 1315 } 1316 1317 QSize EffectsHandlerImpl::virtualScreenSize() const 1318 { 1319 return Workspace::self()->geometry().size(); 1320 } 1321 1322 void EffectsHandlerImpl::defineCursor(Qt::CursorShape shape) 1323 { 1324 input()->pointer()->setEffectsOverrideCursor(shape); 1325 } 1326 1327 bool EffectsHandlerImpl::checkInputWindowEvent(QMouseEvent *e) 1328 { 1329 if (m_grabbedMouseEffects.isEmpty()) { 1330 return false; 1331 } 1332 for (Effect *effect : std::as_const(m_grabbedMouseEffects)) { 1333 effect->windowInputMouseEvent(e); 1334 } 1335 return true; 1336 } 1337 1338 bool EffectsHandlerImpl::checkInputWindowEvent(QWheelEvent *e) 1339 { 1340 if (m_grabbedMouseEffects.isEmpty()) { 1341 return false; 1342 } 1343 for (Effect *effect : std::as_const(m_grabbedMouseEffects)) { 1344 effect->windowInputMouseEvent(e); 1345 } 1346 return true; 1347 } 1348 1349 void EffectsHandlerImpl::connectNotify(const QMetaMethod &signal) 1350 { 1351 if (signal == QMetaMethod::fromSignal(&EffectsHandler::cursorShapeChanged)) { 1352 if (!m_trackingCursorChanges) { 1353 connect(Cursors::self()->mouse(), &Cursor::cursorChanged, this, &EffectsHandler::cursorShapeChanged); 1354 Cursors::self()->mouse()->startCursorTracking(); 1355 } 1356 ++m_trackingCursorChanges; 1357 } 1358 EffectsHandler::connectNotify(signal); 1359 } 1360 1361 void EffectsHandlerImpl::disconnectNotify(const QMetaMethod &signal) 1362 { 1363 if (signal == QMetaMethod::fromSignal(&EffectsHandler::cursorShapeChanged)) { 1364 Q_ASSERT(m_trackingCursorChanges > 0); 1365 if (!--m_trackingCursorChanges) { 1366 Cursors::self()->mouse()->stopCursorTracking(); 1367 disconnect(Cursors::self()->mouse(), &Cursor::cursorChanged, this, &EffectsHandler::cursorShapeChanged); 1368 } 1369 } 1370 EffectsHandler::disconnectNotify(signal); 1371 } 1372 1373 void EffectsHandlerImpl::checkInputWindowStacking() 1374 { 1375 if (m_grabbedMouseEffects.isEmpty()) { 1376 return; 1377 } 1378 doCheckInputWindowStacking(); 1379 } 1380 1381 void EffectsHandlerImpl::doCheckInputWindowStacking() 1382 { 1383 } 1384 1385 QPoint EffectsHandlerImpl::cursorPos() const 1386 { 1387 return Cursors::self()->mouse()->pos(); 1388 } 1389 1390 void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border, Effect *effect) 1391 { 1392 workspace()->screenEdges()->reserve(border, effect, "borderActivated"); 1393 } 1394 1395 void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border, Effect *effect) 1396 { 1397 workspace()->screenEdges()->unreserve(border, effect); 1398 } 1399 1400 void EffectsHandlerImpl::registerTouchBorder(ElectricBorder border, QAction *action) 1401 { 1402 workspace()->screenEdges()->reserveTouch(border, action); 1403 } 1404 1405 void EffectsHandlerImpl::registerRealtimeTouchBorder(ElectricBorder border, QAction *action, EffectsHandler::TouchBorderCallback progressCallback) 1406 { 1407 workspace()->screenEdges()->reserveTouch(border, action, [progressCallback](ElectricBorder border, const QPointF &deltaProgress, Output *output) { 1408 progressCallback(border, deltaProgress, EffectScreenImpl::get(output)); 1409 }); 1410 } 1411 1412 void EffectsHandlerImpl::unregisterTouchBorder(ElectricBorder border, QAction *action) 1413 { 1414 workspace()->screenEdges()->unreserveTouch(border, action); 1415 } 1416 1417 QPainter *EffectsHandlerImpl::scenePainter() 1418 { 1419 return m_scene->renderer()->painter(); 1420 } 1421 1422 void EffectsHandlerImpl::toggleEffect(const QString &name) 1423 { 1424 if (isEffectLoaded(name)) { 1425 unloadEffect(name); 1426 } else { 1427 loadEffect(name); 1428 } 1429 } 1430 1431 QStringList EffectsHandlerImpl::loadedEffects() const 1432 { 1433 QStringList listModules; 1434 listModules.reserve(loaded_effects.count()); 1435 std::transform(loaded_effects.constBegin(), loaded_effects.constEnd(), 1436 std::back_inserter(listModules), 1437 [](const EffectPair &pair) { 1438 return pair.first; 1439 }); 1440 return listModules; 1441 } 1442 1443 QStringList EffectsHandlerImpl::listOfEffects() const 1444 { 1445 return m_effectLoader->listOfKnownEffects(); 1446 } 1447 1448 bool EffectsHandlerImpl::loadEffect(const QString &name) 1449 { 1450 makeOpenGLContextCurrent(); 1451 m_compositor->scene()->addRepaintFull(); 1452 1453 return m_effectLoader->loadEffect(name); 1454 } 1455 1456 void EffectsHandlerImpl::unloadEffect(const QString &name) 1457 { 1458 auto it = std::find_if(effect_order.begin(), effect_order.end(), 1459 [name](EffectPair &pair) { 1460 return pair.first == name; 1461 }); 1462 if (it == effect_order.end()) { 1463 qCDebug(KWIN_CORE) << "EffectsHandler::unloadEffect : Effect not loaded :" << name; 1464 return; 1465 } 1466 1467 qCDebug(KWIN_CORE) << "EffectsHandler::unloadEffect : Unloading Effect :" << name; 1468 destroyEffect((*it).second); 1469 effect_order.erase(it); 1470 effectsChanged(); 1471 1472 m_compositor->scene()->addRepaintFull(); 1473 } 1474 1475 void EffectsHandlerImpl::destroyEffect(Effect *effect) 1476 { 1477 makeOpenGLContextCurrent(); 1478 1479 if (fullscreen_effect == effect) { 1480 setActiveFullScreenEffect(nullptr); 1481 } 1482 1483 if (keyboard_grab_effect == effect) { 1484 ungrabKeyboard(); 1485 } 1486 1487 stopMouseInterception(effect); 1488 1489 const QList<QByteArray> properties = m_propertiesForEffects.keys(); 1490 for (const QByteArray &property : properties) { 1491 removeSupportProperty(property, effect); 1492 } 1493 1494 delete effect; 1495 } 1496 1497 void EffectsHandlerImpl::reconfigureEffect(const QString &name) 1498 { 1499 for (QVector<EffectPair>::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 1500 if ((*it).first == name) { 1501 kwinApp()->config()->reparseConfiguration(); 1502 makeOpenGLContextCurrent(); 1503 (*it).second->reconfigure(Effect::ReconfigureAll); 1504 return; 1505 } 1506 } 1507 } 1508 1509 bool EffectsHandlerImpl::isEffectLoaded(const QString &name) const 1510 { 1511 auto it = std::find_if(loaded_effects.constBegin(), loaded_effects.constEnd(), 1512 [&name](const EffectPair &pair) { 1513 return pair.first == name; 1514 }); 1515 return it != loaded_effects.constEnd(); 1516 } 1517 1518 bool EffectsHandlerImpl::isEffectSupported(const QString &name) 1519 { 1520 // If the effect is loaded, it is obviously supported. 1521 if (isEffectLoaded(name)) { 1522 return true; 1523 } 1524 1525 // next checks might require a context 1526 makeOpenGLContextCurrent(); 1527 1528 return m_effectLoader->isEffectSupported(name); 1529 } 1530 1531 QList<bool> EffectsHandlerImpl::areEffectsSupported(const QStringList &names) 1532 { 1533 QList<bool> retList; 1534 retList.reserve(names.count()); 1535 std::transform(names.constBegin(), names.constEnd(), 1536 std::back_inserter(retList), 1537 [this](const QString &name) { 1538 return isEffectSupported(name); 1539 }); 1540 return retList; 1541 } 1542 1543 void EffectsHandlerImpl::reloadEffect(Effect *effect) 1544 { 1545 QString effectName; 1546 for (QVector<EffectPair>::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 1547 if ((*it).second == effect) { 1548 effectName = (*it).first; 1549 break; 1550 } 1551 } 1552 if (!effectName.isNull()) { 1553 unloadEffect(effectName); 1554 m_effectLoader->loadEffect(effectName); 1555 } 1556 } 1557 1558 void EffectsHandlerImpl::effectsChanged() 1559 { 1560 loaded_effects.clear(); 1561 m_activeEffects.clear(); // it's possible to have a reconfigure and a quad rebuild between two paint cycles - bug #308201 1562 1563 loaded_effects.reserve(effect_order.count()); 1564 std::copy(effect_order.constBegin(), effect_order.constEnd(), 1565 std::back_inserter(loaded_effects)); 1566 1567 m_activeEffects.reserve(loaded_effects.count()); 1568 1569 m_currentPaintScreenIterator = m_activeEffects.constBegin(); 1570 m_currentPaintWindowIterator = m_activeEffects.constBegin(); 1571 m_currentDrawWindowIterator = m_activeEffects.constBegin(); 1572 } 1573 1574 QStringList EffectsHandlerImpl::activeEffects() const 1575 { 1576 QStringList ret; 1577 for (QVector<KWin::EffectPair>::const_iterator it = loaded_effects.constBegin(), 1578 end = loaded_effects.constEnd(); 1579 it != end; ++it) { 1580 if (it->second->isActive()) { 1581 ret << it->first; 1582 } 1583 } 1584 return ret; 1585 } 1586 1587 bool EffectsHandlerImpl::blocksDirectScanout() const 1588 { 1589 return std::any_of(m_activeEffects.constBegin(), m_activeEffects.constEnd(), [](const Effect *effect) { 1590 return effect->blocksDirectScanout(); 1591 }); 1592 } 1593 1594 KWaylandServer::Display *EffectsHandlerImpl::waylandDisplay() const 1595 { 1596 if (waylandServer()) { 1597 return waylandServer()->display(); 1598 } 1599 return nullptr; 1600 } 1601 1602 std::unique_ptr<EffectFrame> EffectsHandlerImpl::effectFrame(EffectFrameStyle style, bool staticSize, const QPoint &position, Qt::Alignment alignment) const 1603 { 1604 return std::make_unique<EffectFrameImpl>(style, staticSize, position, alignment); 1605 } 1606 1607 QVariant EffectsHandlerImpl::kwinOption(KWinOption kwopt) 1608 { 1609 switch (kwopt) { 1610 case CloseButtonCorner: { 1611 // TODO: this could become per window and be derived from the actual position in the deco 1612 const auto settings = Workspace::self()->decorationBridge()->settings(); 1613 return settings && settings->decorationButtonsLeft().contains(KDecoration2::DecorationButtonType::Close) ? Qt::TopLeftCorner : Qt::TopRightCorner; 1614 } 1615 case SwitchDesktopOnScreenEdge: 1616 return workspace()->screenEdges()->isDesktopSwitching(); 1617 case SwitchDesktopOnScreenEdgeMovingWindows: 1618 return workspace()->screenEdges()->isDesktopSwitchingMovingClients(); 1619 default: 1620 return QVariant(); // an invalid one 1621 } 1622 } 1623 1624 QString EffectsHandlerImpl::supportInformation(const QString &name) const 1625 { 1626 auto it = std::find_if(loaded_effects.constBegin(), loaded_effects.constEnd(), 1627 [name](const EffectPair &pair) { 1628 return pair.first == name; 1629 }); 1630 if (it == loaded_effects.constEnd()) { 1631 return QString(); 1632 } 1633 1634 QString support((*it).first + QLatin1String(":\n")); 1635 const QMetaObject *metaOptions = (*it).second->metaObject(); 1636 for (int i = 0; i < metaOptions->propertyCount(); ++i) { 1637 const QMetaProperty property = metaOptions->property(i); 1638 if (qstrcmp(property.name(), "objectName") == 0) { 1639 continue; 1640 } 1641 support += QString::fromUtf8(property.name()) + QLatin1String(": ") + (*it).second->property(property.name()).toString() + QLatin1Char('\n'); 1642 } 1643 1644 return support; 1645 } 1646 1647 bool EffectsHandlerImpl::isScreenLocked() const 1648 { 1649 #if KWIN_BUILD_SCREENLOCKER 1650 return kwinApp()->screenLockerWatcher()->isLocked(); 1651 #else 1652 return false; 1653 #endif 1654 } 1655 1656 QString EffectsHandlerImpl::debug(const QString &name, const QString ¶meter) const 1657 { 1658 QString internalName = name.toLower(); 1659 for (QVector<EffectPair>::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { 1660 if ((*it).first == internalName) { 1661 return it->second->debug(parameter); 1662 } 1663 } 1664 return QString(); 1665 } 1666 1667 bool EffectsHandlerImpl::makeOpenGLContextCurrent() 1668 { 1669 return m_scene->makeOpenGLContextCurrent(); 1670 } 1671 1672 void EffectsHandlerImpl::doneOpenGLContextCurrent() 1673 { 1674 m_scene->doneOpenGLContextCurrent(); 1675 } 1676 1677 bool EffectsHandlerImpl::animationsSupported() const 1678 { 1679 static const QByteArray forceEnvVar = qgetenv("KWIN_EFFECTS_FORCE_ANIMATIONS"); 1680 if (!forceEnvVar.isEmpty()) { 1681 static const int forceValue = forceEnvVar.toInt(); 1682 return forceValue == 1; 1683 } 1684 return m_scene->animationsSupported(); 1685 } 1686 1687 void EffectsHandlerImpl::highlightWindows(const QVector<EffectWindow *> &windows) 1688 { 1689 Effect *e = provides(Effect::HighlightWindows); 1690 if (!e) { 1691 return; 1692 } 1693 e->perform(Effect::HighlightWindows, QVariantList{QVariant::fromValue(windows)}); 1694 } 1695 1696 PlatformCursorImage EffectsHandlerImpl::cursorImage() const 1697 { 1698 return kwinApp()->cursorImage(); 1699 } 1700 1701 void EffectsHandlerImpl::hideCursor() 1702 { 1703 Cursors::self()->hideCursor(); 1704 } 1705 1706 void EffectsHandlerImpl::showCursor() 1707 { 1708 Cursors::self()->showCursor(); 1709 } 1710 1711 void EffectsHandlerImpl::startInteractiveWindowSelection(std::function<void(KWin::EffectWindow *)> callback) 1712 { 1713 kwinApp()->startInteractiveWindowSelection([callback](KWin::Window *window) { 1714 if (window && window->effectWindow()) { 1715 callback(window->effectWindow()); 1716 } else { 1717 callback(nullptr); 1718 } 1719 }); 1720 } 1721 1722 void EffectsHandlerImpl::startInteractivePositionSelection(std::function<void(const QPoint &)> callback) 1723 { 1724 kwinApp()->startInteractivePositionSelection(callback); 1725 } 1726 1727 void EffectsHandlerImpl::showOnScreenMessage(const QString &message, const QString &iconName) 1728 { 1729 OSD::show(message, iconName); 1730 } 1731 1732 void EffectsHandlerImpl::hideOnScreenMessage(OnScreenMessageHideFlags flags) 1733 { 1734 OSD::HideFlags osdFlags; 1735 if (flags.testFlag(OnScreenMessageHideFlag::SkipsCloseAnimation)) { 1736 osdFlags |= OSD::HideFlag::SkipCloseAnimation; 1737 } 1738 OSD::hide(osdFlags); 1739 } 1740 1741 KSharedConfigPtr EffectsHandlerImpl::config() const 1742 { 1743 return kwinApp()->config(); 1744 } 1745 1746 KSharedConfigPtr EffectsHandlerImpl::inputConfig() const 1747 { 1748 return InputConfig::self()->inputConfig(); 1749 } 1750 1751 Effect *EffectsHandlerImpl::findEffect(const QString &name) const 1752 { 1753 auto it = std::find_if(loaded_effects.constBegin(), loaded_effects.constEnd(), [name](const EffectPair &pair) { 1754 return pair.first == name; 1755 }); 1756 if (it == loaded_effects.constEnd()) { 1757 return nullptr; 1758 } 1759 return (*it).second; 1760 } 1761 1762 void EffectsHandlerImpl::renderOffscreenQuickView(OffscreenQuickView *w) const 1763 { 1764 if (!w->isVisible()) { 1765 return; 1766 } 1767 if (compositingType() == OpenGLCompositing) { 1768 GLTexture *t = w->bufferAsTexture(); 1769 if (!t) { 1770 return; 1771 } 1772 1773 ShaderTraits traits = ShaderTrait::MapTexture; 1774 const qreal a = w->opacity(); 1775 if (a != 1.0) { 1776 traits |= ShaderTrait::Modulate; 1777 } 1778 1779 GLShader *shader = ShaderManager::instance()->pushShader(traits); 1780 const QRectF rect = scaledRect(w->geometry(), m_scene->renderer()->renderTargetScale()); 1781 1782 QMatrix4x4 mvp(m_scene->renderer()->renderTargetProjectionMatrix()); 1783 mvp.translate(rect.x(), rect.y()); 1784 shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp); 1785 1786 if (a != 1.0) { 1787 shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a)); 1788 } 1789 1790 glEnable(GL_BLEND); 1791 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 1792 t->bind(); 1793 t->render(w->geometry(), m_scene->renderer()->renderTargetScale()); 1794 t->unbind(); 1795 glDisable(GL_BLEND); 1796 1797 ShaderManager::instance()->popShader(); 1798 } else if (compositingType() == QPainterCompositing) { 1799 QPainter *painter = effects->scenePainter(); 1800 const QImage buffer = w->bufferAsImage(); 1801 if (buffer.isNull()) { 1802 return; 1803 } 1804 painter->save(); 1805 painter->setOpacity(w->opacity()); 1806 painter->drawImage(w->geometry(), buffer); 1807 painter->restore(); 1808 } 1809 } 1810 1811 SessionState EffectsHandlerImpl::sessionState() const 1812 { 1813 return Workspace::self()->sessionManager()->state(); 1814 } 1815 1816 QList<EffectScreen *> EffectsHandlerImpl::screens() const 1817 { 1818 return m_effectScreens; 1819 } 1820 1821 EffectScreen *EffectsHandlerImpl::screenAt(const QPoint &point) const 1822 { 1823 return EffectScreenImpl::get(Workspace::self()->outputAt(point)); 1824 } 1825 1826 EffectScreen *EffectsHandlerImpl::findScreen(const QString &name) const 1827 { 1828 for (EffectScreen *screen : std::as_const(m_effectScreens)) { 1829 if (screen->name() == name) { 1830 return screen; 1831 } 1832 } 1833 return nullptr; 1834 } 1835 1836 EffectScreen *EffectsHandlerImpl::findScreen(int screenId) const 1837 { 1838 return m_effectScreens.value(screenId); 1839 } 1840 1841 void EffectsHandlerImpl::slotOutputAdded(Output *output) 1842 { 1843 EffectScreen *screen = new EffectScreenImpl(output, this); 1844 m_effectScreens.append(screen); 1845 Q_EMIT screenAdded(screen); 1846 } 1847 1848 void EffectsHandlerImpl::slotOutputRemoved(Output *output) 1849 { 1850 EffectScreen *screen = EffectScreenImpl::get(output); 1851 m_effectScreens.removeOne(screen); 1852 Q_EMIT screenRemoved(screen); 1853 delete screen; 1854 } 1855 1856 void EffectsHandlerImpl::renderScreen(EffectScreen *screen) 1857 { 1858 RenderTarget renderTarget(GLFramebuffer::currentFramebuffer()); 1859 renderTarget.setDevicePixelRatio(screen->devicePixelRatio()); 1860 1861 auto output = static_cast<EffectScreenImpl *>(screen)->platformOutput(); 1862 1863 RenderLayer layer(output->renderLoop()); 1864 SceneDelegate delegate(m_scene, output); 1865 delegate.setLayer(&layer); 1866 1867 m_scene->prePaint(&delegate); 1868 m_scene->paint(&renderTarget, output->geometry()); 1869 m_scene->postPaint(); 1870 } 1871 1872 bool EffectsHandlerImpl::isCursorHidden() const 1873 { 1874 return Cursors::self()->isCursorHidden(); 1875 } 1876 1877 QRect EffectsHandlerImpl::renderTargetRect() const 1878 { 1879 return m_scene->renderer()->renderTargetRect(); 1880 } 1881 1882 qreal EffectsHandlerImpl::renderTargetScale() const 1883 { 1884 return m_scene->renderer()->renderTargetScale(); 1885 } 1886 1887 KWin::EffectWindow *EffectsHandlerImpl::inputPanel() const 1888 { 1889 if (!kwinApp()->inputMethod() || !kwinApp()->inputMethod()->isEnabled()) { 1890 return nullptr; 1891 } 1892 1893 auto panel = kwinApp()->inputMethod()->panel(); 1894 if (panel) { 1895 return panel->effectWindow(); 1896 } 1897 return nullptr; 1898 } 1899 1900 bool EffectsHandlerImpl::isInputPanelOverlay() const 1901 { 1902 if (!kwinApp()->inputMethod() || !kwinApp()->inputMethod()->isEnabled()) { 1903 return true; 1904 } 1905 1906 auto panel = kwinApp()->inputMethod()->panel(); 1907 if (panel) { 1908 return panel->mode() == InputPanelV1Window::Mode::Overlay; 1909 } 1910 return true; 1911 } 1912 1913 //**************************************** 1914 // EffectScreenImpl 1915 //**************************************** 1916 1917 EffectScreenImpl::EffectScreenImpl(Output *output, QObject *parent) 1918 : EffectScreen(parent) 1919 , m_platformOutput(output) 1920 { 1921 m_platformOutput->m_effectScreen = this; 1922 1923 connect(output, &Output::aboutToChange, this, &EffectScreen::aboutToChange); 1924 connect(output, &Output::changed, this, &EffectScreen::changed); 1925 connect(output, &Output::wakeUp, this, &EffectScreen::wakeUp); 1926 connect(output, &Output::aboutToTurnOff, this, &EffectScreen::aboutToTurnOff); 1927 connect(output, &Output::scaleChanged, this, &EffectScreen::devicePixelRatioChanged); 1928 connect(output, &Output::geometryChanged, this, &EffectScreen::geometryChanged); 1929 } 1930 1931 EffectScreenImpl::~EffectScreenImpl() 1932 { 1933 if (m_platformOutput) { 1934 m_platformOutput->m_effectScreen = nullptr; 1935 } 1936 } 1937 1938 EffectScreenImpl *EffectScreenImpl::get(Output *output) 1939 { 1940 return output->m_effectScreen; 1941 } 1942 1943 Output *EffectScreenImpl::platformOutput() const 1944 { 1945 return m_platformOutput; 1946 } 1947 1948 QString EffectScreenImpl::name() const 1949 { 1950 return m_platformOutput->name(); 1951 } 1952 1953 QString EffectScreenImpl::manufacturer() const 1954 { 1955 return m_platformOutput->manufacturer(); 1956 } 1957 1958 QString EffectScreenImpl::model() const 1959 { 1960 return m_platformOutput->model(); 1961 } 1962 1963 QString EffectScreenImpl::serialNumber() const 1964 { 1965 return m_platformOutput->serialNumber(); 1966 } 1967 1968 qreal EffectScreenImpl::devicePixelRatio() const 1969 { 1970 return m_platformOutput->scale(); 1971 } 1972 1973 QRect EffectScreenImpl::geometry() const 1974 { 1975 return m_platformOutput->geometry(); 1976 } 1977 1978 int EffectScreenImpl::refreshRate() const 1979 { 1980 return m_platformOutput->refreshRate(); 1981 } 1982 1983 EffectScreen::Transform EffectScreenImpl::transform() const 1984 { 1985 return EffectScreen::Transform(m_platformOutput->transform()); 1986 } 1987 1988 //**************************************** 1989 // EffectWindowImpl 1990 //**************************************** 1991 1992 EffectWindowImpl::EffectWindowImpl(Window *window) 1993 : m_window(window) 1994 , m_windowItem(nullptr) 1995 { 1996 // Deleted windows are not managed. So, when windowClosed signal is 1997 // emitted, effects can't distinguish managed windows from unmanaged 1998 // windows(e.g. combo box popups, popup menus, etc). Save value of the 1999 // managed property during construction of EffectWindow. At that time, 2000 // parent can be Client, XdgShellClient, or Unmanaged. So, later on, when 2001 // an instance of Deleted becomes parent of the EffectWindow, effects 2002 // can still figure out whether it is/was a managed window. 2003 managed = window->isClient(); 2004 2005 m_waylandWindow = qobject_cast<KWin::WaylandWindow *>(window) != nullptr; 2006 m_x11Window = qobject_cast<KWin::X11Window *>(window) != nullptr || qobject_cast<KWin::Unmanaged *>(window) != nullptr; 2007 } 2008 2009 EffectWindowImpl::~EffectWindowImpl() 2010 { 2011 } 2012 2013 void EffectWindowImpl::refVisible(const EffectWindowVisibleRef *holder) 2014 { 2015 m_windowItem->refVisible(holder->reason()); 2016 } 2017 2018 void EffectWindowImpl::unrefVisible(const EffectWindowVisibleRef *holder) 2019 { 2020 m_windowItem->unrefVisible(holder->reason()); 2021 } 2022 2023 void EffectWindowImpl::addRepaint(const QRect &r) 2024 { 2025 m_windowItem->scheduleRepaint(QRegion(r)); 2026 } 2027 2028 void EffectWindowImpl::addRepaintFull() 2029 { 2030 m_windowItem->scheduleRepaint(m_windowItem->boundingRect()); 2031 } 2032 2033 void EffectWindowImpl::addLayerRepaint(const QRect &r) 2034 { 2035 m_windowItem->scheduleRepaint(m_windowItem->mapFromGlobal(r)); 2036 } 2037 2038 const EffectWindowGroup *EffectWindowImpl::group() const 2039 { 2040 if (auto c = qobject_cast<X11Window *>(m_window)) { 2041 return c->group()->effectGroup(); 2042 } 2043 return nullptr; // TODO 2044 } 2045 2046 void EffectWindowImpl::refWindow() 2047 { 2048 if (auto d = static_cast<Deleted *>(m_window->isDeleted() ? m_window : nullptr)) { 2049 return d->refWindow(); 2050 } 2051 Q_UNREACHABLE(); // TODO 2052 } 2053 2054 void EffectWindowImpl::unrefWindow() 2055 { 2056 if (auto d = static_cast<Deleted *>(m_window->isDeleted() ? m_window : nullptr)) { 2057 return d->unrefWindow(); // delays deletion in case 2058 } 2059 Q_UNREACHABLE(); // TODO 2060 } 2061 2062 EffectScreen *EffectWindowImpl::screen() const 2063 { 2064 return EffectScreenImpl::get(m_window->output()); 2065 } 2066 2067 #define WINDOW_HELPER(rettype, prototype, toplevelPrototype) \ 2068 rettype EffectWindowImpl::prototype() const \ 2069 { \ 2070 return m_window->toplevelPrototype(); \ 2071 } 2072 2073 WINDOW_HELPER(double, opacity, opacity) 2074 WINDOW_HELPER(qreal, x, x) 2075 WINDOW_HELPER(qreal, y, y) 2076 WINDOW_HELPER(qreal, width, width) 2077 WINDOW_HELPER(qreal, height, height) 2078 WINDOW_HELPER(QPointF, pos, pos) 2079 WINDOW_HELPER(QSizeF, size, size) 2080 WINDOW_HELPER(QRectF, geometry, frameGeometry) 2081 WINDOW_HELPER(QRectF, frameGeometry, frameGeometry) 2082 WINDOW_HELPER(QRectF, bufferGeometry, bufferGeometry) 2083 WINDOW_HELPER(QRectF, clientGeometry, clientGeometry) 2084 WINDOW_HELPER(QRectF, expandedGeometry, visibleGeometry) 2085 WINDOW_HELPER(QRectF, rect, rect) 2086 WINDOW_HELPER(int, desktop, desktop) 2087 WINDOW_HELPER(bool, isDesktop, isDesktop) 2088 WINDOW_HELPER(bool, isDock, isDock) 2089 WINDOW_HELPER(bool, isToolbar, isToolbar) 2090 WINDOW_HELPER(bool, isMenu, isMenu) 2091 WINDOW_HELPER(bool, isNormalWindow, isNormalWindow) 2092 WINDOW_HELPER(bool, isDialog, isDialog) 2093 WINDOW_HELPER(bool, isSplash, isSplash) 2094 WINDOW_HELPER(bool, isUtility, isUtility) 2095 WINDOW_HELPER(bool, isDropdownMenu, isDropdownMenu) 2096 WINDOW_HELPER(bool, isPopupMenu, isPopupMenu) 2097 WINDOW_HELPER(bool, isTooltip, isTooltip) 2098 WINDOW_HELPER(bool, isNotification, isNotification) 2099 WINDOW_HELPER(bool, isCriticalNotification, isCriticalNotification) 2100 WINDOW_HELPER(bool, isAppletPopup, isAppletPopup) 2101 WINDOW_HELPER(bool, isOnScreenDisplay, isOnScreenDisplay) 2102 WINDOW_HELPER(bool, isComboBox, isComboBox) 2103 WINDOW_HELPER(bool, isDNDIcon, isDNDIcon) 2104 WINDOW_HELPER(bool, isDeleted, isDeleted) 2105 WINDOW_HELPER(QString, windowRole, windowRole) 2106 WINDOW_HELPER(QStringList, activities, activities) 2107 WINDOW_HELPER(bool, skipsCloseAnimation, skipsCloseAnimation) 2108 WINDOW_HELPER(KWaylandServer::SurfaceInterface *, surface, surface) 2109 WINDOW_HELPER(bool, isPopupWindow, isPopupWindow) 2110 WINDOW_HELPER(bool, isOutline, isOutline) 2111 WINDOW_HELPER(bool, isLockScreen, isLockScreen) 2112 WINDOW_HELPER(pid_t, pid, pid) 2113 WINDOW_HELPER(qlonglong, windowId, window) 2114 WINDOW_HELPER(QUuid, internalId, internalId) 2115 WINDOW_HELPER(bool, isHidden, isHiddenInternal) 2116 2117 #undef WINDOW_HELPER 2118 2119 // TODO: Merge Window and Deleted. 2120 #define MANAGED_HELPER(rettype, prototype, propertyname, defaultValue) \ 2121 rettype EffectWindowImpl::prototype() const \ 2122 { \ 2123 auto client = static_cast<Window *>(m_window->isClient() ? m_window : nullptr); \ 2124 if (client) { \ 2125 return client->propertyname(); \ 2126 } \ 2127 auto deleted = static_cast<Deleted *>(m_window->isDeleted() ? m_window : nullptr); \ 2128 if (deleted) { \ 2129 return deleted->propertyname(); \ 2130 } \ 2131 return defaultValue; \ 2132 } 2133 2134 MANAGED_HELPER(bool, isMinimized, isMinimized, false) 2135 MANAGED_HELPER(bool, isModal, isModal, false) 2136 MANAGED_HELPER(bool, isFullScreen, isFullScreen, false) 2137 MANAGED_HELPER(bool, keepAbove, keepAbove, false) 2138 MANAGED_HELPER(bool, keepBelow, keepBelow, false) 2139 MANAGED_HELPER(QString, caption, caption, QString()); 2140 MANAGED_HELPER(QVector<uint>, desktops, x11DesktopIds, QVector<uint>()); 2141 MANAGED_HELPER(bool, isMovable, isMovable, false) 2142 MANAGED_HELPER(bool, isMovableAcrossScreens, isMovableAcrossScreens, false) 2143 MANAGED_HELPER(bool, isUserMove, isInteractiveMove, false) 2144 MANAGED_HELPER(bool, isUserResize, isInteractiveResize, false) 2145 MANAGED_HELPER(QRectF, iconGeometry, iconGeometry, QRectF()) 2146 MANAGED_HELPER(bool, isSpecialWindow, isSpecialWindow, true) 2147 MANAGED_HELPER(bool, acceptsFocus, wantsInput, true) // We don't actually know... 2148 MANAGED_HELPER(QIcon, icon, icon, QIcon()) 2149 MANAGED_HELPER(bool, isSkipSwitcher, skipSwitcher, false) 2150 MANAGED_HELPER(bool, decorationHasAlpha, decorationHasAlpha, false) 2151 MANAGED_HELPER(bool, isUnresponsive, unresponsive, false) 2152 2153 #undef MANAGED_HELPER 2154 2155 // legacy from tab groups, can be removed when no effects use this any more. 2156 bool EffectWindowImpl::isCurrentTab() const 2157 { 2158 return true; 2159 } 2160 2161 QString EffectWindowImpl::windowClass() const 2162 { 2163 return m_window->resourceName() + QLatin1Char(' ') + m_window->resourceClass(); 2164 } 2165 2166 QRectF EffectWindowImpl::contentsRect() const 2167 { 2168 return QRectF(m_window->clientPos(), m_window->clientSize()); 2169 } 2170 2171 NET::WindowType EffectWindowImpl::windowType() const 2172 { 2173 return m_window->windowType(); 2174 } 2175 2176 QSizeF EffectWindowImpl::basicUnit() const 2177 { 2178 if (auto window = qobject_cast<X11Window *>(m_window)) { 2179 return window->basicUnit(); 2180 } 2181 return QSize(1, 1); 2182 } 2183 2184 void EffectWindowImpl::setWindow(Window *w) 2185 { 2186 m_window = w; 2187 setParent(w); 2188 } 2189 2190 void EffectWindowImpl::setWindowItem(WindowItem *item) 2191 { 2192 m_windowItem = item; 2193 } 2194 2195 QRectF EffectWindowImpl::decorationInnerRect() const 2196 { 2197 return m_window->rect() - m_window->frameMargins(); 2198 } 2199 2200 KDecoration2::Decoration *EffectWindowImpl::decoration() const 2201 { 2202 return m_window->decoration(); 2203 } 2204 2205 QByteArray EffectWindowImpl::readProperty(long atom, long type, int format) const 2206 { 2207 if (!kwinApp()->x11Connection()) { 2208 return QByteArray(); 2209 } 2210 return readWindowProperty(window()->window(), atom, type, format); 2211 } 2212 2213 void EffectWindowImpl::deleteProperty(long int atom) const 2214 { 2215 if (kwinApp()->x11Connection()) { 2216 deleteWindowProperty(window()->window(), atom); 2217 } 2218 } 2219 2220 EffectWindow *EffectWindowImpl::findModal() 2221 { 2222 Window *modal = m_window->findModal(); 2223 if (modal) { 2224 return modal->effectWindow(); 2225 } 2226 2227 return nullptr; 2228 } 2229 2230 EffectWindow *EffectWindowImpl::transientFor() 2231 { 2232 Window *transientFor = m_window->transientFor(); 2233 if (transientFor) { 2234 return transientFor->effectWindow(); 2235 } 2236 2237 return nullptr; 2238 } 2239 2240 QWindow *EffectWindowImpl::internalWindow() const 2241 { 2242 if (auto window = qobject_cast<InternalWindow *>(m_window)) { 2243 return window->handle(); 2244 } 2245 return nullptr; 2246 } 2247 2248 template<typename T> 2249 EffectWindowList getMainWindows(T *c) 2250 { 2251 const auto mainwindows = c->mainWindows(); 2252 EffectWindowList ret; 2253 ret.reserve(mainwindows.size()); 2254 std::transform(std::cbegin(mainwindows), std::cend(mainwindows), 2255 std::back_inserter(ret), 2256 [](auto window) { 2257 return window->effectWindow(); 2258 }); 2259 return ret; 2260 } 2261 2262 EffectWindowList EffectWindowImpl::mainWindows() const 2263 { 2264 if (auto client = static_cast<Window *>(m_window->isClient() ? m_window : nullptr)) { 2265 return getMainWindows(client); 2266 } 2267 2268 if (auto deleted = static_cast<Deleted *>(m_window->isDeleted() ? m_window : nullptr)) { 2269 return getMainWindows(deleted); 2270 } 2271 2272 return {}; 2273 } 2274 2275 void EffectWindowImpl::setData(int role, const QVariant &data) 2276 { 2277 if (!data.isNull()) { 2278 dataMap[role] = data; 2279 } else { 2280 dataMap.remove(role); 2281 } 2282 Q_EMIT effects->windowDataChanged(this, role); 2283 } 2284 2285 QVariant EffectWindowImpl::data(int role) const 2286 { 2287 return dataMap.value(role); 2288 } 2289 2290 void EffectWindowImpl::elevate(bool elevate) 2291 { 2292 effects->setElevatedWindow(this, elevate); 2293 } 2294 2295 void EffectWindowImpl::minimize() 2296 { 2297 if (m_window->isClient()) { 2298 m_window->minimize(); 2299 } 2300 } 2301 2302 void EffectWindowImpl::unminimize() 2303 { 2304 if (m_window->isClient()) { 2305 m_window->unminimize(); 2306 } 2307 } 2308 2309 void EffectWindowImpl::closeWindow() 2310 { 2311 if (m_window->isClient()) { 2312 m_window->closeWindow(); 2313 } 2314 } 2315 2316 void EffectWindowImpl::referencePreviousWindowPixmap() 2317 { 2318 // TODO: Implement. 2319 } 2320 2321 void EffectWindowImpl::unreferencePreviousWindowPixmap() 2322 { 2323 // TODO: Implement. 2324 } 2325 2326 bool EffectWindowImpl::isManaged() const 2327 { 2328 return managed; 2329 } 2330 2331 bool EffectWindowImpl::isWaylandClient() const 2332 { 2333 return m_waylandWindow; 2334 } 2335 2336 bool EffectWindowImpl::isX11Client() const 2337 { 2338 return m_x11Window; 2339 } 2340 2341 //**************************************** 2342 // EffectWindowGroupImpl 2343 //**************************************** 2344 2345 EffectWindowList EffectWindowGroupImpl::members() const 2346 { 2347 const auto memberList = group->members(); 2348 EffectWindowList ret; 2349 ret.reserve(memberList.size()); 2350 std::transform(std::cbegin(memberList), std::cend(memberList), std::back_inserter(ret), [](auto window) { 2351 return window->effectWindow(); 2352 }); 2353 return ret; 2354 } 2355 2356 //**************************************** 2357 // EffectFrameImpl 2358 //**************************************** 2359 2360 EffectFrameQuickScene::EffectFrameQuickScene(EffectFrameStyle style, bool staticSize, QPoint position, 2361 Qt::Alignment alignment, QObject *parent) 2362 : OffscreenQuickScene(parent) 2363 , m_style(style) 2364 , m_static(staticSize) 2365 , m_point(position) 2366 , m_alignment(alignment) 2367 { 2368 2369 QString name; 2370 switch (style) { 2371 case EffectFrameNone: 2372 name = QStringLiteral("none"); 2373 break; 2374 case EffectFrameUnstyled: 2375 name = QStringLiteral("unstyled"); 2376 break; 2377 case EffectFrameStyled: 2378 name = QStringLiteral("styled"); 2379 break; 2380 } 2381 2382 const QString defaultPath = QStringLiteral("kwin/frames/plasma/frame_%1.qml").arg(name); 2383 // TODO read from kwinApp()->config() "QmlPath" like Outline/OnScreenNotification 2384 // *if* someone really needs this to be configurable. 2385 const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, defaultPath); 2386 2387 setSource(QUrl::fromLocalFile(path), QVariantMap{{QStringLiteral("effectFrame"), QVariant::fromValue(this)}}); 2388 2389 if (rootItem()) { 2390 connect(rootItem(), &QQuickItem::implicitWidthChanged, this, &EffectFrameQuickScene::reposition); 2391 connect(rootItem(), &QQuickItem::implicitHeightChanged, this, &EffectFrameQuickScene::reposition); 2392 } 2393 } 2394 2395 EffectFrameQuickScene::~EffectFrameQuickScene() = default; 2396 2397 EffectFrameStyle EffectFrameQuickScene::style() const 2398 { 2399 return m_style; 2400 } 2401 2402 bool EffectFrameQuickScene::isStatic() const 2403 { 2404 return m_static; 2405 } 2406 2407 const QFont &EffectFrameQuickScene::font() const 2408 { 2409 return m_font; 2410 } 2411 2412 void EffectFrameQuickScene::setFont(const QFont &font) 2413 { 2414 if (m_font == font) { 2415 return; 2416 } 2417 2418 m_font = font; 2419 Q_EMIT fontChanged(font); 2420 reposition(); 2421 } 2422 2423 const QIcon &EffectFrameQuickScene::icon() const 2424 { 2425 return m_icon; 2426 } 2427 2428 void EffectFrameQuickScene::setIcon(const QIcon &icon) 2429 { 2430 m_icon = icon; 2431 Q_EMIT iconChanged(icon); 2432 reposition(); 2433 } 2434 2435 const QSize &EffectFrameQuickScene::iconSize() const 2436 { 2437 return m_iconSize; 2438 } 2439 2440 void EffectFrameQuickScene::setIconSize(const QSize &iconSize) 2441 { 2442 if (m_iconSize == iconSize) { 2443 return; 2444 } 2445 2446 m_iconSize = iconSize; 2447 Q_EMIT iconSizeChanged(iconSize); 2448 reposition(); 2449 } 2450 2451 const QString &EffectFrameQuickScene::text() const 2452 { 2453 return m_text; 2454 } 2455 2456 void EffectFrameQuickScene::setText(const QString &text) 2457 { 2458 if (m_text == text) { 2459 return; 2460 } 2461 2462 m_text = text; 2463 Q_EMIT textChanged(text); 2464 reposition(); 2465 } 2466 2467 qreal EffectFrameQuickScene::frameOpacity() const 2468 { 2469 return m_frameOpacity; 2470 } 2471 2472 void EffectFrameQuickScene::setFrameOpacity(qreal frameOpacity) 2473 { 2474 if (m_frameOpacity != frameOpacity) { 2475 m_frameOpacity = frameOpacity; 2476 Q_EMIT frameOpacityChanged(frameOpacity); 2477 } 2478 } 2479 2480 bool EffectFrameQuickScene::crossFadeEnabled() const 2481 { 2482 return m_crossFadeEnabled; 2483 } 2484 2485 void EffectFrameQuickScene::setCrossFadeEnabled(bool enabled) 2486 { 2487 if (m_crossFadeEnabled != enabled) { 2488 m_crossFadeEnabled = enabled; 2489 Q_EMIT crossFadeEnabledChanged(enabled); 2490 } 2491 } 2492 2493 qreal EffectFrameQuickScene::crossFadeProgress() const 2494 { 2495 return m_crossFadeProgress; 2496 } 2497 2498 void EffectFrameQuickScene::setCrossFadeProgress(qreal progress) 2499 { 2500 if (m_crossFadeProgress != progress) { 2501 m_crossFadeProgress = progress; 2502 Q_EMIT crossFadeProgressChanged(progress); 2503 } 2504 } 2505 2506 Qt::Alignment EffectFrameQuickScene::alignment() const 2507 { 2508 return m_alignment; 2509 } 2510 2511 void EffectFrameQuickScene::setAlignment(Qt::Alignment alignment) 2512 { 2513 if (m_alignment == alignment) { 2514 return; 2515 } 2516 2517 m_alignment = alignment; 2518 reposition(); 2519 } 2520 2521 QPoint EffectFrameQuickScene::position() const 2522 { 2523 return m_point; 2524 } 2525 2526 void EffectFrameQuickScene::setPosition(const QPoint &point) 2527 { 2528 if (m_point == point) { 2529 return; 2530 } 2531 2532 m_point = point; 2533 reposition(); 2534 } 2535 2536 void EffectFrameQuickScene::reposition() 2537 { 2538 if (!rootItem() || m_point.x() < 0 || m_point.y() < 0) { 2539 return; 2540 } 2541 2542 QSizeF size; 2543 if (m_static) { 2544 size = rootItem()->size(); 2545 } else { 2546 size = QSizeF(rootItem()->implicitWidth(), rootItem()->implicitHeight()); 2547 } 2548 2549 QRect geometry(QPoint(), size.toSize()); 2550 2551 if (m_alignment & Qt::AlignLeft) 2552 geometry.moveLeft(m_point.x()); 2553 else if (m_alignment & Qt::AlignRight) 2554 geometry.moveLeft(m_point.x() - geometry.width()); 2555 else 2556 geometry.moveLeft(m_point.x() - geometry.width() / 2); 2557 if (m_alignment & Qt::AlignTop) 2558 geometry.moveTop(m_point.y()); 2559 else if (m_alignment & Qt::AlignBottom) 2560 geometry.moveTop(m_point.y() - geometry.height()); 2561 else 2562 geometry.moveTop(m_point.y() - geometry.height() / 2); 2563 2564 if (geometry == this->geometry()) { 2565 return; 2566 } 2567 2568 setGeometry(geometry); 2569 } 2570 2571 EffectFrameImpl::EffectFrameImpl(EffectFrameStyle style, bool staticSize, QPoint position, Qt::Alignment alignment) 2572 : QObject(nullptr) 2573 , EffectFrame() 2574 , m_view(new EffectFrameQuickScene(style, staticSize, position, alignment, nullptr)) 2575 { 2576 connect(m_view, &OffscreenQuickScene::repaintNeeded, this, [this] { 2577 effects->addRepaint(geometry()); 2578 }); 2579 connect(m_view, &OffscreenQuickScene::geometryChanged, this, [this](const QRect &oldGeometry, const QRect &newGeometry) { 2580 effects->addRepaint(oldGeometry); 2581 m_geometry = newGeometry; 2582 effects->addRepaint(newGeometry); 2583 }); 2584 } 2585 2586 EffectFrameImpl::~EffectFrameImpl() 2587 { 2588 // Effects often destroy their cached TextFrames in pre/postPaintScreen. 2589 // Destroying an OffscreenQuickView changes GL context, which we 2590 // must not do during effect rendering. 2591 // Delay destruction of the view until after the rendering. 2592 m_view->deleteLater(); 2593 } 2594 2595 Qt::Alignment EffectFrameImpl::alignment() const 2596 { 2597 return m_view->alignment(); 2598 } 2599 2600 void EffectFrameImpl::setAlignment(Qt::Alignment alignment) 2601 { 2602 m_view->setAlignment(alignment); 2603 } 2604 2605 const QFont &EffectFrameImpl::font() const 2606 { 2607 return m_view->font(); 2608 } 2609 2610 void EffectFrameImpl::setFont(const QFont &font) 2611 { 2612 m_view->setFont(font); 2613 } 2614 2615 void EffectFrameImpl::free() 2616 { 2617 m_view->hide(); 2618 } 2619 2620 const QRect &EffectFrameImpl::geometry() const 2621 { 2622 // Can't forward to OffscreenQuickScene::geometry() because we return a reference. 2623 return m_geometry; 2624 } 2625 2626 void EffectFrameImpl::setGeometry(const QRect &geometry, bool force) 2627 { 2628 m_view->setGeometry(geometry); 2629 } 2630 2631 const QIcon &EffectFrameImpl::icon() const 2632 { 2633 return m_view->icon(); 2634 } 2635 2636 void EffectFrameImpl::setIcon(const QIcon &icon) 2637 { 2638 m_view->setIcon(icon); 2639 2640 if (m_view->iconSize().isEmpty() && !icon.availableSizes().isEmpty()) { // Set a size if we don't already have one 2641 setIconSize(icon.availableSizes().constFirst()); 2642 } 2643 } 2644 2645 const QSize &EffectFrameImpl::iconSize() const 2646 { 2647 return m_view->iconSize(); 2648 } 2649 2650 void EffectFrameImpl::setIconSize(const QSize &size) 2651 { 2652 m_view->setIconSize(size); 2653 } 2654 2655 void EffectFrameImpl::setPosition(const QPoint &point) 2656 { 2657 m_view->setPosition(point); 2658 } 2659 2660 void EffectFrameImpl::render(const QRegion ®ion, double opacity, double frameOpacity) 2661 { 2662 if (!m_view->rootItem()) { 2663 return; 2664 } 2665 2666 m_view->show(); 2667 2668 m_view->setOpacity(opacity); 2669 m_view->setFrameOpacity(frameOpacity); 2670 2671 effects->renderOffscreenQuickView(m_view); 2672 } 2673 2674 const QString &EffectFrameImpl::text() const 2675 { 2676 return m_view->text(); 2677 } 2678 2679 void EffectFrameImpl::setText(const QString &text) 2680 { 2681 m_view->setText(text); 2682 } 2683 2684 EffectFrameStyle EffectFrameImpl::style() const 2685 { 2686 return m_view->style(); 2687 } 2688 2689 bool EffectFrameImpl::isCrossFade() const 2690 { 2691 return m_view->crossFadeEnabled(); 2692 } 2693 2694 void EffectFrameImpl::enableCrossFade(bool enable) 2695 { 2696 m_view->setCrossFadeEnabled(enable); 2697 } 2698 2699 qreal EffectFrameImpl::crossFadeProgress() const 2700 { 2701 return m_view->crossFadeProgress(); 2702 } 2703 2704 void EffectFrameImpl::setCrossFadeProgress(qreal progress) 2705 { 2706 m_view->setCrossFadeProgress(progress); 2707 } 2708 2709 } // namespace