File indexing completed on 2024-05-05 05:34:05

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