diff --git a/app/wm/tracker/trackerwindows.cpp b/app/wm/tracker/trackerwindows.cpp index cf2a7d88..d8d341ce 100644 --- a/app/wm/tracker/trackerwindows.cpp +++ b/app/wm/tracker/trackerwindows.cpp @@ -1,697 +1,880 @@ /* * 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 "trackerwindows.h" // local #include "lastactivewindow.h" #include "schemes.h" #include "trackedlayoutinfo.h" #include "trackedviewinfo.h" #include "../abstractwindowinterface.h" #include "../schemecolors.h" #include "../../lattecorona.h" #include "../../layout/genericlayout.h" #include "../../layouts/manager.h" #include "../../view/view.h" #include "../../view/positioner.h" #include "../../../liblatte2/types.h" namespace Latte { namespace WindowSystem { namespace Tracker { Windows::Windows(AbstractWindowInterface *parent) : QObject(parent) { m_wm = parent; init(); } Windows::~Windows() { //! clear all the m_views tracking information for (QHash::iterator i=m_views.begin(); i!=m_views.end(); ++i) { i.value()->deleteLater(); m_views[i.key()] = nullptr; } m_views.clear(); //! clear all the m_layouts tracking layouts for (QHash::iterator i=m_layouts.begin(); i!=m_layouts.end(); ++i) { i.value()->deleteLater(); m_layouts[i.key()] = nullptr; } m_layouts.clear(); } void Windows::init() { connect(m_wm->corona(), &Plasma::Corona::availableScreenRectChanged, this, &Windows::updateAvailableScreenGeometries); connect(m_wm, &AbstractWindowInterface::windowChanged, this, [&](WindowId wid) { m_windows[wid] = m_wm->requestInfo(wid); - updateViewsHints(); + updateAllHints(); emit windowChanged(wid); }); connect(m_wm, &AbstractWindowInterface::windowRemoved, this, [&](WindowId wid) { m_windows.remove(wid); - updateViewsHints(); + updateAllHints(); emit windowRemoved(wid); }); connect(m_wm, &AbstractWindowInterface::windowAdded, this, [&](WindowId wid) { if (!m_windows.contains(wid)) { m_windows.insert(wid, m_wm->requestInfo(wid)); } - updateViewsHints(); + updateAllHints(); }); connect(m_wm, &AbstractWindowInterface::activeWindowChanged, this, [&](WindowId wid) { //! for some reason this is needed in order to update properly activeness values //! when the active window changes the previous active windows should be also updated for (const auto view : m_views.keys()) { WindowId lastWinId = m_views[view]->lastActiveWindow()->winId(); if ((lastWinId) != wid && m_windows.contains(lastWinId)) { m_windows[lastWinId] = m_wm->requestInfo(lastWinId); } } m_windows[wid] = m_wm->requestInfo(wid); - updateViewsHints(); + updateAllHints(); emit activeWindowChanged(wid); }); connect(m_wm, &AbstractWindowInterface::currentDesktopChanged, this, [&] { - updateViewsHints(); + updateAllHints(); }); connect(m_wm, &AbstractWindowInterface::currentActivityChanged, this, [&] { if (m_wm->corona()->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { //! this is needed in MultipleLayouts because there is a chance that multiple //! layouts are providing different available screen geometries in different Activities updateAvailableScreenGeometries(); } - updateViewsHints(); + updateAllHints(); }); } +void Windows::initLayoutHints(Latte::Layout::GenericLayout *layout) +{ + if (!m_layouts.contains(layout)) { + return; + } + + setActiveWindowMaximized(layout, false); + setExistsWindowActive(layout, false); + setExistsWindowMaximized(layout, false); + setActiveWindowScheme(layout, nullptr); +} + void Windows::initViewHints(Latte::View *view) { if (!m_views.contains(view)) { return; } setActiveWindowMaximized(view, false); setActiveWindowTouching(view, false); setExistsWindowActive(view, false); setExistsWindowTouching(view, false); setExistsWindowMaximized(view, false); setActiveWindowScheme(view, nullptr); setTouchingWindowScheme(view, nullptr); } AbstractWindowInterface *Windows::wm() { return m_wm; } void Windows::addView(Latte::View *view) { if (m_views.contains(view)) { return; } m_views[view] = new TrackedViewInfo(this, view); updateAvailableScreenGeometries(); //! Consider Layouts addRelevantLayout(view); connect(view, &Latte::View::layoutChanged, this, [&, view]() { addRelevantLayout(view); }); updateHints(view); } void Windows::removeView(Latte::View *view) { if (!m_views.contains(view)) { return; } m_views[view]->deleteLater(); m_views.remove(view); updateRelevantLayouts(); } void Windows::addRelevantLayout(Latte::View *view) { - if (view->layout() && !m_layouts.contains(view->layout())) { - m_layouts[view->layout()] = new TrackedLayoutInfo(this, view->layout()); + if (view->layout() && !m_layouts.contains(view->layout())) { + m_layouts[view->layout()] = new TrackedLayoutInfo(this, view->layout()); - updateRelevantLayouts(); - } + updateRelevantLayouts(); + } } void Windows::updateRelevantLayouts() { QList orphanedLayouts; //! REMOVE Orphaned Relevant layouts that have been removed or they dont contain any Views anymore for (QHash::iterator i=m_layouts.begin(); i!=m_layouts.end(); ++i) { bool hasView{false}; for (QHash::iterator j=m_views.begin(); j!=m_views.end(); ++j) { if (j.key() && i.key() && i.key() == j.key()->layout()) { hasView = true; break; } } if (!hasView) { if (i.value()) { i.value()->deleteLater(); } orphanedLayouts << i.key(); } } for(const auto &layout : orphanedLayouts) { m_layouts.remove(layout); } //! UPDATE Enabled layout window tracking based on the Views that are requesting windows tracking for (QHash::iterator i=m_layouts.begin(); i!=m_layouts.end(); ++i) { bool hasViewEnabled{false}; for (QHash::iterator j=m_views.begin(); j!=m_views.end(); ++j) { if (i.key() == j.key()->layout() && j.value()->enabled()) { hasViewEnabled = true; break; } } if (i.value()) { i.value()->setEnabled(hasViewEnabled); + + if (!hasViewEnabled) { + initLayoutHints(i.key()); + } } } } //! Views Properties And Hints bool Windows::enabled(Latte::View *view) { if (!m_views.contains(view)) { return false; } return m_views[view]->enabled(); } void Windows::setEnabled(Latte::View *view, const bool enabled) { if (!m_views.contains(view) || m_views[view]->enabled() == enabled) { return; } m_views[view]->setEnabled(enabled); if (enabled) { updateHints(view); } else { initViewHints(view); } updateRelevantLayouts(); emit enabledChanged(view); } bool Windows::activeWindowMaximized(Latte::View *view) const { if (!m_views.contains(view)) { return false; } return m_views[view]->activeWindowMaximized(); } void Windows::setActiveWindowMaximized(Latte::View *view, bool activeMaximized) { if (!m_views.contains(view) || m_views[view]->activeWindowMaximized() == activeMaximized) { return; } m_views[view]->setActiveWindowMaximized(activeMaximized); emit activeWindowMaximizedChanged(view); } bool Windows::activeWindowTouching(Latte::View *view) const { if (!m_views.contains(view)) { return false; } return m_views[view]->activeWindowTouching(); } void Windows::setActiveWindowTouching(Latte::View *view, bool activeTouching) { if (!m_views.contains(view) || m_views[view]->activeWindowTouching() == activeTouching) { return; } m_views[view]->setActiveWindowTouching(activeTouching); emit activeWindowTouchingChanged(view); } bool Windows::existsWindowActive(Latte::View *view) const { if (!m_views.contains(view)) { return false; } return m_views[view]->existsWindowActive(); } void Windows::setExistsWindowActive(Latte::View *view, bool windowActive) { if (!m_views.contains(view) || m_views[view]->existsWindowActive() == windowActive) { return; } m_views[view]->setExistsWindowActive(windowActive); emit existsWindowActiveChanged(view); } bool Windows::existsWindowMaximized(Latte::View *view) const { if (!m_views.contains(view)) { return false; } return m_views[view]->existsWindowMaximized(); } void Windows::setExistsWindowMaximized(Latte::View *view, bool windowMaximized) { if (!m_views.contains(view) || m_views[view]->existsWindowMaximized() == windowMaximized) { return; } m_views[view]->setExistsWindowMaximized(windowMaximized); emit existsWindowMaximizedChanged(view); } bool Windows::existsWindowTouching(Latte::View *view) const { if (!m_views.contains(view)) { return false; } return m_views[view]->existsWindowTouching(); } void Windows::setExistsWindowTouching(Latte::View *view, bool windowTouching) { if (!m_views.contains(view) || m_views[view]->existsWindowTouching() == windowTouching) { return; } m_views[view]->setExistsWindowTouching(windowTouching); emit existsWindowTouchingChanged(view); } SchemeColors *Windows::activeWindowScheme(Latte::View *view) const { if (!m_views.contains(view)) { return nullptr; } return m_views[view]->activeWindowScheme(); } void Windows::setActiveWindowScheme(Latte::View *view, WindowSystem::SchemeColors *scheme) { if (!m_views.contains(view) || m_views[view]->activeWindowScheme() == scheme) { return; } m_views[view]->setActiveWindowScheme(scheme); emit activeWindowSchemeChanged(view); } SchemeColors *Windows::touchingWindowScheme(Latte::View *view) const { if (!m_views.contains(view)) { return nullptr; } return m_views[view]->touchingWindowScheme(); } void Windows::setTouchingWindowScheme(Latte::View *view, WindowSystem::SchemeColors *scheme) { if (!m_views.contains(view) || m_views[view]->touchingWindowScheme() == scheme) { return; } m_views[view]->setTouchingWindowScheme(scheme); emit touchingWindowSchemeChanged(view); } LastActiveWindow *Windows::lastActiveWindow(Latte::View *view) { if (!m_views.contains(view)) { return nullptr; } return m_views[view]->lastActiveWindow(); } +//! Layouts +bool Windows::activeWindowMaximized(Latte::Layout::GenericLayout *layout) const +{ + if (!m_layouts.contains(layout)) { + return false; + } + + return m_layouts[layout]->activeWindowMaximized(); +} + +void Windows::setActiveWindowMaximized(Latte::Layout::GenericLayout *layout, bool activeMaximized) +{ + if (!m_layouts.contains(layout) || m_layouts[layout]->activeWindowMaximized() == activeMaximized) { + return; + } + + m_layouts[layout]->setActiveWindowMaximized(activeMaximized); + emit activeWindowMaximizedChangedForLayout(layout); +} + +bool Windows::existsWindowActive(Latte::Layout::GenericLayout *layout) const +{ + if (!m_layouts.contains(layout)) { + return false; + } + + return m_layouts[layout]->existsWindowActive(); +} + +void Windows::setExistsWindowActive(Latte::Layout::GenericLayout *layout, bool windowActive) +{ + if (!m_layouts.contains(layout) || m_layouts[layout]->existsWindowActive() == windowActive) { + return; + } + + m_layouts[layout]->setExistsWindowActive(windowActive); + emit existsWindowActiveChangedForLayout(layout); +} + +bool Windows::existsWindowMaximized(Latte::Layout::GenericLayout *layout) const +{ + if (!m_layouts.contains(layout)) { + return false; + } + + return m_layouts[layout]->existsWindowMaximized(); +} + +void Windows::setExistsWindowMaximized(Latte::Layout::GenericLayout *layout, bool windowMaximized) +{ + if (!m_layouts.contains(layout) || m_layouts[layout]->existsWindowMaximized() == windowMaximized) { + return; + } + + m_layouts[layout]->setExistsWindowMaximized(windowMaximized); + emit existsWindowMaximizedChangedForLayout(layout); +} + +SchemeColors *Windows::activeWindowScheme(Latte::Layout::GenericLayout *layout) const +{ + if (!m_layouts.contains(layout)) { + return nullptr; + } + + return m_layouts[layout]->activeWindowScheme(); +} + +void Windows::setActiveWindowScheme(Latte::Layout::GenericLayout *layout, WindowSystem::SchemeColors *scheme) +{ + if (!m_layouts.contains(layout) || m_layouts[layout]->activeWindowScheme() == scheme) { + return; + } + + m_layouts[layout]->setActiveWindowScheme(scheme); + emit activeWindowSchemeChangedForLayout(layout); +} + +LastActiveWindow *Windows::lastActiveWindow(Latte::Layout::GenericLayout *layout) +{ + if (!m_layouts.contains(layout)) { + return nullptr; + } + + return m_layouts[layout]->lastActiveWindow(); +} + + +//! Windows bool Windows::isValidFor(const WindowId &wid) const { if (!m_windows.contains(wid)) { return false; } return m_windows[wid].isValid() && !m_windows[wid].isPlasmaDesktop(); } QIcon Windows::iconFor(const WindowId &wid) { if (!m_windows.contains(wid)) { return QIcon(); } if (m_windows[wid].icon().isNull()) { AppData data = m_wm->appDataFor(wid); QIcon icon = data.icon; if (icon.isNull()) { icon = m_wm->iconFor(wid); } m_windows[wid].setIcon(icon); return icon; } return m_windows[wid].icon(); } QString Windows::appNameFor(const WindowId &wid) { if (!m_windows.contains(wid)) { return QString(); } if (m_windows[wid].appName().isEmpty()) { AppData data = m_wm->appDataFor(wid); m_windows[wid].setAppName(data.name); return data.name; } return m_windows[wid].appName(); } WindowInfoWrap Windows::infoFor(const WindowId &wid) const { if (!m_windows.contains(wid)) { return WindowInfoWrap(); } return m_windows[wid]; } //! Windows Criteria Functions bool Windows::inCurrentDesktopActivity(const WindowInfoWrap &winfo) { return (winfo.isValid() && winfo.isOnDesktop(m_wm->currentDesktop()) && winfo.isOnActivity(m_wm->currentActivity())); } bool Windows::intersects(Latte::View *view, const WindowInfoWrap &winfo) { return (!winfo.isMinimized() && !winfo.isShaded() && winfo.geometry().intersects(view->absoluteGeometry())); } bool Windows::isActive(const WindowInfoWrap &winfo) { return (winfo.isValid() && winfo.isActive() && !winfo.isPlasmaDesktop() && !winfo.isMinimized()); } bool Windows::isActiveInViewScreen(Latte::View *view, const WindowInfoWrap &winfo) { return (winfo.isValid() && winfo.isActive() && !winfo.isPlasmaDesktop() && !winfo.isMinimized() && m_views[view]->availableScreenGeometry().contains(winfo.geometry().center())); } bool Windows::isMaximizedInViewScreen(Latte::View *view, const WindowInfoWrap &winfo) { auto viewIntersectsMaxVert = [&]() noexcept -> bool { return ((winfo.isMaxVert() || (view->screen() && view->screen()->availableSize().height() <= winfo.geometry().height())) && intersects(view, winfo)); }; auto viewIntersectsMaxHoriz = [&]() noexcept -> bool { return ((winfo.isMaxHoriz() || (view->screen() && view->screen()->availableSize().width() <= winfo.geometry().width())) && intersects(view, 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 return (winfo.isValid() && !winfo.isPlasmaDesktop() && !winfo.isMinimized() && (winfo.isMaximized() || viewIntersectsMaxVert() || viewIntersectsMaxHoriz()) && m_views[view]->availableScreenGeometry().contains(winfo.geometry().center())); } bool Windows::isTouchingView(Latte::View *view, const WindowSystem::WindowInfoWrap &winfo) { return (winfo.isValid() && !winfo.isPlasmaDesktop() && intersects(view, winfo)); } bool Windows::isTouchingViewEdge(Latte::View *view, const WindowInfoWrap &winfo) { if (winfo.isValid() && !winfo.isPlasmaDesktop() && !winfo.isMinimized()) { bool touchingViewEdge{false}; QRect screenGeometry = view->screenGeometry(); QRect availableScreenGeometry = m_views[view]->availableScreenGeometry(); bool inCurrentScreen{screenGeometry.contains(winfo.geometry().topLeft()) || screenGeometry.contains(winfo.geometry().bottomRight())}; if (inCurrentScreen) { if (view->location() == Plasma::Types::TopEdge) { touchingViewEdge = (winfo.geometry().y() == availableScreenGeometry.y()); } else if (view->location() == Plasma::Types::BottomEdge) { touchingViewEdge = (winfo.geometry().bottom() == availableScreenGeometry.bottom()); } else if (view->location() == Plasma::Types::LeftEdge) { touchingViewEdge = (winfo.geometry().x() == availableScreenGeometry.x()); } else if (view->location() == Plasma::Types::RightEdge) { touchingViewEdge = (winfo.geometry().right() == availableScreenGeometry.right()); } } return touchingViewEdge; } return false; } void Windows::cleanupFaultyWindows() { for (const 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); } } } void Windows::updateAvailableScreenGeometries() { for (const auto view : m_views.keys()) { if (m_views[view]->enabled()) { int currentScrId = view->positioner()->currentScreenId(); QRect tempAvailableScreenGeometry = m_wm->corona()->availableScreenRectWithCriteria(currentScrId, {Types::AlwaysVisible}, {}); if (tempAvailableScreenGeometry != m_views[view]->availableScreenGeometry()) { m_views[view]->setAvailableScreenGeometry(tempAvailableScreenGeometry); updateHints(view); } } } } void Windows::setPlasmaDesktop(WindowId wid) { if (!m_windows.contains(wid)) { return; } if (!m_windows[wid].isPlasmaDesktop()) { m_windows[wid].setIsPlasmaDesktop(true); qDebug() << " plasmashell updated..."; - updateViewsHints(); + updateAllHints(); } } -void Windows::updateViewsHints() +void Windows::updateAllHints() { for (const auto view : m_views.keys()) { - if (m_views[view]->enabled()) { - updateHints(view); - } + updateHints(view); + } + + for (const auto layout : m_layouts.keys()) { + updateHints(layout); } } void Windows::updateHints(Latte::View *view) { - if (!m_views.contains(view) || !view->isOnActivity(m_wm->currentActivity())) { + if (!m_views.contains(view) || !m_views[view]->enabled() || !m_views[view]->isTrackingCurrentActivity()) { return; } bool foundActive{false}; bool foundActiveInCurScreen{false}; bool foundActiveTouchInCurScreen{false}; bool foundTouchInCurScreen{false}; bool foundMaximizedInCurScreen{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 activeWinId; WindowId touchWinId; WindowId activeTouchWinId; for (const auto &winfo : m_windows) { if (winfo.isPlasmaDesktop() || !inCurrentDesktopActivity(winfo)) { continue; } if (isActive(winfo)) { foundActive = true; } if (isActiveInViewScreen(view, winfo)) { foundActiveInCurScreen = true; activeWinId = winfo.wid(); } if (isTouchingViewEdge(view, winfo) || isTouchingView(view, winfo)) { if (winfo.isActive()) { foundActiveTouchInCurScreen = true; activeTouchWinId = winfo.wid(); if (isMaximizedInViewScreen(view, winfo)) { //! active maximized windows have higher priority than the rest maximized windows foundMaximizedInCurScreen = true; maxWinId = winfo.wid(); } } else { foundTouchInCurScreen = true; touchWinId = winfo.wid(); } if (!foundMaximizedInCurScreen && isMaximizedInViewScreen(view, winfo)) { foundMaximizedInCurScreen = true; maxWinId = winfo.wid(); } } if (!existsFaultyWindow && winfo.geometry() == QRect(0, 0, 0, 0)) { existsFaultyWindow = true; } //qDebug() << "window geometry ::: " << winfo.geometry(); } if (existsFaultyWindow) { cleanupFaultyWindows(); } //! HACK: KWin Effects such as ShowDesktop have no way to be identified and as such //! create issues with identifying properly touching and maximized windows. BUT when //! they are enabled then NO ACTIVE window is found. This is a way to identify these //! effects trigerring and disable the touch flags. //! BUG: 404483 //! Disabled because it has fault identifications, e.g. when a window is maximized and //! Latte or Plasma are showing their View settings //foundMaximizedInCurScreen = foundMaximizedInCurScreen && foundActive; //foundTouchInCurScreen = foundTouchInCurScreen && foundActive; //! assign flags setExistsWindowActive(view, foundActiveInCurScreen); setActiveWindowTouching(view, foundActiveTouchInCurScreen); setActiveWindowMaximized(view, (maxWinId.toInt()>0 && (maxWinId == activeTouchWinId))); setExistsWindowMaximized(view, foundMaximizedInCurScreen); setExistsWindowTouching(view, (foundTouchInCurScreen || foundActiveTouchInCurScreen)); //! update color schemes for active and touching windows setActiveWindowScheme(view, (foundActiveInCurScreen ? m_wm->schemesTracker()->schemeForWindow(activeWinId) : nullptr)); if (foundActiveTouchInCurScreen) { setTouchingWindowScheme(view, m_wm->schemesTracker()->schemeForWindow(activeTouchWinId)); } else if (foundMaximizedInCurScreen) { setTouchingWindowScheme(view, m_wm->schemesTracker()->schemeForWindow(maxWinId)); } else if (foundTouchInCurScreen) { setTouchingWindowScheme(view, m_wm->schemesTracker()->schemeForWindow(touchWinId)); } else { setTouchingWindowScheme(view, nullptr); } //! update LastActiveWindow if (foundActiveInCurScreen) { m_views[view]->setActiveWindow(activeWinId); } //! Debug //qDebug() << "TRACKING | SCREEN: " << view->positioner()->currentScreenId() << " , EDGE:" << view->location() << " , ENABLED:" << enabled(view); //qDebug() << "TRACKING | activeWindowTouching: " << foundActiveTouchInCurScreen << " ,activeWindowMaximized: " << activeWindowMaximized(view); //qDebug() << "TRACKING | existsWindowActive: " << foundActiveInCurScreen << " , existsWindowMaximized:" << existsWindowMaximized(view) // << " , existsWindowTouching:"<enabled() || !m_layouts[layout]->isTrackingCurrentActivity()) { + return; + } + + bool foundActive{false}; + bool foundActiveMaximized{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 activeWinId; + WindowId maxWinId; + + for (const auto &winfo : m_windows) { + if (winfo.isPlasmaDesktop() || !inCurrentDesktopActivity(winfo)) { + continue; + } + + if (isActive(winfo)) { + foundActive = true; + activeWinId = winfo.wid(); + + if (winfo.isMaximized() && !winfo.isMinimized()) { + foundActiveMaximized = true; + maxWinId = winfo.wid(); + } + } + + if (!foundActiveMaximized && winfo.isMaximized() && !winfo.isMinimized()) { + foundMaximized = true; + maxWinId = winfo.wid(); + } + + if (!existsFaultyWindow && winfo.geometry() == QRect(0, 0, 0, 0)) { + existsFaultyWindow = true; + } + + //qDebug() << "window geometry ::: " << winfo.geometry(); + } + + if (existsFaultyWindow) { + cleanupFaultyWindows(); + } + + //! HACK: KWin Effects such as ShowDesktop have no way to be identified and as such + //! create issues with identifying properly touching and maximized windows. BUT when + //! they are enabled then NO ACTIVE window is found. This is a way to identify these + //! effects trigerring and disable the touch flags. + //! BUG: 404483 + //! Disabled because it has fault identifications, e.g. when a window is maximized and + //! Latte or Plasma are showing their View settings + //foundMaximizedInCurScreen = foundMaximizedInCurScreen && foundActive; + //foundTouchInCurScreen = foundTouchInCurScreen && foundActive; + + //! assign flags + setExistsWindowActive(layout, foundActive); + setActiveWindowMaximized(layout, foundActiveMaximized); + setExistsWindowMaximized(layout, foundActiveMaximized || foundMaximized); + + //! update color schemes for active and touching windows + setActiveWindowScheme(layout, (foundActive ? m_wm->schemesTracker()->schemeForWindow(activeWinId) : nullptr)); + + //! update LastActiveWindow + if (foundActive) { + m_layouts[layout]->setActiveWindow(activeWinId); + } + + //! Debug + //qDebug() << "TRACKING | SCREEN: " << view->positioner()->currentScreenId() << " , EDGE:" << view->location() << " , ENABLED:" << enabled(view); + //qDebug() << "TRACKING | activeWindowTouching: " << foundActiveTouchInCurScreen << " ,activeWindowMaximized: " << activeWindowMaximized(view); + //qDebug() << "TRACKING | existsWindowActive: " << foundActiveInCurScreen << " , existsWindowMaximized:" << existsWindowMaximized(view) + // << " , existsWindowTouching:"< * * 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 . */ #ifndef WINDOWSYSTEMWINDOWSTRACKER_H #define WINDOWSYSTEMWINDOWSTRACKER_H // local #include "../windowinfowrap.h" // Qt #include #include #include namespace Latte { class View; namespace Layout { class GenericLayout; } namespace WindowSystem { class AbstractWindowInterface; class SchemeColors; namespace Tracker { class LastActiveWindow; class TrackedLayoutInfo; class TrackedViewInfo; } } } namespace Latte { namespace WindowSystem { namespace Tracker { class Windows : public QObject { Q_OBJECT public: Windows(AbstractWindowInterface *parent); ~Windows() override; void addView(Latte::View *view); void removeView(Latte::View *view); + //! Views Tracking (current screen specific) bool enabled(Latte::View *view); void setEnabled(Latte::View *view, const bool enabled); bool activeWindowMaximized(Latte::View *view) const; bool activeWindowTouching(Latte::View *view) const; bool existsWindowActive(Latte::View *view) const; bool existsWindowMaximized(Latte::View *view) const; bool existsWindowTouching(Latte::View *view) const; SchemeColors *activeWindowScheme(Latte::View *view) const; SchemeColors *touchingWindowScheme(Latte::View *view) const; LastActiveWindow *lastActiveWindow(Latte::View *view); + //! Layouts Tracking (all screens) + bool activeWindowMaximized(Latte::Layout::GenericLayout *layout) const; + bool existsWindowActive(Latte::Layout::GenericLayout *layout) const; + bool existsWindowMaximized(Latte::Layout::GenericLayout *layout) const; + SchemeColors *activeWindowScheme(Latte::Layout::GenericLayout *layout) const; + LastActiveWindow *lastActiveWindow(Latte::Layout::GenericLayout *layout); + + //! Windows management bool isValidFor(const WindowId &wid) const; QIcon iconFor(const WindowId &wid); QString appNameFor(const WindowId &wid); WindowInfoWrap infoFor(const WindowId &wid) const; void setPlasmaDesktop(WindowId wid); AbstractWindowInterface *wm(); signals: + //! Views void enabledChanged(const Latte::View *view); void activeWindowMaximizedChanged(const Latte::View *view); void activeWindowTouchingChanged(const Latte::View *view); void existsWindowActiveChanged(const Latte::View *view); void existsWindowMaximizedChanged(const Latte::View *view); void existsWindowTouchingChanged(const Latte::View *view); void activeWindowSchemeChanged(const Latte::View *view); void touchingWindowSchemeChanged(const Latte::View *view); + //! Layouts + void enabledChangedForLayout(const Latte::Layout::GenericLayout *layout); + void activeWindowMaximizedChangedForLayout(const Latte::Layout::GenericLayout *layout); + void existsWindowActiveChangedForLayout(const Latte::Layout::GenericLayout *layout); + void existsWindowMaximizedChangedForLayout(const Latte::Layout::GenericLayout *layout); + void activeWindowSchemeChangedForLayout(const Latte::Layout::GenericLayout *layout); + //! overloading WM signals in order to update first m_windows and afterwards //! inform consumers for window changes void activeWindowChanged(const WindowId &wid); void windowChanged(const WindowId &wid); void windowRemoved(const WindowId &wid); private slots: void updateAvailableScreenGeometries(); void addRelevantLayout(Latte::View *view); void updateRelevantLayouts(); private: void init(); + void initLayoutHints(Latte::Layout::GenericLayout *layout); void initViewHints(Latte::View *view); void cleanupFaultyWindows(); - void updateViewsHints(); + void updateAllHints(); + + //! Views void updateHints(Latte::View *view); + void updateHints(Latte::Layout::GenericLayout *layout); void setActiveWindowMaximized(Latte::View *view, bool activeMaximized); void setActiveWindowTouching(Latte::View *view, bool activeTouching); void setExistsWindowActive(Latte::View *view, bool windowActive); void setExistsWindowMaximized(Latte::View *view, bool windowMaximized); void setExistsWindowTouching(Latte::View *view, bool windowTouching); void setActiveWindowScheme(Latte::View *view, WindowSystem::SchemeColors *scheme); void setTouchingWindowScheme(Latte::View *view, WindowSystem::SchemeColors *scheme); + //! Layouts + void setActiveWindowMaximized(Latte::Layout::GenericLayout *layout, bool activeMaximized); + void setExistsWindowActive(Latte::Layout::GenericLayout *layout, bool windowActive); + void setExistsWindowMaximized(Latte::Layout::GenericLayout *layout, bool windowMaximized); + void setActiveWindowScheme(Latte::Layout::GenericLayout *layout, WindowSystem::SchemeColors *scheme); + + //! Windows bool inCurrentDesktopActivity(const WindowInfoWrap &winfo); bool intersects(Latte::View *view, const WindowInfoWrap &winfo); bool isActive(const WindowInfoWrap &winfo); bool isActiveInViewScreen(Latte::View *view, const WindowInfoWrap &winfo); bool isMaximizedInViewScreen(Latte::View *view, const WindowInfoWrap &winfo); bool isTouchingView(Latte::View *view, const WindowSystem::WindowInfoWrap &winfo); bool isTouchingViewEdge(Latte::View *view, const WindowInfoWrap &winfo); private: AbstractWindowInterface *m_wm; QHash m_views; QHash m_layouts; QMap m_windows; }; } } } #endif