File indexing completed on 2024-06-16 14:04:38

0001 /*
0002 *  Copyright 2018  Michail Vourlakos <mvourlakos@gmail.com>
0003 *
0004 *  This file is part of Latte-Dock
0005 *
0006 *  Latte-Dock is free software; you can redistribute it and/or
0007 *  modify it under the terms of the GNU General Public License as
0008 *  published by the Free Software Foundation; either version 2 of
0009 *  the License, or (at your option) any later version.
0010 *
0011 *  Latte-Dock is distributed in the hope that it will be useful,
0012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 *  GNU General Public License for more details.
0015 *
0016 *  You should have received a copy of the GNU General Public License
0017 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018 */
0019 
0020 #include "positioner.h"
0021 
0022 // local
0023 #include "effects.h"
0024 #include "view.h"
0025 #include "../lattecorona.h"
0026 #include "../screenpool.h"
0027 #include "../settings/universalsettings.h"
0028 #include "../../liblatte2/types.h"
0029 
0030 // Qt
0031 #include <QDebug>
0032 
0033 // KDE
0034 #include <KWayland/Client/plasmashell.h>
0035 #include <KWayland/Client/surface.h>
0036 #include <KWindowSystem>
0037 
0038 namespace Latte {
0039 namespace ViewPart {
0040 
0041 Positioner::Positioner(Latte::View *parent)
0042     : QObject(parent),
0043       m_view(parent)
0044 {
0045     m_screenSyncTimer.setSingleShot(true);
0046     m_screenSyncTimer.setInterval(2000);
0047     connect(&m_screenSyncTimer, &QTimer::timeout, this, &Positioner::reconsiderScreen);
0048 
0049     //! under X11 it was identified that windows many times especially under screen changes
0050     //! don't end up at the correct position and size. This timer will enforce repositionings
0051     //! and resizes every 500ms if the window hasn't end up to correct values and until this
0052     //! is achieved
0053     m_validateGeometryTimer.setSingleShot(true);
0054     m_validateGeometryTimer.setInterval(500);
0055     connect(&m_validateGeometryTimer, &QTimer::timeout, this, &Positioner::syncGeometry);
0056 
0057     m_corona = qobject_cast<Latte::Corona *>(m_view->corona());
0058 
0059     if (m_corona) {
0060         if (KWindowSystem::isPlatformX11()) {
0061             m_trackedWindowId = m_view->winId();
0062             m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
0063 
0064             connect(m_view, &Latte::View::forcedShown, this, [&]() {
0065                 m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId);
0066                 m_trackedWindowId = m_view->winId();
0067                 m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
0068             });
0069         } else {
0070             connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, [&]() {
0071                 if (m_trackedWindowId.isNull()) {
0072                     m_trackedWindowId = m_corona->wm()->winIdFor("latte-dock", m_view->geometry());
0073                     m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
0074                 }
0075             });
0076         }
0077 
0078         /////
0079 
0080         m_screenSyncTimer.setInterval(qMax(m_corona->universalSettings()->screenTrackerInterval() - 500, 1000));
0081         connect(m_corona->universalSettings(), &UniversalSettings::screenTrackerIntervalChanged, this, [&]() {
0082             m_screenSyncTimer.setInterval(qMax(m_corona->universalSettings()->screenTrackerInterval() - 500, 1000));
0083         });
0084 
0085         connect(m_corona, &Latte::Corona::viewLocationChanged, this, [&]() {
0086             //! check if an edge has been freed for a primary dock
0087             //! from another screen
0088             if (m_view->onPrimary()) {
0089                 m_screenSyncTimer.start();
0090             }
0091         });
0092     }
0093 
0094     init();
0095 }
0096 
0097 Positioner::~Positioner()
0098 {
0099     m_inDelete = true;
0100     m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId);
0101 
0102     m_screenSyncTimer.stop();
0103     m_validateGeometryTimer.stop();
0104 }
0105 
0106 void Positioner::init()
0107 {
0108     //! connections
0109     connect(this, &Positioner::screenGeometryChanged, this, &Positioner::syncGeometry);
0110 
0111     connect(m_view, &QQuickWindow::xChanged, this, &Positioner::validateDockGeometry);
0112     connect(m_view, &QQuickWindow::yChanged, this, &Positioner::validateDockGeometry);
0113     connect(m_view, &QQuickWindow::widthChanged, this, &Positioner::validateDockGeometry);
0114     connect(m_view, &QQuickWindow::heightChanged, this, &Positioner::validateDockGeometry);
0115     connect(m_view, &QQuickWindow::screenChanged, this, &Positioner::currentScreenChanged);
0116     connect(m_view, &QQuickWindow::screenChanged, this, &Positioner::screenChanged);
0117 
0118     connect(m_view, &Latte::View::behaveAsPlasmaPanelChanged, this, &Positioner::syncGeometry);
0119     connect(m_view, &Latte::View::maxThicknessChanged, this, &Positioner::syncGeometry);
0120     connect(m_view, &Latte::View::maxLengthChanged, this, &Positioner::syncGeometry);
0121     connect(m_view, &Latte::View::offsetChanged, this, &Positioner::syncGeometry);
0122 
0123     connect(m_view, &Latte::View::absoluteGeometryChanged, this, [&]() {
0124         if (m_view->behaveAsPlasmaPanel()) {
0125             syncGeometry();
0126         }
0127     });
0128 
0129     connect(m_view, &Latte::View::locationChanged, this, [&]() {
0130         updateFormFactor();
0131         syncGeometry();
0132     });
0133 
0134     connect(m_view, &Latte::View::normalThicknessChanged, this, [&]() {
0135         if (m_view->behaveAsPlasmaPanel()) {
0136             syncGeometry();
0137         }
0138     });
0139 
0140     connect(m_view->effects(), &Latte::ViewPart::Effects::drawShadowsChanged, this, [&]() {
0141         if (!m_view->behaveAsPlasmaPanel()) {
0142             syncGeometry();
0143         }
0144     });
0145 
0146     connect(m_view->effects(), &Latte::ViewPart::Effects::innerShadowChanged, this, [&]() {
0147         if (m_view->behaveAsPlasmaPanel()) {
0148             syncGeometry();
0149         }
0150     });
0151 
0152     connect(qGuiApp, &QGuiApplication::screenAdded, this, &Positioner::screenChanged);
0153     connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &Positioner::screenChanged);
0154 
0155     initSignalingForLocationChangeSliding();
0156 }
0157 
0158 int Positioner::currentScreenId() const
0159 {
0160     auto *latteCorona = qobject_cast<Latte::Corona *>(m_view->corona());
0161 
0162     if (latteCorona) {
0163         return latteCorona->screenPool()->id(m_screenToFollowId);
0164     }
0165 
0166     return -1;
0167 }
0168 
0169 QString Positioner::currentScreenName() const
0170 {
0171     return m_screenToFollowId;
0172 }
0173 
0174 bool Positioner::setCurrentScreen(const QString id)
0175 {
0176     QScreen *nextScreen{qGuiApp->primaryScreen()};
0177 
0178     if (id != "primary") {
0179         for (const auto scr : qGuiApp->screens()) {
0180             if (scr && scr->name() == id) {
0181                 nextScreen = scr;
0182                 break;
0183             }
0184         }
0185     }
0186 
0187     if (m_screenToFollow == nextScreen) {
0188         return true;
0189     }
0190 
0191     if (nextScreen) {
0192         if (m_view->layout()) {
0193             auto freeEdges = m_view->layout()->freeEdges(nextScreen);
0194 
0195             if (!freeEdges.contains(m_view->location())) {
0196                 return false;
0197             } else {
0198                 m_goToScreen = nextScreen;
0199 
0200                 //! asynchronous call in order to not crash from configwindow
0201                 //! deletion from sliding out animation
0202                 QTimer::singleShot(100, [this]() {
0203                     emit hideDockDuringScreenChangeStarted();
0204                 });
0205             }
0206         }
0207     }
0208 
0209     return true;
0210 }
0211 
0212 //! this function updates the dock's associated screen.
0213 //! updateScreenId = true, update also the m_screenToFollowId
0214 //! updateScreenId = false, do not update the m_screenToFollowId
0215 //! that way an explicit dock can be shown in another screen when
0216 //! there isnt a tasks dock running in the system and for that
0217 //! dock its first origin screen is stored and that way when
0218 //! that screen is reconnected the dock will return to its original
0219 //! place
0220 void Positioner::setScreenToFollow(QScreen *scr, bool updateScreenId)
0221 {
0222     if (!scr || (scr && (m_screenToFollow == scr) && (m_view->screen() == scr))) {
0223         return;
0224     }
0225 
0226     qDebug() << "setScreenToFollow() called for screen:" << scr->name() << " update:" << updateScreenId;
0227 
0228     m_screenToFollow = scr;
0229 
0230     if (updateScreenId) {
0231         m_screenToFollowId = scr->name();
0232     }
0233 
0234     qDebug() << "adapting to screen...";
0235     m_view->setScreen(scr);
0236 
0237     if (m_view->containment()) {
0238         m_view->containment()->reactToScreenChange();
0239     }
0240 
0241     connect(scr, &QScreen::geometryChanged, this, &Positioner::screenGeometryChanged);
0242     syncGeometry();
0243     m_view->updateAbsoluteGeometry(true);
0244     qDebug() << "setScreenToFollow() ended...";
0245 
0246     emit screenGeometryChanged();
0247     emit currentScreenChanged();
0248 }
0249 
0250 //! the main function which decides if this dock is at the
0251 //! correct screen
0252 void Positioner::reconsiderScreen()
0253 {
0254     if (m_inDelete) {
0255         return;
0256     }
0257 
0258     qDebug() << "reconsiderScreen() called...";
0259     qDebug() << "  Delayer  ";
0260 
0261     for (const auto scr : qGuiApp->screens()) {
0262         qDebug() << "      D, found screen: " << scr->name();
0263     }
0264 
0265     bool screenExists{false};
0266 
0267     //!check if the associated screen is running
0268     for (const auto scr : qGuiApp->screens()) {
0269         if (m_screenToFollowId == scr->name()
0270             || (m_view->onPrimary() && scr == qGuiApp->primaryScreen())) {
0271             screenExists = true;
0272         }
0273     }
0274 
0275     qDebug() << "dock screen exists  ::: " << screenExists;
0276 
0277     //! 1.a primary dock must be always on the primary screen
0278     if (m_view->onPrimary() && (m_screenToFollowId != qGuiApp->primaryScreen()->name()
0279                                 || m_screenToFollow != qGuiApp->primaryScreen()
0280                                 || m_view->screen() != qGuiApp->primaryScreen())) {
0281         using Plasma::Types;
0282         QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge,
0283                                      Types::TopEdge, Types::RightEdge};
0284 
0285         edges = m_view->layout() ? m_view->layout()->availableEdgesForView(qGuiApp->primaryScreen(), m_view) : edges;
0286 
0287         //change to primary screen only if the specific edge is free
0288         qDebug() << "updating the primary screen for dock...";
0289         qDebug() << "available primary screen edges:" << edges;
0290         qDebug() << "dock location:" << m_view->location();
0291 
0292         if (edges.contains(m_view->location())) {
0293             //! case 1
0294             qDebug() << "reached case 1: of updating dock primary screen...";
0295             setScreenToFollow(qGuiApp->primaryScreen());
0296         }
0297     } else if (!m_view->onPrimary()) {
0298         //! 2.an explicit dock must be always on the correct associated screen
0299         //! there are cases that window manager misplaces the dock, this function
0300         //! ensures that this dock will return at its correct screen
0301         for (const auto scr : qGuiApp->screens()) {
0302             if (scr && scr->name() == m_screenToFollowId) {
0303                 qDebug() << "reached case 2: updating the explicit screen for dock...";
0304                 setScreenToFollow(scr);
0305                 break;
0306             }
0307         }
0308     }
0309 
0310     syncGeometry();
0311     qDebug() << "reconsiderScreen() ended...";
0312 }
0313 
0314 void Positioner::screenChanged(QScreen *scr)
0315 {
0316     m_screenSyncTimer.start();
0317 
0318     //! this is needed in order to update the struts on screen change
0319     //! and even though the geometry has been set correctly the offsets
0320     //! of the screen must be updated to the new ones
0321     if (m_view->visibility() && m_view->visibility()->mode() == Latte::Types::AlwaysVisible) {
0322         m_view->updateAbsoluteGeometry(true);
0323     }
0324 }
0325 
0326 void Positioner::syncGeometry()
0327 {
0328     if (!(m_view->screen() && m_view->containment()) || m_inDelete) {
0329         return;
0330     }
0331 
0332     bool found{false};
0333 
0334     qDebug() << "syncGeometry() called...";
0335 
0336     //! before updating the positioning and geometry of the dock
0337     //! we make sure that the dock is at the correct screen
0338     if (m_view->screen() != m_screenToFollow) {
0339         qDebug() << "Sync Geometry screens inconsistent!!!! ";
0340 
0341         if (m_screenToFollow) {
0342             qDebug() << "Sync Geometry screens inconsistent for m_screenToFollow:" << m_screenToFollow->name() << " dock screen:" << m_view->screen()->name();
0343         }
0344 
0345         if (!m_screenSyncTimer.isActive()) {
0346             m_screenSyncTimer.start();
0347         }
0348     } else {
0349         found = true;
0350     }
0351 
0352     //! if the dock isnt at the correct screen the calculations
0353     //! are not executed
0354     if (found) {
0355         //! compute the free screen rectangle for vertical panels only once
0356         //! this way the costly QRegion computations are calculated only once
0357         //! instead of two times (both inside the resizeWindow and the updatePosition)
0358         QRegion freeRegion;;
0359         QRect maximumRect;
0360         QRect availableScreenRect{m_view->screen()->geometry()};
0361 
0362         if (m_view->formFactor() == Plasma::Types::Vertical) {
0363             QString layoutName = m_view->layout() ? m_view->layout()->name() : QString();
0364             auto latteCorona = qobject_cast<Latte::Corona *>(m_view->corona());
0365             int fixedScreen = m_view->onPrimary() ? latteCorona->screenPool()->primaryScreenId() : m_view->containment()->screen();
0366 
0367             QList<Types::Visibility> modes({Latte::Types::AlwaysVisible,
0368                                             Latte::Types::DodgeActive,
0369                                             Latte::Types::DodgeMaximized,
0370                                             Latte::Types::DodgeAllWindows,
0371                                             Latte::Types::WindowsGoBelow});
0372 
0373             QList<Plasma::Types::Location> edges({Plasma::Types::TopEdge,
0374                                                   Plasma::Types::BottomEdge});
0375 
0376             freeRegion = latteCorona->availableScreenRegionWithCriteria(fixedScreen, layoutName, modes, edges);
0377 
0378             maximumRect = maximumNormalGeometry();
0379             QRegion availableRegion = freeRegion.intersected(maximumRect);
0380             availableScreenRect = freeRegion.intersected(maximumRect).boundingRect();
0381             float area = 0;
0382 
0383             //! it is used to choose which or the availableRegion rectangles will
0384             //! be the one representing dock geometry
0385             for (QRegion::const_iterator p_rect=availableRegion.begin(); p_rect!=availableRegion.end(); ++p_rect) {
0386                 //! the area of each rectangle in calculated in squares of 50x50
0387                 //! this is a way to avoid enourmous numbers for area value
0388                 float tempArea = (float)((*p_rect).width() * (*p_rect).height()) / 2500;
0389 
0390                 if (tempArea > area) {
0391                     availableScreenRect = (*p_rect);
0392                     area = tempArea;
0393                 }
0394             }
0395 
0396             if (availableRegion.rectCount() > 1 && m_view->behaveAsPlasmaPanel()) {
0397                 m_view->effects()->setForceDrawCenteredBorders(true);
0398             } else {
0399                 m_view->effects()->setForceDrawCenteredBorders(false);
0400             }
0401         } else {
0402             m_view->effects()->setForceDrawCenteredBorders(false);
0403         }
0404 
0405         m_view->effects()->updateEnabledBorders();
0406         resizeWindow(availableScreenRect);
0407         updatePosition(availableScreenRect);
0408 
0409         qDebug() << "syncGeometry() calculations for screen: " << m_view->screen()->name() << " _ " << m_view->screen()->geometry();
0410         qDebug() << "syncGeometry() calculations for edge: " << m_view->location();
0411     }
0412 
0413     qDebug() << "syncGeometry() ended...";
0414 
0415     // qDebug() << "dock geometry:" << qRectToStr(geometry());
0416 }
0417 
0418 void Positioner::validateDockGeometry()
0419 {
0420     if (m_view->geometry() != m_validGeometry) {
0421         m_validateGeometryTimer.start();
0422     }
0423 }
0424 
0425 //! this is used mainly from vertical panels in order to
0426 //! to get the maximum geometry that can be used from the dock
0427 //! based on their alignment type and the location dock
0428 QRect Positioner::maximumNormalGeometry()
0429 {
0430     int xPos = 0;
0431     int yPos = m_view->screen()->geometry().y();;
0432     int maxHeight = m_view->screen()->geometry().height();
0433     int maxWidth = m_view->normalThickness();
0434     QRect maxGeometry;
0435     maxGeometry.setRect(0, 0, maxWidth, maxHeight);
0436 
0437     switch (m_view->location()) {
0438         case Plasma::Types::LeftEdge:
0439             xPos = m_view->screen()->geometry().x();
0440             maxGeometry.setRect(xPos, yPos, maxWidth, maxHeight);
0441             break;
0442 
0443         case Plasma::Types::RightEdge:
0444             xPos = m_view->screen()->geometry().right() - maxWidth + 1;
0445             maxGeometry.setRect(xPos, yPos, maxWidth, maxHeight);
0446             break;
0447 
0448         default:
0449             //! bypass clang warnings
0450             break;
0451     }
0452 
0453     //! this is needed in order to preserve that the top dock will be above
0454     //! the others in case flag bypasswindowmanagerhint hasn't be set,
0455     //! such a case is the AlwaysVisible mode
0456     if (m_view->location() == Plasma::Types::TopEdge) {
0457         KWindowSystem::setState(m_view->winId(), NET::KeepAbove);
0458     } else {
0459         KWindowSystem::clearState(m_view->winId(), NET::KeepAbove);
0460     }
0461 
0462     return maxGeometry;
0463 }
0464 
0465 void Positioner::updatePosition(QRect availableScreenRect)
0466 {
0467     QRect screenGeometry{availableScreenRect};
0468     QPoint position;
0469     position = {0, 0};
0470 
0471     const auto length = [&](int length) -> int {
0472         float offs = static_cast<float>(m_view->offset());
0473         return static_cast<int>(length * ((1 - m_view->maxLength()) / 2) + length * (offs / 100));
0474     };
0475     int cleanThickness = m_view->normalThickness() - m_view->effects()->innerShadow();
0476 
0477     switch (m_view->location()) {
0478         case Plasma::Types::TopEdge:
0479             if (m_view->behaveAsPlasmaPanel()) {
0480                 position = {screenGeometry.x() + length(screenGeometry.width()), screenGeometry.y()};
0481             } else {
0482                 position = {screenGeometry.x(), screenGeometry.y()};
0483             }
0484 
0485             break;
0486 
0487         case Plasma::Types::BottomEdge:
0488             if (m_view->behaveAsPlasmaPanel()) {
0489                 position = {screenGeometry.x() + length(screenGeometry.width()),
0490                             screenGeometry.y() + screenGeometry.height() - cleanThickness
0491                            };
0492             } else {
0493                 position = {screenGeometry.x(), screenGeometry.y() + screenGeometry.height() - m_view->height()};
0494             }
0495 
0496             break;
0497 
0498         case Plasma::Types::RightEdge:
0499             if (m_view->behaveAsPlasmaPanel()) {
0500                 position = {availableScreenRect.right() - cleanThickness + 1,
0501                             availableScreenRect.y() + length(availableScreenRect.height())
0502                            };
0503             } else {
0504                 position = {availableScreenRect.right() - m_view->width() + 1, availableScreenRect.y()};
0505             }
0506 
0507             break;
0508 
0509         case Plasma::Types::LeftEdge:
0510             if (m_view->behaveAsPlasmaPanel()) {
0511                 position = {availableScreenRect.x(), availableScreenRect.y() + length(availableScreenRect.height())};
0512             } else {
0513                 position = {availableScreenRect.x(), availableScreenRect.y()};
0514             }
0515 
0516             break;
0517 
0518         default:
0519             qWarning() << "wrong location, couldn't update the panel position"
0520                        << m_view->location();
0521     }
0522 
0523     m_validGeometry.setTopLeft(position);
0524 
0525     m_view->setPosition(position);
0526 
0527     if (m_view->surface()) {
0528         m_view->surface()->setPosition(position);
0529     }
0530 }
0531 
0532 void Positioner::resizeWindow(QRect availableScreenRect)
0533 {
0534     QSize screenSize = m_view->screen()->size();
0535     QSize size = (m_view->formFactor() == Plasma::Types::Vertical) ? QSize(m_view->maxThickness(), availableScreenRect.height()) : QSize(screenSize.width(), m_view->maxThickness());
0536 
0537     if (m_view->formFactor() == Plasma::Types::Vertical) {
0538         //qDebug() << "MAXIMUM RECT :: " << maximumRect << " - AVAILABLE RECT :: " << availableRect;
0539         if (m_view->behaveAsPlasmaPanel()) {
0540             size.setWidth(m_view->normalThickness());
0541             size.setHeight(static_cast<int>(m_view->maxLength() * availableScreenRect.height()));
0542         }
0543     } else {
0544         if (m_view->behaveAsPlasmaPanel()) {
0545             size.setWidth(static_cast<int>(m_view->maxLength() * screenSize.width()));
0546             size.setHeight(m_view->normalThickness());
0547         }
0548     }
0549 
0550     m_validGeometry.setSize(size);
0551 
0552     m_view->setMinimumSize(size);
0553     m_view->setMaximumSize(size);
0554     m_view->resize(size);
0555 
0556     if (m_view->formFactor() == Plasma::Types::Horizontal) {
0557         emit windowSizeChanged();
0558     }
0559 }
0560 
0561 void Positioner::updateFormFactor()
0562 {
0563     if (!m_view->containment())
0564         return;
0565 
0566     switch (m_view->location()) {
0567         case Plasma::Types::TopEdge:
0568         case Plasma::Types::BottomEdge:
0569             m_view->containment()->setFormFactor(Plasma::Types::Horizontal);
0570             break;
0571 
0572         case Plasma::Types::LeftEdge:
0573         case Plasma::Types::RightEdge:
0574             m_view->containment()->setFormFactor(Plasma::Types::Vertical);
0575             break;
0576 
0577         default:
0578             qWarning() << "wrong location, couldn't update the panel position" << m_view->location();
0579     }
0580 }
0581 
0582 void Positioner::initSignalingForLocationChangeSliding()
0583 {
0584     //! signals to handle the sliding-in/out during location changes
0585     connect(this, &Positioner::hideDockDuringLocationChangeStarted, this, &Positioner::onHideWindowsForSlidingOut);
0586 
0587     connect(m_view, &View::locationChanged, this, [&]() {
0588         if (m_goToLocation != Plasma::Types::Floating) {
0589             m_goToLocation = Plasma::Types::Floating;
0590             QTimer::singleShot(100, [this]() {
0591                 m_view->effects()->setAnimationsBlocked(false);
0592                 emit showDockAfterLocationChangeFinished();
0593                 m_view->showSettingsWindow();
0594 
0595                 if (m_view->layout()) {
0596                     //! This is needed in case the edge is occupied and the occupying
0597                     //! view must be deleted
0598                     m_view->layout()->syncLatteViewsToScreens();
0599                 }
0600 
0601                 emit edgeChanged();
0602             });
0603         }
0604     });
0605 
0606     //! signals to handle the sliding-in/out during screen changes
0607     connect(this, &Positioner::hideDockDuringScreenChangeStarted, this, &Positioner::onHideWindowsForSlidingOut);
0608 
0609     connect(this, &Positioner::currentScreenChanged, this, [&]() {
0610         if (m_goToScreen) {
0611             m_goToScreen = nullptr;
0612             QTimer::singleShot(100, [this]() {
0613                 m_view->effects()->setAnimationsBlocked(false);
0614                 emit showDockAfterScreenChangeFinished();
0615                 m_view->showSettingsWindow();
0616 
0617                 if (m_view->layout()) {
0618                     //! This is needed in case the edge is occupied and the occupying
0619                     //! view must be deleted
0620                     m_view->layout()->syncLatteViewsToScreens();
0621                 }
0622 
0623                 emit edgeChanged();
0624             });
0625         }
0626     });
0627 
0628     //! signals to handle the sliding-in/out during moving to another layout
0629     connect(this, &Positioner::hideDockDuringMovingToLayoutStarted, this, &Positioner::onHideWindowsForSlidingOut);
0630 
0631     connect(m_view, &View::layoutChanged, this, [&]() {
0632         if (!m_moveToLayout.isEmpty() && m_view->layout()) {
0633             m_moveToLayout = "";
0634             QTimer::singleShot(100, [this]() {
0635                 m_view->effects()->setAnimationsBlocked(false);
0636                 emit showDockAfterMovingToLayoutFinished();
0637                 m_view->showSettingsWindow();
0638                 emit edgeChanged();
0639             });
0640         }
0641     });
0642 
0643     //!    ----  both cases   ----  !//
0644     //! this is used for both location and screen change cases, this signal
0645     //! is send when the sliding-out animation has finished
0646     connect(this, &Positioner::hideDockDuringLocationChangeFinished, this, [&]() {
0647         m_view->effects()->setAnimationsBlocked(true);
0648 
0649         if (m_goToLocation != Plasma::Types::Floating) {
0650             m_view->setLocation(m_goToLocation);
0651         } else if (m_goToScreen) {
0652             setScreenToFollow(m_goToScreen);
0653         } else if (!m_moveToLayout.isEmpty()) {
0654             m_view->moveToLayout(m_moveToLayout);
0655         }
0656     });
0657 }
0658 
0659 bool Positioner::inLocationChangeAnimation()
0660 {
0661     return ((m_goToLocation != Plasma::Types::Floating) || (m_moveToLayout != "") || m_goToScreen);
0662 }
0663 
0664 void Positioner::hideDockDuringLocationChange(int goToLocation)
0665 {
0666     m_goToLocation = static_cast<Plasma::Types::Location>(goToLocation);
0667     emit hideDockDuringLocationChangeStarted();
0668 }
0669 
0670 void Positioner::hideDockDuringMovingToLayout(QString layoutName)
0671 {
0672     m_moveToLayout = layoutName;
0673     emit hideDockDuringMovingToLayoutStarted();
0674 }
0675 
0676 }
0677 }