File indexing completed on 2024-12-08 13:22:24

0001 /*
0002 *  Copyright 2016  Smith AR <audoban@openmailbox.org>
0003 *                  Michail Vourlakos <mvourlakos@gmail.com>
0004 *
0005 *  This file is part of Latte-Dock
0006 *
0007 *  Latte-Dock is free software; you can redistribute it and/or
0008 *  modify it under the terms of the GNU General Public License as
0009 *  published by the Free Software Foundation; either version 2 of
0010 *  the License, or (at your option) any later version.
0011 *
0012 *  Latte-Dock is distributed in the hope that it will be useful,
0013 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015 *  GNU General Public License for more details.
0016 *
0017 *  You should have received a copy of the GNU General Public License
0018 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include "visibilitymanager.h"
0022 
0023 // local
0024 #include "positioner.h"
0025 #include "screenedgeghostwindow.h"
0026 #include "view.h"
0027 #include "windowstracker/currentscreentracker.h"
0028 #include "../lattecorona.h"
0029 #include "../screenpool.h"
0030 #include "../layouts/manager.h"
0031 #include "../wm/abstractwindowinterface.h"
0032 #include "../../liblatte2/extras.h"
0033 
0034 // Qt
0035 #include <QDebug>
0036 
0037 // KDE
0038 #include <KWindowSystem>
0039 #include <KWayland/Client/plasmashell.h>
0040 #include <KWayland/Client/surface.h>
0041 
0042 //! Hide Timer can create cases that when it is low it does not allow the
0043 //! view to be show. For example !compositing+kwin_edges+hide inteval<50ms
0044 const int HIDEMINIMUMINTERVAL = 50;
0045 
0046 namespace Latte {
0047 namespace ViewPart {
0048 
0049 //! BEGIN: VisiblityManager implementation
0050 
0051 VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view)
0052     : QObject(view)
0053 {
0054     qDebug() << "VisibilityManager creating...";
0055 
0056     m_latteView = qobject_cast<Latte::View *>(view);
0057     m_corona = qobject_cast<Latte::Corona *>(view->corona());
0058     m_wm = m_corona->wm();
0059 
0060     connect(this, &VisibilityManager::slideInFinished, this, &VisibilityManager::updateHiddenState);
0061     connect(this, &VisibilityManager::slideOutFinished, this, &VisibilityManager::updateHiddenState);
0062 
0063     connect(this, &VisibilityManager::enableKWinEdgesChanged, this, &VisibilityManager::updateKWinEdgesSupport);
0064     connect(this, &VisibilityManager::modeChanged, this, &VisibilityManager::updateKWinEdgesSupport);
0065 
0066     if (m_latteView) {
0067         connect(m_latteView, &Latte::View::eventTriggered, this, &VisibilityManager::viewEventManager);
0068         connect(m_latteView, &Latte::View::byPassWMChanged, this, &VisibilityManager::updateKWinEdgesSupport);
0069 
0070         connect(m_latteView, &Latte::View::absoluteGeometryChanged, this, [&]() {
0071             if (m_mode == Types::AlwaysVisible && m_latteView->screen()) {
0072                 updateStrutsBasedOnLayoutsAndActivities();
0073             }
0074         });
0075 
0076         connect(this, &VisibilityManager::modeChanged, this, [&]() {
0077             emit m_latteView->availableScreenRectChangedFrom(m_latteView);
0078         });
0079     }
0080 
0081     m_timerStartUp.setInterval(5000);
0082     m_timerStartUp.setSingleShot(true);
0083     m_timerShow.setSingleShot(true);
0084     m_timerHide.setSingleShot(true);
0085 
0086     connect(&m_timerShow, &QTimer::timeout, this, [&]() {
0087         if (m_isHidden) {
0088             //   qDebug() << "must be shown";
0089             emit mustBeShown();
0090         }
0091     });
0092     connect(&m_timerHide, &QTimer::timeout, this, [&]() {
0093         if (!m_blockHiding && !m_isHidden && !m_dragEnter) {
0094             //   qDebug() << "must be hide";
0095             emit mustBeHide();
0096         }
0097     });
0098 
0099     restoreConfig();
0100 }
0101 
0102 VisibilityManager::~VisibilityManager()
0103 {
0104     qDebug() << "VisibilityManager deleting...";
0105     m_wm->removeViewStruts(*m_latteView);
0106 
0107     if (m_edgeGhostWindow) {
0108         m_edgeGhostWindow->deleteLater();
0109     }
0110 }
0111 
0112 Types::Visibility VisibilityManager::mode() const
0113 {
0114     return m_mode;
0115 }
0116 
0117 void VisibilityManager::setMode(Latte::Types::Visibility mode)
0118 {
0119     if (m_mode == mode)
0120         return;
0121 
0122     Q_ASSERT_X(mode != Types::None, staticMetaObject.className(), "set visibility to Types::None");
0123 
0124     // clear mode
0125     for (auto &c : m_connections) {
0126         disconnect(c);
0127     }
0128 
0129     int base{0};
0130 
0131     m_publishedStruts = QRect();
0132 
0133     if (m_mode == Types::AlwaysVisible) {
0134         //! remove struts for old always visible mode
0135         m_wm->removeViewStruts(*m_latteView);
0136     }
0137 
0138     m_timerShow.stop();
0139     m_timerHide.stop();
0140     m_mode = mode;
0141 
0142     if (mode != Types::AlwaysVisible && mode != Types::WindowsGoBelow) {
0143         //set wayland visibility mode
0144         if (m_latteView->surface()) {
0145             m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow);
0146         }
0147 
0148         m_connections[0] = connect(m_wm, &WindowSystem::AbstractWindowInterface::currentDesktopChanged, this, [&] {
0149             if (m_raiseOnDesktopChange) {
0150                 raiseViewTemporarily();
0151             }
0152         });
0153         m_connections[1] = connect(m_wm, &WindowSystem::AbstractWindowInterface::currentActivityChanged, this, [&]() {
0154             if (m_raiseOnActivityChange) {
0155                 raiseViewTemporarily();
0156             } else {
0157                 updateHiddenState();
0158             }
0159         });
0160 
0161         base = 2;
0162     } else {
0163         //set wayland visibility mode
0164         if (m_latteView->surface()) {
0165             m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide);
0166         }
0167     }
0168 
0169     switch (m_mode) {
0170     case Types::AlwaysVisible: {
0171         if (m_latteView->containment() && m_latteView->screen()) {
0172             updateStrutsBasedOnLayoutsAndActivities();
0173         }
0174 
0175         m_connections[base] = connect(m_latteView, &Latte::View::normalThicknessChanged, this, [&]() {
0176             updateStrutsBasedOnLayoutsAndActivities();
0177         });
0178 
0179         m_connections[base+1] = connect(m_corona->layoutsManager(),  &Layouts::Manager::currentLayoutNameChanged, this, [&]() {
0180             if (m_corona && m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) {
0181                 updateStrutsBasedOnLayoutsAndActivities(true);
0182             }
0183         });
0184 
0185         m_connections[base+2] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() {
0186             if (m_corona && m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) {
0187                 updateStrutsBasedOnLayoutsAndActivities(true);
0188             }
0189         });
0190 
0191         raiseView(true);
0192         break;
0193     }
0194 
0195     case Types::AutoHide: {
0196         m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged, this, [&]() {
0197             raiseView(m_containsMouse);
0198         });
0199 
0200         raiseView(m_containsMouse);
0201         break;
0202     }
0203 
0204     case Types::DodgeActive: {
0205         m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged
0206                                       , this, &VisibilityManager::dodgeActive);
0207         m_connections[base+1] = connect(m_latteView->windowsTracker()->currentScreen(), &TrackerPart::CurrentScreenTracker::activeWindowTouchingChanged
0208                                         , this, &VisibilityManager::dodgeActive);
0209 
0210         dodgeActive();
0211         break;
0212     }
0213 
0214     case Types::DodgeMaximized: {
0215         m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged
0216                                       , this, &VisibilityManager::dodgeMaximized);
0217         m_connections[base+1] = connect(m_latteView->windowsTracker()->currentScreen(), &TrackerPart::CurrentScreenTracker::activeWindowMaximizedChanged
0218                                         , this, &VisibilityManager::dodgeMaximized);
0219 
0220         dodgeMaximized();
0221         break;
0222     }
0223 
0224     case Types::DodgeAllWindows: {
0225         m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged
0226                                       , this, &VisibilityManager::dodgeAllWindows);
0227 
0228         m_connections[base+1] = connect(m_latteView->windowsTracker()->currentScreen(), &TrackerPart::CurrentScreenTracker::existsWindowTouchingChanged
0229                                         , this, &VisibilityManager::dodgeAllWindows);
0230 
0231         dodgeAllWindows();
0232         break;
0233     }
0234 
0235     case Types::WindowsGoBelow:
0236         break;
0237 
0238     default:
0239         break;
0240     }
0241 
0242     m_latteView->containment()->config().writeEntry("visibility", static_cast<int>(m_mode));
0243 
0244     updateKWinEdgesSupport();
0245 
0246     emit modeChanged();
0247 }
0248 
0249 void VisibilityManager::updateStrutsBasedOnLayoutsAndActivities(bool forceUpdate)
0250 {
0251     bool multipleLayoutsAndCurrent = (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts
0252                                       && m_latteView->layout() && !m_latteView->positioner()->inLocationChangeAnimation()
0253                                       && m_latteView->layout()->isCurrent());
0254 
0255     if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout || multipleLayoutsAndCurrent) {
0256         QRect computedStruts = acceptableStruts();
0257         if (m_publishedStruts != computedStruts || forceUpdate) {
0258             //! Force update is needed when very important events happen in DE and there is a chance
0259             //! that previously even though struts where sent the DE did not accept them.
0260             //! Such a case is when STOPPING an Activity and windows faulty become invisible even
0261             //! though they should not. In such case setting struts when the windows are hidden
0262             //! the struts do not take any effect
0263             m_publishedStruts = computedStruts;
0264             m_wm->setViewStruts(*m_latteView, m_publishedStruts, m_latteView->location());
0265         }
0266     } else {
0267         m_publishedStruts = QRect();
0268         m_wm->removeViewStruts(*m_latteView);
0269     }
0270 }
0271 
0272 QRect VisibilityManager::acceptableStruts()
0273 {
0274     QRect calcs;
0275 
0276     switch (m_latteView->location()) {
0277     case Plasma::Types::TopEdge: {
0278         calcs = QRect(m_latteView->x(), m_latteView->y(), m_latteView->width(), m_latteView->normalThickness());
0279         break;
0280     }
0281 
0282     case Plasma::Types::BottomEdge: {
0283         int y = m_latteView->y() + m_latteView->height() - m_latteView->normalThickness();
0284         calcs = QRect(m_latteView->x(), y, m_latteView->width(), m_latteView->normalThickness());
0285         break;
0286     }
0287 
0288     case Plasma::Types::LeftEdge: {
0289         calcs = QRect(m_latteView->x(), m_latteView->y(), m_latteView->normalThickness(), m_latteView->height());
0290         break;
0291     }
0292 
0293     case Plasma::Types::RightEdge: {
0294         int x = m_latteView->x() + m_latteView->width() - m_latteView->normalThickness();
0295         calcs = QRect(x, m_latteView->y(), m_latteView->normalThickness(), m_latteView->height());
0296         break;
0297     }
0298     }
0299 
0300     return calcs;
0301 }
0302 
0303 bool VisibilityManager::raiseOnDesktop() const
0304 {
0305     return m_raiseOnDesktopChange;
0306 }
0307 
0308 void VisibilityManager::setRaiseOnDesktop(bool enable)
0309 {
0310     if (enable == m_raiseOnDesktopChange)
0311         return;
0312 
0313     m_raiseOnDesktopChange = enable;
0314     emit raiseOnDesktopChanged();
0315 }
0316 
0317 bool VisibilityManager::raiseOnActivity() const
0318 {
0319     return m_raiseOnActivityChange;
0320 }
0321 
0322 void VisibilityManager::setRaiseOnActivity(bool enable)
0323 {
0324     if (enable == m_raiseOnActivityChange)
0325         return;
0326 
0327     m_raiseOnActivityChange = enable;
0328     emit raiseOnActivityChanged();
0329 }
0330 
0331 bool VisibilityManager::isHidden() const
0332 {
0333     return m_isHidden;
0334 }
0335 
0336 void VisibilityManager::setIsHidden(bool isHidden)
0337 {
0338     if (m_isHidden == isHidden)
0339         return;
0340 
0341     if (m_blockHiding && isHidden) {
0342         qWarning() << "isHidden property is blocked, ignoring update";
0343         return;
0344     }
0345 
0346     m_isHidden = isHidden;
0347 
0348     updateGhostWindowState();
0349 
0350     emit isHiddenChanged();
0351 }
0352 
0353 bool VisibilityManager::blockHiding() const
0354 {
0355     return m_blockHiding;
0356 }
0357 
0358 void VisibilityManager::setBlockHiding(bool blockHiding)
0359 {
0360     if (m_blockHiding == blockHiding) {
0361         return;
0362     }
0363 
0364     m_blockHiding = blockHiding;
0365     // qDebug() << "blockHiding:" << blockHiding;
0366 
0367     if (m_blockHiding) {
0368         m_timerHide.stop();
0369 
0370         if (m_isHidden) {
0371             emit mustBeShown();
0372         }
0373     } else {
0374         updateHiddenState();
0375     }
0376 
0377     emit blockHidingChanged();
0378 }
0379 
0380 int VisibilityManager::timerShow() const
0381 {
0382     return m_timerShow.interval();
0383 }
0384 
0385 void VisibilityManager::setTimerShow(int msec)
0386 {
0387     if (m_timerShow.interval() == msec) {
0388         return;
0389     }
0390 
0391     m_timerShow.setInterval(msec);
0392     emit timerShowChanged();
0393 }
0394 
0395 int VisibilityManager::timerHide() const
0396 {
0397     return m_timerHide.interval();
0398 }
0399 
0400 void VisibilityManager::setTimerHide(int msec)
0401 {
0402     int interval = qMax(HIDEMINIMUMINTERVAL, msec);
0403 
0404     if (m_timerHide.interval() == interval) {
0405         return;
0406     }
0407 
0408     m_timerHide.setInterval(interval);
0409     emit timerHideChanged();
0410 }
0411 
0412 bool VisibilityManager::supportsKWinEdges() const
0413 {
0414     return (m_edgeGhostWindow != nullptr);
0415 }
0416 
0417 void VisibilityManager::updateGhostWindowState()
0418 {
0419     if (supportsKWinEdges()) {
0420         bool inCurrentLayout = (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout ||
0421                                 (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts
0422                                  && m_latteView->layout() && !m_latteView->positioner()->inLocationChangeAnimation()
0423                                  && m_latteView->layout()->isCurrent()));
0424 
0425         if (inCurrentLayout) {
0426             m_wm->setActiveEdge(m_edgeGhostWindow, m_isHidden);
0427         } else {
0428             m_wm->setActiveEdge(m_edgeGhostWindow, false);
0429         }
0430     }
0431 }
0432 
0433 void VisibilityManager::hide()
0434 {
0435     if (KWindowSystem::isPlatformX11()) {
0436         m_latteView->hide();
0437     }
0438 }
0439 
0440 void VisibilityManager::show()
0441 {
0442     if (KWindowSystem::isPlatformX11()) {
0443         m_latteView->show();
0444     }
0445 }
0446 
0447 
0448 void VisibilityManager::raiseView(bool raise)
0449 {
0450     if (m_blockHiding)
0451         return;
0452 
0453     if (raise) {
0454         m_timerHide.stop();
0455 
0456         if (!m_timerShow.isActive()) {
0457             m_timerShow.start();
0458         }
0459     } else if (!m_dragEnter) {
0460         m_timerShow.stop();
0461 
0462         if (m_hideNow) {
0463             m_hideNow = false;
0464             emit mustBeHide();
0465         } else if (!m_timerHide.isActive()) {
0466             m_timerHide.start();
0467         }
0468     }
0469 }
0470 
0471 void VisibilityManager::raiseViewTemporarily()
0472 {
0473     if (m_raiseTemporarily)
0474         return;
0475 
0476     m_raiseTemporarily = true;
0477     m_timerHide.stop();
0478     m_timerShow.stop();
0479 
0480     if (m_isHidden)
0481         emit mustBeShown();
0482 
0483     QTimer::singleShot(qBound(1800, 2 * m_timerHide.interval(), 3000), this, [&]() {
0484         m_raiseTemporarily = false;
0485         m_hideNow = true;
0486         updateHiddenState();
0487     });
0488 }
0489 
0490 void VisibilityManager::updateHiddenState()
0491 {
0492     if (m_dragEnter)
0493         return;
0494 
0495     switch (m_mode) {
0496     case Types::AutoHide:
0497         raiseView(m_containsMouse);
0498         break;
0499 
0500     case Types::DodgeActive:
0501         dodgeActive();
0502         break;
0503 
0504     case Types::DodgeMaximized:
0505         dodgeMaximized();
0506         break;
0507 
0508     case Types::DodgeAllWindows:
0509         dodgeAllWindows();
0510         break;
0511 
0512     default:
0513         break;
0514     }
0515 }
0516 
0517 void VisibilityManager::applyActivitiesToHiddenWindows(const QStringList &activities)
0518 {
0519     if (m_edgeGhostWindow) {
0520         m_wm->setWindowOnActivities(*m_edgeGhostWindow, activities);
0521     }
0522 }
0523 
0524 void VisibilityManager::dodgeActive()
0525 {
0526     if (m_raiseTemporarily)
0527         return;
0528 
0529     //!don't send false raiseView signal when containing mouse
0530     if (m_containsMouse) {
0531         raiseView(true);
0532         return;
0533     }
0534 
0535     raiseView(!m_latteView->windowsTracker()->currentScreen()->activeWindowTouching());
0536 }
0537 
0538 void VisibilityManager::dodgeMaximized()
0539 {
0540     if (m_raiseTemporarily)
0541         return;
0542 
0543     //!don't send false raiseView signal when containing mouse
0544     if (m_containsMouse) {
0545         raiseView(true);
0546         return;
0547     }
0548 
0549     raiseView(!m_latteView->windowsTracker()->currentScreen()->activeWindowMaximized());
0550 }
0551 
0552 void VisibilityManager::dodgeAllWindows()
0553 {
0554     if (m_raiseTemporarily)
0555         return;
0556 
0557     if (m_containsMouse) {
0558         raiseView(true);
0559     }
0560 
0561     bool windowIntersects{m_latteView->windowsTracker()->currentScreen()->activeWindowTouching() || m_latteView->windowsTracker()->currentScreen()->existsWindowTouching()};
0562 
0563     raiseView(!windowIntersects);
0564 }
0565 
0566 void VisibilityManager::saveConfig()
0567 {
0568     if (!m_latteView->containment())
0569         return;
0570 
0571     auto config = m_latteView->containment()->config();
0572 
0573     config.writeEntry("enableKWinEdges", m_enableKWinEdgesFromUser);
0574     config.writeEntry("timerShow", m_timerShow.interval());
0575     config.writeEntry("timerHide", m_timerHide.interval());
0576     config.writeEntry("raiseOnDesktopChange", m_raiseOnDesktopChange);
0577     config.writeEntry("raiseOnActivityChange", m_raiseOnActivityChange);
0578 
0579     m_latteView->containment()->configNeedsSaving();
0580 }
0581 
0582 void VisibilityManager::restoreConfig()
0583 {
0584     if (!m_latteView || !m_latteView->containment()){
0585         return;
0586     }
0587 
0588     auto config = m_latteView->containment()->config();
0589     m_timerShow.setInterval(config.readEntry("timerShow", 0));
0590     m_timerHide.setInterval(qMax(HIDEMINIMUMINTERVAL, config.readEntry("timerHide", 700)));
0591     emit timerShowChanged();
0592     emit timerHideChanged();
0593 
0594     m_enableKWinEdgesFromUser = config.readEntry("enableKWinEdges", true);
0595     emit enableKWinEdgesChanged();
0596 
0597     setRaiseOnDesktop(config.readEntry("raiseOnDesktopChange", false));
0598     setRaiseOnActivity(config.readEntry("raiseOnActivityChange", false));
0599 
0600     auto storedMode = static_cast<Types::Visibility>(m_latteView->containment()->config().readEntry("visibility", static_cast<int>(Types::DodgeActive)));
0601 
0602     if (storedMode == Types::AlwaysVisible) {
0603         qDebug() << "Loading visibility mode: Always Visible , on startup...";
0604         setMode(Types::AlwaysVisible);
0605     } else {
0606         connect(&m_timerStartUp, &QTimer::timeout, this, [&]() {
0607             if (!m_latteView || !m_latteView->containment()) {
0608                 return;
0609             }
0610 
0611             auto fMode = static_cast<Types::Visibility>(m_latteView->containment()->config().readEntry("visibility", static_cast<int>(Types::DodgeActive)));
0612             qDebug() << "Loading visibility mode:" << fMode << " on startup...";
0613             setMode(fMode);
0614         });
0615         connect(m_latteView->containment(), &Plasma::Containment::userConfiguringChanged
0616                 , this, [&](bool configuring) {
0617             if (configuring && m_timerStartUp.isActive())
0618                 m_timerStartUp.start(100);
0619         });
0620 
0621         m_timerStartUp.start();
0622     }
0623 
0624     connect(m_latteView->containment(), &Plasma::Containment::userConfiguringChanged
0625             , this, [&](bool configuring) {
0626         if (!configuring) {
0627             saveConfig();
0628         }
0629     });
0630 }
0631 
0632 bool VisibilityManager::containsMouse() const
0633 {
0634     return m_containsMouse;
0635 }
0636 
0637 void VisibilityManager::setContainsMouse(bool contains)
0638 {
0639     if (m_containsMouse == contains) {
0640         return;
0641     }
0642 
0643     m_containsMouse = contains;
0644     emit containsMouseChanged();
0645 
0646     if (contains && m_mode != Types::AlwaysVisible) {
0647         raiseView(true);
0648     }
0649 }
0650 
0651 void VisibilityManager::viewEventManager(QEvent *ev)
0652 {
0653     switch (ev->type()) {
0654     case QEvent::Enter:
0655         setContainsMouse(true);
0656         break;
0657 
0658     case QEvent::Leave:
0659         m_dragEnter = false;
0660         setContainsMouse(false);
0661         break;
0662 
0663     case QEvent::DragEnter:
0664         m_dragEnter = true;
0665 
0666         if (m_isHidden) {
0667             emit mustBeShown();
0668         }
0669 
0670         break;
0671 
0672     case QEvent::DragLeave:
0673     case QEvent::Drop:
0674         m_dragEnter = false;
0675         updateHiddenState();
0676         break;
0677 
0678     default:
0679         break;
0680     }
0681 }
0682 
0683 //! KWin Edges Support functions
0684 bool VisibilityManager::enableKWinEdges() const
0685 {
0686     return m_enableKWinEdgesFromUser;
0687 }
0688 
0689 void VisibilityManager::setEnableKWinEdges(bool enable)
0690 {
0691     if (m_enableKWinEdgesFromUser == enable) {
0692         return;
0693     }
0694 
0695     m_enableKWinEdgesFromUser = enable;
0696 
0697     emit enableKWinEdgesChanged();
0698 }
0699 
0700 void VisibilityManager::updateKWinEdgesSupport()
0701 {
0702     if ((m_mode == Types::AutoHide
0703          || m_mode == Types::DodgeActive
0704          || m_mode == Types::DodgeAllWindows
0705          || m_mode == Types::DodgeMaximized)
0706             && (!m_latteView->byPassWM()) ) {
0707         if (m_enableKWinEdgesFromUser) {
0708             createEdgeGhostWindow();
0709         } else if (!m_enableKWinEdgesFromUser) {
0710             deleteEdgeGhostWindow();
0711         }
0712     } else if (m_mode == Types::AlwaysVisible
0713                || m_mode == Types::WindowsGoBelow) {
0714         deleteEdgeGhostWindow();
0715     }
0716 }
0717 
0718 void VisibilityManager::createEdgeGhostWindow()
0719 {
0720     if (!m_edgeGhostWindow) {
0721         m_edgeGhostWindow = new ScreenEdgeGhostWindow(m_latteView);
0722 
0723         m_wm->setViewExtraFlags(*m_edgeGhostWindow);
0724 
0725         connect(m_edgeGhostWindow, &ScreenEdgeGhostWindow::containsMouseChanged, this, [ = ](bool contains) {
0726             if (contains) {
0727                 raiseView(true);
0728             } else {
0729                 m_timerShow.stop();
0730                 updateGhostWindowState();
0731             }
0732         });
0733 
0734         connect(m_edgeGhostWindow, &ScreenEdgeGhostWindow::dragEntered, this, [&]() {
0735             if (m_isHidden) {
0736                 emit mustBeShown();
0737             }
0738         });
0739 
0740         m_connectionsKWinEdges[0] = connect(m_wm, &WindowSystem::AbstractWindowInterface::currentActivityChanged,
0741                                             this, [&]() {
0742             bool inCurrentLayout = (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout ||
0743                                     (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts
0744                                      && m_latteView->layout() && !m_latteView->positioner()->inLocationChangeAnimation()
0745                                      && m_latteView->layout()->isCurrent()));
0746 
0747             if (m_edgeGhostWindow) {
0748                 if (inCurrentLayout) {
0749                     m_wm->setActiveEdge(m_edgeGhostWindow, m_isHidden);
0750                 } else {
0751                     m_wm->setActiveEdge(m_edgeGhostWindow, false);
0752                 }
0753             }
0754         });
0755 
0756         emit supportsKWinEdgesChanged();
0757     }
0758 }
0759 
0760 void VisibilityManager::deleteEdgeGhostWindow()
0761 {
0762     if (m_edgeGhostWindow) {
0763         m_edgeGhostWindow->deleteLater();
0764         m_edgeGhostWindow = nullptr;
0765 
0766         for (auto &c : m_connectionsKWinEdges) {
0767             disconnect(c);
0768         }
0769 
0770         emit supportsKWinEdgesChanged();
0771     }
0772 }
0773 
0774 //! END: VisibilityManager implementation
0775 
0776 }
0777 }