diff --git a/app/view/visibilitymanager.cpp b/app/view/visibilitymanager.cpp index 7c3f5ee6..de91eb9d 100644 --- a/app/view/visibilitymanager.cpp +++ b/app/view/visibilitymanager.cpp @@ -1,768 +1,765 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "visibilitymanager.h" // local #include "positioner.h" #include "screenedgeghostwindow.h" #include "view.h" #include "../lattecorona.h" #include "../layoutmanager.h" #include "../screenpool.h" #include "../wm/windowinfowrap.h" #include "../../liblatte2/extras.h" // Qt #include // KDE #include #include namespace Latte { namespace ViewPart { //! BEGIN: VisiblityManager implementation VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view) : QObject(view) { qDebug() << "VisibilityManager creating..."; m_latteView = qobject_cast(view); m_corona = qobject_cast(view->corona()); wm = m_corona->wm(); if (m_latteView) { connect(m_latteView, &Latte::View::absGeometryChanged, this, &VisibilityManager::setViewGeometry); connect(m_latteView, &Latte::View::eventTriggered, this, &VisibilityManager::viewEventManager); } if (m_corona) { connect(this, &VisibilityManager::modeChanged, m_corona, &Plasma::Corona::availableScreenRectChanged); } m_timerStartUp.setInterval(5000); m_timerStartUp.setSingleShot(true); m_timerShow.setSingleShot(true); m_timerHide.setSingleShot(true); connect(&m_timerShow, &QTimer::timeout, this, [&]() { if (m_isHidden) { // qDebug() << "must be shown"; emit mustBeShown(); } }); connect(&m_timerHide, &QTimer::timeout, this, [&]() { if (!m_blockHiding && !m_isHidden && !dragEnter) { // qDebug() << "must be hide"; emit mustBeHide(); } }); wm->setViewExtraFlags(*m_latteView); wm->addView(m_latteView->winId()); restoreConfig(); } VisibilityManager::~VisibilityManager() { qDebug() << "VisibilityManager deleting..."; wm->removeViewStruts(*m_latteView); wm->removeView(m_latteView->winId()); if (edgeGhostWindow) { edgeGhostWindow->deleteLater(); } } Types::Visibility VisibilityManager::mode() const { return m_mode; } void VisibilityManager::setMode(Latte::Types::Visibility mode) { if (m_mode == mode) return; Q_ASSERT_X(m_mode != Types::None, staticMetaObject.className(), "set visibility to Types::None"); // clear mode for (auto &c : connections) { disconnect(c); } if (m_mode == Types::AlwaysVisible) { wm->removeViewStruts(*m_latteView); } else { connections[3] = connect(wm, &WindowSystem::currentDesktopChanged , this, [&] { if (raiseOnDesktopChange) raiseViewTemporarily(); }); connections[4] = connect(wm, &WindowSystem::currentActivityChanged , this, [&]() { if (raiseOnActivityChange) raiseViewTemporarily(); else updateHiddenState(); }); } m_timerShow.stop(); m_timerHide.stop(); m_mode = mode; switch (m_mode) { case Types::AlwaysVisible: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } if (m_latteView->containment() && !m_latteView->inEditMode() && m_latteView->screen()) { updateStrutsBasedOnLayoutsAndActivities(); } connections[0] = connect(m_latteView->containment(), &Plasma::Containment::locationChanged , this, [&]() { if (m_latteView->inEditMode()) wm->removeViewStruts(*m_latteView); }); connections[1] = connect(m_latteView, &Latte::View::inEditModeChanged , this, [&]() { if (!m_latteView->inEditMode() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->screen()) wm->setViewStruts(*m_latteView, m_viewGeometry, m_latteView->containment()->location()); }); if (m_corona && m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { connections[2] = connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() { updateStrutsBasedOnLayoutsAndActivities(); }); connections[3] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() { updateStrutsBasedOnLayoutsAndActivities(); }); } raiseView(true); } break; case Types::AutoHide: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } raiseView(m_containsMouse); } break; case Types::DodgeActive: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } connections[0] = connect(wm, &WindowSystem::activeWindowChanged , this, &VisibilityManager::dodgeActive); connections[1] = connect(wm, &WindowSystem::windowChanged , this, &VisibilityManager::dodgeActive); dodgeActive(wm->activeWindow()); } break; case Types::DodgeMaximized: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } connections[0] = connect(wm, &WindowSystem::activeWindowChanged , this, &VisibilityManager::dodgeMaximized); connections[1] = connect(wm, &WindowSystem::windowChanged , this, &VisibilityManager::dodgeMaximized); dodgeMaximized(wm->activeWindow()); } break; case Types::DodgeAllWindows: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } connections[0] = connect(this, &VisibilityManager::containsMouseChanged , this, &VisibilityManager::dodgeAllWindows); connections[1] = connect(m_latteView->windowsTracker(), &WindowsTracker::existsWindowTouchingChanged , this, &VisibilityManager::dodgeAllWindows); - - connections[2] = connect(m_latteView->windowsTracker(), &WindowsTracker::activeWindowTouchingChanged - , this, &VisibilityManager::dodgeAllWindows); } break; case Types::WindowsGoBelow: //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } break; default: break; } m_latteView->containment()->config().writeEntry("visibility", static_cast(m_mode)); updateKWinEdgesSupport(); emit modeChanged(); } void VisibilityManager::updateStrutsBasedOnLayoutsAndActivities() { bool multipleLayoutsAndCurrent = (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName()); if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || multipleLayoutsAndCurrent) { wm->setViewStruts(*m_latteView, m_viewGeometry, m_latteView->location()); } else { wm->removeViewStruts(*m_latteView); } } bool VisibilityManager::raiseOnDesktop() const { return raiseOnDesktopChange; } void VisibilityManager::setRaiseOnDesktop(bool enable) { if (enable == raiseOnDesktopChange) return; raiseOnDesktopChange = enable; emit raiseOnDesktopChanged(); } bool VisibilityManager::raiseOnActivity() const { return raiseOnActivityChange; } void VisibilityManager::setRaiseOnActivity(bool enable) { if (enable == raiseOnActivityChange) return; raiseOnActivityChange = enable; emit raiseOnActivityChanged(); } bool VisibilityManager::isHidden() const { return m_isHidden; } void VisibilityManager::setIsHidden(bool isHidden) { if (m_isHidden == isHidden) return; if (m_blockHiding && isHidden) { qWarning() << "isHidden property is blocked, ignoring update"; return; } m_isHidden = isHidden; if (supportsKWinEdges()) { bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName())); if (inCurrentLayout) { wm->setEdgeStateFor(edgeGhostWindow, m_isHidden); } else { wm->setEdgeStateFor(edgeGhostWindow, false); } } emit isHiddenChanged(); } bool VisibilityManager::blockHiding() const { return m_blockHiding; } void VisibilityManager::setBlockHiding(bool blockHiding) { if (m_blockHiding == blockHiding) { return; } m_blockHiding = blockHiding; // qDebug() << "blockHiding:" << blockHiding; if (m_blockHiding) { m_timerHide.stop(); if (m_isHidden) { emit mustBeShown(); } } else { updateHiddenState(); } emit blockHidingChanged(); } int VisibilityManager::timerShow() const { return m_timerShow.interval(); } void VisibilityManager::setTimerShow(int msec) { m_timerShow.setInterval(msec); emit timerShowChanged(); } int VisibilityManager::timerHide() const { return m_timerHide.interval(); } void VisibilityManager::setTimerHide(int msec) { m_timerHide.setInterval(msec); emit timerHideChanged(); } bool VisibilityManager::supportsKWinEdges() const { return (edgeGhostWindow != nullptr); } void VisibilityManager::raiseView(bool raise) { if (m_blockHiding) return; if (raise) { m_timerHide.stop(); if (!m_timerShow.isActive()) { m_timerShow.start(); } } else if (!dragEnter) { m_timerShow.stop(); if (hideNow) { hideNow = false; emit mustBeHide(); } else if (!m_timerHide.isActive()) { m_timerHide.start(); } } } void VisibilityManager::raiseViewTemporarily() { if (raiseTemporarily) return; raiseTemporarily = true; m_timerHide.stop(); m_timerShow.stop(); if (m_isHidden) emit mustBeShown(); QTimer::singleShot(qBound(1800, 2 * m_timerHide.interval(), 3000), this, [&]() { raiseTemporarily = false; hideNow = true; updateHiddenState(); }); } void VisibilityManager::updateHiddenState() { if (dragEnter) return; switch (m_mode) { case Types::AutoHide: raiseView(m_containsMouse); break; case Types::DodgeActive: dodgeActive(wm->activeWindow()); break; case Types::DodgeMaximized: dodgeMaximized(wm->activeWindow()); break; case Types::DodgeAllWindows: dodgeAllWindows(); break; default: break; } } void VisibilityManager::setViewGeometry(const QRect &geometry) { if (!m_latteView->containment()) return; m_viewGeometry = geometry; if (m_mode == Types::AlwaysVisible && !m_latteView->inEditMode() && m_latteView->screen()) { updateStrutsBasedOnLayoutsAndActivities(); } } void VisibilityManager::applyActivitiesToHiddenWindows(const QStringList &activities) { if (edgeGhostWindow) { wm->setWindowOnActivities(*edgeGhostWindow, activities); } } void VisibilityManager::activeWindowDraggingStarted() { setContainsMouse(false); updateHiddenState(); } void VisibilityManager::dodgeActive(WindowId wid) { if (raiseTemporarily) return; //!don't send false raiseView signal when containing mouse if (m_containsMouse) { raiseView(true); return; } auto winfo = wm->requestInfo(wid); if (!winfo.isValid() || !winfo.isActive()) { winfo = wm->requestInfo(wm->activeWindow()); if (!winfo.isValid()) { //! very rare case that window manager doesn't have any active window at all raiseView(true); return; } } //! don't send false raiseView signal when containing mouse, // Johan comment //! I don't know why that wasn't winfo.wid() //active window, but just wid//the window that made the call if (wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { bool overlaps{intersects(winfo)}; raiseView(!overlaps); } } void VisibilityManager::dodgeMaximized(WindowId wid) { if (raiseTemporarily) return; //!don't send false raiseView signal when containing mouse if (m_containsMouse) { raiseView(true); return; } auto winfo = wm->requestInfo(wid); if (!winfo.isValid() || !winfo.isActive()) { winfo = wm->requestInfo(wm->activeWindow()); if (!winfo.isValid()) { //! very rare case that window manager doesn't have any active window at all raiseView(true); return; } } auto intersectsMaxVert = [&]() noexcept -> bool { return ((winfo.isMaxVert() || (m_latteView->screen() && m_latteView->screen()->availableSize().height() <= winfo.geometry().height())) && intersects(winfo)); }; auto intersectsMaxHoriz = [&]() noexcept -> bool { return ((winfo.isMaxHoriz() || (m_latteView->screen() && m_latteView->screen()->availableSize().width() <= winfo.geometry().width())) && intersects(winfo)); }; //! don't send false raiseView signal when containing mouse, // Johan comment //! I don't know why that wasn't winfo.wid() //active window, but just wid//the window that made the call if (wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { bool overlapsMaximized{m_latteView->formFactor() == Plasma::Types::Vertical ? intersectsMaxHoriz() : intersectsMaxVert()}; raiseView(!overlapsMaximized); } } void VisibilityManager::dodgeAllWindows() { if (raiseTemporarily) return; if (m_containsMouse) { raiseView(true); } bool windowIntersects{m_latteView->windowsTracker()->activeWindowTouching() || m_latteView->windowsTracker()->existsWindowTouching()}; raiseView(!windowIntersects); } bool VisibilityManager::intersects(const WindowInfoWrap &winfo) { return (!winfo.isMinimized() && wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid()) && winfo.geometry().intersects(m_viewGeometry) && !winfo.isShaded()); } void VisibilityManager::saveConfig() { if (!m_latteView->containment()) return; auto config = m_latteView->containment()->config(); config.writeEntry("enableKWinEdges", enableKWinEdgesFromUser); config.writeEntry("timerShow", m_timerShow.interval()); config.writeEntry("timerHide", m_timerHide.interval()); config.writeEntry("raiseOnDesktopChange", raiseOnDesktopChange); config.writeEntry("raiseOnActivityChange", raiseOnActivityChange); m_latteView->containment()->configNeedsSaving(); } void VisibilityManager::restoreConfig() { if (!m_latteView || !m_latteView->containment()){ return; } auto config = m_latteView->containment()->config(); m_timerShow.setInterval(config.readEntry("timerShow", 0)); m_timerHide.setInterval(config.readEntry("timerHide", 700)); emit timerShowChanged(); emit timerHideChanged(); enableKWinEdgesFromUser = config.readEntry("enableKWinEdges", true); emit enableKWinEdgesChanged(); setRaiseOnDesktop(config.readEntry("raiseOnDesktopChange", false)); setRaiseOnActivity(config.readEntry("raiseOnActivityChange", false)); auto storedMode = static_cast(m_latteView->containment()->config().readEntry("visibility", static_cast(Types::DodgeActive))); if (storedMode == Types::AlwaysVisible) { qDebug() << "Loading visibility mode: Always Visible , on startup..."; setMode(Types::AlwaysVisible); } else { connect(&m_timerStartUp, &QTimer::timeout, this, [&]() { auto fMode = static_cast(m_latteView->containment()->config().readEntry("visibility", static_cast(Types::DodgeActive))); qDebug() << "Loading visibility mode:" << fMode << " on startup..."; setMode(fMode); }); connect(m_latteView->containment(), &Plasma::Containment::userConfiguringChanged , this, [&](bool configuring) { if (configuring && m_timerStartUp.isActive()) m_timerStartUp.start(100); }); m_timerStartUp.start(); } connect(m_latteView->containment(), &Plasma::Containment::userConfiguringChanged , this, [&](bool configuring) { if (!configuring) { saveConfig(); } }); } bool VisibilityManager::containsMouse() const { return m_containsMouse; } void VisibilityManager::setContainsMouse(bool contains) { if (m_containsMouse == contains) { return; } m_containsMouse = contains; emit containsMouseChanged(); if (contains && m_mode != Types::AlwaysVisible) { raiseView(true); } } void VisibilityManager::viewEventManager(QEvent *ev) { switch (ev->type()) { case QEvent::Enter: setContainsMouse(true); break; case QEvent::Leave: setContainsMouse(false); updateHiddenState(); break; case QEvent::DragEnter: dragEnter = true; if (m_isHidden) emit mustBeShown(); break; case QEvent::DragLeave: case QEvent::Drop: dragEnter = false; updateHiddenState(); break; case QEvent::Show: wm->setViewExtraFlags(*m_latteView); break; default: break; } } //! KWin Edges Support functions bool VisibilityManager::enableKWinEdges() const { return enableKWinEdgesFromUser; } void VisibilityManager::setEnableKWinEdges(bool enable) { if (enableKWinEdgesFromUser == enable) { return; } enableKWinEdgesFromUser = enable; emit enableKWinEdgesChanged(); updateKWinEdgesSupport(); } void VisibilityManager::updateKWinEdgesSupport() { if (m_mode == Types::AutoHide || m_mode == Types::DodgeActive || m_mode == Types::DodgeAllWindows || m_mode == Types::DodgeMaximized) { if (enableKWinEdgesFromUser) { createEdgeGhostWindow(); } else if (!enableKWinEdgesFromUser) { deleteEdgeGhostWindow(); } } else if (m_mode == Types::AlwaysVisible || m_mode == Types::WindowsGoBelow) { deleteEdgeGhostWindow(); } } void VisibilityManager::createEdgeGhostWindow() { if (!edgeGhostWindow) { edgeGhostWindow = new ScreenEdgeGhostWindow(m_latteView); wm->setViewExtraFlags(*edgeGhostWindow); connect(edgeGhostWindow, &ScreenEdgeGhostWindow::containsMouseChanged, this, [ = ](bool contains) { if (contains) { emit mustBeShown(); } }); connectionsKWinEdges[0] = connect(wm, &WindowSystem::currentActivityChanged, this, [&]() { bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName())); if (edgeGhostWindow) { if (inCurrentLayout) { wm->setEdgeStateFor(edgeGhostWindow, m_isHidden); } else { wm->setEdgeStateFor(edgeGhostWindow, false); } } }); emit supportsKWinEdgesChanged(); } } void VisibilityManager::deleteEdgeGhostWindow() { if (edgeGhostWindow) { edgeGhostWindow->deleteLater(); edgeGhostWindow = nullptr; for (auto &c : connectionsKWinEdges) { disconnect(c); } emit supportsKWinEdgesChanged(); } } //! END: VisibilityManager implementation } } diff --git a/app/view/windowstracker.cpp b/app/view/windowstracker.cpp index 30dad31f..c6c905db 100644 --- a/app/view/windowstracker.cpp +++ b/app/view/windowstracker.cpp @@ -1,354 +1,354 @@ /* * Copyright 2019 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "windowstracker.h" // local #include "positioner.h" #include "view.h" #include "../lattecorona.h" #include "../../liblatte2/types.h" namespace Latte { namespace ViewPart { WindowsTracker::WindowsTracker(Latte::View *parent) : QObject(parent), m_latteView(parent) { qDebug() << "WindowsTracker creating..."; m_corona = qobject_cast(m_latteView->corona()); m_wm = m_corona->wm(); } WindowsTracker::~WindowsTracker() { qDebug() << "WindowsTracker removing..."; } bool WindowsTracker::activeWindowTouching() const { return m_activeWindowIsTouchingFlag; } void WindowsTracker::setActiveWindowTouching(bool activeTouching) { if (m_activeWindowIsTouchingFlag == activeTouching) { return; } m_activeWindowIsTouchingFlag = activeTouching; emit activeWindowTouchingChanged(); } bool WindowsTracker::existsWindowMaximized() const { return m_windowIsMaximizedFlag; } void WindowsTracker::setExistsWindowMaximized(bool windowMaximized) { if (m_windowIsMaximizedFlag == windowMaximized) { return; } m_windowIsMaximizedFlag = windowMaximized; emit existsWindowMaximizedChanged(); } bool WindowsTracker::existsWindowTouching() const { return m_windowIsTouchingFlag; } void WindowsTracker::setExistsWindowTouching(bool windowTouching) { if (m_windowIsTouchingFlag == windowTouching) { return; } m_windowIsTouchingFlag = windowTouching; emit existsWindowTouchingChanged(); } SchemeColors *WindowsTracker::touchingWindowScheme() const { return m_touchingScheme; } void WindowsTracker::setTouchingWindowScheme(SchemeColors *scheme) { if (m_touchingScheme == scheme) { return; } m_touchingScheme = scheme; emit touchingWindowSchemeChanged(); } bool WindowsTracker::enabled() const { return m_enabled; } void WindowsTracker::setEnabled(bool active) { if (m_enabled == active) { return; } m_enabled = active; if (m_enabled) { m_windows.clear(); for (const auto &wid : m_wm->windows()) { m_windows.insert(wid, m_wm->requestInfo(wid)); } m_connections[0] = connect(m_corona, &Plasma::Corona::availableScreenRectChanged, this, &WindowsTracker::updateAvailableScreenGeometry); m_connections[1] = connect(m_wm, &WindowSystem::windowChanged, this, [&](WindowId wid) { m_windows[wid] = m_wm->requestInfo(wid); updateFlags(); }); m_connections[2] = connect(m_wm, &WindowSystem::windowRemoved, this, [&](WindowId wid) { m_windows.remove(wid); }); m_connections[3] = connect(m_wm, &WindowSystem::windowAdded, this, [&](WindowId wid) { m_windows.insert(wid, m_wm->requestInfo(wid)); updateFlags(); }); m_connections[4] = connect(m_wm, &WindowSystem::activeWindowChanged, this, [&](WindowId wid) { if (m_windows.contains(m_lastActiveWindowWid)) { m_windows[m_lastActiveWindowWid] = m_wm->requestInfo(m_lastActiveWindowWid); } m_windows[wid] = m_wm->requestInfo(wid); m_lastActiveWindowWid = wid; updateFlags(); }); m_connections[5] = connect(m_wm, &WindowSystem::currentDesktopChanged, this, [&] { updateFlags(); }); m_connections[6] = connect(m_wm, &WindowSystem::currentActivityChanged, this, [&] { updateFlags(); }); updateAvailableScreenGeometry(); updateFlags(); } else { // clear mode for (auto &c : m_connections) { disconnect(c); } m_windows.clear(); setActiveWindowTouching(false); setExistsWindowMaximized(false); setExistsWindowTouching(false); } emit enabledChanged(); } void WindowsTracker::updateAvailableScreenGeometry() { if (!m_latteView || !m_latteView->containment()) { return; } int currentScrId = m_latteView->positioner()->currentScreenId(); QRect tempAvailableScreenGeometry = m_corona->availableScreenRectWithCriteria(currentScrId, {Types::AlwaysVisible}, {}); if (tempAvailableScreenGeometry != m_availableScreenGeometry) { m_availableScreenGeometry = tempAvailableScreenGeometry; updateFlags(); } } void WindowsTracker::updateFlags() { bool foundActiveTouch{false}; bool foundTouch{false}; bool foundMaximized{false}; //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), //! maybe a garbage collector here is a good idea!!! bool existsFaultyWindow{false}; WindowId maxWinId; WindowId activeTouchWinId; WindowId touchWinId; for (const auto &winfo : m_windows) { if (isMaximizedInCurrentScreen(winfo)) { foundMaximized = true; maxWinId = winfo.wid(); } if ((isTouchingPanelEdge(winfo) || (m_latteView->visibility()->intersects(winfo)))) { if (winfo.isActive()) { foundActiveTouch = true; activeTouchWinId = winfo.wid(); } else { foundTouch = true; touchWinId = winfo.wid(); } } if (!existsFaultyWindow && winfo.geometry() == QRect(0, 0, 0, 0)) { existsFaultyWindow = true; } //qDebug() << "window geometry ::: " << winfo.geometry(); } if (existsFaultyWindow) { cleanupFaultyWindows(); } setActiveWindowTouching(foundActiveTouch); setExistsWindowMaximized(foundMaximized); - setExistsWindowTouching(foundTouch); + setExistsWindowTouching(foundTouch || foundActiveTouch); //! update color scheme for touching window if (foundActiveTouch) { setTouchingWindowScheme(m_wm->schemeForWindow(activeTouchWinId)); } else if (foundMaximized) { setTouchingWindowScheme(m_wm->schemeForWindow(maxWinId)); } else { setTouchingWindowScheme(nullptr); } } bool WindowsTracker::isMaximizedInCurrentScreen(const WindowInfoWrap &winfo) { //! updated implementation to identify the screen that the maximized window is present //! in order to avoid: https://bugs.kde.org/show_bug.cgi?id=397700 if (winfo.isValid() && !winfo.isMinimized() && m_wm->isOnCurrentDesktop(winfo.wid()) && m_wm->isOnCurrentActivity(winfo.wid())) { if (winfo.isMaximized() && m_availableScreenGeometry.contains(winfo.geometry().center())) { return true; } } return false; } bool WindowsTracker::isTouchingPanelEdge(const WindowInfoWrap &winfo) { if (winfo.isValid() && !winfo.isMinimized() && m_wm->isOnCurrentDesktop(winfo.wid()) && m_wm->isOnCurrentActivity(winfo.wid())) { bool touchingPanelEdge{false}; QRect screenGeometry = m_latteView->screenGeometry(); bool inCurrentScreen{screenGeometry.contains(winfo.geometry().topLeft()) || screenGeometry.contains(winfo.geometry().bottomRight())}; if (inCurrentScreen) { if (m_latteView->location() == Plasma::Types::TopEdge) { touchingPanelEdge = (winfo.geometry().y() == m_availableScreenGeometry.y()); } else if (m_latteView->location() == Plasma::Types::BottomEdge) { touchingPanelEdge = (winfo.geometry().bottom() == m_availableScreenGeometry.bottom()); } else if (m_latteView->location() == Plasma::Types::LeftEdge) { touchingPanelEdge = (winfo.geometry().x() == m_availableScreenGeometry.x()); } else if (m_latteView->location() == Plasma::Types::RightEdge) { touchingPanelEdge = (winfo.geometry().right() == m_availableScreenGeometry.right()); } } return touchingPanelEdge; } return false; } void WindowsTracker::cleanupFaultyWindows() { foreach (auto key, m_windows.keys()) { auto winfo = m_windows[key]; //! garbage windows removing if (winfo.geometry() == QRect(0, 0, 0, 0)) { //qDebug() << "Faulty Geometry ::: " << winfo.wid(); m_windows.remove(key); } } } //! Window Functions void WindowsTracker::setWindowOnActivities(QWindow &window, const QStringList &activities) { m_wm->setWindowOnActivities(window, activities); } void WindowsTracker::requestToggleMaximizeForActiveWindow() { WindowInfoWrap actInfo = m_wm->requestInfoActive(); //active window can be toggled only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { m_wm->requestToggleMaximized(actInfo.wid()); } } void WindowsTracker::requestMoveActiveWindow(int localX, int localY) { WindowInfoWrap actInfo = m_wm->requestInfoActive(); //active window can be dragged only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { QPoint globalPoint{m_latteView->x() + localX, m_latteView->y() + localY}; m_wm->requestMoveWindow(actInfo.wid(), globalPoint); //! This timer is needed because otherwise the mouse position //! in the dragged window changes to TopLeft corner QTimer::singleShot(250, this, [&, actInfo, globalPoint]() { m_wm->releaseMouseEventFor(m_latteView->winId()); }); m_latteView->visibility()->activeWindowDraggingStarted(); } } bool WindowsTracker::activeWindowCanBeDragged() { WindowInfoWrap actInfo = m_wm->requestInfoActive(); //active window can be dragged only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { return m_wm->windowCanBeDragged(actInfo.wid()); } return false; } } }