From kde-core-devel Fri Aug 28 14:01:55 2009 From: =?ISO-8859-1?Q?Aur=E9lien_G=E2teau?= Date: Fri, 28 Aug 2009 14:01:55 +0000 To: kde-core-devel Subject: [PATCH] Detecting notification popup server capabilities Message-Id: <4A97E353.7040504 () canonical ! com> X-MARC-Message: https://marc.info/?l=kde-core-devel&m=125146818810377 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--------------060902030905080508060105" This is a multi-part message in MIME format. --------------060902030905080508060105 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Hi, As you (may) know, KDE visual notifications (aka popup or bubbles) are now using FreeDesktop notification spec, this makes it possible for a GNOME app running on KDE to have its notifications displayed by Plasma, or for a KDE app running on GNOME to have its notifications displayed by notification-daemon (the original implementation) or notify-osd (Ubuntu implemention of the spec). You may also know that notify-osd is (in)famous for not supporting notification with actions. A side effect of this is that KDE applications running on a desktop which uses notify-osd now gets ugly dialog boxes whenever they try to show a notification with actions. The attached patches add a new static method to KNotification: popupServerCapabilities(). This method makes it possible for KDE applications to check what the notification server supports and act accordingly. What do you think about them? Can they go in? Aurélien --------------060902030905080508060105 Content-Type: text/x-diff; name="0001-Added-a-DBus-adaptor-to-NotifyByPopup-so-that-applica.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename*0="0001-Added-a-DBus-adaptor-to-NotifyByPopup-so-that-applica.d"; filename*1="iff" From 94092422de9e7535b046736a555a95f7d305f187 Mon Sep 17 00:00:00 2001 From: Aurelien Gateau Date: Thu, 27 Aug 2009 17:50:58 +0200 Subject: [PATCH] Added a DBus adaptor to NotifyByPopup, so that applications can check the capabilities of the popup notification server --- runtime/knotify/notifybypopup.cpp | 36 ++++++++++++++++++++++++++++++++++++ runtime/knotify/notifybypopup.h | 21 +++++++++++++++++++++ 2 files changed, 57 insertions(+), 0 deletions(-) diff --git a/runtime/knotify/notifybypopup.cpp b/runtime/knotify/notifybypopup.cpp index 91c9fee..57b6cf8 100644 --- a/runtime/knotify/notifybypopup.cpp +++ b/runtime/knotify/notifybypopup.cpp @@ -46,6 +46,9 @@ static const char dbusPath[] = "/org/freedesktop/Notifications"; NotifyByPopup::NotifyByPopup(QObject *parent) : KNotifyPlugin(parent) , m_animationTimer(0), m_dbusServiceExists(false) { + new NotifyByPopupAdaptor(this); + QDBusConnection::sessionBus().registerObject("/NotifyByPopup", this); + QRect screen = QApplication::desktop()->availableGeometry(); m_nextPosition = screen.top(); @@ -292,6 +295,8 @@ void NotifyByPopup::slotServiceOwnerChanged( const QString & serviceName, kWarning(300) << "warning: failed to connect to NotificationClosed dbus signal"; } } + + emit popupServerChanged(); } } @@ -435,4 +440,35 @@ void NotifyByPopup::closeNotificationDBus(int id) } +QStringList NotifyByPopup::popupServerCapabilities() const +{ + if (!m_dbusServiceExists) { + // Return capabilities of the KPassivePopup implementation + return QStringList() << "actions" << "body" << "body-hyperlinks" << "body-markup"; + } + QDBusMessage m = QDBusMessage::createMethodCall( dbusServiceName, dbusPath, dbusInterfaceName, "GetCapabilities" ); + QDBusMessage replyMsg = QDBusConnection::sessionBus().call(m); + if(replyMsg.type() != QDBusMessage::ReplyMessage) { + kWarning(300) << "Error while calling popup server GetCapabilities()"; + return QStringList(); + } + + if (replyMsg.arguments().isEmpty()) { + kWarning(300) << "popup server GetCapabilities() returned an empty reply"; + return QStringList(); + } + + return replyMsg.arguments().at(0).toStringList(); +} + +NotifyByPopupAdaptor::NotifyByPopupAdaptor(QObject *parent) +: QDBusAbstractAdaptor(parent) +{ + setAutoRelaySignals(true); +} + +QStringList NotifyByPopupAdaptor::popupServerCapabilities() const +{ + return static_cast(parent())->popupServerCapabilities(); +} #include "notifybypopup.moc" diff --git a/runtime/knotify/notifybypopup.h b/runtime/knotify/notifybypopup.h index 6e7fc1d..80ed5e0 100644 --- a/runtime/knotify/notifybypopup.h +++ b/runtime/knotify/notifybypopup.h @@ -23,6 +23,7 @@ #define NOTIFYBYPOPUP_H #include "knotifyplugin.h" +#include #include #include @@ -38,6 +39,12 @@ class NotifyByPopup : public KNotifyPlugin virtual void notify(int id , KNotifyConfig *config); virtual void close( int id ); virtual void update(int id, KNotifyConfig *config); + + QStringList popupServerCapabilities() const; + + Q_SIGNALS: + void popupServerChanged(); + private: QMap m_popups; // the y coordinate of the next position popup should appears @@ -87,4 +94,18 @@ class NotifyByPopup : public KNotifyPlugin QHash m_idMap; }; +class NotifyByPopupAdaptor : public QDBusAbstractAdaptor +{ Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.NotifyByPopup") + +public: + NotifyByPopupAdaptor(QObject *); + +public Q_SLOTS: + QStringList popupServerCapabilities() const; + +Q_SIGNALS: + void popupServerChanged(); +}; + #endif -- 1.6.3.3 --------------060902030905080508060105 Content-Type: text/x-diff; name="0001-New-method-popupServerCapabilities.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="0001-New-method-popupServerCapabilities.diff" From f6cd930732b13cb64eab796b3122787826948912 Mon Sep 17 00:00:00 2001 From: Aurelien Gateau Date: Fri, 28 Aug 2009 15:35:13 +0200 Subject: [PATCH] New method: popupServerCapabilities() Makes it possible to check what the server implementing the FreeDesktop.org notification spec can handle. --- kdeui/util/knotification.cpp | 4 ++ kdeui/util/knotification.h | 43 +++++++++++++++++++++++++ kdeui/util/knotificationmanager.cpp | 59 ++++++++++++++++++++++++++++++++++- kdeui/util/knotificationmanager_p.h | 9 +++++ 4 files changed, 114 insertions(+), 1 deletions(-) diff --git a/kdeui/util/knotification.cpp b/kdeui/util/knotification.cpp index 59832c1..b8c007d 100644 --- a/kdeui/util/knotification.cpp +++ b/kdeui/util/knotification.cpp @@ -417,5 +417,9 @@ bool KNotification::eventFilter( QObject * watched, QEvent * event ) return false; } +KNotification::PopupServerCapabilities KNotification::popupServerCapabilities() +{ + return KNotificationManager::self()->popupServerCapabilities(); +} #include "knotification.moc" diff --git a/kdeui/util/knotification.h b/kdeui/util/knotification.h index 22c0d1e..1a31c84 100644 --- a/kdeui/util/knotification.h +++ b/kdeui/util/knotification.h @@ -255,6 +255,38 @@ public: */ enum StandardEvent { Notification , Warning , Error , Catastrophe }; + /** + * What the popup notification server is capable of doing + */ + enum PopupServerCapability + { + /** + * The server can show actions + */ + ActionCapability = 1<<0, + + /** + * The server can show a text in addition to a title. Some + * implementations may only show the title (for instance, onscreen + * displays, marquee/scrollers) + */ + TextCapability = 1<<1, + + /** + * The server supports hyperlinks in the notifications. + */ + HyperLinkCapability = 1<<2, + + /** + * Supports markup in the text. If marked up text is sent to a server + * that does not give this cap, the markup will show through as regular + * text so must be stripped clientside. + */ + MarkupCapability = 1<<3 + }; + + Q_DECLARE_FLAGS(PopupServerCapabilities, PopupServerCapability) + /** * Create a new notification. * @@ -567,11 +599,22 @@ public: * @param widget the widget the notification refers to */ static void beep( const QString& reason = QString() , QWidget *widget=0L); + + /** + * What is the popup notification server capable of showing. + * + * To ensure better cross-desktop integrations, applications should check + * whether a capability is available before using it. + * + * @since 4.4 + */ + static PopupServerCapabilities popupServerCapabilities(); //prevent warning using QObject::event; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KNotification::NotificationFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(KNotification::PopupServerCapabilities) #endif diff --git a/kdeui/util/knotificationmanager.cpp b/kdeui/util/knotificationmanager.cpp index 01cffd8..efa1df3 100644 --- a/kdeui/util/knotificationmanager.cpp +++ b/kdeui/util/knotificationmanager.cpp @@ -32,13 +32,52 @@ #include typedef QHash Dict; +typedef QHash CapabilityDict; struct KNotificationManager::Private { QHash notifications; QDBusInterface *knotify; + QDBusInterface *notifyByPopup; + bool popupServerCapabilitiesInitialized; + KNotification::PopupServerCapabilities popupServerCapabilities; + + void initPopupServerCapabilities(); }; +void KNotificationManager::Private::initPopupServerCapabilities() +{ + if (popupServerCapabilitiesInitialized) { + return; + } + + static CapabilityDict translator; + if (translator.isEmpty()) { + translator.insert("actions" , KNotification::ActionCapability); + translator.insert("body" , KNotification::TextCapability); + translator.insert("body-hyperlinks" , KNotification::HyperLinkCapability); + translator.insert("body-markup" , KNotification::MarkupCapability); + } + + popupServerCapabilities = 0; + + QDBusReply reply = notifyByPopup->call("popupServerCapabilities"); + if (notifyByPopup->lastError().isValid()) { + kWarning() << "Error asking popupServerCapabilities():" << notifyByPopup->lastError().message(); + return; + } + + CapabilityDict::ConstIterator end = translator.end(); + foreach(const QString& str, reply.value()) { + CapabilityDict::ConstIterator it = translator.find(str); + if (it != end) { + popupServerCapabilities |= it.value(); + } + } + + popupServerCapabilitiesInitialized = true; +} + KNotificationManager * KNotificationManager::self() { K_GLOBAL_STATIC(KNotificationManager, s_self) @@ -49,6 +88,8 @@ KNotificationManager * KNotificationManager::self() KNotificationManager::KNotificationManager() : d(new Private) { + d->popupServerCapabilitiesInitialized = false; + d->popupServerCapabilities = 0; if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.knotify")) { QString error; int ret = KToolInvocation::startServiceByDesktopPath("knotify4.desktop", @@ -67,13 +108,19 @@ KNotificationManager::KNotificationManager() QLatin1String("org.kde.KNotify"), QLatin1String("notificationActivated"), this, SLOT(notificationActivated(int,int))); - + d->notifyByPopup = + new QDBusInterface(QLatin1String("org.kde.knotify"), QLatin1String("/NotifyByPopup"), QLatin1String("org.kde.NotifyByPopup"), QDBusConnection::sessionBus(), this); + d->notifyByPopup->connection().connect(QLatin1String("org.kde.knotify"), QLatin1String("/NotifyByPopup"), + QLatin1String("org.kde.NotifyByPopup"), + QLatin1String("popupServerChanged"), + this, SLOT(popupServerChanged())); } KNotificationManager::~KNotificationManager() { delete d->knotify; + delete d->notifyByPopup; delete d; } @@ -179,5 +226,15 @@ void KNotificationManager::reemit(KNotification * n, int id) d->knotify->call(QDBus::NoBlock, "reemit", id, contextList); } +KNotification::PopupServerCapabilities KNotificationManager::popupServerCapabilities() const +{ + d->initPopupServerCapabilities(); + return d->popupServerCapabilities; +} + +void KNotificationManager::popupServerChanged() +{ + d->popupServerCapabilitiesInitialized = false; +} #include "knotificationmanager_p.moc" diff --git a/kdeui/util/knotificationmanager_p.h b/kdeui/util/knotificationmanager_p.h index 2500abc..f263417 100644 --- a/kdeui/util/knotificationmanager_p.h +++ b/kdeui/util/knotificationmanager_p.h @@ -66,9 +66,18 @@ public: */ void reemit(KNotification *n, int id); + /** + * What is the popup notification server capable of showing. + * + * To ensure better cross-desktop integration, applications should check + * whether a capability is available before using it. + */ + KNotification::PopupServerCapabilities popupServerCapabilities() const; + private Q_SLOTS: void notificationClosed( int id ); void notificationActivated( int id, int action); + void popupServerChanged(); private: struct Private; -- 1.6.3.3 --------------060902030905080508060105--