File indexing completed on 2024-04-28 16:49:31

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 "lastactivewindow.h"
0021 
0022 // local
0023 #include "schemes.h"
0024 #include "trackedgeneralinfo.h"
0025 #include "windowstracker.h"
0026 #include "../abstractwindowinterface.h"
0027 #include "../tasktools.h"
0028 #include "../../view/view.h"
0029 
0030 // Qt
0031 #include <QDebug>
0032 #include <QHoverEvent>
0033 #include <QPoint>
0034 #include <QTimer>
0035 
0036 
0037 namespace Latte {
0038 namespace WindowSystem {
0039 namespace Tracker {
0040 
0041 const int INVALIDWID = -1;
0042 const int PREFHISTORY = 8;
0043 const int MAXHISTORY = 15;
0044 
0045 LastActiveWindow::LastActiveWindow(TrackedGeneralInfo *trackedInfo)
0046     : QObject(trackedInfo),
0047       m_trackedInfo(trackedInfo),
0048       m_windowsTracker(trackedInfo->wm()->windowsTracker()),
0049       m_wm(trackedInfo->wm())
0050 {
0051     connect(m_wm->schemesTracker(), &Schemes::colorSchemeChanged, this, [&](WindowId wid) {
0052         if (wid == m_winId) {
0053             updateColorScheme();
0054         }
0055     });
0056 
0057     connect(m_windowsTracker, &Windows::applicationDataChanged, this, &LastActiveWindow::applicationDataChanged);
0058     connect(m_windowsTracker, &Windows::windowChanged, this, &LastActiveWindow::windowChanged);
0059     connect(m_windowsTracker, &Windows::windowRemoved, this, &LastActiveWindow::windowRemoved);
0060 }
0061 
0062 LastActiveWindow::~LastActiveWindow()
0063 {
0064 }
0065 
0066 bool LastActiveWindow::isActive() const
0067 {
0068     return m_isActive;
0069 }
0070 
0071 void LastActiveWindow::setActive(bool active)
0072 {
0073     if (m_isActive == active) {
0074         return;
0075     }
0076 
0077     m_isActive = active;
0078     emit isActiveChanged();
0079 }
0080 
0081 bool LastActiveWindow::isMinimized() const
0082 {
0083     return m_isMinimized;
0084 }
0085 
0086 void LastActiveWindow::setIsMinimized(bool minimized)
0087 {
0088     if (m_isMinimized == minimized) {
0089         return;
0090     }
0091 
0092     m_isMinimized = minimized;
0093     emit isMinimizedChanged();
0094 }
0095 
0096 bool LastActiveWindow::isMaximized() const
0097 {
0098     return m_isMaximized;
0099 }
0100 
0101 void LastActiveWindow::setIsMaximized(bool maximized)
0102 {
0103     if (m_isMaximized == maximized) {
0104         return;
0105     }
0106 
0107     m_isMaximized = maximized;
0108     emit isMaximizedChanged();
0109 }
0110 
0111 bool LastActiveWindow::isFullScreen() const
0112 {
0113     return m_isFullScreen;
0114 }
0115 
0116 void LastActiveWindow::setIsFullScreen(bool fullscreen)
0117 {
0118     if (m_isFullScreen == fullscreen) {
0119         return;
0120     }
0121 
0122     m_isFullScreen = fullscreen;
0123     emit isFullScreenChanged();
0124 }
0125 
0126 bool LastActiveWindow::isKeepAbove() const
0127 {
0128     return m_isKeepAbove;
0129 }
0130 
0131 void LastActiveWindow::setIsKeepAbove(bool above)
0132 {
0133     if (m_isKeepAbove == above) {
0134         return;
0135     }
0136 
0137     m_isKeepAbove = above;
0138     emit isKeepAboveChanged();
0139 }
0140 
0141 bool LastActiveWindow::isOnAllDesktops() const
0142 {
0143     return m_isOnAllDesktops;
0144 }
0145 
0146 void LastActiveWindow::setIsOnAllDesktops(bool all)
0147 {
0148     if (m_isOnAllDesktops == all) {
0149         return;
0150     }
0151 
0152     m_isOnAllDesktops = all;
0153     emit isOnAllDesktopsChanged();
0154 }
0155 
0156 bool LastActiveWindow::isShaded() const
0157 {
0158     return m_isShaded;
0159 }
0160 
0161 void LastActiveWindow::setIsShaded(bool shaded)
0162 {
0163     if (m_isShaded == shaded) {
0164         return;
0165     }
0166 
0167     m_isShaded = shaded;
0168     emit isShadedChanged();
0169 }
0170 
0171 bool LastActiveWindow::isValid() const
0172 {
0173     return m_isValid;
0174 }
0175 
0176 void LastActiveWindow::setIsValid(bool valid)
0177 {
0178     if (m_isValid == valid) {
0179         return;
0180     }
0181 
0182     m_isValid = valid;
0183     emit isValidChanged();
0184 }
0185 
0186 bool LastActiveWindow::hasSkipTaskbar() const
0187 {
0188     return m_hasSkipTaskbar;
0189 }
0190 
0191 void LastActiveWindow::setHasSkipTaskbar(bool skip)
0192 {
0193     if (m_hasSkipTaskbar == skip) {
0194         return;
0195     }
0196 
0197     m_hasSkipTaskbar = skip;
0198     emit hasSkipTaskbarChanged();
0199 }
0200 
0201 //! BEGIN: Window Abitilities
0202 bool LastActiveWindow::isClosable() const
0203 {
0204     return m_isClosable;
0205 }
0206 
0207 void LastActiveWindow::setIsClosable(bool closable)
0208 {
0209     if (m_isClosable == closable) {
0210         return;
0211     }
0212 
0213     m_isClosable = closable;
0214     emit isClosableChanged();
0215 }
0216 
0217 bool LastActiveWindow::isFullScreenable() const
0218 {
0219     return m_isFullScreenable;
0220 }
0221 
0222 void LastActiveWindow::setIsFullScreenable(bool fullscreenable)
0223 {
0224     if (m_isFullScreenable == fullscreenable) {
0225         return;
0226     }
0227 
0228     m_isFullScreenable = fullscreenable;
0229     emit isFullScreenableChanged();
0230 }
0231 
0232 bool LastActiveWindow::isGroupable() const
0233 {
0234     return m_isGroupable;
0235 }
0236 
0237 void LastActiveWindow::setIsGroupable(bool groupable)
0238 {
0239     if (m_isGroupable == groupable) {
0240         return;
0241     }
0242 
0243     m_isGroupable = groupable;
0244     emit isGroupableChanged();
0245 }
0246 
0247 
0248 bool LastActiveWindow::isMaximizable() const
0249 {
0250     return m_isMaximizable;
0251 }
0252 
0253 void LastActiveWindow::setIsMaximizable(bool maximizable)
0254 {
0255     if (m_isMaximizable == maximizable) {
0256         return;
0257     }
0258 
0259     m_isMaximizable = maximizable;
0260     emit isMaximizableChanged();
0261 }
0262 
0263 bool LastActiveWindow::isMinimizable() const
0264 {
0265     return m_isMinimizable;
0266 }
0267 
0268 void LastActiveWindow::setIsMinimizable(bool minimizable)
0269 {
0270     if (m_isMinimizable == minimizable) {
0271         return;
0272     }
0273 
0274     m_isMinimizable = minimizable;
0275     emit isMinimizableChanged();
0276 }
0277 
0278 bool LastActiveWindow::isMovable() const
0279 {
0280     return m_isMovable;
0281 }
0282 
0283 void LastActiveWindow::setIsMovable(bool movable)
0284 {
0285     if (m_isMovable == movable) {
0286         return;
0287     }
0288 
0289     m_isMovable = movable;
0290     emit isMovableChanged();
0291 }
0292 
0293 bool LastActiveWindow::isResizable() const
0294 {
0295     return m_isResizable;
0296 }
0297 
0298 void LastActiveWindow::setIsResizable(bool resizable)
0299 {
0300     if (m_isResizable == resizable) {
0301         return;
0302     }
0303 
0304     m_isResizable = resizable;
0305     emit isResizableChanged();
0306 }
0307 
0308 bool LastActiveWindow::isShadeable() const
0309 {
0310     return m_isShadeable;
0311 }
0312 
0313 void LastActiveWindow::setIsShadeable(bool shadeable)
0314 {
0315     if (m_isShadeable == shadeable) {
0316         return;
0317     }
0318 
0319     m_isShadeable = shadeable;
0320     emit isShadeableChanged();
0321 }
0322 
0323 bool LastActiveWindow::isVirtualDesktopChangeable() const
0324 {
0325     return m_isVirtualDesktopsChangeable;
0326 }
0327 
0328 void LastActiveWindow::setIsVirtualDesktopsChangeable(bool virtualdestkopschangeable)
0329 {
0330     if (m_isVirtualDesktopsChangeable == virtualdestkopschangeable) {
0331         return;
0332     }
0333 
0334     m_isVirtualDesktopsChangeable = virtualdestkopschangeable;
0335     emit isVirtualDesktopChangeableChanged();
0336 }
0337 //! END: Window Abitilities
0338 
0339 
0340 QRect LastActiveWindow::geometry() const
0341 {
0342     return m_geometry;
0343 }
0344 
0345 void LastActiveWindow::setGeometry(QRect geometry)
0346 {
0347     if (m_geometry == geometry) {
0348         return;
0349     }
0350 
0351     m_geometry = geometry;
0352     emit geometryChanged();
0353 }
0354 
0355 QString LastActiveWindow::appName() const
0356 {
0357     return m_appName;
0358 }
0359 
0360 void LastActiveWindow::setAppName(QString appName)
0361 {
0362     if (m_appName == appName) {
0363         return;
0364     }
0365 
0366     m_appName = appName;
0367     emit appNameChanged();
0368 }
0369 
0370 QString LastActiveWindow::colorScheme() const
0371 {
0372     return m_colorScheme;
0373 }
0374 
0375 void LastActiveWindow::setColorScheme(QString scheme)
0376 {
0377     if (m_colorScheme == scheme){
0378         return;
0379     }
0380 
0381     m_colorScheme = scheme;
0382     emit colorSchemeChanged();
0383 }
0384 
0385 QString LastActiveWindow::display() const
0386 {
0387     return m_display;
0388 }
0389 
0390 void LastActiveWindow::setDisplay(QString display)
0391 {
0392     if (m_display == display) {
0393         return;
0394     }
0395 
0396     m_display = display;
0397     emit displayChanged();
0398 }
0399 
0400 QIcon LastActiveWindow::icon() const
0401 {
0402     return m_icon;
0403 }
0404 
0405 void LastActiveWindow::setIcon(QIcon icon)
0406 {
0407     m_icon = icon;
0408     emit iconChanged();
0409 }
0410 
0411 QVariant LastActiveWindow::winId() const
0412 {
0413     return m_winId;
0414 }
0415 
0416 void LastActiveWindow::setWinId(QVariant winId)
0417 {
0418     if (m_winId == winId && isValid()) {
0419         return;
0420     }
0421 
0422     if (!m_history.contains(winId)) {
0423         m_history.prepend(winId);
0424         cleanHistory();
0425     } else {
0426         int p = m_history.indexOf(winId);
0427         //! move to start
0428         m_history.move(p, 0);
0429     }
0430 
0431     m_winId = winId;
0432     emit winIdChanged();
0433 }
0434 
0435 void LastActiveWindow::setInformation(const WindowInfoWrap &info)
0436 {
0437     bool firstActiveness{false};
0438 
0439     if (m_winId != info.wid()) {
0440         firstActiveness = true;
0441     }
0442 
0443     setWinId(info.wid());
0444 
0445     setIsValid(true);
0446     setActive(info.isActive());
0447     setIsMinimized(info.isMinimized());
0448     setIsMaximized(info.isMaximized());
0449     setIsOnAllDesktops(info.isOnAllDesktops());
0450 
0451     //! Window Abilities
0452     setIsClosable(info.isCloseable());
0453     setIsFullScreenable(info.isFullScreenable());
0454     setIsGroupable(info.isGroupable());
0455     setIsMaximizable(info.isMaximizable());
0456     setIsMinimizable(info.isMinimizable());
0457     setIsMovable(info.isMovable());
0458     setIsResizable(info.isResizable());
0459     setIsShadeable(info.isShadeable());
0460     setIsVirtualDesktopsChangeable(info.isVirtualDesktopsChangeable());
0461     //! Window Abilities
0462 
0463     setAppName(info.appName());
0464     setDisplay(info.display());
0465     setGeometry(info.geometry());
0466     setIsKeepAbove(info.isKeepAbove());
0467 
0468     if (firstActiveness) {
0469         updateColorScheme();
0470     }
0471 
0472     if (info.appName().isEmpty()) {
0473         setAppName(m_windowsTracker->appNameFor(info.wid()));
0474     } else {
0475         setAppName(info.appName());
0476     }
0477 
0478     if (info.icon().isNull()) {
0479         setIcon(m_windowsTracker->iconFor(info.wid()));
0480     } else {
0481         setIcon(info.icon());
0482     }
0483 }
0484 
0485 //! PRIVATE SLOTS
0486 void LastActiveWindow::applicationDataChanged(const WindowId &wid)
0487 {
0488     if (m_winId == wid) {
0489         setAppName(m_windowsTracker->appNameFor(wid));
0490         setIcon(m_windowsTracker->iconFor(wid));
0491     }
0492 }
0493 
0494 
0495 void LastActiveWindow::windowChanged(const WindowId &wid)
0496 {
0497     if (!m_trackedInfo->enabled()) {
0498         // qDebug() << " Last Active Window, Window Changed : TrackedInfo is disabled...";
0499         return;
0500     }
0501 
0502     if (m_history.contains(wid)) {
0503         //! remove from history minimized windows or windows that changed screen
0504         //! and update information accordingly with the first valid window found from
0505         //! history after the removal
0506         WindowInfoWrap winfo = m_windowsTracker->infoFor(wid);
0507 
0508         bool firstItemRemoved{false};
0509 
0510         //! Remove minimized windows OR NOT-TRACKED windows from history
0511         if (winfo.isMinimized() || !m_trackedInfo->isTracking(winfo)) {
0512             if (m_history[0] == wid) {
0513                 firstItemRemoved = true;
0514             }
0515 
0516             m_history.removeAll(wid);
0517             cleanHistory();
0518         }
0519 
0520         if (m_history.count() > 0) {
0521             if (m_history[0] == wid || firstItemRemoved) {
0522                 WindowInfoWrap history1 = m_windowsTracker->infoFor(m_history[0]);
0523 
0524                 //! Check if first found History window is still valid to show its information
0525                 if (history1.isMinimized() || !m_trackedInfo->isTracking(history1)) {
0526                     windowChanged(m_history[0]);
0527                 } else {
0528                     setInformation(history1);
0529                 }
0530             }
0531         } else {
0532             //! History is empty so any demonstrated information are invalid
0533             setIsValid(false);
0534         }
0535 
0536         //qDebug() << " HISTORY ::: " << m_history;
0537     } else {
0538         //qDebug() << " LastActiveWindow : window is not in history";
0539     }
0540 }
0541 
0542 void LastActiveWindow::windowRemoved(const WindowId &wid)
0543 {
0544     if (m_history.contains(wid)) {
0545         bool firstItemRemoved{false};
0546 
0547         if (m_history.count() > 0 && m_history[0] == wid) {
0548             firstItemRemoved = true;
0549         }
0550 
0551         m_history.removeAll(wid);
0552         m_history.removeAll(wid);
0553 
0554         if (m_history.count() > 0 && firstItemRemoved) {
0555             windowChanged(m_history[0]);
0556         } else {
0557             setIsValid(false);
0558         }
0559     }
0560 }
0561 
0562 void LastActiveWindow::cleanHistory()
0563 {
0564     if (m_history.count() > MAXHISTORY) {
0565         int size = m_history.count();
0566         for(int i=0; i<(size-PREFHISTORY); ++i) {
0567             if (!m_history.isEmpty()) {
0568                 m_history.removeLast();
0569             }
0570         }
0571     }
0572 }
0573 
0574 void LastActiveWindow::updateColorScheme()
0575 {
0576     auto scheme = m_wm->schemesTracker()->schemeForWindow(m_winId);
0577     if (scheme) {
0578         setColorScheme(scheme->schemeFile());
0579     }
0580 }
0581 
0582 
0583 //! FUNCTIONALITY
0584 void LastActiveWindow::requestActivate()
0585 {
0586     m_wm->requestActivate(m_winId);
0587 }
0588 
0589 void LastActiveWindow::requestClose()
0590 {
0591     m_wm->requestClose(m_winId);
0592 }
0593 
0594 void LastActiveWindow::requestMove(Latte::View *fromView, int localX, int localY)
0595 {
0596     if (!fromView || !canBeDragged()) {
0597         return;
0598     }
0599 
0600     QPoint globalPoint{fromView->x() + localX, fromView->y() + localY};
0601     m_wm->requestMoveWindow(m_winId, globalPoint);
0602 
0603     fromView->unblockMouse(localX, localY);
0604 }
0605 
0606 void LastActiveWindow::requestToggleIsOnAllDesktops()
0607 {
0608     m_wm->requestToggleIsOnAllDesktops(m_winId);
0609 }
0610 
0611 void LastActiveWindow::requestToggleKeepAbove()
0612 {
0613     m_wm->requestToggleKeepAbove(m_winId);
0614 }
0615 
0616 void LastActiveWindow::requestToggleMinimized()
0617 {
0618     m_wm->requestToggleMinimized(m_winId);
0619 }
0620 
0621 void LastActiveWindow::requestToggleMaximized()
0622 {
0623     m_wm->requestToggleMaximized(m_winId);
0624 }
0625 
0626 bool LastActiveWindow::canBeDragged()
0627 {
0628     return m_wm->windowCanBeDragged(m_winId);
0629 }
0630 
0631 }
0632 }
0633 }