File indexing completed on 2024-07-21 13:09:48

0001 /*
0002 *  Copyright 2016  Smith AR <audoban@openmailbox.org>
0003 *                  Michail Vourlakos <mvourlakos@gmail.com>
0004 *
0005 *  This file is part of Latte-Dock
0006 *
0007 *  Latte-Dock is free software; you can redistribute it and/or
0008 *  modify it under the terms of the GNU General Public License as
0009 *  published by the Free Software Foundation; either version 2 of
0010 *  the License, or (at your option) any later version.
0011 *
0012 *  Latte-Dock is distributed in the hope that it will be useful,
0013 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015 *  GNU General Public License for more details.
0016 *
0017 *  You should have received a copy of the GNU General Public License
0018 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include "abstractwindowinterface.h"
0022 
0023 // local
0024 #include "tracker/schemes.h"
0025 #include "tracker/windowstracker.h"
0026 #include "../lattecorona.h"
0027 
0028 // Qt
0029 #include <QDebug>
0030 
0031 // KDE
0032 #include <KActivities/Controller>
0033 
0034 namespace Latte {
0035 namespace WindowSystem {
0036 
0037 #define MAXPLASMAPANELTHICKNESS 96
0038 
0039 AbstractWindowInterface::AbstractWindowInterface(QObject *parent)
0040     : QObject(parent)
0041 {
0042     m_activities = new KActivities::Consumer(this);
0043     m_currentActivity = m_activities->currentActivity();
0044 
0045     m_corona = qobject_cast<Latte::Corona *>(parent);
0046     m_windowsTracker = new Tracker::Windows(this);
0047     m_schemesTracker = new Tracker::Schemes(this);
0048 
0049     rulesConfig = KSharedConfig::openConfig(QStringLiteral("taskmanagerrulesrc"));
0050 
0051     m_windowWaitingTimer.setInterval(150);
0052     m_windowWaitingTimer.setSingleShot(true);
0053 
0054     connect(&m_windowWaitingTimer, &QTimer::timeout, this, [&]() {
0055         WindowId wid = m_windowChangedWaiting;
0056         m_windowChangedWaiting = QVariant();
0057         emit windowChanged(wid);
0058     });
0059 
0060     connect(this, &AbstractWindowInterface::windowRemoved, this, &AbstractWindowInterface::windowRemovedSlot);
0061 
0062     // connect(this, &AbstractWindowInterface::windowChanged, this, [&](WindowId wid) {
0063     //     qDebug() << "WINDOW CHANGED ::: " << wid;
0064     // });
0065 
0066     connect(m_activities.data(), &KActivities::Consumer::currentActivityChanged, this, [&](const QString &id) {
0067         m_currentActivity = id;
0068         emit currentActivityChanged();
0069     });
0070 
0071 }
0072 
0073 AbstractWindowInterface::~AbstractWindowInterface()
0074 {
0075     m_windowWaitingTimer.stop();
0076 
0077     m_schemesTracker->deleteLater();
0078     m_windowsTracker->deleteLater();
0079 }
0080 
0081 QString AbstractWindowInterface::currentDesktop() const
0082 {
0083     return m_currentDesktop;
0084 }
0085 
0086 QString AbstractWindowInterface::currentActivity() const
0087 {
0088     return m_currentActivity;
0089 }
0090 
0091 Latte::Corona *AbstractWindowInterface::corona()
0092 {
0093     return m_corona;
0094 }
0095 
0096 Tracker::Schemes *AbstractWindowInterface::schemesTracker()
0097 {
0098     return m_schemesTracker;
0099 }
0100 
0101 Tracker::Windows *AbstractWindowInterface::windowsTracker() const
0102 {
0103     return m_windowsTracker;
0104 }
0105 
0106 bool AbstractWindowInterface::isIgnored(const WindowId &wid)
0107 {
0108     return m_ignoredWindows.contains(wid);
0109 }
0110 
0111 bool AbstractWindowInterface::isPlasmaDesktop(const QRect &wGeometry) const
0112 {
0113     if (wGeometry.isEmpty()) {
0114         return false;
0115     }
0116 
0117     for (const auto scr : qGuiApp->screens()) {
0118         if (wGeometry == scr->geometry()) {
0119             return true;
0120         }
0121     }
0122 
0123     return false;
0124 }
0125 
0126 bool AbstractWindowInterface::isPlasmaPanel(const QRect &wGeometry) const
0127 {     
0128     if (wGeometry.isEmpty()) {
0129         return false;
0130     }
0131 
0132     bool isTouchingHorizontalEdge{false};
0133     bool isTouchingVerticalEdge{false};
0134 
0135     for (const auto scr : qGuiApp->screens()) {
0136         if (scr->geometry().contains(wGeometry.center())) {
0137             if (wGeometry.y() == scr->geometry().y() || wGeometry.bottom() == scr->geometry().bottom()) {
0138                 isTouchingHorizontalEdge = true;
0139             }
0140 
0141             if (wGeometry.left() == scr->geometry().left() || wGeometry.right() == scr->geometry().right()) {
0142                 isTouchingVerticalEdge = true;
0143             }
0144 
0145             if (isTouchingVerticalEdge && isTouchingHorizontalEdge) {
0146                 break;
0147             }
0148         }
0149     }
0150 
0151     if ((isTouchingHorizontalEdge && wGeometry.height() < MAXPLASMAPANELTHICKNESS)
0152             || (isTouchingVerticalEdge && wGeometry.width() < MAXPLASMAPANELTHICKNESS)) {
0153         return true;
0154     }
0155 
0156     return false;
0157 }
0158 
0159 bool AbstractWindowInterface::isRegisteredPlasmaPanel(const WindowId &wid)
0160 {
0161     return m_plasmaPanels.contains(wid);
0162 }
0163 
0164 bool AbstractWindowInterface::inCurrentDesktopActivity(const WindowInfoWrap &winfo) const
0165 {
0166     return (winfo.isValid() && winfo.isOnDesktop(currentDesktop()) && winfo.isOnActivity(currentActivity()));
0167 }
0168 
0169 //! Register Latte Ignored Windows in order to NOT be tracked
0170 void AbstractWindowInterface::registerIgnoredWindow(WindowId wid)
0171 {
0172     if (!wid.isNull() && !m_ignoredWindows.contains(wid)) {
0173         m_ignoredWindows.append(wid);
0174         emit windowChanged(wid);
0175     }
0176 }
0177 
0178 void AbstractWindowInterface::unregisterIgnoredWindow(WindowId wid)
0179 {
0180     if (m_ignoredWindows.contains(wid)) {
0181         m_ignoredWindows.removeAll(wid);
0182         emit windowRemoved(wid);
0183     }
0184 }
0185 
0186 void AbstractWindowInterface::registerPlasmaPanel(WindowId wid)
0187 {
0188     if (!wid.isNull() && !m_plasmaPanels.contains(wid)) {
0189         m_plasmaPanels.append(wid);
0190         emit windowChanged(wid);
0191     }
0192 }
0193 
0194 void AbstractWindowInterface::unregisterPlasmaPanel(WindowId wid)
0195 {
0196     if (m_plasmaPanels.contains(wid)) {
0197         m_plasmaPanels.removeAll(wid);
0198     }
0199 }
0200 
0201 void AbstractWindowInterface::windowRemovedSlot(WindowId wid)
0202 {
0203     if (m_plasmaPanels.contains(wid)) {
0204         unregisterPlasmaPanel(wid);
0205     }
0206 }
0207 
0208 //! Activities switching
0209 void AbstractWindowInterface::switchToNextActivity()
0210 {
0211     QStringList runningActivities = m_activities->activities(KActivities::Info::State::Running);
0212     if (runningActivities.count() <= 1) {
0213         return;
0214     }
0215 
0216     int curPos = runningActivities.indexOf(m_currentActivity);
0217     int nextPos = curPos + 1;
0218 
0219     if (curPos == runningActivities.count() -1) {
0220         nextPos = 0;
0221     }
0222 
0223     KActivities::Controller activitiesController;
0224     activitiesController.setCurrentActivity(runningActivities.at(nextPos));
0225 }
0226 
0227 void AbstractWindowInterface::switchToPreviousActivity()
0228 {
0229     QStringList runningActivities = m_activities->activities(KActivities::Info::State::Running);
0230     if (runningActivities.count() <= 1) {
0231         return;
0232     }
0233 
0234     int curPos = runningActivities.indexOf(m_currentActivity);
0235     int nextPos = curPos - 1;
0236 
0237     if (curPos == 0) {
0238         nextPos = runningActivities.count() - 1;
0239     }
0240 
0241     KActivities::Controller activitiesController;
0242     activitiesController.setCurrentActivity(runningActivities.at(nextPos));
0243 }
0244 
0245 //! Delay window changed trigerring
0246 void AbstractWindowInterface::considerWindowChanged(WindowId wid)
0247 {
0248     //! Consider if the windowChanged signal should be sent DIRECTLY or WAIT
0249 
0250     if (m_windowChangedWaiting == wid && m_windowWaitingTimer.isActive()) {
0251         //! window should be sent later
0252         m_windowWaitingTimer.start();
0253         return;
0254     }
0255 
0256     if (m_windowChangedWaiting != wid && !m_windowWaitingTimer.isActive()) {
0257         //! window should be sent later
0258         m_windowChangedWaiting = wid;
0259         m_windowWaitingTimer.start();
0260     }
0261 
0262     if (m_windowChangedWaiting != wid && m_windowWaitingTimer.isActive()) {
0263         m_windowWaitingTimer.stop();
0264         //! sent previous waiting window
0265         emit windowChanged(m_windowChangedWaiting);
0266 
0267         //! retrigger waiting for the upcoming window
0268         m_windowChangedWaiting = wid;
0269         m_windowWaitingTimer.start();
0270     }
0271 }
0272 
0273 }
0274 }
0275