[sip-comm-dev] Issue #588: Use libnotify when available for notifications

Hello Linux-loving devs,

As you've probably notices on the commits mailing list, yesterday I
added the initial implementation of notification popups using
freedesktop.org's Desktop Notifications in r6183.

Emil thought I should announce it here as well because the request
originally came from Sébastien Mazy (smazy) so the chances are that
there are other Linux developers interested in test driving it.

I'm personally very satisfied with these new notifications. I only
added the basic support for PopupMessage title and message because I
wanted to see whether it was going to work and I didn't have enough
time this weekend to implement the display of icons and the
mouse-click detection. It looks like these two missing features will
be possible to implement so the expectation is to have them added at a
later time.

I'm not sure though I'll be able to focus on them in the coming weeks
so please feel free to not only test the current implementation but
also expand it in any way you see fit including by adding the two
missing features mentioned above.

Regards,
Lubomir

···

On Sun, Oct 25, 2009 at 2:58 PM, <lubomir_m@dev.java.net> wrote:

Author: lubomir_m
Date: 2009-10-25 12:58:30+0000
New Revision: 6183

Added:
trunk/lib/native/linux/libgalagonotification.so (contents, props changed)
trunk/src/native/linux/galagonotification/
trunk/src/native/linux/galagonotification/Makefile
trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.c
trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.h
trunk/src/net/java/sip/communicator/impl/galagonotification/
trunk/src/net/java/sip/communicator/impl/galagonotification/DBusException.java
trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotification.java
trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotificationActivator.java
trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoPopupMessageHandler.java
trunk/src/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf
Modified:
trunk/build.xml
trunk/resources/languages/resources.properties

Log:
Introduces an initial implementation of notification popups on Linux using freedesktop.org's Desktop Notifications through the native libdbus library. The committed code represents work in progress and does not support images, click reporting back to the Java code, matching notifications to Java components. That's why the introduced galagonotification bundle is built in build.xml but not started in felix.client.run.properties.

Modified: trunk/build.xml
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/build.xml?view=diff&rev=6183&p1=trunk/build.xml&p2=trunk/build.xml&r1=6182&r2=6183

--- trunk/build.xml (original)
+++ trunk/build.xml 2009-10-25 12:58:30+0000
@@ -799,8 +799,8 @@
bundle-plugin-msnaccregwizz,bundle-plugin-sipaccregwizz,
bundle-plugin-yahooaccregwizz,bundle-plugin-aimaccregwizz,
bundle-version,bundle-version-impl,bundle-shutdown-timeout,
- bundle-growlnotification,bundle-swingnotification,bundle-sparkle,
- bundle-plugin-branding,
+ bundle-growlnotification,bundle-swingnotification,bundle-galagonotification,
+ bundle-sparkle, bundle-plugin-branding,
bundle-osdependent,bundle-browserlauncher,bundle-gibberish,
bundle-gibberish-slick,bundle-plugin-gibberishaccregwizz,
bundle-plugin-call-history-form,
@@ -1058,6 +1058,8 @@
prefix="net/java/sip/communicator/impl/media/codec/audio"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/codec/video&quot; prefix=&quot;net/java/sip/communicator/impl/media/codec/video&quot;/&gt; \+ &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/conference"
+ prefix="net/java/sip/communicator/impl/media/conference"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/protocol&quot; prefix=&quot;net/java/sip/communicator/impl/media/protocol&quot;/&gt; &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/renderer"
@@ -1092,6 +1094,8 @@
prefix="net/java/sip/communicator/impl/media/codec/audio"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/codec/video&quot; prefix=&quot;net/java/sip/communicator/impl/media/codec/video&quot;/&gt; \+ &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/conference"
+ prefix="net/java/sip/communicator/impl/media/conference"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/protocol&quot; prefix=&quot;net/java/sip/communicator/impl/media/protocol&quot;/&gt; &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/renderer"
@@ -1125,6 +1129,8 @@
prefix="net/java/sip/communicator/impl/media/codec/audio"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/codec/video&quot; prefix=&quot;net/java/sip/communicator/impl/media/codec/video&quot;/&gt; \+ &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/conference"
+ prefix="net/java/sip/communicator/impl/media/conference"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/protocol&quot; prefix=&quot;net/java/sip/communicator/impl/media/protocol&quot;/&gt; &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/renderer"
@@ -1650,6 +1656,16 @@
</jar>
</target>

+ <!--BUNDLE-GALAGONOTIFICATION-->
+ <target name="bundle-galagonotification">
+ <!-- Creates a bundle for the galagonotification plugin. -->
+ <jar compress="false" destfile="\{bundles\.dest\.lin\}/galagonotification\.jar&quot; \+ manifest=&quot;{src}/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf">
+ <zipfileset dir="\{dest\}/net/java/sip/communicator/impl/galagonotification&quot; \+ prefix=&quot;net/java/sip/communicator/impl/galagonotification&quot; /&gt; \+ &lt;/jar&gt; \+ &lt;/target&gt; \+ &lt;\!\-\-BUNDLE\-POPUPMESSAGEHANDLER\-SLICK\-\-&gt; &lt;target name=&quot;bundle\-popupmessagehandler\-slick&quot;&gt; &lt;jar compress=&quot;false&quot; destfile=&quot;{bundles.dest}/popupmessagehandler-slick.jar"

Added: trunk/lib/native/linux/libgalagonotification.so
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/lib/native/linux/libgalagonotification.so?view=auto&rev=6183

Binary file. No diff available.

Modified: trunk/resources/languages/resources.properties
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/resources/languages/resources.properties?view=diff&rev=6183&p1=trunk/resources/languages/resources.properties&p2=trunk/resources/languages/resources.properties&r1=6182&r2=6183

--- trunk/resources/languages/resources.properties (original)
+++ trunk/resources/languages/resources.properties 2009-10-25 12:58:30+0000
@@ -402,6 +402,7 @@
impl.systray.POPUP_MESSAGE_HANDLER=Systray balloon messages
impl.swingnotification.POPUP_MESSAGE_HANDLER=SIP Communicator popups
impl.growlnotification.POPUP_MESSAGE_HANDLER=Growl notifications
+impl.galagonotification.POPUP_MESSAGE_HANDLER=freedesktop.org Desktop Notifications

# New Account Dialog
impl.gui.main.account.DEFAULT_PAGE_TITLE=Select Network

Added: trunk/src/native/linux/galagonotification/Makefile
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/native/linux/galagonotification/Makefile?view=auto&rev=6183

--- (empty file)
+++ trunk/src/native/linux/galagonotification/Makefile 2009-10-25 12:58:30+0000
@@ -0,0 +1,15 @@
+JAVA_HOME?=/usr/lib/jvm/java-6-sun
+
+ARCH=\(shell uname \-m | sed \-e s/x86\_64/\-64/ \-e s/i\.86//\) \+TARGET=\.\./\.\./\.\./\.\./lib/native/linux(ARCH)/libgalagonotification.so
+
+CC=gcc
+CPPFLAGS=-DJNI_IMPLEMENTATION \
+ -Wall -Wreturn-type \
+ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \
+ \(shell pkg\-config \-\-cflags dbus\-1\) \+LDFLAGS=\-shared \+LIBS=(shell pkg-config --libs dbus-1)
+
+\(TARGET\): net\_java\_sip\_communicator\_impl\_galagonotification\_GalagoNotification\.c net\_java\_sip\_communicator\_impl\_galagonotification\_GalagoNotification\.h \+ (CC) \(CPPFLAGS\) < \(LDFLAGS\) \-o @ $(LIBS)

Added: trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.c
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.c?view=auto&rev=6183

--- (empty file)
+++ trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.c 2009-10-25 12:58:30+0000
@@ -0,0 +1,292 @@
+#include "net_java_sip_communicator_impl_galagonotification_GalagoNotification.h"
+
+#include <dbus/dbus.h>
+
+static dbus_bool_t
+GalagoNotification_messageAppendString(
+ JNIEnv *env, DBusMessageIter *iter, jstring jstr)
+{
+ const jbyte *str;
+ dbus_bool_t success;
+ const char *emptyStr = "";
+
+ if (jstr)
+ {
+ str = (*env)->GetStringUTFChars(env, jstr, NULL);
+ if (!str)
+ return FALSE;
+ }
+ else
+ str = NULL;
+ success
+ = dbus_message_iter_append_basic(
+ iter,
+ DBUS_TYPE_STRING,
+ str ? &str : &emptyStr);
+ if (str)
+ (*env)->ReleaseStringUTFChars(env, jstr, str);
+ return success;
+}
+
+static dbus_bool_t
+GalagoNotification_notifyAppendArgs(
+ JNIEnv *env, DBusMessage *message, jstring appName, jlong replacesId,
+ jstring appIcon, jstring summary, jstring body)
+{
+ DBusMessageIter iter;
+ dbus_uint32_t _replacesId;
+ DBusMessageIter subIter;
+ dbus_int32_t _expireTimeout;
+
+ dbus_message_iter_init_append(message, &iter);
+
+ if (!GalagoNotification_messageAppendString(env, &iter, appName))
+ return FALSE;
+
+ _replacesId = replacesId;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &_replacesId))
+ return FALSE;
+
+ if (!GalagoNotification_messageAppendString(env, &iter, appIcon))
+ return FALSE;
+
+ if (!GalagoNotification_messageAppendString(env, &iter, summary))
+ return FALSE;
+
+ if (!GalagoNotification_messageAppendString(env, &iter, body))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(
+ &iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING,
+ &subIter))
+ return FALSE;
+ if (!dbus_message_iter_close_container(&iter, &subIter))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(
+ &iter,
+ DBUS_TYPE_ARRAY,
+ "{sv}",
+ &subIter))
+ return FALSE;
+ if (!dbus_message_iter_close_container(&iter, &subIter))
+ return FALSE;
+
+ _expireTimeout = -1;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &_expireTimeout))
+ return FALSE;
+
+ return TRUE;
+}
+
+static jobjectArray
+GalagoNotification_stringArray2jstringArray(
+ JNIEnv *env, char **stringArray, int stringArraySize)
+{
+ jclass stringClass;
+ jobjectArray jstringArray;
+
+ stringClass = (*env)->FindClass(env, "java/lang/String");
+ if (stringClass)
+ {
+ jstringArray
+ = (*env)->NewObjectArray(env, stringArraySize, stringClass, NULL);
+ if (jstringArray)
+ {
+ int i;
+
+ for (i = 0; i < stringArraySize; i++)
+ {
+ jstring jstr = (*env)->NewStringUTF(env, *(stringArray + i));
+
+ if (jstr)
+ {
+ (*env)->SetObjectArrayElement(env, jstringArray, i, jstr);
+ if ((*env)->ExceptionCheck(env))
+ {
+ jstringArray = NULL;
+ break;
+ }
+ }
+ else
+ {
+ jstringArray = NULL;
+ break;
+ }
+ }
+ }
+ }
+ else
+ jstringArray = NULL;
+ return jstringArray;
+}
+
+static void
+GalagoNotification_throwException(JNIEnv *env, DBusError *error)
+{
+ /* TODO Auto-generated method stub */
+ jclass clazz
+ = (*env)
+ ->FindClass(
+ env,
+ "net/java/sip/communicator/impl/galagonotification/DBusException");
+
+ if (clazz)
+ (*env)->ThrowNew(env, clazz, error->message);
+}
+
+JNIEXPORT jlong JNICALL
+Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_dbus_1bus_1get_1session(
+ JNIEnv *env, jclass clazz)
+{
+ DBusError error;
+ DBusConnection *connection;
+
+ dbus_error_init(&error);
+ connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
+
+ if (connection)
+ dbus_connection_set_exit_on_disconnect(connection, FALSE);
+ else if (dbus_error_is_set(&error))
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ return connection;
+}
+
+JNIEXPORT void JNICALL
+Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_dbus_1connection_1unref(
+ JNIEnv *env, jclass clazz, jlong connection)
+{
+ dbus_connection_unref((DBusConnection *) connection);
+}
+
+JNIEXPORT jobjectArray JNICALL
+Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_getCapabilities(
+ JNIEnv *env, jclass clazz, jlong connection)
+{
+ DBusMessage *message;
+ jobjectArray jcapabilities = NULL;
+
+ message
+ = dbus_message_new_method_call(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications",
+ "GetCapabilities");
+ if (message)
+ {
+ DBusError error;
+ DBusMessage *reply;
+
+ dbus_error_init(&error);
+ reply
+ = dbus_connection_send_with_reply_and_block(
+ (DBusConnection *) connection,
+ message,
+ -1,
+ &error);
+ if (reply)
+ {
+ char **capabilities;
+ int capabilityCount;
+
+ if (dbus_message_get_args(
+ reply,
+ &error,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING,
+ &capabilities,
+ &capabilityCount,
+ DBUS_TYPE_INVALID))
+ {
+ jcapabilities
+ = GalagoNotification_stringArray2jstringArray(
+ env,
+ capabilities,
+ capabilityCount);
+ dbus_free_string_array(capabilities);
+ }
+ else
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ dbus_message_unref(reply);
+ }
+ else if (dbus_error_is_set(&error))
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ dbus_message_unref(message);
+ }
+ return jcapabilities;
+}
+
+JNIEXPORT jlong JNICALL
+Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_notify(
+ JNIEnv *env, jclass clazz, jlong connection, jstring appName,
+ jlong replacesId, jstring appIcon, jstring summary, jstring body)
+{
+ DBusMessage *message;
+ jlong jid = 0;
+
+ message
+ = dbus_message_new_method_call(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications",
+ "Notify");
+ if (message)
+ {
+ if (GalagoNotification_notifyAppendArgs(
+ env,
+ message,
+ appName,
+ replacesId,
+ appIcon,
+ summary,
+ body))
+ {
+ DBusError error;
+ DBusMessage *reply;
+
+ dbus_error_init(&error);
+ reply
+ = dbus_connection_send_with_reply_and_block(
+ (DBusConnection *) connection,
+ message,
+ -1,
+ &error);
+ if (reply)
+ {
+ dbus_uint32_t id;
+
+ if (dbus_message_get_args(
+ reply,
+ &error,
+ DBUS_TYPE_UINT32,
+ &id,
+ DBUS_TYPE_INVALID))
+ jid = id;
+ else
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ dbus_message_unref(reply);
+ }
+ else if (dbus_error_is_set(&error))
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ }
+ dbus_message_unref(message);
+ }
+ return jid;
+}

Added: trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.h
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.h?view=auto&rev=6183

--- (empty file)
+++ trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.h 2009-10-25 12:58:30+0000
@@ -0,0 +1,45 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class net_java_sip_communicator_impl_galagonotification_GalagoNotification */
+
+#ifndef _Included_net_java_sip_communicator_impl_galagonotification_GalagoNotification
+#define _Included_net_java_sip_communicator_impl_galagonotification_GalagoNotification
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: net_java_sip_communicator_impl_galagonotification_GalagoNotification
+ * Method: dbus_bus_get_session
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_dbus_1bus_1get_1session
+ (JNIEnv *, jclass);
+
+/*
+ * Class: net_java_sip_communicator_impl_galagonotification_GalagoNotification
+ * Method: dbus_connection_unref
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_dbus_1connection_1unref
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: net_java_sip_communicator_impl_galagonotification_GalagoNotification
+ * Method: getCapabilities
+ * Signature: (J)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_getCapabilities
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: net_java_sip_communicator_impl_galagonotification_GalagoNotification
+ * Method: notify
+ * Signature: (JLjava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_notify
+ (JNIEnv *, jclass, jlong, jstring, jlong, jstring, jstring, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/DBusException.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/DBusException.java?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/DBusException.java 2009-10-25 12:58:30+0000
@@ -0,0 +1,30 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.galagonotification;
+
+/**
+ * Implements <tt>Exception</tt> for D-Bus errors reported through the native
+ * <tt>DBusError</tt> structure.
+ *
+ * @author Lubomir Marinov
+ */
+public class DBusException
+ extends Exception
+{
+
+ /**
+ * Initializes a new <tt>DBusException</tt> instance with the specified
+ * detail message.
+ *
+ * @param message the detail message to later be reported by the new
+ * instance through its {@link #getMessage()}
+ */
+ public DBusException(String message)
+ {
+ super(message);
+ }
+}

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotification.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotification.java?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotification.java 2009-10-25 12:58:30+0000
@@ -0,0 +1,95 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.galagonotification;
+
+/**
+ * Declares the native functions required by the galagonotification bundle.
+ *
+ * @author Lubomir Marinov
+ */
+public final class GalagoNotification
+{
+ static
+ {
+ System.loadLibrary("galagonotification");
+ }
+
+ /**
+ * Connects to the <tt>DBUS_BUS_SESSION</tt> D-Bus bus daemon and registers
+ * with it.
+ *
+ * @return a new reference to a <tt>DBusConnection</tt> to the
+ * <tt>DBUS_BUS_SESSION</tt> D-Bus bus daemon
+ * @throws DBusException if connecting to and registering with the
+ * <tt>DBUS_BUS_SESSION</tt> D-Bus bus daemon fails
+ */
+ public static native long dbus_bus_get_session()
+ throws DBusException;
+
+ /**
+ * Decrements the reference count of the specified <tt>DBusConnection</tt>
+ * and finalizes it if the count reaches zero.
+ *
+ * @param connection the <tt>DBusConnection</tt> to decrement the reference
+ * count of
+ */
+ public static native void dbus_connection_unref(long connection);
+
+ /**
+ * Invokes <tt>org.freedesktop.Notifications.GetCapabilities</tt> through
+ * the specified <tt>DBusConnection</tt> in order to retrieve the optional
+ * capabilities supported by the freedesktop.org Desktop Notifications
+ * server.
+ *
+ * @param connection the <tt>DBusConnection</tt> with the freedesktop.org
+ * Desktop Notifications server
+ * @return an array of <tt>String</tt>s listing the optional capabilities
+ * supported by the freedesktop.org Desktop Notifications server
+ * @throws DBusException if retrieving the optional capabilities of the
+ * freedesktop.org Desktop Notifications server fails
+ */
+ public static native String[] getCapabilities(long connection)
+ throws DBusException;
+
+ /**
+ * Invokes <tt>org.freedesktop.Notifications.Notify</tt> through the
+ * specified <tt>DBusConnection</tt> in order to send a notification to the
+ * freedesktop.org Desktop Notifications server.
+ *
+ * @param connection the <tt>DBusConnection</tt> with the freedesktop.org
+ * Desktop Notifications server
+ * @param appName the optional name of the application sending the
+ * notification
+ * @param replacesId the optional notification identifier of an existing
+ * notification to be replaced by the notification being sent; <tt>0</tt> to
+ * not replace any existing notification
+ * @param appIcon the optional program icon of the application sending the
+ * notification. Not supported at this time.
+ * @param summary the summary text briefly describing the notification
+ * @param body the optional detailed body text of the notification
+ * @return the unique identifier of the sent notification if
+ * <tt>replacesId</tt> is <tt>0</tt>; <tt>replacesId</tt> if
+ * <tt>replacesId</tt> is not <tt>0</tt>
+ * @throws DBusException if sending the notification to the freedesktop.org
+ * Desktop Notifications server fails
+ */
+ public static native long notify(
+ long connection,
+ String appName,
+ long replacesId,
+ String appIcon,
+ String summary,
+ String body)
+ throws DBusException;
+
+ /**
+ * Prevents the creation of <tt>GalagoNotification</tt> instances.
+ */
+ private GalagoNotification()
+ {
+ }
+}

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotificationActivator.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotificationActivator.java?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotificationActivator.java 2009-10-25 12:58:30+0000
@@ -0,0 +1,159 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.galagonotification;
+
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.service.systray.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * Implements <tt>BundleActivator</tt> for the galagonotification bundle which
+ * provides an implementation of <tt>PopupMessageHandler</tt> according to the
+ * freedesktop.org Desktop Notifications spec.
+ *
+ * @author Lubomir Marinov
+ */
+public class GalagoNotificationActivator
+ implements BundleActivator
+{
+
+ /**
+ * The <tt>Logger</tt> used by the <tt>GalagoNotificationActivator</tt>
+ * class and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(GalagoNotificationActivator.class);
+
+ /**
+ * The context in which the galagonotification bundle is executing.
+ */
+ private static BundleContext bundleContext;
+
+ /**
+ * The <tt>DBusConnection</tt> pointer to the D-Bus connection through which
+ * the freedesktop.org Desktop Notifications are being sent.
+ */
+ static long dbusConnection;
+
+ /**
+ * The resources such as internationalized and localized text and images
+ * used by the galagonotification bundle.
+ */
+ private static ResourceManagementService resources;
+
+ /**
+ * Gets the resources such as internationalized and localized text and
+ * images used by the galagonotification bundle.
+ *
+ * @return the resources such as internationalized and localized text and
+ * images used by the galagonotification bundle
+ */
+ public static ResourceManagementService getResources()
+ {
+ if (resources == null)
+ resources = ResourceManagementServiceUtils.getService(bundleContext);
+ return resources;
+ }
+
+ /**
+ * Starts the galagonotification bundle. Registers its
+ * <tt>PopupMessageHandler</tt> implementation if it is supported by the
+ * current operating system.
+ *
+ * @param bundleContext the context in which the galagonotification bundle
+ * is to execute
+ * @throws Exception if the <tt>PopupMessageHandler</tt> implementation of
+ * the galagonotification bundle is not supported by the current operating
+ * system
+ * @see BundleActivator#start(BundleContext)
+ */
+ public void start(BundleContext bundleContext)
+ throws Exception
+ {
+ long dbusConnection = GalagoNotification.dbus_bus_get_session();
+
+ if (dbusConnection != 0)
+ {
+
+ /*
+ * We don't much care about the very capabilities because they are
+ * optional, we just want to make sure that the service exists.
+ */
+ String[] capabilities
+ = GalagoNotification.getCapabilities(dbusConnection);
+
+ if (capabilities != null)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger
+ .debug(
+ "org.freedesktop.Notifications.GetCapabilities:");
+ for (String capability : capabilities)
+ logger.debug("\t" + capability);
+ }
+
+ /*
+ * The native counterpart may return null without throwing an
+ * exception even when it fails to retrieve the capabilities. So
+ * it will not be safe to use galagonotification in this case.
+ * It is also unclear whether the server will return null when
+ * it does not support any optional capabilities. So it's not
+ * totally safe to assume that null means that
+ * galagonotification cannot be used. Anyway, displaying only
+ * the message title may be insufficient for our purposes so
+ * we'll require the optional "body" capability and solve the
+ * above questions.
+ */
+ boolean bodyIsImplemented = false;
+
+ for (String capability : capabilities)
+ if ("body".equals(capability))
+ {
+ bodyIsImplemented = true;
+ break;
+ }
+ if (bodyIsImplemented)
+ {
+ GalagoNotificationActivator.bundleContext = bundleContext;
+ GalagoNotificationActivator.dbusConnection = dbusConnection;
+
+ bundleContext
+ .registerService(
+ PopupMessageHandler.class.getName(),
+ new GalagoPopupMessageHandler(),
+ null);
+ }
+ else
+ GalagoNotification.dbus_connection_unref(dbusConnection);
+ }
+ }
+ }
+
+ /**
+ * Stops the galagonotification bundle.
+ *
+ * @param bundleContext the context in which the galagonotification bundle
+ * is to stop its execution
+ * @throws Exception if there was an error during the stopping of the native
+ * functionality supporting the <tt>PopupNotificationHandler</tt>
+ * implementation of the galagonotification bundle
+ */
+ public void stop(BundleContext bundleContext)
+ throws Exception
+ {
+ if (dbusConnection != 0)
+ {
+ GalagoNotification.dbus_connection_unref(dbusConnection);
+ dbusConnection = 0;
+ }
+ if (bundleContext.equals(GalagoNotificationActivator.bundleContext))
+ GalagoNotificationActivator.bundleContext = null;
+ }
+}

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoPopupMessageHandler.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoPopupMessageHandler.java?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoPopupMessageHandler.java 2009-10-25 12:58:30+0000
@@ -0,0 +1,85 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.galagonotification;
+
+import net.java.sip.communicator.service.systray.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Implements <tt>PopupMessageHandler</tt> according to the freedesktop.org
+ * Desktop Notifications spec.
+ *
+ * @author Lubomir Marinov
+ */
+public class GalagoPopupMessageHandler
+ extends AbstractPopupMessageHandler
+{
+
+ /**
+ * The <tt>Logger</tt> used by the <tt>GalagoPopupMessageHandler</tt> class
+ * and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(GalagoPopupMessageHandler.class);
+
+ /**
+ * Returns the preference index of this <tt>PopupMessageHandler</tt> which
+ * indicates how many features it supports.
+ *
+ * @return the preference index of this <tt>PopupMessageHandler</tt> which
+ * indicates how many features it supports
+ * @see PopupMessageHandler#getPreferenceIndex()
+ */
+ public int getPreferenceIndex()
+ {
+ return 1; // using a native popup mechanism
+ }
+
+ /**
+ * Shows the title and the message of the specified <tt>PopupMessage</tt>.
+ *
+ * @param popupMessage the <tt>PopupMessage</tt> specifying the title and
+ * the message to be shown
+ * @see PopupMessageHandler#showPopupMessage(PopupMessage)
+ */
+ public void showPopupMessage(PopupMessage popupMessage)
+ {
+ try
+ {
+ GalagoNotification
+ .notify(
+ GalagoNotificationActivator.dbusConnection,
+ null,
+ 0,
+ null,
+ popupMessage.getMessageTitle(),
+ popupMessage.getMessage());
+ }
+ catch (DBusException dbe)
+ {
+ logger.error("Failed to show PopupMessage " + popupMessage, dbe);
+ }
+ }
+
+ /**
+ * Gets the human-readable localized description of this
+ * <tt>PopupMessageHandler</tt>.
+ *
+ * @return the human-readable localized description of this
+ * <tt>PopupMessageHandler</tt>
+ * @see PopupMessageHandler#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return
+ GalagoNotificationActivator
+ .getResources()
+ .getI18NString(
+ "impl.galagonotification.POPUP_MESSAGE_HANDLER");
+ }
+}

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf 2009-10-25 12:58:30+0000
@@ -0,0 +1,10 @@
+Bundle-Activator: net.java.sip.communicator.impl.galagonotification.GalagoNotificationActivator
+Bundle-Name: Desktop Notifications Provider
+Bundle-Description: A bundle which implements notifications according to the freedesktop.org Desktop Notifications spec.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Import-Package: net.java.sip.communicator.service.systray,
+ net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.util,
+ org.osgi.framework

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

Hi again,

To keep the thread on dev complete, I'm letting you here know that
r6201 implements the icon display in the notification popups on Linux
which use freedesktop.org's Desktop Notifications. Please feel free to
test them and report issues, make suggestions, etc.

Regards,
Lubomir

···

On Mon, Oct 26, 2009 at 12:41 PM, Lubomir Marinov <lubo@sip-communicator.org> wrote:

Hello Linux-loving devs,

As you've probably notices on the commits mailing list, yesterday I
added the initial implementation of notification popups using
freedesktop.org's Desktop Notifications in r6183.

Emil thought I should announce it here as well because the request
originally came from Sébastien Mazy (smazy) so the chances are that
there are other Linux developers interested in test driving it.

I'm personally very satisfied with these new notifications. I only
added the basic support for PopupMessage title and message because I
wanted to see whether it was going to work and I didn't have enough
time this weekend to implement the display of icons and the
mouse-click detection. It looks like these two missing features will
be possible to implement so the expectation is to have them added at a
later time.

I'm not sure though I'll be able to focus on them in the coming weeks
so please feel free to not only test the current implementation but
also expand it in any way you see fit including by adding the two
missing features mentioned above.

Regards,
Lubomir

On Sun, Oct 25, 2009 at 2:58 PM, <lubomir_m@dev.java.net> wrote:

Author: lubomir_m
Date: 2009-10-25 12:58:30+0000
New Revision: 6183

Added:
trunk/lib/native/linux/libgalagonotification.so (contents, props changed)
trunk/src/native/linux/galagonotification/
trunk/src/native/linux/galagonotification/Makefile
trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.c
trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.h
trunk/src/net/java/sip/communicator/impl/galagonotification/
trunk/src/net/java/sip/communicator/impl/galagonotification/DBusException.java
trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotification.java
trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotificationActivator.java
trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoPopupMessageHandler.java
trunk/src/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf
Modified:
trunk/build.xml
trunk/resources/languages/resources.properties

Log:
Introduces an initial implementation of notification popups on Linux using freedesktop.org's Desktop Notifications through the native libdbus library. The committed code represents work in progress and does not support images, click reporting back to the Java code, matching notifications to Java components. That's why the introduced galagonotification bundle is built in build.xml but not started in felix.client.run.properties.

Modified: trunk/build.xml
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/build.xml?view=diff&rev=6183&p1=trunk/build.xml&p2=trunk/build.xml&r1=6182&r2=6183

--- trunk/build.xml (original)
+++ trunk/build.xml 2009-10-25 12:58:30+0000
@@ -799,8 +799,8 @@
bundle-plugin-msnaccregwizz,bundle-plugin-sipaccregwizz,
bundle-plugin-yahooaccregwizz,bundle-plugin-aimaccregwizz,
bundle-version,bundle-version-impl,bundle-shutdown-timeout,
- bundle-growlnotification,bundle-swingnotification,bundle-sparkle,
- bundle-plugin-branding,
+ bundle-growlnotification,bundle-swingnotification,bundle-galagonotification,
+ bundle-sparkle, bundle-plugin-branding,
bundle-osdependent,bundle-browserlauncher,bundle-gibberish,
bundle-gibberish-slick,bundle-plugin-gibberishaccregwizz,
bundle-plugin-call-history-form,
@@ -1058,6 +1058,8 @@
prefix="net/java/sip/communicator/impl/media/codec/audio"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/codec/video&quot; prefix=&quot;net/java/sip/communicator/impl/media/codec/video&quot;/&gt; \+ &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/conference"
+ prefix="net/java/sip/communicator/impl/media/conference"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/protocol&quot; prefix=&quot;net/java/sip/communicator/impl/media/protocol&quot;/&gt; &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/renderer"
@@ -1092,6 +1094,8 @@
prefix="net/java/sip/communicator/impl/media/codec/audio"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/codec/video&quot; prefix=&quot;net/java/sip/communicator/impl/media/codec/video&quot;/&gt; \+ &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/conference"
+ prefix="net/java/sip/communicator/impl/media/conference"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/protocol&quot; prefix=&quot;net/java/sip/communicator/impl/media/protocol&quot;/&gt; &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/renderer"
@@ -1125,6 +1129,8 @@
prefix="net/java/sip/communicator/impl/media/codec/audio"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/codec/video&quot; prefix=&quot;net/java/sip/communicator/impl/media/codec/video&quot;/&gt; \+ &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/conference"
+ prefix="net/java/sip/communicator/impl/media/conference"/>
<zipfileset dir="\{dest\}/net/java/sip/communicator/impl/media/protocol&quot; prefix=&quot;net/java/sip/communicator/impl/media/protocol&quot;/&gt; &lt;zipfileset dir=&quot;{dest}/net/java/sip/communicator/impl/media/renderer"
@@ -1650,6 +1656,16 @@
</jar>
</target>

+ <!--BUNDLE-GALAGONOTIFICATION-->
+ <target name="bundle-galagonotification">
+ <!-- Creates a bundle for the galagonotification plugin. -->
+ <jar compress="false" destfile="\{bundles\.dest\.lin\}/galagonotification\.jar&quot; \+ manifest=&quot;{src}/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf">
+ <zipfileset dir="\{dest\}/net/java/sip/communicator/impl/galagonotification&quot; \+ prefix=&quot;net/java/sip/communicator/impl/galagonotification&quot; /&gt; \+ &lt;/jar&gt; \+ &lt;/target&gt; \+ &lt;\!\-\-BUNDLE\-POPUPMESSAGEHANDLER\-SLICK\-\-&gt; &lt;target name=&quot;bundle\-popupmessagehandler\-slick&quot;&gt; &lt;jar compress=&quot;false&quot; destfile=&quot;{bundles.dest}/popupmessagehandler-slick.jar"

Added: trunk/lib/native/linux/libgalagonotification.so
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/lib/native/linux/libgalagonotification.so?view=auto&rev=6183

Binary file. No diff available.

Modified: trunk/resources/languages/resources.properties
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/resources/languages/resources.properties?view=diff&rev=6183&p1=trunk/resources/languages/resources.properties&p2=trunk/resources/languages/resources.properties&r1=6182&r2=6183

--- trunk/resources/languages/resources.properties (original)
+++ trunk/resources/languages/resources.properties 2009-10-25 12:58:30+0000
@@ -402,6 +402,7 @@
impl.systray.POPUP_MESSAGE_HANDLER=Systray balloon messages
impl.swingnotification.POPUP_MESSAGE_HANDLER=SIP Communicator popups
impl.growlnotification.POPUP_MESSAGE_HANDLER=Growl notifications
+impl.galagonotification.POPUP_MESSAGE_HANDLER=freedesktop.org Desktop Notifications

# New Account Dialog
impl.gui.main.account.DEFAULT_PAGE_TITLE=Select Network

Added: trunk/src/native/linux/galagonotification/Makefile
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/native/linux/galagonotification/Makefile?view=auto&rev=6183

--- (empty file)
+++ trunk/src/native/linux/galagonotification/Makefile 2009-10-25 12:58:30+0000
@@ -0,0 +1,15 @@
+JAVA_HOME?=/usr/lib/jvm/java-6-sun
+
+ARCH=\(shell uname \-m | sed \-e s/x86\_64/\-64/ \-e s/i\.86//\) \+TARGET=\.\./\.\./\.\./\.\./lib/native/linux(ARCH)/libgalagonotification.so
+
+CC=gcc
+CPPFLAGS=-DJNI_IMPLEMENTATION \
+ -Wall -Wreturn-type \
+ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \
+ \(shell pkg\-config \-\-cflags dbus\-1\) \+LDFLAGS=\-shared \+LIBS=(shell pkg-config --libs dbus-1)
+
+\(TARGET\): net\_java\_sip\_communicator\_impl\_galagonotification\_GalagoNotification\.c net\_java\_sip\_communicator\_impl\_galagonotification\_GalagoNotification\.h \+ (CC) \(CPPFLAGS\) < \(LDFLAGS\) \-o @ $(LIBS)

Added: trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.c
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.c?view=auto&rev=6183

--- (empty file)
+++ trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.c 2009-10-25 12:58:30+0000
@@ -0,0 +1,292 @@
+#include "net_java_sip_communicator_impl_galagonotification_GalagoNotification.h"
+
+#include <dbus/dbus.h>
+
+static dbus_bool_t
+GalagoNotification_messageAppendString(
+ JNIEnv *env, DBusMessageIter *iter, jstring jstr)
+{
+ const jbyte *str;
+ dbus_bool_t success;
+ const char *emptyStr = "";
+
+ if (jstr)
+ {
+ str = (*env)->GetStringUTFChars(env, jstr, NULL);
+ if (!str)
+ return FALSE;
+ }
+ else
+ str = NULL;
+ success
+ = dbus_message_iter_append_basic(
+ iter,
+ DBUS_TYPE_STRING,
+ str ? &str : &emptyStr);
+ if (str)
+ (*env)->ReleaseStringUTFChars(env, jstr, str);
+ return success;
+}
+
+static dbus_bool_t
+GalagoNotification_notifyAppendArgs(
+ JNIEnv *env, DBusMessage *message, jstring appName, jlong replacesId,
+ jstring appIcon, jstring summary, jstring body)
+{
+ DBusMessageIter iter;
+ dbus_uint32_t _replacesId;
+ DBusMessageIter subIter;
+ dbus_int32_t _expireTimeout;
+
+ dbus_message_iter_init_append(message, &iter);
+
+ if (!GalagoNotification_messageAppendString(env, &iter, appName))
+ return FALSE;
+
+ _replacesId = replacesId;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &_replacesId))
+ return FALSE;
+
+ if (!GalagoNotification_messageAppendString(env, &iter, appIcon))
+ return FALSE;
+
+ if (!GalagoNotification_messageAppendString(env, &iter, summary))
+ return FALSE;
+
+ if (!GalagoNotification_messageAppendString(env, &iter, body))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(
+ &iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING,
+ &subIter))
+ return FALSE;
+ if (!dbus_message_iter_close_container(&iter, &subIter))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(
+ &iter,
+ DBUS_TYPE_ARRAY,
+ "{sv}",
+ &subIter))
+ return FALSE;
+ if (!dbus_message_iter_close_container(&iter, &subIter))
+ return FALSE;
+
+ _expireTimeout = -1;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &_expireTimeout))
+ return FALSE;
+
+ return TRUE;
+}
+
+static jobjectArray
+GalagoNotification_stringArray2jstringArray(
+ JNIEnv *env, char **stringArray, int stringArraySize)
+{
+ jclass stringClass;
+ jobjectArray jstringArray;
+
+ stringClass = (*env)->FindClass(env, "java/lang/String");
+ if (stringClass)
+ {
+ jstringArray
+ = (*env)->NewObjectArray(env, stringArraySize, stringClass, NULL);
+ if (jstringArray)
+ {
+ int i;
+
+ for (i = 0; i < stringArraySize; i++)
+ {
+ jstring jstr = (*env)->NewStringUTF(env, *(stringArray + i));
+
+ if (jstr)
+ {
+ (*env)->SetObjectArrayElement(env, jstringArray, i, jstr);
+ if ((*env)->ExceptionCheck(env))
+ {
+ jstringArray = NULL;
+ break;
+ }
+ }
+ else
+ {
+ jstringArray = NULL;
+ break;
+ }
+ }
+ }
+ }
+ else
+ jstringArray = NULL;
+ return jstringArray;
+}
+
+static void
+GalagoNotification_throwException(JNIEnv *env, DBusError *error)
+{
+ /* TODO Auto-generated method stub */
+ jclass clazz
+ = (*env)
+ ->FindClass(
+ env,
+ "net/java/sip/communicator/impl/galagonotification/DBusException");
+
+ if (clazz)
+ (*env)->ThrowNew(env, clazz, error->message);
+}
+
+JNIEXPORT jlong JNICALL
+Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_dbus_1bus_1get_1session(
+ JNIEnv *env, jclass clazz)
+{
+ DBusError error;
+ DBusConnection *connection;
+
+ dbus_error_init(&error);
+ connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
+
+ if (connection)
+ dbus_connection_set_exit_on_disconnect(connection, FALSE);
+ else if (dbus_error_is_set(&error))
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ return connection;
+}
+
+JNIEXPORT void JNICALL
+Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_dbus_1connection_1unref(
+ JNIEnv *env, jclass clazz, jlong connection)
+{
+ dbus_connection_unref((DBusConnection *) connection);
+}
+
+JNIEXPORT jobjectArray JNICALL
+Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_getCapabilities(
+ JNIEnv *env, jclass clazz, jlong connection)
+{
+ DBusMessage *message;
+ jobjectArray jcapabilities = NULL;
+
+ message
+ = dbus_message_new_method_call(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications",
+ "GetCapabilities");
+ if (message)
+ {
+ DBusError error;
+ DBusMessage *reply;
+
+ dbus_error_init(&error);
+ reply
+ = dbus_connection_send_with_reply_and_block(
+ (DBusConnection *) connection,
+ message,
+ -1,
+ &error);
+ if (reply)
+ {
+ char **capabilities;
+ int capabilityCount;
+
+ if (dbus_message_get_args(
+ reply,
+ &error,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING,
+ &capabilities,
+ &capabilityCount,
+ DBUS_TYPE_INVALID))
+ {
+ jcapabilities
+ = GalagoNotification_stringArray2jstringArray(
+ env,
+ capabilities,
+ capabilityCount);
+ dbus_free_string_array(capabilities);
+ }
+ else
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ dbus_message_unref(reply);
+ }
+ else if (dbus_error_is_set(&error))
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ dbus_message_unref(message);
+ }
+ return jcapabilities;
+}
+
+JNIEXPORT jlong JNICALL
+Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_notify(
+ JNIEnv *env, jclass clazz, jlong connection, jstring appName,
+ jlong replacesId, jstring appIcon, jstring summary, jstring body)
+{
+ DBusMessage *message;
+ jlong jid = 0;
+
+ message
+ = dbus_message_new_method_call(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications",
+ "Notify");
+ if (message)
+ {
+ if (GalagoNotification_notifyAppendArgs(
+ env,
+ message,
+ appName,
+ replacesId,
+ appIcon,
+ summary,
+ body))
+ {
+ DBusError error;
+ DBusMessage *reply;
+
+ dbus_error_init(&error);
+ reply
+ = dbus_connection_send_with_reply_and_block(
+ (DBusConnection *) connection,
+ message,
+ -1,
+ &error);
+ if (reply)
+ {
+ dbus_uint32_t id;
+
+ if (dbus_message_get_args(
+ reply,
+ &error,
+ DBUS_TYPE_UINT32,
+ &id,
+ DBUS_TYPE_INVALID))
+ jid = id;
+ else
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ dbus_message_unref(reply);
+ }
+ else if (dbus_error_is_set(&error))
+ {
+ GalagoNotification_throwException(env, &error);
+ dbus_error_free(&error);
+ }
+ }
+ dbus_message_unref(message);
+ }
+ return jid;
+}

Added: trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.h
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.h?view=auto&rev=6183

--- (empty file)
+++ trunk/src/native/linux/galagonotification/net_java_sip_communicator_impl_galagonotification_GalagoNotification.h 2009-10-25 12:58:30+0000
@@ -0,0 +1,45 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class net_java_sip_communicator_impl_galagonotification_GalagoNotification */
+
+#ifndef _Included_net_java_sip_communicator_impl_galagonotification_GalagoNotification
+#define _Included_net_java_sip_communicator_impl_galagonotification_GalagoNotification
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: net_java_sip_communicator_impl_galagonotification_GalagoNotification
+ * Method: dbus_bus_get_session
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_dbus_1bus_1get_1session
+ (JNIEnv *, jclass);
+
+/*
+ * Class: net_java_sip_communicator_impl_galagonotification_GalagoNotification
+ * Method: dbus_connection_unref
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_dbus_1connection_1unref
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: net_java_sip_communicator_impl_galagonotification_GalagoNotification
+ * Method: getCapabilities
+ * Signature: (J)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_getCapabilities
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: net_java_sip_communicator_impl_galagonotification_GalagoNotification
+ * Method: notify
+ * Signature: (JLjava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_galagonotification_GalagoNotification_notify
+ (JNIEnv *, jclass, jlong, jstring, jlong, jstring, jstring, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/DBusException.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/DBusException.java?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/DBusException.java 2009-10-25 12:58:30+0000
@@ -0,0 +1,30 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.galagonotification;
+
+/**
+ * Implements <tt>Exception</tt> for D-Bus errors reported through the native
+ * <tt>DBusError</tt> structure.
+ *
+ * @author Lubomir Marinov
+ */
+public class DBusException
+ extends Exception
+{
+
+ /**
+ * Initializes a new <tt>DBusException</tt> instance with the specified
+ * detail message.
+ *
+ * @param message the detail message to later be reported by the new
+ * instance through its {@link #getMessage()}
+ */
+ public DBusException(String message)
+ {
+ super(message);
+ }
+}

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotification.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotification.java?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotification.java 2009-10-25 12:58:30+0000
@@ -0,0 +1,95 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.galagonotification;
+
+/**
+ * Declares the native functions required by the galagonotification bundle.
+ *
+ * @author Lubomir Marinov
+ */
+public final class GalagoNotification
+{
+ static
+ {
+ System.loadLibrary("galagonotification");
+ }
+
+ /**
+ * Connects to the <tt>DBUS_BUS_SESSION</tt> D-Bus bus daemon and registers
+ * with it.
+ *
+ * @return a new reference to a <tt>DBusConnection</tt> to the
+ * <tt>DBUS_BUS_SESSION</tt> D-Bus bus daemon
+ * @throws DBusException if connecting to and registering with the
+ * <tt>DBUS_BUS_SESSION</tt> D-Bus bus daemon fails
+ */
+ public static native long dbus_bus_get_session()
+ throws DBusException;
+
+ /**
+ * Decrements the reference count of the specified <tt>DBusConnection</tt>
+ * and finalizes it if the count reaches zero.
+ *
+ * @param connection the <tt>DBusConnection</tt> to decrement the reference
+ * count of
+ */
+ public static native void dbus_connection_unref(long connection);
+
+ /**
+ * Invokes <tt>org.freedesktop.Notifications.GetCapabilities</tt> through
+ * the specified <tt>DBusConnection</tt> in order to retrieve the optional
+ * capabilities supported by the freedesktop.org Desktop Notifications
+ * server.
+ *
+ * @param connection the <tt>DBusConnection</tt> with the freedesktop.org
+ * Desktop Notifications server
+ * @return an array of <tt>String</tt>s listing the optional capabilities
+ * supported by the freedesktop.org Desktop Notifications server
+ * @throws DBusException if retrieving the optional capabilities of the
+ * freedesktop.org Desktop Notifications server fails
+ */
+ public static native String[] getCapabilities(long connection)
+ throws DBusException;
+
+ /**
+ * Invokes <tt>org.freedesktop.Notifications.Notify</tt> through the
+ * specified <tt>DBusConnection</tt> in order to send a notification to the
+ * freedesktop.org Desktop Notifications server.
+ *
+ * @param connection the <tt>DBusConnection</tt> with the freedesktop.org
+ * Desktop Notifications server
+ * @param appName the optional name of the application sending the
+ * notification
+ * @param replacesId the optional notification identifier of an existing
+ * notification to be replaced by the notification being sent; <tt>0</tt> to
+ * not replace any existing notification
+ * @param appIcon the optional program icon of the application sending the
+ * notification. Not supported at this time.
+ * @param summary the summary text briefly describing the notification
+ * @param body the optional detailed body text of the notification
+ * @return the unique identifier of the sent notification if
+ * <tt>replacesId</tt> is <tt>0</tt>; <tt>replacesId</tt> if
+ * <tt>replacesId</tt> is not <tt>0</tt>
+ * @throws DBusException if sending the notification to the freedesktop.org
+ * Desktop Notifications server fails
+ */
+ public static native long notify(
+ long connection,
+ String appName,
+ long replacesId,
+ String appIcon,
+ String summary,
+ String body)
+ throws DBusException;
+
+ /**
+ * Prevents the creation of <tt>GalagoNotification</tt> instances.
+ */
+ private GalagoNotification()
+ {
+ }
+}

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotificationActivator.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotificationActivator.java?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoNotificationActivator.java 2009-10-25 12:58:30+0000
@@ -0,0 +1,159 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.galagonotification;
+
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.service.systray.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * Implements <tt>BundleActivator</tt> for the galagonotification bundle which
+ * provides an implementation of <tt>PopupMessageHandler</tt> according to the
+ * freedesktop.org Desktop Notifications spec.
+ *
+ * @author Lubomir Marinov
+ */
+public class GalagoNotificationActivator
+ implements BundleActivator
+{
+
+ /**
+ * The <tt>Logger</tt> used by the <tt>GalagoNotificationActivator</tt>
+ * class and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(GalagoNotificationActivator.class);
+
+ /**
+ * The context in which the galagonotification bundle is executing.
+ */
+ private static BundleContext bundleContext;
+
+ /**
+ * The <tt>DBusConnection</tt> pointer to the D-Bus connection through which
+ * the freedesktop.org Desktop Notifications are being sent.
+ */
+ static long dbusConnection;
+
+ /**
+ * The resources such as internationalized and localized text and images
+ * used by the galagonotification bundle.
+ */
+ private static ResourceManagementService resources;
+
+ /**
+ * Gets the resources such as internationalized and localized text and
+ * images used by the galagonotification bundle.
+ *
+ * @return the resources such as internationalized and localized text and
+ * images used by the galagonotification bundle
+ */
+ public static ResourceManagementService getResources()
+ {
+ if (resources == null)
+ resources = ResourceManagementServiceUtils.getService(bundleContext);
+ return resources;
+ }
+
+ /**
+ * Starts the galagonotification bundle. Registers its
+ * <tt>PopupMessageHandler</tt> implementation if it is supported by the
+ * current operating system.
+ *
+ * @param bundleContext the context in which the galagonotification bundle
+ * is to execute
+ * @throws Exception if the <tt>PopupMessageHandler</tt> implementation of
+ * the galagonotification bundle is not supported by the current operating
+ * system
+ * @see BundleActivator#start(BundleContext)
+ */
+ public void start(BundleContext bundleContext)
+ throws Exception
+ {
+ long dbusConnection = GalagoNotification.dbus_bus_get_session();
+
+ if (dbusConnection != 0)
+ {
+
+ /*
+ * We don't much care about the very capabilities because they are
+ * optional, we just want to make sure that the service exists.
+ */
+ String[] capabilities
+ = GalagoNotification.getCapabilities(dbusConnection);
+
+ if (capabilities != null)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger
+ .debug(
+ "org.freedesktop.Notifications.GetCapabilities:");
+ for (String capability : capabilities)
+ logger.debug("\t" + capability);
+ }
+
+ /*
+ * The native counterpart may return null without throwing an
+ * exception even when it fails to retrieve the capabilities. So
+ * it will not be safe to use galagonotification in this case.
+ * It is also unclear whether the server will return null when
+ * it does not support any optional capabilities. So it's not
+ * totally safe to assume that null means that
+ * galagonotification cannot be used. Anyway, displaying only
+ * the message title may be insufficient for our purposes so
+ * we'll require the optional "body" capability and solve the
+ * above questions.
+ */
+ boolean bodyIsImplemented = false;
+
+ for (String capability : capabilities)
+ if ("body".equals(capability))
+ {
+ bodyIsImplemented = true;
+ break;
+ }
+ if (bodyIsImplemented)
+ {
+ GalagoNotificationActivator.bundleContext = bundleContext;
+ GalagoNotificationActivator.dbusConnection = dbusConnection;
+
+ bundleContext
+ .registerService(
+ PopupMessageHandler.class.getName(),
+ new GalagoPopupMessageHandler(),
+ null);
+ }
+ else
+ GalagoNotification.dbus_connection_unref(dbusConnection);
+ }
+ }
+ }
+
+ /**
+ * Stops the galagonotification bundle.
+ *
+ * @param bundleContext the context in which the galagonotification bundle
+ * is to stop its execution
+ * @throws Exception if there was an error during the stopping of the native
+ * functionality supporting the <tt>PopupNotificationHandler</tt>
+ * implementation of the galagonotification bundle
+ */
+ public void stop(BundleContext bundleContext)
+ throws Exception
+ {
+ if (dbusConnection != 0)
+ {
+ GalagoNotification.dbus_connection_unref(dbusConnection);
+ dbusConnection = 0;
+ }
+ if (bundleContext.equals(GalagoNotificationActivator.bundleContext))
+ GalagoNotificationActivator.bundleContext = null;
+ }
+}

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoPopupMessageHandler.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoPopupMessageHandler.java?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/GalagoPopupMessageHandler.java 2009-10-25 12:58:30+0000
@@ -0,0 +1,85 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.galagonotification;
+
+import net.java.sip.communicator.service.systray.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Implements <tt>PopupMessageHandler</tt> according to the freedesktop.org
+ * Desktop Notifications spec.
+ *
+ * @author Lubomir Marinov
+ */
+public class GalagoPopupMessageHandler
+ extends AbstractPopupMessageHandler
+{
+
+ /**
+ * The <tt>Logger</tt> used by the <tt>GalagoPopupMessageHandler</tt> class
+ * and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(GalagoPopupMessageHandler.class);
+
+ /**
+ * Returns the preference index of this <tt>PopupMessageHandler</tt> which
+ * indicates how many features it supports.
+ *
+ * @return the preference index of this <tt>PopupMessageHandler</tt> which
+ * indicates how many features it supports
+ * @see PopupMessageHandler#getPreferenceIndex()
+ */
+ public int getPreferenceIndex()
+ {
+ return 1; // using a native popup mechanism
+ }
+
+ /**
+ * Shows the title and the message of the specified <tt>PopupMessage</tt>.
+ *
+ * @param popupMessage the <tt>PopupMessage</tt> specifying the title and
+ * the message to be shown
+ * @see PopupMessageHandler#showPopupMessage(PopupMessage)
+ */
+ public void showPopupMessage(PopupMessage popupMessage)
+ {
+ try
+ {
+ GalagoNotification
+ .notify(
+ GalagoNotificationActivator.dbusConnection,
+ null,
+ 0,
+ null,
+ popupMessage.getMessageTitle(),
+ popupMessage.getMessage());
+ }
+ catch (DBusException dbe)
+ {
+ logger.error("Failed to show PopupMessage " + popupMessage, dbe);
+ }
+ }
+
+ /**
+ * Gets the human-readable localized description of this
+ * <tt>PopupMessageHandler</tt>.
+ *
+ * @return the human-readable localized description of this
+ * <tt>PopupMessageHandler</tt>
+ * @see PopupMessageHandler#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return
+ GalagoNotificationActivator
+ .getResources()
+ .getI18NString(
+ "impl.galagonotification.POPUP_MESSAGE_HANDLER");
+ }
+}

Added: trunk/src/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf?view=auto&rev=6183

--- (empty file)
+++ trunk/src/net/java/sip/communicator/impl/galagonotification/galagonotification.manifest.mf 2009-10-25 12:58:30+0000
@@ -0,0 +1,10 @@
+Bundle-Activator: net.java.sip.communicator.impl.galagonotification.GalagoNotificationActivator
+Bundle-Name: Desktop Notifications Provider
+Bundle-Description: A bundle which implements notifications according to the freedesktop.org Desktop Notifications spec.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Import-Package: net.java.sip.communicator.service.systray,
+ net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.util,
+ org.osgi.framework

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net