File indexing completed on 2024-06-02 05:24:51

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     utils/systemtrayicon.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2007, 2009 Klarälvdalens Datakonsult AB
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-kleopatra.h>
0011 
0012 #include "systemtrayicon.h"
0013 
0014 #ifndef QT_NO_SYSTEMTRAYICON
0015 
0016 #include "kleopatra_debug.h"
0017 #include <QEvent>
0018 #include <QPointer>
0019 #include <QTimer>
0020 #include <QWidget>
0021 
0022 using namespace Kleo;
0023 
0024 static const int ATTENTION_ANIMATION_FRAMES_PER_SEC = 1;
0025 
0026 class SystemTrayIcon::Private
0027 {
0028     friend class ::SystemTrayIcon;
0029     SystemTrayIcon *const q;
0030 
0031 public:
0032     explicit Private(SystemTrayIcon *qq);
0033     ~Private();
0034 
0035 private:
0036     bool attentionWanted() const
0037     {
0038         return attentionAnimationTimer.isActive();
0039     }
0040 
0041     void setAttentionWantedImpl(bool on)
0042     {
0043         if (on) {
0044             attentionAnimationTimer.start();
0045         } else {
0046             attentionAnimationTimer.stop();
0047             attentionIconShown = false;
0048             q->setIcon(normalIcon);
0049         }
0050     }
0051 
0052     void slotActivated(ActivationReason reason)
0053     {
0054         if (reason == QSystemTrayIcon::Trigger) {
0055             q->doActivated();
0056         }
0057     }
0058 
0059     void slotAttentionAnimationTimerTimout()
0060     {
0061         if (attentionIconShown) {
0062             attentionIconShown = false;
0063             q->setIcon(normalIcon);
0064         } else {
0065             attentionIconShown = true;
0066             q->setIcon(attentionIcon);
0067         }
0068     }
0069 
0070 private:
0071     bool attentionIconShown;
0072 
0073     QIcon normalIcon, attentionIcon;
0074 
0075     QTimer attentionAnimationTimer;
0076 
0077     QPointer<QWidget> mainWindow;
0078     QPointer<QWidget> attentionWindow;
0079 };
0080 
0081 SystemTrayIcon::Private::Private(SystemTrayIcon *qq)
0082     : q(qq)
0083     , attentionIconShown(false)
0084     , attentionAnimationTimer()
0085     , mainWindow()
0086     , attentionWindow()
0087 {
0088     KDAB_SET_OBJECT_NAME(attentionAnimationTimer);
0089 
0090     attentionAnimationTimer.setSingleShot(false);
0091     attentionAnimationTimer.setInterval(1000 * ATTENTION_ANIMATION_FRAMES_PER_SEC / 2);
0092 
0093     connect(q, &QSystemTrayIcon::activated, q, [this](QSystemTrayIcon::ActivationReason reason) {
0094         slotActivated(reason);
0095     });
0096     connect(&attentionAnimationTimer, &QTimer::timeout, q, [this]() {
0097         slotAttentionAnimationTimerTimout();
0098     });
0099 }
0100 
0101 SystemTrayIcon::Private::~Private()
0102 {
0103 }
0104 
0105 SystemTrayIcon::SystemTrayIcon(QObject *p)
0106     : QSystemTrayIcon(p)
0107     , d(new Private(this))
0108 {
0109 }
0110 
0111 SystemTrayIcon::SystemTrayIcon(const QIcon &icon, QObject *p)
0112     : QSystemTrayIcon(icon, p)
0113     , d(new Private(this))
0114 {
0115     d->normalIcon = d->attentionIcon = icon;
0116 }
0117 
0118 SystemTrayIcon::~SystemTrayIcon()
0119 {
0120 }
0121 
0122 void SystemTrayIcon::setMainWindow(QWidget *mw)
0123 {
0124     if (d->mainWindow) {
0125         return;
0126     }
0127     d->mainWindow = mw;
0128     if (mw) {
0129         mw->installEventFilter(this);
0130     }
0131     doMainWindowSet(mw);
0132     slotEnableDisableActions();
0133 }
0134 
0135 QWidget *SystemTrayIcon::mainWindow() const
0136 {
0137     return d->mainWindow;
0138 }
0139 
0140 void SystemTrayIcon::setAttentionWindow(QWidget *mw)
0141 {
0142     if (d->attentionWindow) {
0143         return;
0144     }
0145     d->attentionWindow = mw;
0146     if (mw) {
0147         mw->installEventFilter(this);
0148     }
0149     slotEnableDisableActions();
0150 }
0151 
0152 QWidget *SystemTrayIcon::attentionWindow() const
0153 {
0154     return d->attentionWindow;
0155 }
0156 
0157 bool SystemTrayIcon::eventFilter(QObject *o, QEvent *e)
0158 {
0159     if (o == d->mainWindow)
0160         switch (e->type()) {
0161         case QEvent::Close:
0162             doMainWindowClosed(static_cast<QWidget *>(o));
0163             // fall through:
0164             [[fallthrough]];
0165         case QEvent::Show:
0166         case QEvent::DeferredDelete:
0167             QMetaObject::invokeMethod(this, "slotEnableDisableActions", Qt::QueuedConnection);
0168         default:;
0169         }
0170     else if (o == d->attentionWindow)
0171         switch (e->type()) {
0172         case QEvent::Close:
0173             doAttentionWindowClosed(static_cast<QWidget *>(o));
0174             // fall through:
0175             [[fallthrough]];
0176         case QEvent::Show:
0177         case QEvent::DeferredDelete:
0178             QMetaObject::invokeMethod(this, "slotEnableDisableActions", Qt::QueuedConnection);
0179         default:;
0180         }
0181     return false;
0182 }
0183 
0184 void SystemTrayIcon::setAttentionWanted(bool on)
0185 {
0186     if (d->attentionWanted() == on) {
0187         return;
0188     }
0189     qCDebug(KLEOPATRA_LOG) << d->attentionWanted() << "->" << on;
0190     d->setAttentionWantedImpl(on);
0191 }
0192 
0193 bool SystemTrayIcon::attentionWanted() const
0194 {
0195     return d->attentionWanted();
0196 }
0197 
0198 void SystemTrayIcon::setNormalIcon(const QIcon &icon)
0199 {
0200     if (d->normalIcon.cacheKey() == icon.cacheKey()) {
0201         return;
0202     }
0203     d->normalIcon = icon;
0204     if (!d->attentionWanted() || !d->attentionIconShown) {
0205         setIcon(icon);
0206     }
0207 }
0208 
0209 QIcon SystemTrayIcon::normalIcon() const
0210 {
0211     return d->normalIcon;
0212 }
0213 
0214 void SystemTrayIcon::setAttentionIcon(const QIcon &icon)
0215 {
0216     if (d->attentionIcon.cacheKey() == icon.cacheKey()) {
0217         return;
0218     }
0219     d->attentionIcon = icon;
0220     if (d->attentionWanted() && d->attentionIconShown) {
0221         setIcon(icon);
0222     }
0223 }
0224 
0225 QIcon SystemTrayIcon::attentionIcon() const
0226 {
0227     return d->attentionIcon;
0228 }
0229 
0230 void SystemTrayIcon::doMainWindowSet(QWidget *)
0231 {
0232 }
0233 void SystemTrayIcon::doMainWindowClosed(QWidget *)
0234 {
0235 }
0236 void SystemTrayIcon::doAttentionWindowClosed(QWidget *)
0237 {
0238 }
0239 
0240 #include "moc_systemtrayicon.cpp"
0241 
0242 #endif // QT_NO_SYSTEMTRAYICON