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