File indexing completed on 2024-12-01 13:38:02
0001 /* 0002 * Copyright 2019 Michail Vourlakos <mvourlakos@gmail.com> 0003 * 0004 * This file is part of Latte-Dock 0005 * 0006 * Latte-Dock is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU General Public License as 0008 * published by the Free Software Foundation; either version 2 of 0009 * the License, or (at your option) any later version. 0010 * 0011 * Latte-Dock is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "windowstracker.h" 0021 0022 // local 0023 #include "lastactivewindow.h" 0024 #include "schemes.h" 0025 #include "trackedlayoutinfo.h" 0026 #include "trackedviewinfo.h" 0027 #include "../abstractwindowinterface.h" 0028 #include "../schemecolors.h" 0029 #include "../../lattecorona.h" 0030 #include "../../layout/genericlayout.h" 0031 #include "../../layouts/manager.h" 0032 #include "../../view/view.h" 0033 #include "../../view/positioner.h" 0034 #include "../../../liblatte2/types.h" 0035 0036 namespace Latte { 0037 namespace WindowSystem { 0038 namespace Tracker { 0039 0040 Windows::Windows(AbstractWindowInterface *parent) 0041 : QObject(parent) 0042 { 0043 m_wm = parent; 0044 0045 m_extraViewHintsTimer.setInterval(600); 0046 m_extraViewHintsTimer.setSingleShot(true); 0047 0048 connect(&m_extraViewHintsTimer, &QTimer::timeout, this, &Windows::updateExtraViewHints); 0049 0050 //! delayed application data 0051 m_updateApplicationDataTimer.setInterval(1500); 0052 m_updateApplicationDataTimer.setSingleShot(true); 0053 connect(&m_updateApplicationDataTimer, &QTimer::timeout, this, &Windows::updateApplicationData); 0054 0055 init(); 0056 } 0057 0058 Windows::~Windows() 0059 { 0060 //! clear all the m_views tracking information 0061 for (QHash<Latte::View *, TrackedViewInfo *>::iterator i=m_views.begin(); i!=m_views.end(); ++i) { 0062 i.value()->deleteLater(); 0063 m_views[i.key()] = nullptr; 0064 } 0065 0066 m_views.clear(); 0067 0068 //! clear all the m_layouts tracking layouts 0069 for (QHash<Latte::Layout::GenericLayout *, TrackedLayoutInfo *>::iterator i=m_layouts.begin(); i!=m_layouts.end(); ++i) { 0070 i.value()->deleteLater(); 0071 m_layouts[i.key()] = nullptr; 0072 } 0073 0074 m_layouts.clear(); 0075 } 0076 0077 void Windows::init() 0078 { 0079 connect(m_wm->corona(), &Plasma::Corona::availableScreenRectChanged, this, &Windows::updateAvailableScreenGeometries); 0080 0081 connect(m_wm, &AbstractWindowInterface::windowChanged, this, [&](WindowId wid) { 0082 m_windows[wid] = m_wm->requestInfo(wid); 0083 updateAllHints(); 0084 0085 emit windowChanged(wid); 0086 }); 0087 0088 connect(m_wm, &AbstractWindowInterface::windowRemoved, this, [&](WindowId wid) { 0089 m_windows.remove(wid); 0090 0091 //! application data 0092 m_initializedApplicationData.removeAll(wid); 0093 m_delayedApplicationData.removeAll(wid); 0094 0095 updateAllHints(); 0096 0097 emit windowRemoved(wid); 0098 }); 0099 0100 connect(m_wm, &AbstractWindowInterface::windowAdded, this, [&](WindowId wid) { 0101 if (!m_windows.contains(wid)) { 0102 m_windows.insert(wid, m_wm->requestInfo(wid)); 0103 } 0104 updateAllHints(); 0105 }); 0106 0107 connect(m_wm, &AbstractWindowInterface::activeWindowChanged, this, [&](WindowId wid) { 0108 //! for some reason this is needed in order to update properly activeness values 0109 //! when the active window changes the previous active windows should be also updated 0110 for (const auto view : m_views.keys()) { 0111 WindowId lastWinId = m_views[view]->lastActiveWindow()->winId(); 0112 if ((lastWinId) != wid && m_windows.contains(lastWinId)) { 0113 m_windows[lastWinId] = m_wm->requestInfo(lastWinId); 0114 } 0115 } 0116 0117 m_windows[wid] = m_wm->requestInfo(wid); 0118 updateAllHints(); 0119 0120 emit activeWindowChanged(wid); 0121 }); 0122 0123 connect(m_wm, &AbstractWindowInterface::currentDesktopChanged, this, [&] { 0124 updateAllHints(); 0125 }); 0126 0127 connect(m_wm, &AbstractWindowInterface::currentActivityChanged, this, [&] { 0128 if (m_wm->corona()->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 0129 //! this is needed in MultipleLayouts because there is a chance that multiple 0130 //! layouts are providing different available screen geometries in different Activities 0131 updateAvailableScreenGeometries(); 0132 } 0133 0134 updateAllHints(); 0135 }); 0136 } 0137 0138 void Windows::initLayoutHints(Latte::Layout::GenericLayout *layout) 0139 { 0140 if (!m_layouts.contains(layout)) { 0141 return; 0142 } 0143 0144 setActiveWindowMaximized(layout, false); 0145 setExistsWindowActive(layout, false); 0146 setExistsWindowMaximized(layout, false); 0147 setActiveWindowScheme(layout, nullptr); 0148 } 0149 0150 void Windows::initViewHints(Latte::View *view) 0151 { 0152 if (!m_views.contains(view)) { 0153 return; 0154 } 0155 0156 setActiveWindowMaximized(view, false); 0157 setActiveWindowTouching(view, false); 0158 setExistsWindowActive(view, false); 0159 setExistsWindowTouching(view, false); 0160 setExistsWindowMaximized(view, false); 0161 setIsTouchingBusyVerticalView(view, false); 0162 setActiveWindowScheme(view, nullptr); 0163 setTouchingWindowScheme(view, nullptr); 0164 } 0165 0166 AbstractWindowInterface *Windows::wm() 0167 { 0168 return m_wm; 0169 } 0170 0171 0172 void Windows::addView(Latte::View *view) 0173 { 0174 if (m_views.contains(view)) { 0175 return; 0176 } 0177 0178 m_views[view] = new TrackedViewInfo(this, view); 0179 0180 updateAvailableScreenGeometries(); 0181 0182 //! Consider Layouts 0183 addRelevantLayout(view); 0184 0185 connect(view, &Latte::View::layoutChanged, this, [&, view]() { 0186 addRelevantLayout(view); 0187 }); 0188 0189 connect(view, &Latte::View::isTouchingBottomViewAndIsBusyChanged, this, &Windows::updateExtraViewHints); 0190 connect(view, &Latte::View::isTouchingTopViewAndIsBusyChanged, this, &Windows::updateExtraViewHints); 0191 0192 updateAllHints(); 0193 0194 emit informationAnnounced(view); 0195 } 0196 0197 void Windows::removeView(Latte::View *view) 0198 { 0199 if (!m_views.contains(view)) { 0200 return; 0201 } 0202 0203 m_views[view]->deleteLater(); 0204 m_views.remove(view); 0205 0206 updateRelevantLayouts(); 0207 } 0208 0209 void Windows::addRelevantLayout(Latte::View *view) 0210 { 0211 if (view->layout()) { 0212 bool initializing {false}; 0213 0214 if (!m_layouts.contains(view->layout())) { 0215 initializing = true; 0216 m_layouts[view->layout()] = new TrackedLayoutInfo(this, view->layout()); 0217 } 0218 0219 //! Update always the AllScreens tracking because there is a chance a view delayed to be assigned in a layout 0220 //! and that could create a state the AllScreens tracking will be disabled if there is a View requesting 0221 //! tracking and one that it does not during startup 0222 updateRelevantLayouts(); 0223 0224 if (initializing) { 0225 updateHints(view->layout()); 0226 emit informationAnnouncedForLayout(view->layout()); 0227 } 0228 } 0229 } 0230 0231 void Windows::updateRelevantLayouts() 0232 { 0233 QList<Latte::Layout::GenericLayout*> orphanedLayouts; 0234 0235 //! REMOVE Orphaned Relevant layouts that have been removed or they don't contain any Views anymore 0236 for (QHash<Latte::Layout::GenericLayout *, TrackedLayoutInfo *>::iterator i=m_layouts.begin(); i!=m_layouts.end(); ++i) { 0237 bool hasView{false}; 0238 for (QHash<Latte::View *, TrackedViewInfo *>::iterator j=m_views.begin(); j!=m_views.end(); ++j) { 0239 if (j.key() && i.key() && i.key() == j.key()->layout()) { 0240 hasView = true; 0241 break; 0242 } 0243 } 0244 0245 if (!hasView) { 0246 if (i.value()) { 0247 i.value()->deleteLater(); 0248 } 0249 orphanedLayouts << i.key(); 0250 } 0251 } 0252 0253 for(const auto &layout : orphanedLayouts) { 0254 m_layouts.remove(layout); 0255 } 0256 0257 //! UPDATE Enabled layout window tracking based on the Views that are requesting windows tracking 0258 for (QHash<Latte::Layout::GenericLayout *, TrackedLayoutInfo *>::iterator i=m_layouts.begin(); i!=m_layouts.end(); ++i) { 0259 bool hasViewEnabled{false}; 0260 for (QHash<Latte::View *, TrackedViewInfo *>::iterator j=m_views.begin(); j!=m_views.end(); ++j) { 0261 if (i.key() == j.key()->layout() && j.value()->enabled()) { 0262 hasViewEnabled = true; 0263 break; 0264 } 0265 } 0266 0267 if (i.value()) { 0268 i.value()->setEnabled(hasViewEnabled); 0269 0270 if (!hasViewEnabled) { 0271 initLayoutHints(i.key()); 0272 } 0273 } 0274 } 0275 } 0276 0277 //! Views Properties And Hints 0278 0279 bool Windows::enabled(Latte::View *view) 0280 { 0281 if (!m_views.contains(view)) { 0282 return false; 0283 } 0284 0285 return m_views[view]->enabled(); 0286 } 0287 0288 void Windows::setEnabled(Latte::View *view, const bool enabled) 0289 { 0290 if (!m_views.contains(view) || m_views[view]->enabled() == enabled) { 0291 return; 0292 } 0293 0294 m_views[view]->setEnabled(enabled); 0295 0296 if (enabled) { 0297 updateHints(view); 0298 } else { 0299 initViewHints(view); 0300 } 0301 0302 updateRelevantLayouts(); 0303 0304 emit enabledChanged(view); 0305 } 0306 0307 bool Windows::activeWindowMaximized(Latte::View *view) const 0308 { 0309 if (!m_views.contains(view)) { 0310 return false; 0311 } 0312 0313 return m_views[view]->activeWindowMaximized(); 0314 } 0315 0316 void Windows::setActiveWindowMaximized(Latte::View *view, bool activeMaximized) 0317 { 0318 if (!m_views.contains(view) || m_views[view]->activeWindowMaximized() == activeMaximized) { 0319 return; 0320 } 0321 0322 m_views[view]->setActiveWindowMaximized(activeMaximized); 0323 emit activeWindowMaximizedChanged(view); 0324 } 0325 0326 bool Windows::activeWindowTouching(Latte::View *view) const 0327 { 0328 if (!m_views.contains(view)) { 0329 return false; 0330 } 0331 0332 return m_views[view]->activeWindowTouching(); 0333 } 0334 0335 void Windows::setActiveWindowTouching(Latte::View *view, bool activeTouching) 0336 { 0337 if (!m_views.contains(view) || m_views[view]->activeWindowTouching() == activeTouching) { 0338 return; 0339 } 0340 0341 m_views[view]->setActiveWindowTouching(activeTouching); 0342 emit activeWindowTouchingChanged(view); 0343 } 0344 0345 bool Windows::existsWindowActive(Latte::View *view) const 0346 { 0347 if (!m_views.contains(view)) { 0348 return false; 0349 } 0350 0351 return m_views[view]->existsWindowActive(); 0352 } 0353 0354 void Windows::setExistsWindowActive(Latte::View *view, bool windowActive) 0355 { 0356 if (!m_views.contains(view) || m_views[view]->existsWindowActive() == windowActive) { 0357 return; 0358 } 0359 0360 m_views[view]->setExistsWindowActive(windowActive); 0361 emit existsWindowActiveChanged(view); 0362 } 0363 0364 bool Windows::existsWindowMaximized(Latte::View *view) const 0365 { 0366 if (!m_views.contains(view)) { 0367 return false; 0368 } 0369 0370 return m_views[view]->existsWindowMaximized(); 0371 } 0372 0373 void Windows::setExistsWindowMaximized(Latte::View *view, bool windowMaximized) 0374 { 0375 if (!m_views.contains(view) || m_views[view]->existsWindowMaximized() == windowMaximized) { 0376 return; 0377 } 0378 0379 m_views[view]->setExistsWindowMaximized(windowMaximized); 0380 emit existsWindowMaximizedChanged(view); 0381 } 0382 0383 bool Windows::existsWindowTouching(Latte::View *view) const 0384 { 0385 if (!m_views.contains(view)) { 0386 return false; 0387 } 0388 0389 return m_views[view]->existsWindowTouching(); 0390 } 0391 0392 void Windows::setExistsWindowTouching(Latte::View *view, bool windowTouching) 0393 { 0394 if (!m_views.contains(view) || m_views[view]->existsWindowTouching() == windowTouching) { 0395 return; 0396 } 0397 0398 m_views[view]->setExistsWindowTouching(windowTouching); 0399 emit existsWindowTouchingChanged(view); 0400 } 0401 0402 bool Windows::isTouchingBusyVerticalView(Latte::View *view) const 0403 { 0404 if (!m_views.contains(view)) { 0405 return false; 0406 } 0407 0408 return m_views[view]->isTouchingBusyVerticalView(); 0409 } 0410 0411 void Windows::setIsTouchingBusyVerticalView(Latte::View *view, bool viewTouching) 0412 { 0413 if (!m_views.contains(view) || m_views[view]->isTouchingBusyVerticalView() == viewTouching) { 0414 return; 0415 } 0416 0417 m_views[view]->setIsTouchingBusyVerticalView(viewTouching); 0418 emit isTouchingBusyVerticalViewChanged(view); 0419 } 0420 0421 SchemeColors *Windows::activeWindowScheme(Latte::View *view) const 0422 { 0423 if (!m_views.contains(view)) { 0424 return nullptr; 0425 } 0426 0427 return m_views[view]->activeWindowScheme(); 0428 } 0429 0430 void Windows::setActiveWindowScheme(Latte::View *view, WindowSystem::SchemeColors *scheme) 0431 { 0432 if (!m_views.contains(view) || m_views[view]->activeWindowScheme() == scheme) { 0433 return; 0434 } 0435 0436 m_views[view]->setActiveWindowScheme(scheme); 0437 emit activeWindowSchemeChanged(view); 0438 } 0439 0440 SchemeColors *Windows::touchingWindowScheme(Latte::View *view) const 0441 { 0442 if (!m_views.contains(view)) { 0443 return nullptr; 0444 } 0445 0446 return m_views[view]->touchingWindowScheme(); 0447 } 0448 0449 void Windows::setTouchingWindowScheme(Latte::View *view, WindowSystem::SchemeColors *scheme) 0450 { 0451 if (!m_views.contains(view) || m_views[view]->touchingWindowScheme() == scheme) { 0452 return; 0453 } 0454 0455 m_views[view]->setTouchingWindowScheme(scheme); 0456 emit touchingWindowSchemeChanged(view); 0457 } 0458 0459 LastActiveWindow *Windows::lastActiveWindow(Latte::View *view) 0460 { 0461 if (!m_views.contains(view)) { 0462 return nullptr; 0463 } 0464 0465 return m_views[view]->lastActiveWindow(); 0466 } 0467 0468 //! Layouts 0469 bool Windows::enabled(Latte::Layout::GenericLayout *layout) 0470 { 0471 if (!m_layouts.contains(layout)) { 0472 return false; 0473 } 0474 0475 return m_layouts[layout]->enabled(); 0476 } 0477 0478 bool Windows::activeWindowMaximized(Latte::Layout::GenericLayout *layout) const 0479 { 0480 if (!m_layouts.contains(layout)) { 0481 return false; 0482 } 0483 0484 return m_layouts[layout]->activeWindowMaximized(); 0485 } 0486 0487 void Windows::setActiveWindowMaximized(Latte::Layout::GenericLayout *layout, bool activeMaximized) 0488 { 0489 if (!m_layouts.contains(layout) || m_layouts[layout]->activeWindowMaximized() == activeMaximized) { 0490 return; 0491 } 0492 0493 m_layouts[layout]->setActiveWindowMaximized(activeMaximized); 0494 emit activeWindowMaximizedChangedForLayout(layout); 0495 } 0496 0497 bool Windows::existsWindowActive(Latte::Layout::GenericLayout *layout) const 0498 { 0499 if (!m_layouts.contains(layout)) { 0500 return false; 0501 } 0502 0503 return m_layouts[layout]->existsWindowActive(); 0504 } 0505 0506 void Windows::setExistsWindowActive(Latte::Layout::GenericLayout *layout, bool windowActive) 0507 { 0508 if (!m_layouts.contains(layout) || m_layouts[layout]->existsWindowActive() == windowActive) { 0509 return; 0510 } 0511 0512 m_layouts[layout]->setExistsWindowActive(windowActive); 0513 emit existsWindowActiveChangedForLayout(layout); 0514 } 0515 0516 bool Windows::existsWindowMaximized(Latte::Layout::GenericLayout *layout) const 0517 { 0518 if (!m_layouts.contains(layout)) { 0519 return false; 0520 } 0521 0522 return m_layouts[layout]->existsWindowMaximized(); 0523 } 0524 0525 void Windows::setExistsWindowMaximized(Latte::Layout::GenericLayout *layout, bool windowMaximized) 0526 { 0527 if (!m_layouts.contains(layout) || m_layouts[layout]->existsWindowMaximized() == windowMaximized) { 0528 return; 0529 } 0530 0531 m_layouts[layout]->setExistsWindowMaximized(windowMaximized); 0532 emit existsWindowMaximizedChangedForLayout(layout); 0533 } 0534 0535 SchemeColors *Windows::activeWindowScheme(Latte::Layout::GenericLayout *layout) const 0536 { 0537 if (!m_layouts.contains(layout)) { 0538 return nullptr; 0539 } 0540 0541 return m_layouts[layout]->activeWindowScheme(); 0542 } 0543 0544 void Windows::setActiveWindowScheme(Latte::Layout::GenericLayout *layout, WindowSystem::SchemeColors *scheme) 0545 { 0546 if (!m_layouts.contains(layout) || m_layouts[layout]->activeWindowScheme() == scheme) { 0547 return; 0548 } 0549 0550 m_layouts[layout]->setActiveWindowScheme(scheme); 0551 emit activeWindowSchemeChangedForLayout(layout); 0552 } 0553 0554 LastActiveWindow *Windows::lastActiveWindow(Latte::Layout::GenericLayout *layout) 0555 { 0556 if (!m_layouts.contains(layout)) { 0557 return nullptr; 0558 } 0559 0560 return m_layouts[layout]->lastActiveWindow(); 0561 } 0562 0563 0564 //! Windows 0565 bool Windows::isValidFor(const WindowId &wid) const 0566 { 0567 if (!m_windows.contains(wid)) { 0568 return false; 0569 } 0570 0571 return m_windows[wid].isValid() && !m_windows[wid].isPlasmaDesktop(); 0572 } 0573 0574 QIcon Windows::iconFor(const WindowId &wid) 0575 { 0576 if (!m_windows.contains(wid)) { 0577 return QIcon(); 0578 } 0579 0580 if (m_windows[wid].icon().isNull()) { 0581 AppData data = m_wm->appDataFor(wid); 0582 0583 QIcon icon = data.icon; 0584 0585 if (icon.isNull()) { 0586 icon = m_wm->iconFor(wid); 0587 } 0588 0589 m_windows[wid].setIcon(icon); 0590 return icon; 0591 } 0592 0593 return m_windows[wid].icon(); 0594 } 0595 0596 QString Windows::appNameFor(const WindowId &wid) 0597 { 0598 if (!m_windows.contains(wid)) { 0599 return QString(); 0600 } 0601 0602 if(!m_initializedApplicationData.contains(wid) && !m_delayedApplicationData.contains(wid)) { 0603 m_delayedApplicationData.append(wid); 0604 m_updateApplicationDataTimer.start(); 0605 } 0606 0607 if (m_windows[wid].appName().isEmpty()) { 0608 AppData data = m_wm->appDataFor(wid); 0609 0610 m_windows[wid].setAppName(data.name); 0611 0612 return data.name; 0613 } 0614 0615 return m_windows[wid].appName(); 0616 } 0617 0618 void Windows::updateApplicationData() 0619 { 0620 if (m_delayedApplicationData.count() > 0) { 0621 for(int i=0; i<m_delayedApplicationData.count(); ++i) { 0622 auto wid = m_delayedApplicationData[i]; 0623 0624 if (m_windows.contains(wid)) { 0625 AppData data = m_wm->appDataFor(wid); 0626 0627 QIcon icon = data.icon; 0628 0629 if (icon.isNull()) { 0630 icon = m_wm->iconFor(wid); 0631 } 0632 0633 m_windows[wid].setIcon(icon); 0634 m_windows[wid].setAppName(data.name); 0635 0636 m_initializedApplicationData.append(wid); 0637 0638 emit applicationDataChanged(wid); 0639 } 0640 } 0641 } 0642 0643 m_delayedApplicationData.clear(); 0644 } 0645 0646 WindowInfoWrap Windows::infoFor(const WindowId &wid) const 0647 { 0648 if (!m_windows.contains(wid)) { 0649 return WindowInfoWrap(); 0650 } 0651 0652 return m_windows[wid]; 0653 } 0654 0655 0656 0657 //! Windows Criteria Functions 0658 bool Windows::intersects(Latte::View *view, const WindowInfoWrap &winfo) 0659 { 0660 return (!winfo.isMinimized() && !winfo.isShaded() && winfo.geometry().intersects(view->absoluteGeometry())); 0661 } 0662 0663 bool Windows::isActive(const WindowInfoWrap &winfo) 0664 { 0665 return (winfo.isValid() && winfo.isActive() && !winfo.isPlasmaDesktop() && !winfo.isMinimized()); 0666 } 0667 0668 bool Windows::isActiveInViewScreen(Latte::View *view, const WindowInfoWrap &winfo) 0669 { 0670 return (winfo.isValid() && winfo.isActive() && !winfo.isPlasmaDesktop() && !winfo.isMinimized() 0671 && m_views[view]->availableScreenGeometry().contains(winfo.geometry().center())); 0672 } 0673 0674 bool Windows::isMaximizedInViewScreen(Latte::View *view, const WindowInfoWrap &winfo) 0675 { 0676 /* auto viewIntersectsMaxVert = [&]() noexcept -> bool { 0677 return ((winfo.isMaxVert() 0678 || (view->screen() && view->screen()->availableSize().height() <= winfo.geometry().height())) 0679 && intersects(view, winfo)); 0680 }; 0681 0682 auto viewIntersectsMaxHoriz = [&]() noexcept -> bool { 0683 return ((winfo.isMaxHoriz() 0684 || (view->screen() && view->screen()->availableSize().width() <= winfo.geometry().width())) 0685 && intersects(view, winfo)); 0686 };*/ 0687 0688 //! updated implementation to identify the screen that the maximized window is present 0689 //! in order to avoid: https://bugs.kde.org/show_bug.cgi?id=397700 0690 return (winfo.isValid() && !winfo.isPlasmaDesktop() && !winfo.isMinimized() 0691 && !winfo.isShaded() 0692 && winfo.isMaximized() 0693 && m_views[view]->availableScreenGeometry().contains(winfo.geometry().center())); 0694 } 0695 0696 bool Windows::isTouchingView(Latte::View *view, const WindowSystem::WindowInfoWrap &winfo) 0697 { 0698 return (winfo.isValid() && !winfo.isPlasmaDesktop() && intersects(view, winfo)); 0699 } 0700 0701 bool Windows::isTouchingViewEdge(Latte::View *view, const WindowInfoWrap &winfo) 0702 { 0703 if (winfo.isValid() && !winfo.isPlasmaDesktop() && !winfo.isMinimized()) { 0704 bool inViewThicknessEdge{false}; 0705 bool inViewLengthBoundaries{false}; 0706 0707 QRect screenGeometry = view->screenGeometry(); 0708 0709 bool inCurrentScreen{screenGeometry.contains(winfo.geometry().topLeft()) || screenGeometry.contains(winfo.geometry().bottomRight())}; 0710 0711 if (inCurrentScreen) { 0712 if (view->location() == Plasma::Types::TopEdge) { 0713 inViewThicknessEdge = (winfo.geometry().y() == view->absoluteGeometry().bottom() + 1); 0714 } else if (view->location() == Plasma::Types::BottomEdge) { 0715 inViewThicknessEdge = (winfo.geometry().bottom() == view->absoluteGeometry().top() - 1); 0716 } else if (view->location() == Plasma::Types::LeftEdge) { 0717 inViewThicknessEdge = (winfo.geometry().x() == view->absoluteGeometry().right() + 1); 0718 } else if (view->location() == Plasma::Types::RightEdge) { 0719 inViewThicknessEdge = (winfo.geometry().right() == view->absoluteGeometry().left() - 1); 0720 } 0721 0722 if (view->formFactor() == Plasma::Types::Horizontal) { 0723 int yCenter = view->absoluteGeometry().center().y(); 0724 0725 QPoint leftChecker(winfo.geometry().left(), yCenter); 0726 QPoint rightChecker(winfo.geometry().right(), yCenter); 0727 0728 bool fulloverlap = (winfo.geometry().left()<=view->absoluteGeometry().left()) && (winfo.geometry().right()>=view->absoluteGeometry().right()); 0729 0730 inViewLengthBoundaries = fulloverlap || view->absoluteGeometry().contains(leftChecker) || view->absoluteGeometry().contains(rightChecker); 0731 } else if (view->formFactor() == Plasma::Types::Vertical) { 0732 int xCenter = view->absoluteGeometry().center().x(); 0733 0734 QPoint topChecker(xCenter, winfo.geometry().top()); 0735 QPoint bottomChecker(xCenter, winfo.geometry().bottom()); 0736 0737 bool fulloverlap = (winfo.geometry().top()<=view->absoluteGeometry().top()) && (winfo.geometry().bottom()>=view->absoluteGeometry().bottom()); 0738 0739 inViewLengthBoundaries = fulloverlap || view->absoluteGeometry().contains(topChecker) || view->absoluteGeometry().contains(bottomChecker); 0740 } 0741 } 0742 0743 return (inViewThicknessEdge && inViewLengthBoundaries); 0744 } 0745 0746 return false; 0747 } 0748 0749 void Windows::cleanupFaultyWindows() 0750 { 0751 for (const auto &key : m_windows.keys()) { 0752 auto winfo = m_windows[key]; 0753 0754 //! garbage windows removing 0755 if (winfo.wid()<=0 || winfo.geometry() == QRect(0, 0, 0, 0)) { 0756 //qDebug() << "Faulty Geometry ::: " << winfo.wid(); 0757 m_windows.remove(key); 0758 } 0759 } 0760 } 0761 0762 0763 void Windows::updateAvailableScreenGeometries() 0764 { 0765 for (const auto view : m_views.keys()) { 0766 if (m_views[view]->enabled()) { 0767 int currentScrId = view->positioner()->currentScreenId(); 0768 QRect tempAvailableScreenGeometry = m_wm->corona()->availableScreenRectWithCriteria(currentScrId, {Types::AlwaysVisible}, {}); 0769 0770 if (tempAvailableScreenGeometry != m_views[view]->availableScreenGeometry()) { 0771 m_views[view]->setAvailableScreenGeometry(tempAvailableScreenGeometry); 0772 0773 updateHints(view); 0774 } 0775 } 0776 } 0777 } 0778 0779 void Windows::setPlasmaDesktop(WindowId wid) 0780 { 0781 if (!m_windows.contains(wid)) { 0782 return; 0783 } 0784 0785 if (!m_windows[wid].isPlasmaDesktop()) { 0786 m_windows[wid].setIsPlasmaDesktop(true); 0787 qDebug() << " plasmashell updated..."; 0788 updateAllHints(); 0789 } 0790 } 0791 0792 void Windows::updateAllHints() 0793 { 0794 for (const auto view : m_views.keys()) { 0795 updateHints(view); 0796 } 0797 0798 for (const auto layout : m_layouts.keys()) { 0799 updateHints(layout); 0800 } 0801 0802 if (!m_extraViewHintsTimer.isActive()) { 0803 m_extraViewHintsTimer.start(); 0804 } 0805 } 0806 0807 void Windows::updateExtraViewHints() 0808 { 0809 for (const auto horView : m_views.keys()) { 0810 if (!m_views.contains(horView) || !m_views[horView]->enabled() || !m_views[horView]->isTrackingCurrentActivity()) { 0811 continue; 0812 } 0813 0814 if (horView->formFactor() == Plasma::Types::Horizontal) { 0815 bool touchingBusyVerticalView{false}; 0816 0817 for (const auto verView : m_views.keys()) { 0818 if (!m_views.contains(verView) || !m_views[verView]->enabled() || !m_views[verView]->isTrackingCurrentActivity()) { 0819 continue; 0820 } 0821 0822 bool sameScreen = (verView->positioner()->currentScreenId() == horView->positioner()->currentScreenId()); 0823 0824 if (verView->formFactor() == Plasma::Types::Vertical && sameScreen) { 0825 bool topTouch = verView->isTouchingTopViewAndIsBusy() && horView->location() == Plasma::Types::TopEdge; 0826 bool bottomTouch = verView->isTouchingBottomViewAndIsBusy() && horView->location() == Plasma::Types::BottomEdge; 0827 0828 if (topTouch || bottomTouch) { 0829 touchingBusyVerticalView = true; 0830 break; 0831 } 0832 } 0833 } 0834 0835 //qDebug() << " Touching Busy Vertical View :: " << horView->location() << " - " << horView->positioner()->currentScreenId() << " :: " << touchingBusyVerticalView; 0836 0837 setIsTouchingBusyVerticalView(horView, touchingBusyVerticalView); 0838 } 0839 } 0840 } 0841 0842 void Windows::updateHints(Latte::View *view) 0843 { 0844 if (!m_views.contains(view) || !m_views[view]->enabled() || !m_views[view]->isTrackingCurrentActivity()) { 0845 return; 0846 } 0847 0848 bool foundActive{false}; 0849 bool foundActiveInCurScreen{false}; 0850 bool foundActiveTouchInCurScreen{false}; 0851 bool foundTouchInCurScreen{false}; 0852 bool foundMaximizedInCurScreen{false}; 0853 0854 bool foundActiveGroupTouchInCurScreen{false}; 0855 0856 //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), 0857 //! maybe a garbage collector here is a good idea!!! 0858 bool existsFaultyWindow{false}; 0859 0860 WindowId maxWinId; 0861 WindowId activeWinId; 0862 WindowId touchWinId; 0863 WindowId activeTouchWinId; 0864 0865 //! First Pass 0866 for (const auto &winfo : m_windows) { 0867 if (!existsFaultyWindow && (winfo.wid()<=0 || winfo.geometry() == QRect(0, 0, 0, 0))) { 0868 existsFaultyWindow = true; 0869 } 0870 0871 if (winfo.isPlasmaDesktop() || !m_wm->inCurrentDesktopActivity(winfo) || m_wm->isRegisteredPlasmaPanel(winfo.wid())) { 0872 continue; 0873 } 0874 0875 if (isActive(winfo)) { 0876 foundActive = true; 0877 } 0878 0879 if (isActiveInViewScreen(view, winfo)) { 0880 foundActiveInCurScreen = true; 0881 activeWinId = winfo.wid(); 0882 } 0883 0884 if (isTouchingViewEdge(view, winfo) || isTouchingView(view, winfo)) { 0885 if (winfo.isActive()) { 0886 //qDebug() << " ACTIVE-TOUCH :: " << winfo.wid() << " _ " << winfo.appName() << " _ " << winfo.geometry() << " _ " << winfo.display(); 0887 foundActiveTouchInCurScreen = true; 0888 activeTouchWinId = winfo.wid(); 0889 0890 if (isMaximizedInViewScreen(view, winfo)) { 0891 //! active maximized windows have higher priority than the rest maximized windows 0892 foundMaximizedInCurScreen = true; 0893 maxWinId = winfo.wid(); 0894 } 0895 } else { 0896 //qDebug() << " TOUCH :: " << winfo.wid() << " _ " << winfo.appName() << " _ " << winfo.geometry() << " _ " << winfo.display(); 0897 foundTouchInCurScreen = true; 0898 touchWinId = winfo.wid(); 0899 } 0900 0901 if (!foundMaximizedInCurScreen && isMaximizedInViewScreen(view, winfo)) { 0902 foundMaximizedInCurScreen = true; 0903 maxWinId = winfo.wid(); 0904 } 0905 } 0906 0907 //qDebug() << "window geometry ::: " << winfo.geometry(); 0908 } 0909 0910 if (existsFaultyWindow) { 0911 cleanupFaultyWindows(); 0912 } 0913 0914 //! PASS 2 0915 if (foundActiveInCurScreen && !foundActiveTouchInCurScreen) { 0916 //! Second Pass to track also Child windows if needed 0917 0918 //qDebug() << "Windows Array..."; 0919 //for (const auto &winfo : m_windows) { 0920 // qDebug() << " - " << winfo.wid() << " - " << winfo.isValid() << " - " << winfo.display() << " - " << winfo.geometry() << " parent : " << winfo.parentId(); 0921 //} 0922 //qDebug() << " - - - - - "; 0923 0924 WindowInfoWrap activeInfo = m_windows[activeWinId]; 0925 WindowId mainWindowId = activeInfo.isChildWindow() ? activeInfo.parentId() : activeWinId; 0926 0927 for (const auto &winfo : m_windows) { 0928 if (winfo.isPlasmaDesktop() || !m_wm->inCurrentDesktopActivity(winfo) || m_wm->isRegisteredPlasmaPanel(winfo.wid())) { 0929 continue; 0930 } 0931 0932 bool inActiveGroup = (winfo.wid() == mainWindowId || winfo.parentId() == mainWindowId); 0933 0934 //! consider only windows that belong to active window group meaning the main window 0935 //! and its children 0936 if (!inActiveGroup) { 0937 continue; 0938 } 0939 0940 if (isTouchingViewEdge(view, winfo) || isTouchingView(view, winfo)) { 0941 foundActiveGroupTouchInCurScreen = true; 0942 break; 0943 } 0944 } 0945 } 0946 0947 0948 //! HACK: KWin Effects such as ShowDesktop have no way to be identified and as such 0949 //! create issues with identifying properly touching and maximized windows. BUT when 0950 //! they are enabled then NO ACTIVE window is found. This is a way to identify these 0951 //! effects trigerring and disable the touch flags. 0952 //! BUG: 404483 0953 //! Disabled because it has fault identifications, e.g. when a window is maximized and 0954 //! Latte or Plasma are showing their View settings 0955 //foundMaximizedInCurScreen = foundMaximizedInCurScreen && foundActive; 0956 //foundTouchInCurScreen = foundTouchInCurScreen && foundActive; 0957 0958 //! assign flags 0959 setExistsWindowActive(view, foundActiveInCurScreen); 0960 setActiveWindowTouching(view, foundActiveTouchInCurScreen || foundActiveGroupTouchInCurScreen); 0961 setActiveWindowMaximized(view, (maxWinId.toInt()>0 && (maxWinId == activeTouchWinId))); 0962 setExistsWindowMaximized(view, foundMaximizedInCurScreen); 0963 setExistsWindowTouching(view, (foundTouchInCurScreen || foundActiveTouchInCurScreen || foundActiveGroupTouchInCurScreen)); 0964 0965 //! update color schemes for active and touching windows 0966 setActiveWindowScheme(view, (foundActiveInCurScreen ? m_wm->schemesTracker()->schemeForWindow(activeWinId) : nullptr)); 0967 0968 if (foundActiveTouchInCurScreen) { 0969 setTouchingWindowScheme(view, m_wm->schemesTracker()->schemeForWindow(activeTouchWinId)); 0970 } else if (foundMaximizedInCurScreen) { 0971 setTouchingWindowScheme(view, m_wm->schemesTracker()->schemeForWindow(maxWinId)); 0972 } else if (foundTouchInCurScreen) { 0973 setTouchingWindowScheme(view, m_wm->schemesTracker()->schemeForWindow(touchWinId)); 0974 } else { 0975 setTouchingWindowScheme(view, nullptr); 0976 } 0977 0978 //! update LastActiveWindow 0979 if (foundActiveInCurScreen) { 0980 m_views[view]->setActiveWindow(activeWinId); 0981 } 0982 0983 //! Debug 0984 //qDebug() << " -- TRACKING REPORT (SCREEN)--"; 0985 //qDebug() << "TRACKING | SCREEN: " << view->positioner()->currentScreenId() << " , EDGE:" << view->location() << " , ENABLED:" << enabled(view); 0986 //qDebug() << "TRACKING | activeWindowTouching: " << foundActiveTouchInCurScreen << " ,activeWindowMaximized: " << activeWindowMaximized(view); 0987 //qDebug() << "TRACKING | existsWindowActive: " << foundActiveInCurScreen << " , existsWindowMaximized:" << existsWindowMaximized(view) 0988 // << " , existsWindowTouching:"<<existsWindowTouching(view); 0989 //qDebug() << "TRACKING | existsActiveGroupTouching: " << foundActiveGroupTouchInCurScreen; 0990 } 0991 0992 void Windows::updateHints(Latte::Layout::GenericLayout *layout) { 0993 if (!m_layouts.contains(layout) || !m_layouts[layout]->enabled() || !m_layouts[layout]->isTrackingCurrentActivity()) { 0994 return; 0995 } 0996 0997 bool foundActive{false}; 0998 bool foundActiveMaximized{false}; 0999 bool foundMaximized{false}; 1000 1001 //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), 1002 //! maybe a garbage collector here is a good idea!!! 1003 bool existsFaultyWindow{false}; 1004 1005 WindowId activeWinId; 1006 WindowId maxWinId; 1007 1008 for (const auto &winfo : m_windows) { 1009 if (!existsFaultyWindow && (winfo.wid()<=0 || winfo.geometry() == QRect(0, 0, 0, 0))) { 1010 existsFaultyWindow = true; 1011 } 1012 1013 if (winfo.isPlasmaDesktop() || !m_wm->inCurrentDesktopActivity(winfo) || m_wm->isRegisteredPlasmaPanel(winfo.wid())) { 1014 continue; 1015 } 1016 1017 if (isActive(winfo)) { 1018 foundActive = true; 1019 activeWinId = winfo.wid(); 1020 1021 if (winfo.isMaximized() && !winfo.isMinimized()) { 1022 foundActiveMaximized = true; 1023 maxWinId = winfo.wid(); 1024 } 1025 } 1026 1027 if (!foundActiveMaximized && winfo.isMaximized() && !winfo.isMinimized()) { 1028 foundMaximized = true; 1029 maxWinId = winfo.wid(); 1030 } 1031 1032 //qDebug() << "window geometry ::: " << winfo.geometry(); 1033 } 1034 1035 if (existsFaultyWindow) { 1036 cleanupFaultyWindows(); 1037 } 1038 1039 //! HACK: KWin Effects such as ShowDesktop have no way to be identified and as such 1040 //! create issues with identifying properly touching and maximized windows. BUT when 1041 //! they are enabled then NO ACTIVE window is found. This is a way to identify these 1042 //! effects trigerring and disable the touch flags. 1043 //! BUG: 404483 1044 //! Disabled because it has fault identifications, e.g. when a window is maximized and 1045 //! Latte or Plasma are showing their View settings 1046 //foundMaximizedInCurScreen = foundMaximizedInCurScreen && foundActive; 1047 //foundTouchInCurScreen = foundTouchInCurScreen && foundActive; 1048 1049 //! assign flags 1050 setExistsWindowActive(layout, foundActive); 1051 setActiveWindowMaximized(layout, foundActiveMaximized); 1052 setExistsWindowMaximized(layout, foundActiveMaximized || foundMaximized); 1053 1054 //! update color schemes for active and touching windows 1055 setActiveWindowScheme(layout, (foundActive ? m_wm->schemesTracker()->schemeForWindow(activeWinId) : nullptr)); 1056 1057 //! update LastActiveWindow 1058 if (foundActive) { 1059 m_layouts[layout]->setActiveWindow(activeWinId); 1060 } 1061 1062 //! Debug 1063 //qDebug() << " -- TRACKING REPORT (LAYOUT) --"; 1064 //qDebug() << "TRACKING | LAYOUT: " << layout->name() << " , ENABLED:" << enabled(layout); 1065 //qDebug() << "TRACKING | existsActiveWindow: " << foundActive << " ,activeWindowMaximized: " << foundActiveMaximized; 1066 //qDebug() << "TRACKING | existsWindowMaximized: " << existsWindowMaximized(layout); 1067 } 1068 1069 } 1070 } 1071 }