File indexing completed on 2024-04-14 05:24:44

0001 /*
0002     SPDX-FileCopyrightText: 2018 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "positioner.h"
0007 
0008 // local
0009 #include <coretypes.h>
0010 #include "effects.h"
0011 #include "originalview.h"
0012 #include "view.h"
0013 #include "visibilitymanager.h"
0014 #include "../lattecorona.h"
0015 #include "../screenpool.h"
0016 #include "../data/screendata.h"
0017 #include "../layout/centrallayout.h"
0018 #include "../layouts/manager.h"
0019 #include "../settings/universalsettings.h"
0020 #include "../wm/abstractwindowinterface.h"
0021 
0022 // Qt
0023 #include <QDebug>
0024 
0025 // KDE
0026 #include <KWayland/Client/plasmashell.h>
0027 #include <KWayland/Client/surface.h>
0028 #include <KWindowSystem>
0029 
0030 #define RELOCATIONSHOWINGEVENT "viewInRelocationShowing"
0031 
0032 namespace Latte {
0033 namespace ViewPart {
0034 
0035 Positioner::Positioner(Latte::View *parent)
0036     : QObject(parent),
0037       m_view(parent)
0038 {
0039     m_screenSyncTimer.setSingleShot(true);
0040     m_screenSyncTimer.setInterval(2000);
0041     connect(&m_screenSyncTimer, &QTimer::timeout, this, &Positioner::reconsiderScreen);
0042 
0043     //! under X11 it was identified that windows many times especially under screen changes
0044     //! don't end up at the correct position and size. This timer will enforce repositionings
0045     //! and resizes every 500ms if the window hasn't end up to correct values and until this
0046     //! is achieved
0047     m_validateGeometryTimer.setSingleShot(true);
0048     m_validateGeometryTimer.setInterval(500);
0049     connect(&m_validateGeometryTimer, &QTimer::timeout, this, &Positioner::syncGeometry);
0050 
0051     //! syncGeometry() function is costly, so now we make sure that is not executed too often
0052     m_syncGeometryTimer.setSingleShot(true);
0053     m_syncGeometryTimer.setInterval(150);
0054     connect(&m_syncGeometryTimer, &QTimer::timeout, this, &Positioner::immediateSyncGeometry);
0055 
0056     m_corona = qobject_cast<Latte::Corona *>(m_view->corona());
0057 
0058     if (m_corona) {
0059         if (KWindowSystem::isPlatformX11()) {
0060             m_trackedWindowId = m_view->winId();
0061             m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
0062 
0063             connect(m_view, &Latte::View::forcedShown, this, [&]() {
0064                 m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId);
0065                 m_trackedWindowId = m_view->winId();
0066                 m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
0067             });
0068         } else {
0069             connect(m_view, &QWindow::windowTitleChanged, this, &Positioner::updateWaylandId);
0070             connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, &Positioner::updateWaylandId);
0071         }
0072 
0073         connect(m_corona->layoutsManager(), &Layouts::Manager::currentLayoutIsSwitching, this, &Positioner::onCurrentLayoutIsSwitching);
0074         /////
0075 
0076         m_screenSyncTimer.setInterval(qMax(m_corona->universalSettings()->screenTrackerInterval() - 500, 1000));
0077         connect(m_corona->universalSettings(), &UniversalSettings::screenTrackerIntervalChanged, this, [&]() {
0078             m_screenSyncTimer.setInterval(qMax(m_corona->universalSettings()->screenTrackerInterval() - 500, 1000));
0079         });
0080 
0081         connect(m_corona, &Latte::Corona::viewLocationChanged, this, [&]() {
0082             //! check if an edge has been freed for a primary dock
0083             //! from another screen
0084             if (m_view->onPrimary()) {
0085                 m_screenSyncTimer.start();
0086             }
0087         });
0088     }
0089 
0090     init();
0091 }
0092 
0093 Positioner::~Positioner()
0094 {
0095     m_inDelete = true;
0096     slideOutDuringExit();
0097     m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId);
0098 
0099     m_screenSyncTimer.stop();
0100     m_validateGeometryTimer.stop();
0101 }
0102 
0103 void Positioner::init()
0104 {
0105     //! connections
0106     connect(this, &Positioner::screenGeometryChanged, this, &Positioner::syncGeometry);
0107 
0108     connect(this, &Positioner::hidingForRelocationStarted, this, &Positioner::updateInRelocationAnimation);
0109     connect(this, &Positioner::showingAfterRelocationFinished, this, &Positioner::updateInRelocationAnimation);
0110     connect(this, &Positioner::showingAfterRelocationFinished, this, &Positioner::syncLatteViews);
0111     connect(this, &Positioner::startupFinished, this, &Positioner::onStartupFinished);
0112 
0113     connect(m_view, &Latte::View::onPrimaryChanged, this, &Positioner::syncLatteViews);
0114 
0115     connect(this, &Positioner::inSlideAnimationChanged, this, [&]() {
0116         if (!inSlideAnimation()) {
0117             syncGeometry();
0118         }
0119     });
0120 
0121     connect(this, &Positioner::isStickedOnTopEdgeChanged, this, [&]() {
0122         if (m_view->formFactor() == Plasma::Types::Vertical) {
0123             syncGeometry();
0124         }
0125     });
0126 
0127     connect(this, &Positioner::isStickedOnBottomEdgeChanged, this, [&]() {
0128         if (m_view->formFactor() == Plasma::Types::Vertical) {
0129             syncGeometry();
0130         }
0131     });
0132 
0133     connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() {
0134         if (m_view->formFactor() == Plasma::Types::Vertical && m_view->layout() && m_view->layout()->isCurrent()) {
0135             syncGeometry();
0136         }
0137     });
0138 
0139     connect(this, &Positioner::slideOffsetChanged, this, [&]() {
0140         updatePosition(m_lastAvailableScreenRect);
0141     });
0142 
0143     connect(m_view, &QQuickWindow::xChanged, this, &Positioner::validateDockGeometry);
0144     connect(m_view, &QQuickWindow::yChanged, this, &Positioner::validateDockGeometry);
0145     connect(m_view, &QQuickWindow::widthChanged, this, &Positioner::validateDockGeometry);
0146     connect(m_view, &QQuickWindow::heightChanged, this, &Positioner::validateDockGeometry);
0147     connect(m_view, &QQuickWindow::screenChanged, this, &Positioner::currentScreenChanged);
0148     connect(m_view, &QQuickWindow::screenChanged, this, &Positioner::onScreenChanged);
0149 
0150     connect(m_view, &Latte::View::behaveAsPlasmaPanelChanged, this, &Positioner::syncGeometry);
0151     connect(m_view, &Latte::View::maxThicknessChanged, this, &Positioner::syncGeometry);
0152 
0153     connect(m_view, &Latte::View::behaveAsPlasmaPanelChanged,  this, [&]() {
0154         if (!m_view->behaveAsPlasmaPanel() && m_slideOffset != 0) {
0155             m_slideOffset = 0;
0156             syncGeometry();
0157         }
0158     });
0159 
0160     connect(m_view, &Latte::View::offsetChanged, this, [&]() {
0161         updatePosition(m_lastAvailableScreenRect);
0162     });
0163 
0164     connect(m_view, &Latte::View::locationChanged, this, [&]() {
0165         updateFormFactor();
0166         syncGeometry();
0167     });
0168 
0169     connect(m_view, &Latte::View::editThicknessChanged, this, [&]() {
0170         updateCanvasGeometry(m_lastAvailableScreenRect);
0171     });
0172 
0173     connect(m_view, &Latte::View::maxLengthChanged, this, [&]() {
0174         if (m_view->behaveAsPlasmaPanel()) {
0175             syncGeometry();
0176         }
0177     });
0178 
0179     connect(m_view, &Latte::View::normalThicknessChanged, this, [&]() {
0180         if (m_view->behaveAsPlasmaPanel()) {
0181             syncGeometry();
0182         }
0183     });
0184 
0185     connect(m_view, &Latte::View::screenEdgeMarginEnabledChanged, this, [&]() {
0186         syncGeometry();
0187     });
0188 
0189     connect(m_view, &Latte::View::screenEdgeMarginChanged, this, [&]() {
0190         syncGeometry();
0191     });
0192 
0193     connect(m_view, &View::layoutChanged, this, [&]() {
0194         if (m_nextLayoutName.isEmpty() && m_view->layout() && m_view->formFactor() == Plasma::Types::Vertical) {
0195             syncGeometry();
0196         }
0197     });
0198 
0199     connect(m_view->effects(), &Latte::ViewPart::Effects::drawShadowsChanged, this, [&]() {
0200         if (!m_view->behaveAsPlasmaPanel()) {
0201             syncGeometry();
0202         }
0203     });
0204 
0205     connect(m_view->effects(), &Latte::ViewPart::Effects::innerShadowChanged, this, [&]() {
0206         if (m_view->behaveAsPlasmaPanel()) {
0207             syncGeometry();
0208         }
0209     });
0210 
0211     connect(qGuiApp, &QGuiApplication::screenAdded, this, &Positioner::onScreenChanged);
0212     connect(m_corona->screenPool(), &ScreenPool::primaryScreenChanged, this, &Positioner::onScreenChanged);
0213 
0214     connect(m_view, &Latte::View::visibilityChanged, this, &Positioner::initDelayedSignals);
0215 
0216     initSignalingForLocationChangeSliding();
0217 }
0218 
0219 void Positioner::initDelayedSignals()
0220 {
0221     connect(m_view->visibility(), &ViewPart::VisibilityManager::isHiddenChanged, this, [&]() {
0222         if (m_view->behaveAsPlasmaPanel() && !m_view->visibility()->isHidden() && qAbs(m_slideOffset)>0) {
0223             //! ignore any checks to make sure the panel geometry is up-to-date
0224             immediateSyncGeometry();
0225         }
0226     });
0227 }
0228 
0229 void Positioner::updateWaylandId()
0230 {
0231     QString validTitle = m_view->validTitle();
0232     if (validTitle.isEmpty()) {
0233         return;
0234     }
0235 
0236     Latte::WindowSystem::WindowId newId = m_corona->wm()->winIdFor("latte-dock", validTitle);
0237 
0238     if (m_trackedWindowId != newId) {
0239         if (!m_trackedWindowId.isNull()) {
0240             m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId);
0241         }
0242 
0243         m_trackedWindowId = newId;
0244         m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
0245 
0246         emit winIdChanged();
0247     }
0248 }
0249 
0250 bool Positioner::inRelocationShowing() const
0251 {
0252     return m_inRelocationShowing;
0253 }
0254 
0255 void Positioner::setInRelocationShowing(bool active)
0256 {
0257     if (m_inRelocationShowing == active) {
0258         return;
0259     }
0260 
0261     m_inRelocationShowing = active;
0262 
0263     if (m_inRelocationShowing) {
0264         m_view->visibility()->addBlockHidingEvent(RELOCATIONSHOWINGEVENT);
0265     } else {
0266         m_view->visibility()->removeBlockHidingEvent(RELOCATIONSHOWINGEVENT);
0267     }
0268 }
0269 
0270 bool Positioner::isOffScreen() const
0271 {
0272     return (m_view->absoluteGeometry().x()<-500 || m_view->absoluteGeometry().y()<-500);
0273 }
0274 
0275 int Positioner::currentScreenId() const
0276 {
0277     auto *latteCorona = qobject_cast<Latte::Corona *>(m_view->corona());
0278 
0279     if (latteCorona) {
0280         return latteCorona->screenPool()->id(m_screenNameToFollow);
0281     }
0282 
0283     return -1;
0284 }
0285 
0286 Latte::WindowSystem::WindowId Positioner::trackedWindowId()
0287 {
0288     if (KWindowSystem::isPlatformWayland() && m_trackedWindowId.toInt() <= 0) {
0289         updateWaylandId();
0290     }
0291 
0292     return m_trackedWindowId;
0293 }
0294 
0295 QString Positioner::currentScreenName() const
0296 {
0297     return m_screenNameToFollow;
0298 }
0299 
0300 WindowSystem::AbstractWindowInterface::Slide Positioner::slideLocation(Plasma::Types::Location location)
0301 {
0302     auto slideedge = WindowSystem::AbstractWindowInterface::Slide::None;
0303 
0304     if (location == Plasma::Types::Floating && m_view->containment()) {
0305         location = m_view->containment()->location();
0306     }
0307 
0308     switch (location) {
0309     case Plasma::Types::TopEdge:
0310         slideedge = WindowSystem::AbstractWindowInterface::Slide::Top;
0311         break;
0312 
0313     case Plasma::Types::RightEdge:
0314         slideedge = WindowSystem::AbstractWindowInterface::Slide::Right;
0315         break;
0316 
0317     case Plasma::Types::BottomEdge:
0318         slideedge = WindowSystem::AbstractWindowInterface::Slide::Bottom;
0319         break;
0320 
0321     case Plasma::Types::LeftEdge:
0322         slideedge = WindowSystem::AbstractWindowInterface::Slide::Left;
0323         break;
0324 
0325     default:
0326         qDebug() << staticMetaObject.className() << "wrong location";
0327         break;
0328     }
0329 
0330     return slideedge;
0331 }
0332 
0333 void Positioner::slideOutDuringExit(Plasma::Types::Location location)
0334 {
0335     if (m_view->isVisible()) {
0336         m_corona->wm()->slideWindow(*m_view, slideLocation(location));
0337         m_view->setVisible(false);
0338     }
0339 }
0340 
0341 void Positioner::slideInDuringStartup()
0342 {
0343     m_corona->wm()->slideWindow(*m_view, slideLocation(m_view->containment()->location()));
0344 }
0345 
0346 void Positioner::onStartupFinished()
0347 {
0348     if (m_inStartup) {
0349         m_inStartup = false;
0350         syncGeometry();
0351         emit isOffScreenChanged();
0352     }
0353 }
0354 
0355 void Positioner::onCurrentLayoutIsSwitching(const QString &layoutName)
0356 {
0357     if (!m_view || !m_view->layout() || m_view->layout()->name() != layoutName || !m_view->isVisible()) {
0358         return;
0359     }
0360 
0361     m_inLayoutUnloading = true;
0362     slideOutDuringExit();
0363 }
0364 
0365 void Positioner::setWindowOnActivities(const Latte::WindowSystem::WindowId &wid, const QStringList &activities)
0366 {
0367     m_corona->wm()->setWindowOnActivities(wid, activities);
0368 }
0369 
0370 void Positioner::syncLatteViews()
0371 {
0372     if (m_view->layout()) {
0373         //! This is needed in case the edge there are views that must be deleted
0374         //! after screen edges changes
0375         m_view->layout()->syncLatteViewsToScreens();
0376     }
0377 }
0378 
0379 void Positioner::updateContainmentScreen()
0380 {
0381     if (m_view->containment()) {
0382         m_view->containment()->reactToScreenChange();
0383     }
0384 }
0385 
0386 //! this function updates the dock's associated screen.
0387 //! updateScreenId = true, update also the m_screenNameToFollow
0388 //! updateScreenId = false, do not update the m_screenNameToFollow
0389 //! that way an explicit dock can be shown in another screen when
0390 //! there isnt a tasks dock running in the system and for that
0391 //! dock its first origin screen is stored and that way when
0392 //! that screen is reconnected the dock will return to its original
0393 //! place
0394 void Positioner::setScreenToFollow(QScreen *scr, bool updateScreenId)
0395 {
0396     if (!scr || (scr && (m_screenToFollow == scr) && (m_view->screen() == scr))) {
0397         return;
0398     }
0399 
0400     qDebug() << "setScreenToFollow() called for screen:" << scr->name() << " update:" << updateScreenId;
0401 
0402     m_screenToFollow = scr;
0403 
0404     if (updateScreenId) {
0405         m_screenNameToFollow = scr->name();
0406     }
0407 
0408     qDebug() << "adapting to screen...";
0409     m_view->setScreen(scr);
0410 
0411     updateContainmentScreen();
0412 
0413     connect(scr, &QScreen::geometryChanged, this, &Positioner::screenGeometryChanged);
0414     syncGeometry();
0415     m_view->updateAbsoluteGeometry(true);
0416     qDebug() << "setScreenToFollow() ended...";
0417 
0418     emit screenGeometryChanged();
0419     emit currentScreenChanged();
0420 }
0421 
0422 //! the main function which decides if this dock is at the
0423 //! correct screen
0424 void Positioner::reconsiderScreen()
0425 {
0426     if (m_inDelete) {
0427         return;
0428     }
0429 
0430     qDebug() << "reconsiderScreen() called...";
0431     qDebug() << "  Delayer  ";
0432 
0433     for (const auto scr : qGuiApp->screens()) {
0434         qDebug() << "      D, found screen: " << scr->name();
0435     }
0436 
0437     bool screenExists{false};
0438     QScreen *primaryScreen{m_corona->screenPool()->primaryScreen()};
0439 
0440     //!check if the associated screen is running
0441     for (const auto scr : qGuiApp->screens()) {
0442         if (m_screenNameToFollow == scr->name()
0443                 || (m_view->onPrimary() && scr == primaryScreen)) {
0444             screenExists = true;
0445         }
0446     }
0447 
0448     qDebug() << "dock screen exists  ::: " << screenExists;
0449 
0450     //! 1.a primary dock must be always on the primary screen
0451     if (m_view->onPrimary() && (m_screenNameToFollow != primaryScreen->name()
0452                                 || m_screenToFollow != primaryScreen
0453                                 || m_view->screen() != primaryScreen)) {
0454         //! case 1
0455         qDebug() << "reached case 1: of updating dock primary screen...";
0456         setScreenToFollow(primaryScreen);
0457     } else if (!m_view->onPrimary()) {
0458         //! 2.an explicit dock must be always on the correct associated screen
0459         //! there are cases that window manager misplaces the dock, this function
0460         //! ensures that this dock will return at its correct screen
0461         for (const auto scr : qGuiApp->screens()) {
0462             if (scr && scr->name() == m_screenNameToFollow) {
0463                 qDebug() << "reached case 2: updating the explicit screen for dock...";
0464                 setScreenToFollow(scr);
0465                 break;
0466             }
0467         }
0468     }
0469 
0470     syncGeometry();
0471     qDebug() << "reconsiderScreen() ended...";
0472 }
0473 
0474 void Positioner::onScreenChanged(QScreen *scr)
0475 {
0476     m_screenSyncTimer.start();
0477 
0478     //! this is needed in order to update the struts on screen change
0479     //! and even though the geometry has been set correctly the offsets
0480     //! of the screen must be updated to the new ones
0481     if (m_view->visibility() && m_view->visibility()->mode() == Latte::Types::AlwaysVisible) {
0482         m_view->updateAbsoluteGeometry(true);
0483     }
0484 }
0485 
0486 void Positioner::syncGeometry()
0487 {
0488     if (!(m_view->screen() && m_view->containment()) || m_inDelete || m_slideOffset!=0 || inSlideAnimation()) {
0489         return;
0490     }
0491 
0492     qDebug() << "syncGeometry() called...";
0493 
0494     if (!m_syncGeometryTimer.isActive()) {
0495         m_syncGeometryTimer.start();
0496     }
0497 }
0498 
0499 void Positioner::immediateSyncGeometry()
0500 {
0501     bool found{false};
0502 
0503     qDebug() << "immediateSyncGeometry() called...";
0504 
0505     //! before updating the positioning and geometry of the dock
0506     //! we make sure that the dock is at the correct screen
0507     if (m_view->screen() != m_screenToFollow) {
0508         qDebug() << "Sync Geometry screens inconsistent!!!! ";
0509 
0510         if (m_screenToFollow) {
0511             qDebug() << "Sync Geometry screens inconsistent for m_screenToFollow:" << m_screenToFollow->name() << " dock screen:" << m_view->screen()->name();
0512         }
0513 
0514         if (!m_screenSyncTimer.isActive()) {
0515             m_screenSyncTimer.start();
0516         }
0517     } else {
0518         found = true;
0519     }
0520 
0521     //! if the dock isnt at the correct screen the calculations
0522     //! are not executed
0523     if (found) {
0524         //! compute the free screen rectangle for vertical panels only once
0525         //! this way the costly QRegion computations are calculated only once
0526         //! instead of two times (both inside the resizeWindow and the updatePosition)
0527         QRegion freeRegion;;
0528         QRect maximumRect;
0529         QRect availableScreenRect = m_view->screen()->geometry();
0530 
0531         if (m_inStartup) {
0532             //! paint out-of-screen
0533             availableScreenRect = QRect(-9999, -9999, m_view->screen()->geometry().width(), m_view->screen()->geometry().height());
0534         }
0535 
0536         if (m_view->formFactor() == Plasma::Types::Vertical) {
0537             QString layoutName = m_view->layout() ? m_view->layout()->name() : QString();
0538             auto latteCorona = qobject_cast<Latte::Corona *>(m_view->corona());
0539             int fixedScreen = m_view->onPrimary() ? latteCorona->screenPool()->primaryScreenId() : m_view->containment()->screen();
0540 
0541             QList<Types::Visibility> ignoreModes({Latte::Types::AutoHide,
0542                                                   Latte::Types::SidebarOnDemand,
0543                                                   Latte::Types::SidebarAutoHide});
0544 
0545             QList<Plasma::Types::Location> ignoreEdges({Plasma::Types::LeftEdge,
0546                                                         Plasma::Types::RightEdge});
0547 
0548             if (m_isStickedOnTopEdge && m_isStickedOnBottomEdge) {
0549                 //! dont send an empty edges array because that means include all screen edges in calculations
0550                 ignoreEdges << Plasma::Types::TopEdge;
0551                 ignoreEdges << Plasma::Types::BottomEdge;
0552             } else {
0553                 if (m_isStickedOnTopEdge) {
0554                     ignoreEdges << Plasma::Types::TopEdge;
0555                 }
0556 
0557                 if (m_isStickedOnBottomEdge) {
0558                     ignoreEdges << Plasma::Types::BottomEdge;
0559                 }
0560             }
0561 
0562             QString activityid = m_view->layout() ? m_view->layout()->lastUsedActivity() : QString();
0563             if (m_inStartup) {
0564                 //! paint out-of-screen
0565                 freeRegion = availableScreenRect;
0566             } else {
0567                 freeRegion = latteCorona->availableScreenRegionWithCriteria(fixedScreen, activityid, ignoreModes, ignoreEdges);
0568             }
0569 
0570             //! On startup when offscreen use offscreen screen geometry.
0571             //! This way vertical docks and panels are not showing are shrinked that
0572             //! need to be expanded after sliding-in in startup
0573             maximumRect = maximumNormalGeometry(m_inStartup ? availableScreenRect : QRect());
0574             QRegion availableRegion = freeRegion.intersected(maximumRect);
0575 
0576             availableScreenRect = freeRegion.intersected(maximumRect).boundingRect();
0577             float area = 0;
0578 
0579             //! it is used to choose which or the availableRegion rectangles will
0580             //! be the one representing dock geometry
0581             for (QRegion::const_iterator p_rect=availableRegion.begin(); p_rect!=availableRegion.end(); ++p_rect) {
0582                 //! the area of each rectangle in calculated in squares of 50x50
0583                 //! this is a way to avoid enourmous numbers for area value
0584                 float tempArea = (float)((*p_rect).width() * (*p_rect).height()) / 2500;
0585 
0586                 if (tempArea > area) {
0587                     availableScreenRect = (*p_rect);
0588                     area = tempArea;
0589                 }
0590             }
0591 
0592             validateTopBottomBorders(availableScreenRect, freeRegion);
0593             m_lastAvailableScreenRegion = freeRegion;
0594         } else {
0595             m_view->effects()->setForceTopBorder(false);
0596             m_view->effects()->setForceBottomBorder(false);
0597         }
0598 
0599         m_lastAvailableScreenRect = availableScreenRect;
0600 
0601         m_view->effects()->updateEnabledBorders();
0602 
0603         resizeWindow(availableScreenRect);
0604         updatePosition(availableScreenRect);
0605         updateCanvasGeometry(availableScreenRect);
0606 
0607         qDebug() << "syncGeometry() calculations for screen: " << m_view->screen()->name() << " _ " << m_view->screen()->geometry();
0608         qDebug() << "syncGeometry() calculations for edge: " << m_view->location();
0609     }
0610 
0611     qDebug() << "syncGeometry() ended...";
0612 
0613     // qDebug() << "dock geometry:" << qRectToStr(geometry());
0614 }
0615 
0616 void Positioner::validateDockGeometry()
0617 {
0618     if (m_slideOffset==0 && m_view->geometry() != m_validGeometry) {
0619         m_validateGeometryTimer.start();
0620     }
0621 }
0622 
0623 QRect Positioner::canvasGeometry()
0624 {
0625     return m_canvasGeometry;
0626 }
0627 
0628 void Positioner::setCanvasGeometry(const QRect &geometry)
0629 {
0630     if (m_canvasGeometry == geometry) {
0631         return;
0632     }
0633 
0634     m_canvasGeometry = geometry;
0635     emit canvasGeometryChanged();
0636 }
0637 
0638 
0639 //! this is used mainly from vertical panels in order to
0640 //! to get the maximum geometry that can be used from the dock
0641 //! based on their alignment type and the location dock
0642 QRect Positioner::maximumNormalGeometry(QRect screenGeometry)
0643 {
0644     QRect currentScrGeometry = screenGeometry.isEmpty() ? m_view->screen()->geometry() : screenGeometry;
0645 
0646     int xPos = 0;
0647     int yPos = currentScrGeometry.y();;
0648     int maxHeight = currentScrGeometry.height();
0649     int maxWidth = m_view->maxNormalThickness();
0650     QRect maxGeometry;
0651     maxGeometry.setRect(0, 0, maxWidth, maxHeight);
0652 
0653     switch (m_view->location()) {
0654     case Plasma::Types::LeftEdge:
0655         xPos = currentScrGeometry.x();
0656         maxGeometry.setRect(xPos, yPos, maxWidth, maxHeight);
0657         break;
0658 
0659     case Plasma::Types::RightEdge:
0660         xPos = currentScrGeometry.right() - maxWidth + 1;
0661         maxGeometry.setRect(xPos, yPos, maxWidth, maxHeight);
0662         break;
0663 
0664     default:
0665         //! bypass clang warnings
0666         break;
0667     }
0668 
0669     return maxGeometry;
0670 }
0671 
0672 void Positioner::validateTopBottomBorders(QRect availableScreenRect, QRegion availableScreenRegion)
0673 {
0674     //! Check if the the top/bottom borders must be drawn also
0675     int edgeMargin = qMax(1, m_view->screenEdgeMargin());
0676 
0677     if (availableScreenRect.top() != m_view->screenGeometry().top()) {
0678         //! check top border
0679         int x = m_view->location() == Plasma::Types::LeftEdge ? m_view->screenGeometry().x() : m_view->screenGeometry().right() - edgeMargin + 1;
0680         QRegion fitInRegion = QRect(x, availableScreenRect.y()-1, edgeMargin, 1);
0681         QRegion subtracted = fitInRegion.subtracted(availableScreenRegion);
0682 
0683         if (subtracted.isNull()) {
0684             //!FitIn rectangle fits TOTALLY in the free screen region and as such
0685             //!the top border should be drawn
0686             m_view->effects()->setForceTopBorder(true);
0687         } else {
0688             m_view->effects()->setForceTopBorder(false);
0689         }
0690     } else {
0691         m_view->effects()->setForceTopBorder(false);
0692     }
0693 
0694     if (availableScreenRect.bottom() != m_view->screenGeometry().bottom()) {
0695         //! check top border
0696         int x = m_view->location() == Plasma::Types::LeftEdge ? m_view->screenGeometry().x() : m_view->screenGeometry().right()  - edgeMargin + 1;
0697         QRegion fitInRegion = QRect(x, availableScreenRect.bottom()+1, edgeMargin, 1);
0698         QRegion subtracted = fitInRegion.subtracted(availableScreenRegion);
0699 
0700         if (subtracted.isNull()) {
0701             //!FitIn rectangle fits TOTALLY in the free screen region and as such
0702             //!the BOTTOM border should be drawn
0703             m_view->effects()->setForceBottomBorder(true);
0704         } else {
0705             m_view->effects()->setForceBottomBorder(false);
0706         }
0707     } else {
0708         m_view->effects()->setForceBottomBorder(false);
0709     }
0710 }
0711 
0712 void Positioner::updateCanvasGeometry(QRect availableScreenRect)
0713 {
0714     if (availableScreenRect.isEmpty()) {
0715         return;
0716     }
0717 
0718     QRect canvas;
0719     QRect screenGeometry{m_view->screen()->geometry()};
0720     int thickness{m_view->editThickness()};
0721 
0722     if (m_view->formFactor() == Plasma::Types::Vertical) {
0723         canvas.setWidth(thickness);
0724         canvas.setHeight(availableScreenRect.height());
0725     } else {
0726         canvas.setWidth(screenGeometry.width());
0727         canvas.setHeight(thickness);
0728     }
0729 
0730     switch (m_view->location()) {
0731     case Plasma::Types::TopEdge:
0732         canvas.moveLeft(screenGeometry.x());
0733         canvas.moveTop(screenGeometry.y());
0734         break;
0735 
0736     case Plasma::Types::BottomEdge:
0737         canvas.moveLeft(screenGeometry.x());
0738         canvas.moveTop(screenGeometry.bottom() - thickness + 1);
0739         break;
0740 
0741     case Plasma::Types::RightEdge:
0742         canvas.moveLeft(screenGeometry.right() - thickness + 1);
0743         canvas.moveTop(availableScreenRect.y());
0744         break;
0745 
0746     case Plasma::Types::LeftEdge:
0747         canvas.moveLeft(availableScreenRect.x());
0748         canvas.moveTop(availableScreenRect.y());
0749         break;
0750 
0751     default:
0752         qWarning() << "wrong location, couldn't update the canvas config window geometry " << m_view->location();
0753     }
0754 
0755     setCanvasGeometry(canvas);
0756 }
0757 
0758 void Positioner::updatePosition(QRect availableScreenRect)
0759 {
0760     QRect screenGeometry{availableScreenRect};
0761     QPoint position;
0762     position = {0, 0};
0763 
0764     const auto gap = [&](int scr_length) -> int {
0765         return static_cast<int>(scr_length * m_view->offset());
0766     };
0767     const auto gapCentered = [&](int scr_length) -> int {
0768         return static_cast<int>(scr_length * ((1 - m_view->maxLength()) / 2) + scr_length * m_view->offset());
0769     };
0770     const auto gapReversed = [&](int scr_length) -> int {
0771         return static_cast<int>(scr_length - (scr_length * m_view->maxLength()) - gap(scr_length));
0772     };
0773 
0774     int cleanThickness = m_view->normalThickness() - m_view->effects()->innerShadow();
0775 
0776     int screenEdgeMargin = m_view->behaveAsPlasmaPanel() ? m_view->screenEdgeMargin() - qAbs(m_slideOffset) : 0;
0777 
0778     switch (m_view->location()) {
0779     case Plasma::Types::TopEdge:
0780         if (m_view->behaveAsPlasmaPanel()) {
0781             int y = screenGeometry.y() + screenEdgeMargin;
0782 
0783             if (m_view->alignment() == Latte::Types::Left) {
0784                 position = {screenGeometry.x() + gap(screenGeometry.width()), y};
0785             } else if (m_view->alignment() == Latte::Types::Right) {
0786                 position = {screenGeometry.x() + gapReversed(screenGeometry.width()) + 1, y};
0787             } else {
0788                 position = {screenGeometry.x() + gapCentered(screenGeometry.width()), y};
0789             }
0790         } else {
0791             position = {screenGeometry.x(), screenGeometry.y()};
0792         }
0793 
0794         break;
0795 
0796     case Plasma::Types::BottomEdge:
0797         if (m_view->behaveAsPlasmaPanel()) {
0798             int y = screenGeometry.y() + screenGeometry.height() - cleanThickness - screenEdgeMargin;
0799 
0800             if (m_view->alignment() == Latte::Types::Left) {
0801                 position = {screenGeometry.x() + gap(screenGeometry.width()), y};
0802             } else if (m_view->alignment() == Latte::Types::Right) {
0803                 position = {screenGeometry.x() + gapReversed(screenGeometry.width()) + 1, y};
0804             } else {
0805                 position = {screenGeometry.x() + gapCentered(screenGeometry.width()), y};
0806             }
0807         } else {
0808             position = {screenGeometry.x(), screenGeometry.y() + screenGeometry.height() - m_view->height()};
0809         }
0810 
0811         break;
0812 
0813     case Plasma::Types::RightEdge:
0814         if (m_view->behaveAsPlasmaPanel()) {
0815             int x = availableScreenRect.right() - cleanThickness + 1 - screenEdgeMargin;
0816 
0817             if (m_view->alignment() == Latte::Types::Top) {
0818                 position = {x, availableScreenRect.y() + gap(availableScreenRect.height())};
0819             } else if (m_view->alignment() == Latte::Types::Bottom) {
0820                 position = {x, availableScreenRect.y() + gapReversed(availableScreenRect.height()) + 1};
0821             } else {
0822                 position = {x, availableScreenRect.y() + gapCentered(availableScreenRect.height())};
0823             }
0824         } else {
0825             position = {availableScreenRect.right() - m_view->width() + 1, availableScreenRect.y()};
0826         }
0827 
0828         break;
0829 
0830     case Plasma::Types::LeftEdge:
0831         if (m_view->behaveAsPlasmaPanel()) {
0832             int x = availableScreenRect.x() + screenEdgeMargin;
0833 
0834             if (m_view->alignment() == Latte::Types::Top) {
0835                 position = {x, availableScreenRect.y() + gap(availableScreenRect.height())};
0836             } else if (m_view->alignment() == Latte::Types::Bottom) {
0837                 position = {x, availableScreenRect.y() + gapReversed(availableScreenRect.height()) + 1};
0838             } else {
0839                 position = {x, availableScreenRect.y() + gapCentered(availableScreenRect.height())};
0840             }
0841         } else {
0842             position = {availableScreenRect.x(), availableScreenRect.y()};
0843         }
0844 
0845         break;
0846 
0847     default:
0848         qWarning() << "wrong location, couldn't update the panel position"
0849                    << m_view->location();
0850     }
0851 
0852     if (m_slideOffset == 0 || m_nextScreenEdge != Plasma::Types::Floating /*exactly after relocating and changing screen edge*/) {
0853         //! update valid geometry in normal positioning
0854         m_validGeometry.moveTopLeft(position);
0855     } else {
0856         //! when sliding in/out update only the relevant axis for the screen_edge in
0857         //! to not mess the calculations and the automatic geometry checkers that
0858         //! View::Positioner is using.
0859         if (m_view->formFactor() == Plasma::Types::Horizontal) {
0860             m_validGeometry.moveLeft(position.x());
0861         } else {
0862             m_validGeometry.moveTop(position.y());
0863         }
0864     }
0865 
0866     m_view->setPosition(position);
0867 
0868     if (m_view->surface()) {
0869         m_view->surface()->setPosition(position);
0870     }
0871 }
0872 
0873 int Positioner::slideOffset() const
0874 {
0875     return m_slideOffset;
0876 }
0877 
0878 void Positioner::setSlideOffset(int offset)
0879 {
0880     if (m_slideOffset == offset) {
0881         return;
0882     }
0883 
0884     m_slideOffset = offset;
0885     emit slideOffsetChanged();
0886 }
0887 
0888 
0889 void Positioner::resizeWindow(QRect availableScreenRect)
0890 {
0891     QSize screenSize = m_view->screen()->size();
0892     QSize size = (m_view->formFactor() == Plasma::Types::Vertical) ? QSize(m_view->maxThickness(), availableScreenRect.height()) : QSize(screenSize.width(), m_view->maxThickness());
0893 
0894     if (m_view->formFactor() == Plasma::Types::Vertical) {
0895         //qDebug() << "MAXIMUM RECT :: " << maximumRect << " - AVAILABLE RECT :: " << availableRect;
0896         if (m_view->behaveAsPlasmaPanel()) {
0897             size.setWidth(m_view->normalThickness());
0898             size.setHeight(static_cast<int>(m_view->maxLength() * availableScreenRect.height()));
0899         }
0900     } else {
0901         if (m_view->behaveAsPlasmaPanel()) {
0902             size.setWidth(static_cast<int>(m_view->maxLength() * screenSize.width()));
0903             size.setHeight(m_view->normalThickness());
0904         }
0905     }
0906 
0907     //! protect from invalid window size under wayland
0908     size.setWidth(qMax(1, size.width()));
0909     size.setHeight(qMax(1, size.height()));
0910 
0911     m_validGeometry.setSize(size);
0912 
0913     m_view->setMinimumSize(size);
0914     m_view->setMaximumSize(size);
0915     m_view->resize(size);
0916 
0917     if (m_view->formFactor() == Plasma::Types::Horizontal) {
0918         emit windowSizeChanged();
0919     }
0920 }
0921 
0922 void Positioner::updateFormFactor()
0923 {
0924     if (!m_view->containment())
0925         return;
0926 
0927     switch (m_view->location()) {
0928     case Plasma::Types::TopEdge:
0929     case Plasma::Types::BottomEdge:
0930         m_view->containment()->setFormFactor(Plasma::Types::Horizontal);
0931         break;
0932 
0933     case Plasma::Types::LeftEdge:
0934     case Plasma::Types::RightEdge:
0935         m_view->containment()->setFormFactor(Plasma::Types::Vertical);
0936         break;
0937 
0938     default:
0939         qWarning() << "wrong location, couldn't update the panel position" << m_view->location();
0940     }
0941 }
0942 
0943 void Positioner::onLastRepositionApplyEvent()
0944 {
0945     m_view->effects()->setAnimationsBlocked(false);
0946     setInRelocationShowing(true);
0947     emit showingAfterRelocationFinished();
0948     emit edgeChanged();
0949 
0950     if (m_repositionFromViewSettingsWindow) {
0951         m_repositionFromViewSettingsWindow = false;
0952         m_view->showSettingsWindow();
0953     }
0954 }
0955 
0956 void Positioner::initSignalingForLocationChangeSliding()
0957 {
0958     connect(this, &Positioner::hidingForRelocationStarted, this, &Positioner::onHideWindowsForSlidingOut);
0959 
0960     //! SCREEN_EDGE
0961     connect(m_view, &View::locationChanged, this, [&]() {
0962         if (m_nextScreenEdge != Plasma::Types::Floating) {
0963             bool isrelocationlastevent = isLastHidingRelocationEvent();
0964             immediateSyncGeometry();
0965             m_nextScreenEdge = Plasma::Types::Floating;
0966 
0967             //! make sure that View has been repositioned properly in next screen edge and show view afterwards
0968             if (isrelocationlastevent) {
0969                 QTimer::singleShot(100, [this]() {
0970                     onLastRepositionApplyEvent();
0971                 });
0972             }
0973         }
0974     });
0975 
0976     //! SCREEN
0977     connect(m_view, &QQuickView::screenChanged, this, [&]() {
0978         if (!m_view || !m_nextScreen) {
0979             return;
0980         }
0981 
0982         //[1] if panels are not excluded from confirmed geometry check then they are stuck in sliding out end
0983         //and they do not switch to new screen geometry
0984         //[2] under wayland view geometry may be delayed to be updated even though the screen has been updated correctly
0985         bool confirmedgeometry = KWindowSystem::isPlatformWayland() || m_view->behaveAsPlasmaPanel() || (!m_view->behaveAsPlasmaPanel() && m_nextScreen->geometry().contains(m_view->geometry().center()));
0986 
0987         if (m_nextScreen
0988                 && m_nextScreen == m_view->screen()
0989                 && confirmedgeometry) {
0990             bool isrelocationlastevent = isLastHidingRelocationEvent();
0991             m_nextScreen = nullptr;
0992             m_nextScreenName = "";
0993 
0994             //! make sure that View has been repositioned properly in next screen and show view afterwards
0995             if (isrelocationlastevent) {
0996                 QTimer::singleShot(100, [this]() {
0997                     onLastRepositionApplyEvent();
0998                 });
0999             }
1000         }
1001     });
1002 
1003     //! LAYOUT
1004     connect(m_view, &View::layoutChanged, this, [&]() {
1005         if (!m_nextLayoutName.isEmpty() && m_view->layout()) {
1006             bool isrelocationlastevent = isLastHidingRelocationEvent();
1007             m_nextLayoutName = "";
1008 
1009             //! make sure that View has been repositioned properly in next layout and show view afterwards
1010             if (isrelocationlastevent) {
1011                 QTimer::singleShot(100, [this]() {
1012                     onLastRepositionApplyEvent();
1013                 });
1014             }
1015         }
1016     });
1017 
1018     //! APPLY CHANGES
1019     connect(this, &Positioner::hidingForRelocationFinished, this, [&]() {
1020         //! must be called only if relocation is animated
1021         if (m_repositionIsAnimated) {
1022             m_repositionIsAnimated = false;
1023             m_view->effects()->setAnimationsBlocked(true);
1024         }
1025 
1026         //! LAYOUT
1027         if (!m_nextLayoutName.isEmpty()) {
1028             m_corona->layoutsManager()->moveView(m_view->layout()->name(), m_view->containment()->id(), m_nextLayoutName);
1029         }
1030 
1031         //! SCREEN
1032         if (!m_nextScreenName.isEmpty()) {
1033             bool nextonprimary = (m_nextScreenName == Latte::Data::Screen::ONPRIMARYNAME);
1034             m_nextScreen = m_corona->screenPool()->primaryScreen();
1035 
1036             if (!nextonprimary) {
1037                 for (const auto scr : qGuiApp->screens()) {
1038                     if (scr && scr->name() == m_nextScreenName) {
1039                         m_nextScreen = scr;
1040                         break;
1041                     }
1042                 }
1043             }
1044 
1045             m_view->setOnPrimary(nextonprimary);
1046             setScreenToFollow(m_nextScreen);
1047         }
1048 
1049         //! SCREEN_EDGE
1050         if (m_nextScreenEdge != Plasma::Types::Floating) {
1051             m_view->setLocation(m_nextScreenEdge);
1052         }
1053 
1054         //! ALIGNMENT
1055         if (m_nextAlignment != Latte::Types::NoneAlignment && m_nextAlignment != m_view->alignment()) {
1056             m_view->setAlignment(m_nextAlignment);
1057             m_nextAlignment = Latte::Types::NoneAlignment;
1058         }
1059 
1060         //! SCREENSGROUP
1061         if (m_view->isOriginal()) {
1062             auto originalview = qobject_cast<Latte::OriginalView *>(m_view);
1063             originalview->setScreensGroup(m_nextScreensGroup);
1064         }
1065     });
1066 }
1067 
1068 bool Positioner::inLayoutUnloading()
1069 {
1070     return m_inLayoutUnloading;
1071 }
1072 
1073 bool Positioner::inRelocationAnimation()
1074 {
1075     return ((m_nextScreenEdge != Plasma::Types::Floating) || !m_nextLayoutName.isEmpty() || !m_nextScreenName.isEmpty());
1076 }
1077 
1078 bool Positioner::inSlideAnimation() const
1079 {
1080     return m_inSlideAnimation;
1081 }
1082 
1083 void Positioner::setInSlideAnimation(bool active)
1084 {
1085     if (m_inSlideAnimation == active) {
1086         return;
1087     }
1088 
1089     m_inSlideAnimation = active;
1090     emit inSlideAnimationChanged();
1091 }
1092 
1093 bool Positioner::isCursorInsideView() const
1094 {
1095     return m_view->geometry().contains(QCursor::pos(m_screenToFollow));
1096 }
1097 
1098 bool Positioner::isStickedOnTopEdge() const
1099 {
1100     return m_isStickedOnTopEdge;
1101 }
1102 
1103 void Positioner::setIsStickedOnTopEdge(bool sticked)
1104 {
1105     if (m_isStickedOnTopEdge == sticked) {
1106         return;
1107     }
1108 
1109     m_isStickedOnTopEdge = sticked;
1110     emit isStickedOnTopEdgeChanged();
1111 }
1112 
1113 bool Positioner::isStickedOnBottomEdge() const
1114 {
1115     return m_isStickedOnBottomEdge;
1116 }
1117 
1118 void Positioner::setIsStickedOnBottomEdge(bool sticked)
1119 {
1120     if (m_isStickedOnBottomEdge == sticked) {
1121         return;
1122     }
1123 
1124     m_isStickedOnBottomEdge = sticked;
1125     emit isStickedOnBottomEdgeChanged();
1126 }
1127 
1128 void Positioner::updateInRelocationAnimation()
1129 {
1130     bool inrelocationanimation = inRelocationAnimation();
1131 
1132     if (m_inRelocationAnimation == inrelocationanimation) {
1133         return;
1134     }
1135 
1136     m_inRelocationAnimation = inrelocationanimation;
1137     emit inRelocationAnimationChanged();
1138 }
1139 
1140 bool Positioner::isLastHidingRelocationEvent() const
1141 {
1142     int events{0};
1143 
1144     if (!m_nextLayoutName.isEmpty()) {
1145         events++;
1146     }
1147 
1148     if (!m_nextScreenName.isEmpty()){
1149         events++;
1150     }
1151 
1152     if (m_nextScreenEdge != Plasma::Types::Floating) {
1153         events++;
1154     }
1155 
1156     return (events <= 1);
1157 }
1158 
1159 void Positioner::setNextLocation(const QString layoutName, const int screensGroup, QString screenName, int edge, int alignment)
1160 {
1161     bool isanimated{false};
1162     bool haschanges{false};
1163 
1164     //! LAYOUT
1165     if (!layoutName.isEmpty()) {
1166         auto layout = m_view->layout();
1167         auto origin = qobject_cast<CentralLayout *>(layout);
1168         auto destination = m_corona->layoutsManager()->synchronizer()->centralLayout(layoutName);
1169 
1170         if (origin && destination && origin!=destination) {
1171             //! Needs to be updated; when the next layout is in the same Visible Workarea
1172             //! with the old one changing layouts should be instant
1173             bool inVisibleWorkarea{origin->lastUsedActivity() == destination->lastUsedActivity()};
1174 
1175             haschanges = true;
1176             m_nextLayoutName = layoutName;
1177 
1178             if (!inVisibleWorkarea) {
1179                 isanimated = true;
1180             }
1181         }
1182     }
1183 
1184     //! SCREENSGROUP
1185     if (m_view->isOriginal()) {
1186         auto originalview = qobject_cast<Latte::OriginalView *>(m_view);
1187         //!initialize screens group
1188         m_nextScreensGroup = originalview->screensGroup();
1189 
1190         if (m_nextScreensGroup != screensGroup) {
1191             haschanges = true;
1192             m_nextScreensGroup = static_cast<Latte::Types::ScreensGroup>(screensGroup);
1193 
1194             if (m_nextScreensGroup == Latte::Types::AllScreensGroup) {
1195                 screenName = Latte::Data::Screen::ONPRIMARYNAME;
1196             } else if (m_nextScreensGroup == Latte::Types::AllSecondaryScreensGroup) {
1197                 int scrid = originalview->expectedScreenIdFromScreenGroup(m_nextScreensGroup);
1198 
1199                 if (scrid != Latte::ScreenPool::NOSCREENID) {
1200                     screenName = m_corona->screenPool()->connector(scrid);
1201                 }
1202             }
1203         }
1204     } else {
1205         m_nextScreensGroup = Latte::Types::SingleScreenGroup;
1206     }
1207 
1208     //! SCREEN
1209     if (!screenName.isEmpty()) {
1210         bool nextonprimary = (screenName == Latte::Data::Screen::ONPRIMARYNAME);
1211 
1212         if ( (m_view->onPrimary() && !nextonprimary) /*primary -> explicit*/
1213              || (!m_view->onPrimary() && nextonprimary) /*explicit -> primary*/
1214              || (!m_view->onPrimary() && !nextonprimary && screenName != currentScreenName()) ) { /*explicit -> new_explicit*/
1215 
1216             QString nextscreenname = nextonprimary ? m_corona->screenPool()->primaryScreen()->name() : screenName;
1217 
1218             if (currentScreenName() == nextscreenname) {
1219                 m_view->setOnPrimary(nextonprimary);
1220                 updateContainmentScreen();
1221             } else {
1222                 m_nextScreenName = screenName;
1223                 isanimated = true;
1224                 haschanges = true;
1225             }
1226         }
1227     }
1228 
1229     //! SCREEN_EDGE
1230     if (edge != Plasma::Types::Floating) {
1231         if (edge != m_view->location()) {
1232             m_nextScreenEdge = static_cast<Plasma::Types::Location>(edge);
1233             isanimated = true;
1234             haschanges = true;
1235         }
1236     }
1237 
1238     //! ALIGNMENT
1239     if (alignment != Latte::Types::NoneAlignment && m_view->alignment() != alignment) {
1240         m_nextAlignment = static_cast<Latte::Types::Alignment>(alignment);
1241         haschanges = true;
1242     }
1243 
1244     if (haschanges && m_view->isOriginal()) {
1245         auto originalview = qobject_cast<Latte::OriginalView *>(m_view);
1246         originalview->setNextLocationForClones(layoutName, edge, alignment);
1247     }
1248 
1249     m_repositionIsAnimated = isanimated;
1250     m_repositionFromViewSettingsWindow = m_view->settingsWindowIsShown();
1251 
1252     if (isanimated) {
1253         emit hidingForRelocationStarted();
1254     } else if (haschanges){
1255         emit hidingForRelocationFinished();
1256     }
1257 }
1258 
1259 }
1260 }