qtui: Refactor the system tray implementations
authorManuel Nickschas <sputnick@quassel-irc.org>
Wed, 13 Jun 2018 21:47:52 +0000 (23:47 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Fri, 15 Jun 2018 23:30:32 +0000 (01:30 +0200)
Replace the mess of virtual methods and init() and other weird
shenanigans by a cleaner architecture. Handle mode/state changes
in the base class and let the implementations explicitly act on
changes. This should make it much clearer how the implementations
behave if mode or state change.

Simplify the D-Bus parts of StatusNotifierItem quite a bit by
keeping the SNI watcher always alive; no need to kill it when
unregistering. Add error handling to the final D-Bus registration
call and fall back to the legacy icon if something went wrong.

src/qtui/legacysystemtray.cpp
src/qtui/legacysystemtray.h
src/qtui/mainwin.cpp
src/qtui/statusnotifieritem.cpp
src/qtui/statusnotifieritem.h
src/qtui/systemtray.cpp
src/qtui/systemtray.h

index da27d23..8e7d2b7 100644 (file)
@@ -20,6 +20,8 @@
 
 #ifndef QT_NO_SYSTEMTRAYICON
 
+#include <QIcon>
+
 #include "legacysystemtray.h"
 #include "mainwin.h"
 #include "qtui.h"
@@ -39,103 +41,64 @@ LegacySystemTray::LegacySystemTray(QWidget *parent)
 #endif
 #ifndef Q_OS_MAC
     connect(_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
-        SLOT(on_activated(QSystemTrayIcon::ActivationReason)));
+        SLOT(onActivated(QSystemTrayIcon::ActivationReason)));
 #endif
     connect(_trayIcon, SIGNAL(messageClicked()),
-        SLOT(on_messageClicked()));
-
-    _blinkTimer.setInterval(500);
-    _blinkTimer.setSingleShot(false);
-    connect(&_blinkTimer, SIGNAL(timeout()), SLOT(on_blinkTimeout()));
-
-    connect(this, SIGNAL(toolTipChanged(QString, QString)), SLOT(syncLegacyIcon()));
-}
-
-
-void LegacySystemTray::init()
-{
-    if (mode() == Invalid) // derived class hasn't set a mode itself
-        setMode(Legacy);
-
-    SystemTray::init();
+        SLOT(onMessageClicked()));
 
     _trayIcon->setContextMenu(trayMenu());
-}
+    _trayIcon->setVisible(false);
 
+    setMode(Mode::Legacy);
 
-void LegacySystemTray::syncLegacyIcon()
-{
-    updateIcon();
+    connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(onVisibilityChanged(bool)));
+    connect(this, SIGNAL(modeChanged(Mode)), this, SLOT(onModeChanged(Mode)));
+    connect(this, SIGNAL(stateChanged(State)), this, SLOT(onStateChanged(State)));
+    connect(this, SIGNAL(toolTipChanged(QString, QString)), SLOT(updateToolTip()));
 
-#if defined Q_OS_MAC || defined Q_OS_WIN
-    QString tooltip = QString("%1").arg(toolTipTitle());
-    if (!toolTipSubTitle().isEmpty())
-        tooltip += QString("\n%1").arg(toolTipSubTitle());
-#else
-    QString tooltip = QString("<b>%1</b>").arg(toolTipTitle());
-    if (!toolTipSubTitle().isEmpty())
-        tooltip += QString("<br>%1").arg(toolTipSubTitle());
-#endif
+    _blinkTimer.setInterval(750);
+    _blinkTimer.setSingleShot(false);
+    connect(&_blinkTimer, SIGNAL(timeout()), SLOT(onBlinkTimeout()));
 
-    _trayIcon->setToolTip(tooltip);
+    updateIcon();
+    updateToolTip();
 }
 
 
-void LegacySystemTray::setVisible(bool visible)
+bool LegacySystemTray::isSystemTrayAvailable() const
 {
-    SystemTray::setVisible(visible);
-    if (mode() == Legacy) {
-        if (shouldBeVisible())
-            _trayIcon->show();
-        else
-            _trayIcon->hide();
-    }
+    return mode() == Mode::Legacy
+            ? QSystemTrayIcon::isSystemTrayAvailable()
+            : SystemTray::isSystemTrayAvailable();
 }
 
 
-bool LegacySystemTray::isVisible() const
+void LegacySystemTray::onVisibilityChanged(bool isVisible)
 {
     if (mode() == Legacy) {
-        return _trayIcon->isVisible();
+        _trayIcon->setVisible(isVisible);
     }
-    return SystemTray::isVisible();
 }
 
 
-void LegacySystemTray::setMode(Mode mode_)
+void LegacySystemTray::onModeChanged(Mode mode)
 {
-    if (mode_ == mode())
-        return;
-
-    SystemTray::setMode(mode_);
-
-    if (mode() == Legacy) {
-        syncLegacyIcon();
-        if (shouldBeVisible())
-            _trayIcon->show();
-        else
-            _trayIcon->hide();
-        if (state() == NeedsAttention)
-            _blinkTimer.start();
+    if (mode == Mode::Legacy) {
+        _trayIcon->setVisible(isVisible());
     }
     else {
         _trayIcon->hide();
-        _blinkTimer.stop();
     }
 }
 
 
-void LegacySystemTray::setState(State state_)
+void LegacySystemTray::onStateChanged(State state)
 {
-    State oldstate = state();
-    SystemTray::setState(state_);
-    if (oldstate != state()) {
-        if (state() == NeedsAttention && mode() == Legacy && animationEnabled())
-            _blinkTimer.start();
-        else {
-            _blinkTimer.stop();
-            _blinkState = false;
-        }
+    if (state == NeedsAttention && animationEnabled())
+        _blinkTimer.start();
+    else {
+        _blinkTimer.stop();
+        _blinkState = false;
     }
     updateIcon();
 }
@@ -154,20 +117,36 @@ void LegacySystemTray::updateIcon()
 }
 
 
-void LegacySystemTray::on_blinkTimeout()
+void LegacySystemTray::updateToolTip()
+{
+#if defined Q_OS_MAC || defined Q_OS_WIN
+    QString tooltip = QString("%1").arg(toolTipTitle());
+    if (!toolTipSubTitle().isEmpty())
+        tooltip += QString("\n%1").arg(toolTipSubTitle());
+#else
+    QString tooltip = QString("<b>%1</b>").arg(toolTipTitle());
+    if (!toolTipSubTitle().isEmpty())
+        tooltip += QString("<br>%1").arg(toolTipSubTitle());
+#endif
+
+    _trayIcon->setToolTip(tooltip);
+}
+
+
+void LegacySystemTray::onBlinkTimeout()
 {
     _blinkState = !_blinkState;
     updateIcon();
 }
 
 
-void LegacySystemTray::on_activated(QSystemTrayIcon::ActivationReason reason)
+void LegacySystemTray::onActivated(QSystemTrayIcon::ActivationReason reason)
 {
     activate((SystemTray::ActivationReason)reason);
 }
 
 
-void LegacySystemTray::on_messageClicked()
+void LegacySystemTray::onMessageClicked()
 {
     emit messageClicked(_lastMessageId);
 }
index c4af3df..15134b1 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef LEGACYSYSTEMTRAY_H_
-#define LEGACYSYSTEMTRAY_H_
+#pragma once
 
 #ifndef QT_NO_SYSTEMTRAYICON
 
+#include <QString>
+
 #ifdef HAVE_KDE4
 #  include <KSystemTrayIcon>
 #else
@@ -39,32 +40,24 @@ class LegacySystemTray : public SystemTray
 
 public:
     explicit LegacySystemTray(QWidget *parent);
-    virtual ~LegacySystemTray() {}
-    virtual void init();
 
-    virtual bool isVisible() const;
-    virtual inline bool isSystemTrayAvailable() const;
+    bool isSystemTrayAvailable() const override;
 
 public slots:
-    virtual void setState(State state);
-    virtual void setVisible(bool visible = true);
-    virtual void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int msTimeout = 10000, uint notificationId = 0);
-    virtual void closeMessage(uint notificationId);
+    void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int msTimeout = 10000, uint notificationId = 0) override;
+    void closeMessage(uint notificationId) override;
 
-protected slots:
+private slots:
+    void onModeChanged(Mode mode);
+    void onStateChanged(State state);
+    void onVisibilityChanged(bool isVisible);
 
-protected:
-    virtual void setMode(Mode mode);
+    void onBlinkTimeout();
+    void onActivated(QSystemTrayIcon::ActivationReason);
+    void onMessageClicked();
 
-private:
     void updateIcon();
-
-private slots:
-    void on_blinkTimeout();
-    void on_activated(QSystemTrayIcon::ActivationReason);
-    void on_messageClicked();
-
-    void syncLegacyIcon();
+    void updateToolTip();
 
 private:
     QTimer _blinkTimer;
@@ -81,13 +74,7 @@ private:
 
 // inlines
 
-bool LegacySystemTray::isSystemTrayAvailable() const
-{
-    return mode() == Legacy ? QSystemTrayIcon::isSystemTrayAvailable()
-           : SystemTray::isSystemTrayAvailable();
-}
 
 
-#endif /* QT_NO_SYSTEMTRAYICON */
 
-#endif /* LEGACYSYSTEMTRAY_H_ */
+#endif /* QT_NO_SYSTEMTRAYICON */
index 39b1f38..07c47a4 100644 (file)
@@ -1149,7 +1149,6 @@ void MainWin::setupSystray()
 #else
     _systemTray = new SystemTray(this); // dummy
 #endif
-    _systemTray->init();
 }
 
 
index dc33b97..f3b462b 100644 (file)
 #include "statusnotifieritem.h"
 #include "statusnotifieritemdbus.h"
 
-const int StatusNotifierItem::_protocolVersion = 0;
-const QString StatusNotifierItem::_statusNotifierWatcherServiceName("org.kde.StatusNotifierWatcher");
+constexpr int kProtocolVersion {0};
+
+const QString kSniWatcherService       {QLatin1String{"org.kde.StatusNotifierWatcher"}};
+const QString kSniWatcherPath          {QLatin1String{"/StatusNotifierWatcher"}};
+const QString kSniPath                 {QLatin1String{"/StatusNotifierItem"}};
+const QString kXdgNotificationsService {QLatin1String{"org.freedesktop.Notifications"}};
+const QString kXdgNotificationsPath    {QLatin1String{"/org/freedesktop/Notifications"}};
+const QString kMenuObjectPath          {QLatin1String{"/MenuBar"}};
 
 #ifdef HAVE_DBUSMENU
 #  include "dbusmenuexporter.h"
@@ -67,6 +73,22 @@ StatusNotifierItem::StatusNotifierItem(QWidget *parent)
     , _iconThemeDir{QDir::tempPath() + QLatin1String{"/quassel-sni-XXXXXX"}}
 #endif
 {
+    static bool registered = []() -> bool {
+        qDBusRegisterMetaType<DBusImageStruct>();
+        qDBusRegisterMetaType<DBusImageVector>();
+        qDBusRegisterMetaType<DBusToolTipStruct>();
+        return true;
+    }();
+    Q_UNUSED(registered)
+
+    setMode(Mode::StatusNotifier);
+
+    connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(onVisibilityChanged(bool)));
+    connect(this, SIGNAL(modeChanged(Mode)), this, SLOT(onModeChanged(Mode)));
+    connect(this, SIGNAL(stateChanged(State)), this, SLOT(onStateChanged(State)));
+
+    trayMenu()->installEventFilter(this);
+
     // Create a temporary directory that holds copies of the tray icons. That way, visualizers can find our icons.
     // For Qt4 the relevant icons are installed in hicolor already, so nothing to be done.
 #if QT_VERSION >= 0x050000
@@ -74,44 +96,38 @@ StatusNotifierItem::StatusNotifierItem(QWidget *parent)
         _iconThemePath = _iconThemeDir.path();
     }
     else {
-        qWarning() << StatusNotifierItem::tr("Could not create temporary directory for themed tray icons: %1").arg(_iconThemeDir.errorString());
+        qWarning() << "Could not create temporary directory for themed tray icons!";
     }
 #endif
 
     connect(QtUi::instance(), SIGNAL(iconThemeRefreshed()), this, SLOT(refreshIcons()));
-}
-
-
-StatusNotifierItem::~StatusNotifierItem()
-{
-    delete _statusNotifierWatcher;
-}
-
-
-void StatusNotifierItem::init()
-{
-    qDBusRegisterMetaType<DBusImageStruct>();
-    qDBusRegisterMetaType<DBusImageVector>();
-    qDBusRegisterMetaType<DBusToolTipStruct>();
-
     refreshIcons();
 
+    // Our own SNI service
     _statusNotifierItemDBus = new StatusNotifierItemDBus(this);
-
     connect(this, SIGNAL(toolTipChanged(QString, QString)), _statusNotifierItemDBus, SIGNAL(NewToolTip()));
     connect(this, SIGNAL(animationEnabledChanged(bool)), _statusNotifierItemDBus, SIGNAL(NewAttentionIcon()));
 
-    QDBusServiceWatcher *watcher = new QDBusServiceWatcher(_statusNotifierWatcherServiceName,
-        QDBusConnection::sessionBus(),
-        QDBusServiceWatcher::WatchForOwnerChange,
-        this);
+    // Service watcher to keep track of the StatusNotifierWatcher service
+    QDBusServiceWatcher *watcher = new QDBusServiceWatcher(kSniWatcherService,
+                                                           QDBusConnection::sessionBus(),
+                                                           QDBusServiceWatcher::WatchForOwnerChange,
+                                                           this);
     connect(watcher, SIGNAL(serviceOwnerChanged(QString, QString, QString)), SLOT(serviceChange(QString, QString, QString)));
 
-    setMode(StatusNotifier);
-
-    _notificationsClient = new org::freedesktop::Notifications("org.freedesktop.Notifications", "/org/freedesktop/Notifications",
-        QDBusConnection::sessionBus(), this);
-
+    // Client instance for StatusNotifierWatcher
+    _statusNotifierWatcher = new org::kde::StatusNotifierWatcher(kSniWatcherService,
+                                                                 kSniWatcherPath,
+                                                                 QDBusConnection::sessionBus(),
+                                                                 this);
+    connect(_statusNotifierWatcher, SIGNAL(StatusNotifierHostRegistered()), SLOT(checkForRegisteredHosts()));
+    connect(_statusNotifierWatcher, SIGNAL(StatusNotifierHostUnregistered()), SLOT(checkForRegisteredHosts()));
+
+    // Client instance for notifications
+    _notificationsClient = new org::freedesktop::Notifications(kXdgNotificationsService,
+                                                               kXdgNotificationsPath,
+                                                               QDBusConnection::sessionBus(),
+                                                               this);
     connect(_notificationsClient, SIGNAL(NotificationClosed(uint, uint)), SLOT(notificationClosed(uint, uint)));
     connect(_notificationsClient, SIGNAL(ActionInvoked(uint, QString)), SLOT(notificationInvoked(uint, QString)));
 
@@ -121,63 +137,57 @@ void StatusNotifierItem::init()
         _notificationsClientSupportsActions = desktopCapabilities.contains("actions");
     }
 
-    StatusNotifierItemParent::init();
-    trayMenu()->installEventFilter(this);
-
 #ifdef HAVE_DBUSMENU
-    _menuObjectPath = "/MenuBar";
     new QuasselDBusMenuExporter(menuObjectPath(), trayMenu(), _statusNotifierItemDBus->dbusConnection()); // will be added as menu child
 #endif
 }
 
 
-void StatusNotifierItem::registerToDaemon()
-{
-    if (!_statusNotifierWatcher) {
-        _statusNotifierWatcher = new org::kde::StatusNotifierWatcher(_statusNotifierWatcherServiceName,
-            "/StatusNotifierWatcher",
-            QDBusConnection::sessionBus());
-        connect(_statusNotifierWatcher, SIGNAL(StatusNotifierHostRegistered()), SLOT(checkForRegisteredHosts()));
-        connect(_statusNotifierWatcher, SIGNAL(StatusNotifierHostUnregistered()), SLOT(checkForRegisteredHosts()));
-    }
-    if (_statusNotifierWatcher->isValid()
-        && _statusNotifierWatcher->property("ProtocolVersion").toInt() == _protocolVersion) {
-        _statusNotifierWatcher->RegisterStatusNotifierItem(_statusNotifierItemDBus->service());
-        checkForRegisteredHosts();
-    }
-    else {
-        //qDebug() << "StatusNotifierWatcher not reachable!";
-        setMode(Legacy);
-    }
-}
-
-
 void StatusNotifierItem::serviceChange(const QString &name, const QString &oldOwner, const QString &newOwner)
 {
     Q_UNUSED(name);
     if (newOwner.isEmpty()) {
         //unregistered
-        //qDebug() << "Connection to the StatusNotifierWatcher lost";
-        delete _statusNotifierWatcher;
-        _statusNotifierWatcher = nullptr;
-        setMode(Legacy);
+        setMode(Mode::Legacy);
     }
     else if (oldOwner.isEmpty()) {
         //registered
-        setMode(StatusNotifier);
+        setMode(Mode::StatusNotifier);
+    }
+}
+
+
+void StatusNotifierItem::registerToWatcher()
+{
+    if (_statusNotifierWatcher->isValid() && _statusNotifierWatcher->property("ProtocolVersion").toInt() == kProtocolVersion) {
+        auto registerMethod = QDBusMessage::createMethodCall(kSniWatcherService, kSniWatcherPath, kSniWatcherService,
+                                                             QLatin1String{"RegisterStatusNotifierItem"});
+        registerMethod.setArguments(QVariantList() << _statusNotifierItemDBus->service());
+        _statusNotifierItemDBus->dbusConnection().callWithCallback(registerMethod, this, SLOT(checkForRegisteredHosts()), SLOT(onDBusError(QDBusError)));
+    }
+    else {
+        setMode(Mode::Legacy);
     }
 }
 
 
 void StatusNotifierItem::checkForRegisteredHosts()
 {
-    if (!_statusNotifierWatcher || !_statusNotifierWatcher->property("IsStatusNotifierHostRegistered").toBool())
-        setMode(Legacy);
-    else
-        setMode(StatusNotifier);
+    if (!_statusNotifierWatcher || !_statusNotifierWatcher->property("IsStatusNotifierHostRegistered").toBool()) {
+        setMode(Mode::Legacy);
+    }
+    else {
+        setMode(Mode::StatusNotifier);
+    }
 }
 
 
+void StatusNotifierItem::onDBusError(const QDBusError &error)
+{
+    qWarning() << "StatusNotifierItem encountered a D-Bus error:" << error;
+    setMode(Mode::Legacy);
+}
+
 void StatusNotifierItem::refreshIcons()
 {
 #if QT_VERSION >= 0x050000
@@ -218,65 +228,44 @@ void StatusNotifierItem::refreshIcons()
 
 bool StatusNotifierItem::isSystemTrayAvailable() const
 {
-    if (mode() == StatusNotifier)
+    if (mode() == Mode::StatusNotifier) {
         return true;  // else it should be set to legacy on registration
+    }
 
     return StatusNotifierItemParent::isSystemTrayAvailable();
 }
 
 
-bool StatusNotifierItem::isVisible() const
-{
-    if (mode() == StatusNotifier)
-        return shouldBeVisible();  // we don't have a way to check, so we need to trust everything went right
-
-    return StatusNotifierItemParent::isVisible();
-}
-
-
-void StatusNotifierItem::setMode(Mode mode_)
+void StatusNotifierItem::onModeChanged(Mode mode)
 {
-    if (mode_ == mode())
-        return;
-
-    if (mode_ != StatusNotifier) {
-        _statusNotifierItemDBus->unregisterService();
-    }
-
-    StatusNotifierItemParent::setMode(mode_);
-
-    if (mode() == StatusNotifier) {
+    if (mode == Mode::StatusNotifier) {
         _statusNotifierItemDBus->registerService();
-        registerToDaemon();
+        registerToWatcher();
+    }
+    else {
+        _statusNotifierItemDBus->unregisterService();
     }
 }
 
 
-void StatusNotifierItem::setState(State state_)
+void StatusNotifierItem::onStateChanged(State state)
 {
-    StatusNotifierItemParent::setState(state_);
-
-    emit _statusNotifierItemDBus->NewStatus(metaObject()->enumerator(metaObject()->indexOfEnumerator("State")).valueToKey(state()));
-    emit _statusNotifierItemDBus->NewIcon();
+    if (mode() == Mode::StatusNotifier) {
+        emit _statusNotifierItemDBus->NewIcon();
+        emit _statusNotifierItemDBus->NewStatus(metaObject()->enumerator(metaObject()->indexOfEnumerator("State")).valueToKey(state));
+    }
 }
 
 
-void StatusNotifierItem::setVisible(bool visible)
+void StatusNotifierItem::onVisibilityChanged(bool isVisible)
 {
-    if (visible == isVisible())
-        return;
-
-    LegacySystemTray::setVisible(visible);
-
-    if (mode() == StatusNotifier) {
-        if (shouldBeVisible()) {
+    if (mode() == Mode::StatusNotifier) {
+        if (isVisible) {
             _statusNotifierItemDBus->registerService();
-            registerToDaemon();
+            registerToWatcher();
         }
         else {
             _statusNotifierItemDBus->unregisterService();
-            _statusNotifierWatcher->deleteLater();
-            _statusNotifierWatcher = 0;
         }
     }
 }
@@ -305,7 +294,7 @@ QString StatusNotifierItem::attentionIconName() const
         return SystemTray::iconName(State::NeedsAttention);
     }
     else {
-        return SystemTray::iconName(State::Active);
+        return SystemTray::iconName(State::NeedsAttention);
     }
 }
 
@@ -324,7 +313,7 @@ QString StatusNotifierItem::iconThemePath() const
 
 QString StatusNotifierItem::menuObjectPath() const
 {
-    return _menuObjectPath;
+    return kMenuObjectPath;
 }
 
 
@@ -385,13 +374,15 @@ void StatusNotifierItem::showMessage(const QString &title, const QString &messag
 
 void StatusNotifierItem::closeMessage(uint notificationId)
 {
-    foreach(uint dbusid, _notificationsIdMap.keys()) {
+    for (auto &&dbusid : _notificationsIdMap.keys()) {
         if (_notificationsIdMap.value(dbusid) == notificationId) {
             _notificationsIdMap.remove(dbusid);
             _notificationsClient->CloseNotification(dbusid);
         }
     }
     _lastNotificationsDBusId = 0;
+
+    StatusNotifierItemParent::closeMessage(notificationId);
 }
 
 
index 9a805be..8b8eb96 100644 (file)
@@ -25,7 +25,9 @@
 
 #ifdef HAVE_DBUS
 
-#include <QtGlobal>
+#include <QDBusError>
+#include <QHash>
+#include <QString>
 
 #if QT_VERSION >= 0x050000
 #  include <QTemporaryDir>
@@ -50,21 +52,14 @@ class StatusNotifierItem : public StatusNotifierItemParent
 
 public:
     explicit StatusNotifierItem(QWidget *parent);
-    ~StatusNotifierItem() override;
 
     bool isSystemTrayAvailable() const override;
-    bool isVisible() const override;
 
 public slots:
-    void setState(State state) override;
-    void setVisible(bool visible) override;
     void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int msTimeout = 10000, uint notificationId = 0) override;
     void closeMessage(uint notificationId) override;
 
 protected:
-    void init() override;
-    void setMode(Mode mode) override;
-
     QString title() const;
     QString iconName() const;
     QString attentionIconName() const;
@@ -78,19 +73,21 @@ private slots:
     void activated(const QPoint &pos);
     void serviceChange(const QString &name, const QString &oldOwner, const QString &newOwner);
     void checkForRegisteredHosts();
+    void onDBusError(const QDBusError &error);
 
     void notificationClosed(uint id, uint reason);
     void notificationInvoked(uint id, const QString &action);
 
     void refreshIcons();
 
+    void onModeChanged(Mode mode);
+    void onStateChanged(State state);
+    void onVisibilityChanged(bool isVisible);
+
 private:
-    void registerToDaemon();
+    void registerToWatcher();
 
-    static const int _protocolVersion;
-    static const QString _statusNotifierWatcherServiceName;
     StatusNotifierItemDBus *_statusNotifierItemDBus{nullptr};
-
     org::kde::StatusNotifierWatcher *_statusNotifierWatcher{nullptr};
     org::freedesktop::Notifications *_notificationsClient{nullptr};
     bool _notificationsClientSupportsMarkup{false};
index 679a4b1..4a68dd6 100644 (file)
@@ -42,17 +42,7 @@ SystemTray::SystemTray(QWidget *parent)
 
     NotificationSettings{}.initAndNotify("Systray/Animate", this, SLOT(enableAnimationChanged(QVariant)), true);
     UiStyleSettings{}.initAndNotify("Icons/InvertTray", this, SLOT(invertTrayIconChanged(QVariant)), false);
-}
-
 
-SystemTray::~SystemTray()
-{
-    _trayMenu->deleteLater();
-}
-
-
-void SystemTray::init()
-{
     ActionCollection *coll = QtUi::actionCollection("General");
     _minimizeRestoreAction = new Action(tr("&Minimize"), this, this, SLOT(minimizeRestore()));
 
@@ -81,33 +71,36 @@ void SystemTray::init()
 }
 
 
-QWidget *SystemTray::associatedWidget() const
+SystemTray::~SystemTray()
 {
-    return _associatedWidget;
+    _trayMenu->deleteLater();
 }
 
 
-bool SystemTray::isSystemTrayAvailable() const
+QWidget *SystemTray::associatedWidget() const
 {
-    return false;
+    return _associatedWidget;
 }
 
 
-bool SystemTray::isVisible() const
+bool SystemTray::isSystemTrayAvailable() const
 {
     return false;
 }
 
 
-bool SystemTray::shouldBeVisible() const
+bool SystemTray::isVisible() const
 {
-    return _shouldBeVisible;
+    return _isVisible;
 }
 
 
 void SystemTray::setVisible(bool visible)
 {
-    _shouldBeVisible = visible;
+    if (visible != _isVisible) {
+        _isVisible = visible;
+        emit visibilityChanged(visible);
+    }
 }
 
 
@@ -117,13 +110,13 @@ SystemTray::Mode SystemTray::mode() const
 }
 
 
-void SystemTray::setMode(Mode mode_)
+void SystemTray::setMode(Mode mode)
 {
-    if (mode_ != _mode) {
-        _mode = mode_;
+    if (mode != _mode) {
+        _mode = mode;
 #ifdef HAVE_KDE4
         if (_trayMenu) {
-            if (_mode == Legacy) {
+            if (mode == Mode::Legacy) {
                 _trayMenu->setWindowFlags(Qt::Popup);
             }
             else {
@@ -131,6 +124,7 @@ void SystemTray::setMode(Mode mode_)
             }
         }
 #endif
+        emit modeChanged(mode);
     }
 }
 
@@ -145,6 +139,7 @@ void SystemTray::setState(State state)
 {
     if (_state != state) {
         _state = state;
+        emit stateChanged(state);
     }
 }
 
index 1efdb41..d07edf1 100644 (file)
@@ -63,26 +63,30 @@ public:
 
     explicit SystemTray(QWidget *parent);
     ~SystemTray() override;
-    virtual void init();
 
     Mode mode() const;
     State state() const;
+    bool isVisible() const;
     bool isAlerted() const;
-    void setAlert(bool alerted);
 
-    virtual bool isVisible() const;
     virtual bool isSystemTrayAvailable() const;
 
     QWidget *associatedWidget() const;
 
 public slots:
-    virtual void setState(State);
-    virtual void setVisible(bool visible = true);
-    virtual void setToolTip(const QString &title, const QString &subtitle);
+    void setVisible(bool visible = true);
+    void setState(State);
+    void setAlert(bool alerted);
+
+    void setToolTip(const QString &title, const QString &subtitle);
     virtual void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int msTimeout = 10000, uint notificationId = 0);
     virtual void closeMessage(uint notificationId);
 
 signals:
+    void modeChanged(Mode mode);
+    void stateChanged(State state);
+    void visibilityChanged(bool isVisible);
+
     void activated(SystemTray::ActivationReason);
     void iconChanged(const QIcon &icon);
     void animationEnabledChanged(bool);
@@ -94,8 +98,7 @@ protected slots:
     virtual void activate(SystemTray::ActivationReason = Trigger);
 
 protected:
-    virtual void setMode(Mode mode);
-    bool shouldBeVisible() const;
+    void setMode(Mode mode);
     bool animationEnabled() const;
 
     QString toolTipTitle() const;
@@ -111,9 +114,9 @@ private slots:
     void invertTrayIconChanged(const QVariant &);
 
 private:
+    bool _isVisible{false};
     Mode _mode{Mode::Invalid};
     State _state{State::Passive};
-    bool _shouldBeVisible{true};
     bool _animationEnabled{true};
     bool _trayIconInverted{false};