From 5ba28fb36a747bd9a2c05a58f0533d1e38c2a0de Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Wed, 3 Mar 2010 00:08:21 +0100 Subject: [PATCH] Integrate DesktopNotification into system tray/status notifier Since the DBus notification spec is quite widespread by now, and in fact KDE's StatusNotifierItem uses that same spec for displaying popup messages, we now integrate the former DesktopNotification into StatusNotifierItem. If DBus or a NotificationsClient are not present, we fall back to traditional systray popups. This could be fugly if we have StatusNotifier, but not NotificationsClient, but all platforms supporting the former should also support the latter by now. Having this in SystemTray also makes our notification handling code much nicer, and we have one less backend to care about. Additionally, users using current versions of KDE or GNOME will get pretty popups automatically. --- src/qtui/CMakeLists.txt | 8 +- src/qtui/desktopnotificationbackend.cpp | 243 ------------------ src/qtui/desktopnotificationbackend.h | 98 ------- src/qtui/legacysystemtray.cpp | 25 +- src/qtui/legacysystemtray.h | 5 +- src/qtui/mainwin.cpp | 6 - src/qtui/statusnotifieritem.cpp | 61 ++++- src/qtui/statusnotifieritem.h | 11 +- src/qtui/systemtray.cpp | 3 +- src/qtui/systemtray.h | 7 +- src/qtui/systraynotificationbackend.cpp | 51 ++-- src/qtui/systraynotificationbackend.h | 4 +- .../ui/desktopnotificationconfigwidget.ui | 216 ---------------- 13 files changed, 122 insertions(+), 616 deletions(-) delete mode 100644 src/qtui/desktopnotificationbackend.cpp delete mode 100644 src/qtui/desktopnotificationbackend.h delete mode 100644 src/qtui/ui/desktopnotificationconfigwidget.ui diff --git a/src/qtui/CMakeLists.txt b/src/qtui/CMakeLists.txt index 4b76e972..b806d669 100644 --- a/src/qtui/CMakeLists.txt +++ b/src/qtui/CMakeLists.txt @@ -139,13 +139,6 @@ if(HAVE_KDE) set(SOURCES ${SOURCES} knotificationbackend.cpp) set(MOC_HDRS ${MOC_HDRS} knotificationbackend.h) else(HAVE_KDE) - if(HAVE_DBUS) - set(SOURCES ${SOURCES} desktopnotificationbackend.cpp) - set(MOC_HDRS ${MOC_HDRS} desktopnotificationbackend.h) - set(FORMS ${FORMS} desktopnotificationconfigwidget.ui) - qt4_add_dbus_interface(DBUS ../../interfaces/org.freedesktop.Notifications.xml desktopnotificationinterface) - endif(HAVE_DBUS) - if(HAVE_PHONON) set(SOURCES ${SOURCES} phononnotificationbackend.cpp) set(MOC_HDRS ${MOC_HDRS} phononnotificationbackend.h) @@ -159,6 +152,7 @@ if(HAVE_DBUS) set(MOC_HDRS ${MOC_HDRS} statusnotifieritem.h statusnotifieritemdbus.h) set(FORMS ${FORMS}) qt4_add_dbus_interface(DBUS ../../interfaces/org.kde.StatusNotifierWatcher.xml statusnotifierwatcher) + qt4_add_dbus_interface(DBUS ../../interfaces/org.freedesktop.Notifications.xml notificationsclient) qt4_add_dbus_adaptor(DBUS ../../interfaces/org.kde.StatusNotifierItem.xml statusnotifieritemdbus.h StatusNotifierItemDBus) endif(HAVE_DBUS) diff --git a/src/qtui/desktopnotificationbackend.cpp b/src/qtui/desktopnotificationbackend.cpp deleted file mode 100644 index dedade70..00000000 --- a/src/qtui/desktopnotificationbackend.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/*************************************************************************** -* Copyright (C) 2005-09 by the Quassel Project * -* devel@quassel-irc.org * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) version 3. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License for more details. * -* * -* You should have received a copy of the GNU General Public License * -* along with this program; if not, write to the * -* Free Software Foundation, Inc., * -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -***************************************************************************/ - -#include "desktopnotificationbackend.h" - -#include - -#include "client.h" -#include "clientsettings.h" -#include "networkmodel.h" - -DesktopNotificationBackend::DesktopNotificationBackend(QObject *parent) - : AbstractNotificationBackend(parent), - _lastDbusId(0) -{ - _dbusInterface = new org::freedesktop::Notifications( - "org.freedesktop.Notifications", - "/org/freedesktop/Notifications", - QDBusConnection::sessionBus(), this); - - if(!_dbusInterface->isValid()) { - qWarning() << "DBus notification service not available!"; - return; - } - - QStringList desktopCapabilities = _dbusInterface->GetCapabilities(); - _daemonSupportsMarkup = desktopCapabilities.contains("body-markup"); - - connect(_dbusInterface, SIGNAL(NotificationClosed(uint, uint)), SLOT(desktopNotificationClosed(uint, uint))); - connect(_dbusInterface, SIGNAL(ActionInvoked(uint, const QString &)), SLOT(desktopNotificationInvoked(uint, const QString&))); - - NotificationSettings notificationSettings; - _enabled = notificationSettings.value("DesktopNotification/Enabled", false).toBool(); - _useHints = notificationSettings.value("DesktopNotification/UseHints", false).toBool(); - _xHint = notificationSettings.value("DesktopNotification/XHint", 0).toInt(); - _yHint = notificationSettings.value("DesktopNotification/YHint", 0).toInt(); - _queueNotifications = notificationSettings.value("DesktopNotification/QueueNotifications", true).toBool(); - _timeout = notificationSettings.value("DesktopNotification/Timeout", 10000).toInt(); - _useTimeout = notificationSettings.value("DesktopNotification/UseTimeout", true).toBool(); - - notificationSettings.notify("DesktopNotification/Enabled", this, SLOT(enabledChanged(const QVariant &))); - notificationSettings.notify("DesktopNotification/UseHints", this, SLOT(useHintsChanged(const QVariant &))); - notificationSettings.notify("DesktopNotification/XHint", this, SLOT(xHintChanged(const QVariant &))); - notificationSettings.notify("DesktopNotification/YHint", this, SLOT(yHintChanged(const QVariant &))); - notificationSettings.notify("DesktopNotification/Timeout", this, SLOT(timeoutChanged(const QVariant &))); - notificationSettings.notify("DesktopNotification/UseTimeout", this, SLOT(useTimeoutChanged(const QVariant &))); - notificationSettings.notify("DesktopNotification/QueueNotifications", this, SLOT(queueNotificationsChanged(const QVariant &))); -} - -void DesktopNotificationBackend::enabledChanged(const QVariant &v) { - _enabled = v.toBool(); -} - -void DesktopNotificationBackend::useHintsChanged(const QVariant &v) { - _useHints = v.toBool(); -} - -void DesktopNotificationBackend::xHintChanged(const QVariant &v) { - _xHint = v.toInt(); -} - -void DesktopNotificationBackend::yHintChanged(const QVariant &v) { - _yHint = v.toInt(); -} - -void DesktopNotificationBackend::queueNotificationsChanged(const QVariant &v) { - _queueNotifications = v.toBool(); -} - -void DesktopNotificationBackend::timeoutChanged(const QVariant &v) { - _timeout = v.toInt(); -} - -void DesktopNotificationBackend::useTimeoutChanged(const QVariant &v) { - _useTimeout = v.toBool(); -} - -void DesktopNotificationBackend::notify(const Notification &n) { - if(_enabled && _dbusInterface->isValid() && (n.type == Highlight || n.type == PrivMsg)) { - QStringList actions; - QMap hints; - - if(_useHints) { - hints["x"] = _xHint; // Standard hint: x location for the popup to show up - hints["y"] = _yHint; // Standard hint: y location for the popup to show up - } - - uint oldId = _queueNotifications ? 0 : _lastDbusId; - - actions << "activate" << "View"; - - QString title = Client::networkModel()->networkName(n.bufferId) + " - " + Client::networkModel()->bufferName(n.bufferId); - QString message = QString("<%1> %2").arg(n.sender, n.message); - - if(_daemonSupportsMarkup) - message = Qt::escape(message); - - QDBusReply reply = _dbusInterface->Notify( - "Quassel IRC", // Application name - oldId, // ID of previous notification to replace - "quassel", // Icon to display - title, // Summary / Header of the message to display - message, // Body of the message to display - actions, // Actions from which the user may choose - hints, // Hints to the server displaying the message - _useTimeout? _timeout : 0 // Timeout in milliseconds - ); - - if(!reply.isValid()) { - /* ERROR */ - // could also happen if no notification service runs, so... whatever :) - // qDebug() << "Error on sending notification..." << reply.error(); - return; - } - uint dbusid = reply.value(); - _idMap.insert(n.notificationId, dbusid); - _lastDbusId = dbusid; - } -} - -void DesktopNotificationBackend::close(uint notificationId) { - uint dbusId = _idMap.value(notificationId, 0); - if(dbusId) { - _idMap.remove(notificationId); - _dbusInterface->CloseNotification(dbusId); - } - _lastDbusId = 0; -} - -void DesktopNotificationBackend::desktopNotificationClosed(uint id, uint reason) { - Q_UNUSED(reason); - _idMap.remove(_idMap.key(id)); - _lastDbusId = 0; -} - - -void DesktopNotificationBackend::desktopNotificationInvoked(uint id, const QString & action) { - Q_UNUSED(action); - foreach(uint ourid, _idMap.keys()) { - if(_idMap.value(ourid) != id) - continue; - emit activated(ourid); - return; - } - - emit activated(); -} - -SettingsPage *DesktopNotificationBackend::createConfigWidget() const { - return new ConfigWidget(); -} - -/***************************************************************************/ - -DesktopNotificationBackend::ConfigWidget::ConfigWidget(QWidget *parent) : SettingsPage("Internal", "DesktopNotification", parent) { - ui.setupUi(this); - - connect(ui.enabled, SIGNAL(toggled(bool)), SLOT(widgetChanged())); - connect(ui.useHints, SIGNAL(toggled(bool)), SLOT(widgetChanged())); - connect(ui.xHint, SIGNAL(valueChanged(int)), SLOT(widgetChanged())); - connect(ui.yHint, SIGNAL(valueChanged(int)), SLOT(widgetChanged())); - connect(ui.queueNotifications, SIGNAL(toggled(bool)), SLOT(widgetChanged())); - connect(ui.useTimeout, SIGNAL(toggled(bool)), SLOT(widgetChanged())); - connect(ui.timeout, SIGNAL(valueChanged(int)), SLOT(widgetChanged())); -} - -void DesktopNotificationBackend::ConfigWidget::widgetChanged() { - bool changed = - enabled != ui.enabled->isChecked() - || useHints != ui.useHints->isChecked() - || xHint != ui.xHint->value() - || yHint != ui.yHint->value() - || queueNotifications != ui.queueNotifications->isChecked() - || timeout/1000 != ui.timeout->value() - || useTimeout != ui.useTimeout->isChecked(); - if(changed != hasChanged()) setChangedState(changed); -} - -bool DesktopNotificationBackend::ConfigWidget::hasDefaults() const { - return true; -} - -void DesktopNotificationBackend::ConfigWidget::defaults() { - ui.enabled->setChecked(false); - ui.useTimeout->setChecked(true); - ui.timeout->setValue(10); - ui.useHints->setChecked(false); - ui.xHint->setValue(0); - ui.yHint->setValue(0); - ui.queueNotifications->setChecked(true); - widgetChanged(); -} - -void DesktopNotificationBackend::ConfigWidget::load() { - NotificationSettings s; - enabled = s.value("DesktopNotification/Enabled", false).toBool(); - useTimeout = s.value("DesktopNotification/UseTimeout", true).toBool(); - timeout = s.value("DesktopNotification/Timeout", 10000).toInt(); - useHints = s.value("DesktopNotification/UseHints", false).toBool(); - xHint = s.value("DesktopNotification/XHint", 0).toInt(); - yHint = s.value("DesktopNotification/YHint", 0).toInt(); - queueNotifications = s.value("DesktopNotification/QueueNotifications", true).toBool(); - - ui.enabled->setChecked(enabled); - ui.useTimeout->setChecked(useTimeout); - ui.timeout->setValue(timeout/1000); - ui.useHints->setChecked(useHints); - ui.xHint->setValue(xHint); - ui.yHint->setValue(yHint); - ui.queueNotifications->setChecked(queueNotifications); - - setChangedState(false); -} - -void DesktopNotificationBackend::ConfigWidget::save() { - NotificationSettings s; - s.setValue("DesktopNotification/Enabled", ui.enabled->isChecked()); - s.setValue("DesktopNotification/UseTimeout", ui.useTimeout->isChecked()); - s.setValue("DesktopNotification/Timeout", ui.timeout->value() * 1000); - s.setValue("DesktopNotification/UseHints", ui.useHints->isChecked()); - s.setValue("DesktopNotification/XHint", ui.xHint->value()); - s.setValue("DesktopNotification/YHint", ui.yHint->value()); - s.setValue("DesktopNotification/QueueNotifications", ui.queueNotifications->isChecked()); - - load(); -} diff --git a/src/qtui/desktopnotificationbackend.h b/src/qtui/desktopnotificationbackend.h deleted file mode 100644 index c83a3a1b..00000000 --- a/src/qtui/desktopnotificationbackend.h +++ /dev/null @@ -1,98 +0,0 @@ -/*************************************************************************** -* Copyright (C) 2005-09 by the Quassel Project * -* devel@quassel-irc.org * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) version 3. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License for more details. * -* * -* You should have received a copy of the GNU General Public License * -* along with this program; if not, write to the * -* Free Software Foundation, Inc., * -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -***************************************************************************/ - -#ifndef DESKTOPNOTIFICATIONBACKEND_H_ -#define DESKTOPNOTIFICATIONBACKEND_H_ - -#include - -#include "abstractnotificationbackend.h" - -#include "settingspage.h" - -#include "desktopnotificationinterface.h" -#include "ui_desktopnotificationconfigwidget.h" - -//! Implements the freedesktop.org notifications specification (via D-Bus) -/** - * cf. http://www.galago-project.org/specs/notification/ - * - * This class will only be available if -DHAVE_DBUS is enabled - */ -class DesktopNotificationBackend : public AbstractNotificationBackend { - Q_OBJECT - -public: - DesktopNotificationBackend(QObject *parent = 0); - - void notify(const Notification &); - void close(uint notificationId); - virtual SettingsPage *createConfigWidget() const; - -private slots: - void desktopNotificationClosed(uint id, uint reason); - void desktopNotificationInvoked(uint id, const QString &action); - - void enabledChanged(const QVariant &); - void useHintsChanged(const QVariant &); - void xHintChanged(const QVariant &); - void yHintChanged(const QVariant &); - void queueNotificationsChanged(const QVariant &); - void timeoutChanged(const QVariant &); - void useTimeoutChanged(const QVariant &); - -private: - class ConfigWidget; - - org::freedesktop::Notifications *_dbusInterface; - bool _daemonSupportsMarkup; - quint32 _lastDbusId; - QHash _idMap; ///< Maps our own notification Id to the D-Bus one - - bool _enabled, _queueNotifications, _useHints; - int _xHint, _yHint; - int _timeout; - bool _useTimeout; - -}; - -class DesktopNotificationBackend::ConfigWidget : public SettingsPage { - Q_OBJECT - -public: - ConfigWidget(QWidget *parent = 0); - void save(); - void load(); - bool hasDefaults() const; - void defaults(); - -private slots: - void widgetChanged(); - -private: - Ui::DesktopNotificationConfigWidget ui; - int xHint, yHint; - bool useHints, queueNotifications; - int timeout; - bool useTimeout; - bool enabled; -}; - -#endif diff --git a/src/qtui/legacysystemtray.cpp b/src/qtui/legacysystemtray.cpp index 18186f24..0c6a1e36 100644 --- a/src/qtui/legacysystemtray.cpp +++ b/src/qtui/legacysystemtray.cpp @@ -27,7 +27,8 @@ LegacySystemTray::LegacySystemTray(QWidget *parent) : SystemTray(parent), _blinkState(false), - _isVisible(true) + _isVisible(true), + _lastMessageId(0) { #ifndef HAVE_KDE _trayIcon = new QSystemTrayIcon(associatedWidget()); @@ -42,7 +43,7 @@ LegacySystemTray::LegacySystemTray(QWidget *parent) SLOT(on_activated(QSystemTrayIcon::ActivationReason))); #endif connect(_trayIcon, SIGNAL(messageClicked()), - SIGNAL(messageClicked())); + SLOT(on_messageClicked())); _blinkTimer.setInterval(500); _blinkTimer.setSingleShot(false); @@ -131,8 +132,24 @@ void LegacySystemTray::on_activated(QSystemTrayIcon::ActivationReason reason) { activate((SystemTray::ActivationReason)reason); } -void LegacySystemTray::showMessage(const QString &title, const QString &message, SystemTray::MessageIcon icon, int millisecondsTimeoutHint) { - _trayIcon->showMessage(title, message, (QSystemTrayIcon::MessageIcon)icon, millisecondsTimeoutHint); +void LegacySystemTray::on_messageClicked() { + emit messageClicked(_lastMessageId); +} + +void LegacySystemTray::showMessage(const QString &title, const QString &message, SystemTray::MessageIcon icon, int msTimeout, uint id) { + // fancy stuff later: show messages in order + // for now, we just show the last message + _lastMessageId = id; + _trayIcon->showMessage(title, message, (QSystemTrayIcon::MessageIcon)icon, msTimeout); +} + +void LegacySystemTray::closeMessage(uint notificationId) { + Q_UNUSED(notificationId) + + // there really seems to be no sane way to close the bubble... :( +#ifdef Q_WS_X11 + showMessage("", "", NoIcon, 1); +#endif } #endif /* QT_NO_SYSTEMTRAYICON */ diff --git a/src/qtui/legacysystemtray.h b/src/qtui/legacysystemtray.h index 07c1b1d9..c6cb91bf 100644 --- a/src/qtui/legacysystemtray.h +++ b/src/qtui/legacysystemtray.h @@ -48,7 +48,8 @@ public: 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 millisecondsTimeoutHint = 10000); + virtual void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int msTimeout = 10000, uint notificationId = 0); + virtual void closeMessage(uint notificationId); protected slots: @@ -58,6 +59,7 @@ protected: private slots: void on_blinkTimeout(); void on_activated(QSystemTrayIcon::ActivationReason); + void on_messageClicked(); void syncLegacyIcon(); @@ -65,6 +67,7 @@ private: QTimer _blinkTimer; bool _blinkState; bool _isVisible; + uint _lastMessageId; #ifdef HAVE_KDE KSystemTrayIcon *_trayIcon; diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index c6d4051e..fe050fb3 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -85,9 +85,6 @@ #include "verticaldock.h" #ifndef HAVE_KDE -# ifdef HAVE_DBUS -# include "desktopnotificationbackend.h" -# endif # ifdef HAVE_PHONON # include "phononnotificationbackend.h" # endif @@ -199,9 +196,6 @@ void MainWin::init() { # ifdef HAVE_PHONON QtUi::registerNotificationBackend(new PhononNotificationBackend(this)); # endif -# ifdef HAVE_DBUS - QtUi::registerNotificationBackend(new DesktopNotificationBackend(this)); -# endif #else /* HAVE_KDE */ QtUi::registerNotificationBackend(new KNotificationBackend(this)); diff --git a/src/qtui/statusnotifieritem.cpp b/src/qtui/statusnotifieritem.cpp index 690ed9e4..9d61fa75 100644 --- a/src/qtui/statusnotifieritem.cpp +++ b/src/qtui/statusnotifieritem.cpp @@ -26,22 +26,26 @@ #include "statusnotifieritem.h" #include "statusnotifieritemdbus.h" +#include #include #include +#include const int StatusNotifierItem::_protocolVersion = 0; StatusNotifierItem::StatusNotifierItem(QWidget *parent) : StatusNotifierItemParent(parent), _statusNotifierItemDBus(0), - _statusNotifierWatcher(0) + _statusNotifierWatcher(0), + _notificationsClient(0), + _notificationsClientSupportsMarkup(true), + _lastNotificationsDBusId(0) { } StatusNotifierItem::~StatusNotifierItem() { delete _statusNotifierWatcher; - } void StatusNotifierItem::init() { @@ -57,6 +61,17 @@ void StatusNotifierItem::init() { setMode(StatusNotifier); + _notificationsClient = new org::freedesktop::Notifications("org.freedesktop.Notifications", "/org/freedesktop/Notifications", + QDBusConnection::sessionBus(), this); + + connect(_notificationsClient, SIGNAL(NotificationClosed(uint,uint)), SLOT(notificationClosed(uint,uint))); + connect(_notificationsClient, SIGNAL(ActionInvoked(uint,QString)), SLOT(notificationInvoked(uint,QString))); + + if(_notificationsClient->isValid()) { + QStringList desktopCapabilities = _notificationsClient->GetCapabilities(); + _notificationsClientSupportsMarkup = desktopCapabilities.contains("body-markup"); + } + StatusNotifierItemParent::init(); trayMenu()->installEventFilter(this); } @@ -73,7 +88,7 @@ void StatusNotifierItem::registerToDaemon() { _statusNotifierWatcher->RegisterStatusNotifierItem(_statusNotifierItemDBus->service()); } else { - qDebug() << "StatusNotifierWatcher not reachable!"; + //qDebug() << "StatusNotifierWatcher not reachable!"; setMode(Legacy); } } @@ -175,4 +190,44 @@ bool StatusNotifierItem::eventFilter(QObject *watched, QEvent *event) { return StatusNotifierItemParent::eventFilter(watched, event); } +void StatusNotifierItem::showMessage(const QString &title, const QString &message_, SystemTray::MessageIcon icon, int timeout, uint notificationId) { + QString message = message_; + if(_notificationsClient->isValid()) { + if(_notificationsClientSupportsMarkup) + message = Qt::escape(message); + + QStringList actions = QStringList() << "activate" << "View"; + + // we always queue notifications right now + QDBusReply reply = _notificationsClient->Notify(title, 0, "quassel", title, message, actions, QVariantMap(), timeout); + if(reply.isValid()) { + uint dbusid = reply.value(); + _notificationsIdMap.insert(dbusid, notificationId); + _lastNotificationsDBusId = dbusid; + } + } else + StatusNotifierItemParent::showMessage(title, message, icon, timeout, notificationId); +} + +void StatusNotifierItem::closeMessage(uint notificationId) { + foreach(uint dbusid, _notificationsIdMap.keys()) { + if(_notificationsIdMap.value(dbusid) == notificationId) { + _notificationsIdMap.remove(dbusid); + _notificationsClient->CloseNotification(dbusid); + } + } + _lastNotificationsDBusId = 0; +} + +void StatusNotifierItem::notificationClosed(uint dbusid, uint reason) { + Q_UNUSED(reason) + _lastNotificationsDBusId = 0; + emit messageClosed(_notificationsIdMap.take(dbusid)); +} + +void StatusNotifierItem::notificationInvoked(uint dbusid, const QString &action) { + Q_UNUSED(action) + emit messageClicked(_notificationsIdMap.value(dbusid, 0)); +} + #endif diff --git a/src/qtui/statusnotifieritem.h b/src/qtui/statusnotifieritem.h index 2efbefda..3bed80fa 100644 --- a/src/qtui/statusnotifieritem.h +++ b/src/qtui/statusnotifieritem.h @@ -26,6 +26,7 @@ #ifdef HAVE_DBUS +#include "notificationsclient.h" #include "systemtray.h" #include "statusnotifierwatcher.h" @@ -47,6 +48,8 @@ public: public slots: virtual void setState(State state); + virtual void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int msTimeout = 10000, uint notificationId = 0); + virtual void closeMessage(uint notificationId); protected: virtual void init(); @@ -63,6 +66,9 @@ private slots: void activated(const QPoint &pos); void serviceChange(const QString& name, const QString& oldOwner, const QString& newOwner); + void notificationClosed(uint id, uint reason); + void notificationInvoked(uint id, const QString &action); + private: void registerToDaemon(); @@ -70,7 +76,10 @@ private: StatusNotifierItemDBus *_statusNotifierItemDBus; org::kde::StatusNotifierWatcher *_statusNotifierWatcher; - //org::freedesktop::Notifications *_notificationsClient; + org::freedesktop::Notifications *_notificationsClient; + bool _notificationsClientSupportsMarkup; + quint32 _lastNotificationsDBusId; + QHash _notificationsIdMap; ///< Maps our own notification ID to the D-Bus one friend class StatusNotifierItemDBus; }; diff --git a/src/qtui/systemtray.cpp b/src/qtui/systemtray.cpp index 139c968d..afa7964f 100644 --- a/src/qtui/systemtray.cpp +++ b/src/qtui/systemtray.cpp @@ -144,11 +144,12 @@ void SystemTray::setToolTip(const QString &title, const QString &subtitle) { emit toolTipChanged(title, subtitle); } -void SystemTray::showMessage(const QString &title, const QString &message, MessageIcon icon, int millisecondsTimeoutHint) { +void SystemTray::showMessage(const QString &title, const QString &message, MessageIcon icon, int millisecondsTimeoutHint, uint id) { Q_UNUSED(title) Q_UNUSED(message) Q_UNUSED(icon) Q_UNUSED(millisecondsTimeoutHint) + Q_UNUSED(id) } void SystemTray::activate(SystemTray::ActivationReason reason) { diff --git a/src/qtui/systemtray.h b/src/qtui/systemtray.h index df79ddf5..35a9c173 100644 --- a/src/qtui/systemtray.h +++ b/src/qtui/systemtray.h @@ -77,13 +77,15 @@ public slots: virtual void setState(State); virtual void setVisible(bool visible = true); virtual void setToolTip(const QString &title, const QString &subtitle); - virtual void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int millisecondsTimeoutHint = 10000); + virtual void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int msTimeout = 10000, uint notificationId = 0); + virtual void closeMessage(uint notificationId) { Q_UNUSED(notificationId) } signals: void activated(SystemTray::ActivationReason); void iconChanged(const Icon &); void toolTipChanged(const QString &title, const QString &subtitle); - void messageClicked(); + void messageClicked(uint notificationId); + void messageClosed(uint notificationId); protected slots: virtual void activate(SystemTray::ActivationReason = Trigger); @@ -98,6 +100,7 @@ protected: inline QString toolTipSubTitle() const; inline QMenu *trayMenu() const; + private slots: void minimizeRestore(); void trayMenuAboutToShow(); diff --git a/src/qtui/systraynotificationbackend.cpp b/src/qtui/systraynotificationbackend.cpp index 721ee075..f3bd5a06 100644 --- a/src/qtui/systraynotificationbackend.cpp +++ b/src/qtui/systraynotificationbackend.cpp @@ -18,9 +18,12 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "systraynotificationbackend.h" +#include +#include +#include +#include -#include +#include "systraynotificationbackend.h" #include "client.h" #include "clientsettings.h" @@ -41,7 +44,7 @@ SystrayNotificationBackend::SystrayNotificationBackend(QObject *parent) notificationSettings.notify("Systray/ShowBubble", this, SLOT(showBubbleChanged(const QVariant &))); notificationSettings.notify("Systray/Animate", this, SLOT(animateChanged(const QVariant &))); - connect(QtUi::mainWindow()->systemTray(), SIGNAL(messageClicked()), SLOT(notificationActivated())); + connect(QtUi::mainWindow()->systemTray(), SIGNAL(messageClicked(uint)), SLOT(notificationActivated(uint))); connect(QtUi::mainWindow()->systemTray(), SIGNAL(activated(SystemTray::ActivationReason)), SLOT(notificationActivated(SystemTray::ActivationReason))); @@ -50,13 +53,16 @@ SystrayNotificationBackend::SystrayNotificationBackend(QObject *parent) updateToolTip(); } -void SystrayNotificationBackend::notify(const Notification ¬ification) { - if(notification.type != Highlight && notification.type != PrivMsg) +void SystrayNotificationBackend::notify(const Notification &n) { + if(n.type != Highlight && n.type != PrivMsg) return; - _notifications.append(notification); - if(_showBubble) - showBubble(); + _notifications.append(n); + if(_showBubble) { + QString title = Client::networkModel()->networkName(n.bufferId) + " - " + Client::networkModel()->bufferName(n.bufferId); + QString message = QString("<%1> %2").arg(n.sender, n.message); + QtUi::mainWindow()->systemTray()->showMessage(title, message, SystemTray::Information, 10000, n.notificationId); + } if(_animate) QtUi::mainWindow()->systemTray()->setAlert(true); @@ -73,7 +79,7 @@ void SystrayNotificationBackend::close(uint notificationId) { ++i; } - closeBubble(); + QtUi::mainWindow()->systemTray()->closeMessage(notificationId); if(!_notifications.count()) QtUi::mainWindow()->systemTray()->setAlert(false); @@ -81,30 +87,13 @@ void SystrayNotificationBackend::close(uint notificationId) { updateToolTip(); } -void SystrayNotificationBackend::showBubble() { - // fancy stuff later: show messages in order - // for now, we just show the last message - if(_notifications.isEmpty()) - return; - Notification n = _notifications.last(); - QString title = Client::networkModel()->networkName(n.bufferId) + " - " + Client::networkModel()->bufferName(n.bufferId); - QString message = QString("<%1> %2").arg(n.sender, n.message); - QtUi::mainWindow()->systemTray()->showMessage(title, message); -} - -void SystrayNotificationBackend::closeBubble() { - // there really seems to be no sane way to close the bubble... :( -#ifdef Q_WS_X11 - QtUi::mainWindow()->systemTray()->showMessage("", "", SystemTray::NoIcon, 1); -#endif -} - -void SystrayNotificationBackend::notificationActivated() { +void SystrayNotificationBackend::notificationActivated(uint notificationId) { if(!_blockActivation) { if(QtUi::mainWindow()->systemTray()->isAlerted()) { _blockActivation = true; // prevent double activation because both tray icon and bubble might send a signal - uint id = _notifications.count()? _notifications.last().notificationId : 0; - emit activated(id); + if(!notificationId) + notificationId = _notifications.count()? _notifications.last().notificationId : 0; + emit activated(notificationId); } else GraphicalUi::toggleMainWidget(); } @@ -112,7 +101,7 @@ void SystrayNotificationBackend::notificationActivated() { void SystrayNotificationBackend::notificationActivated(SystemTray::ActivationReason reason) { if(reason == SystemTray::Trigger) { - notificationActivated(); + notificationActivated(0); } } diff --git a/src/qtui/systraynotificationbackend.h b/src/qtui/systraynotificationbackend.h index 4c8ff79b..3a685337 100644 --- a/src/qtui/systraynotificationbackend.h +++ b/src/qtui/systraynotificationbackend.h @@ -41,9 +41,7 @@ protected: virtual bool eventFilter(QObject *obj, QEvent *event); private slots: - void showBubble(); - void closeBubble(); - void notificationActivated(); + void notificationActivated(uint notificationId); void notificationActivated(SystemTray::ActivationReason); void animateChanged(const QVariant &); diff --git a/src/qtui/ui/desktopnotificationconfigwidget.ui b/src/qtui/ui/desktopnotificationconfigwidget.ui deleted file mode 100644 index a26b69f4..00000000 --- a/src/qtui/ui/desktopnotificationconfigwidget.ui +++ /dev/null @@ -1,216 +0,0 @@ - - - DesktopNotificationConfigWidget - - - - 0 - 0 - 435 - 144 - - - - Form - - - - - - Desktop Notification (via D-Bus) - - - true - - - false - - - - - - - - Timeout: - - - true - - - - - - - - - - s - - - 1 - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Position hint: - - - - - - - false - - - px - - - X: - - - 9999 - - - - - - - false - - - px - - - Y: - - - 9999 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Queue unread notifications - - - true - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - enabled - useTimeout - timeout - useHints - xHint - yHint - queueNotifications - - - - - useHints - toggled(bool) - xHint - setEnabled(bool) - - - 92 - 82 - - - 156 - 82 - - - - - useHints - toggled(bool) - yHint - setEnabled(bool) - - - 51 - 78 - - - 262 - 83 - - - - - useTimeout - toggled(bool) - timeout - setEnabled(bool) - - - 58 - 50 - - - 128 - 51 - - - - - -- 2.20.1