[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    [PATCH] Detecting notification popup server capabilities
From:       Aurélien_Gâteau <aurelien.gateau () canonical ! com>
Date:       2009-08-28 14:01:55
Message-ID: 4A97E353.7040504 () canonical ! com
[Download RAW message or body]

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

["0001-Added-a-DBus-adaptor-to-NotifyByPopup-so-that-applica.diff" (text/x-diff)]

From 94092422de9e7535b046736a555a95f7d305f187 Mon Sep 17 00:00:00 2001
From: Aurelien Gateau <aurelien.gateau@canonical.com>
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<NotifyByPopup*>(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 <QDBusAbstractAdaptor>
 #include <QMap>
 #include <QHash>
 
@@ -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<int, KPassivePopup * > m_popups;
 		// the y coordinate of the next position popup should appears
@@ -87,4 +94,18 @@ class NotifyByPopup : public KNotifyPlugin
 		QHash<int,uint> 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


["0001-New-method-popupServerCapabilities.diff" (text/x-diff)]

From f6cd930732b13cb64eab796b3122787826948912 Mon Sep 17 00:00:00 2001
From: Aurelien Gateau <aurelien.gateau@canonical.com>
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 <klocale.h>
 
 typedef QHash<QString,QString> Dict;
+typedef QHash<QString,KNotification::PopupServerCapability> CapabilityDict;
 
 struct KNotificationManager::Private
 {
     QHash<int , KNotification*> 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<QStringList> 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



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic