aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am10
-rw-r--r--src/custom-service-appstore.c177
-rw-r--r--src/custom-service-appstore.h11
-rw-r--r--src/custom-service-marshal.list1
-rw-r--r--src/custom-service-watcher.c183
-rw-r--r--src/custom-service-watcher.h40
-rw-r--r--src/custom-service.c3
-rw-r--r--src/dbus-properties.xml23
-rw-r--r--src/dbus-shared.h9
-rw-r--r--src/indicator-custom.c259
-rw-r--r--src/notification-watcher.xml3
11 files changed, 662 insertions, 57 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 273c2dc..21d7cf8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,6 +4,7 @@ BUILT_SOURCES =
EXTRA_DIST =
include $(top_srcdir)/Makefile.am.enum
+include $(top_srcdir)/Makefile.am.marshal
##################################
# Indicator
@@ -33,7 +34,12 @@ indicator_custom_service_SOURCES = \
custom-service.c \
custom-service-appstore.h \
custom-service-appstore.c \
+ custom-service-marshal.h \
+ custom-service-marshal.c \
custom-service-server.h \
+ custom-service-watcher.h \
+ custom-service-watcher.c \
+ dbus-properties-client.h \
dbus-shared.h \
notification-item-client.h \
notification-watcher-server.h
@@ -43,6 +49,9 @@ indicator_custom_service_CFLAGS = \
indicator_custom_service_LDADD = \
$(INDICATOR_LIBS)
+glib_marshal_list = custom-service-marshal.list
+glib_marshal_prefix = _custom_service_marshal
+
##################################
# Library
##################################
@@ -88,6 +97,7 @@ libcustomindicator_la_LIBADD = \
DBUS_SPECS = \
custom-service.xml \
+ dbus-properties.xml \
notification-item.xml \
notification-watcher.xml
diff --git a/src/custom-service-appstore.c b/src/custom-service-appstore.c
index 1e61852..a69bde6 100644
--- a/src/custom-service-appstore.c
+++ b/src/custom-service-appstore.c
@@ -2,29 +2,53 @@
#include "config.h"
#endif
+#include <dbus/dbus-glib.h>
#include "custom-service-appstore.h"
+#include "custom-service-marshal.h"
+#include "dbus-properties-client.h"
+#include "dbus-shared.h"
/* DBus Prototypes */
-static gboolean _custom_service_server_get_applications (CustomServiceAppstore * appstore, GArray ** apps, gpointer user_data);
-
-static gboolean _notification_watcher_server_register_service (CustomServiceAppstore * appstore, const gchar * service, gpointer user_data);
-static gboolean _notification_watcher_server_registered_services (CustomServiceAppstore * appstore, GArray ** apps, gpointer user_data);
-static gboolean _notification_watcher_server_protocol_version (CustomServiceAppstore * appstore, char ** version, gpointer user_data);
-static gboolean _notification_watcher_server_register_notification_host (CustomServiceAppstore * appstore, const gchar * host, gpointer user_data);
-static gboolean _notification_watcher_server_is_notification_host_registered (CustomServiceAppstore * appstore, gboolean * haveHost, gpointer user_data);
+static gboolean _custom_service_server_get_applications (CustomServiceAppstore * appstore, GArray ** apps);
#include "custom-service-server.h"
-#include "notification-watcher-server.h"
-typedef struct _CustomServiceAppstorePrivate CustomServiceAppstorePrivate;
+#define NOTIFICATION_ITEM_PROP_ID "Id"
+#define NOTIFICATION_ITEM_PROP_CATEGORY "Category"
+#define NOTIFICATION_ITEM_PROP_STATUS "Status"
+#define NOTIFICATION_ITEM_PROP_ICON_NAME "IconName"
+#define NOTIFICATION_ITEM_PROP_AICON_NAME "AttentionIconName"
+#define NOTIFICATION_ITEM_PROP_MENU "Menu"
+/* Private Stuff */
+typedef struct _CustomServiceAppstorePrivate CustomServiceAppstorePrivate;
struct _CustomServiceAppstorePrivate {
- int demo;
+ DBusGConnection * bus;
+ GList * applications;
+};
+
+typedef struct _Application Application;
+struct _Application {
+ gchar * dbus_name;
+ gchar * dbus_object;
+ CustomServiceAppstore * appstore; /* not ref'd */
+ DBusGProxy * dbus_proxy;
+ DBusGProxy * prop_proxy;
};
#define CUSTOM_SERVICE_APPSTORE_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CUSTOM_SERVICE_APPSTORE_TYPE, CustomServiceAppstorePrivate))
+/* Signals Stuff */
+enum {
+ APPLICATION_ADDED,
+ APPLICATION_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* GObject stuff */
static void custom_service_appstore_class_init (CustomServiceAppstoreClass *klass);
static void custom_service_appstore_init (CustomServiceAppstore *self);
static void custom_service_appstore_dispose (GObject *object);
@@ -42,8 +66,22 @@ custom_service_appstore_class_init (CustomServiceAppstoreClass *klass)
object_class->dispose = custom_service_appstore_dispose;
object_class->finalize = custom_service_appstore_finalize;
- dbus_g_object_type_install_info(CUSTOM_SERVICE_APPSTORE_TYPE,
- &dbus_glib__notification_watcher_server_object_info);
+ signals[APPLICATION_ADDED] = g_signal_new ("application-added",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CustomServiceAppstore, application_added),
+ NULL, NULL,
+ _custom_service_marshal_VOID__STRING_INT_STRING_STRING,
+ G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE);
+ signals[APPLICATION_REMOVED] = g_signal_new ("application-removed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CustomServiceAppstore, application_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT, G_TYPE_NONE);
+
+
dbus_g_object_type_install_info(CUSTOM_SERVICE_APPSTORE_TYPE,
&dbus_glib__custom_service_server_object_info);
@@ -53,17 +91,20 @@ custom_service_appstore_class_init (CustomServiceAppstoreClass *klass)
static void
custom_service_appstore_init (CustomServiceAppstore *self)
{
+ CustomServiceAppstorePrivate * priv = CUSTOM_SERVICE_APPSTORE_GET_PRIVATE(self);
+
+ priv->applications = NULL;
GError * error = NULL;
- DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+ priv->bus = dbus_g_bus_get(DBUS_BUS_STARTER, &error);
if (error != NULL) {
g_error("Unable to get session bus: %s", error->message);
g_error_free(error);
return;
}
- dbus_g_connection_register_g_object(session_bus,
- "/my/path",
+ dbus_g_connection_register_g_object(priv->bus,
+ INDICATOR_CUSTOM_DBUS_OBJ,
G_OBJECT(self));
return;
@@ -72,6 +113,13 @@ custom_service_appstore_init (CustomServiceAppstore *self)
static void
custom_service_appstore_dispose (GObject *object)
{
+ CustomServiceAppstorePrivate * priv = CUSTOM_SERVICE_APPSTORE_GET_PRIVATE(object);
+
+ while (priv->applications != NULL) {
+ custom_service_appstore_application_remove(CUSTOM_SERVICE_APPSTORE(object),
+ ((Application *)priv->applications->data)->dbus_name,
+ ((Application *)priv->applications->data)->dbus_object);
+ }
G_OBJECT_CLASS (custom_service_appstore_parent_class)->dispose (object);
return;
@@ -85,44 +133,101 @@ custom_service_appstore_finalize (GObject *object)
return;
}
-/* DBus Interface */
-static gboolean
-_custom_service_server_get_applications (CustomServiceAppstore * appstore, GArray ** apps, gpointer user_data)
+static void
+get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data)
{
+ if (error != NULL) {
+ g_warning("Unable to get properties: %s", error->message);
+ return;
+ }
- return FALSE;
-}
+ Application * app = (Application *)data;
-static gboolean
-_notification_watcher_server_register_service (CustomServiceAppstore * appstore, const gchar * service, gpointer user_data)
-{
+ if (g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_MENU) == NULL ||
+ g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ICON_NAME) == NULL) {
+ g_warning("Notification Item on object %s of %s doesn't have enough properties.", app->dbus_object, app->dbus_name);
+ g_free(app); // Need to do more than this, but it gives the idea of the flow we're going for.
+ return;
+ }
- return FALSE;
-}
+ CustomServiceAppstorePrivate * priv = CUSTOM_SERVICE_APPSTORE_GET_PRIVATE(app->appstore);
+ priv->applications = g_list_prepend(priv->applications, app);
-static gboolean
-_notification_watcher_server_registered_services (CustomServiceAppstore * appstore, GArray ** apps, gpointer user_data)
-{
+ g_signal_emit(G_OBJECT(app->appstore),
+ signals[APPLICATION_ADDED], 0,
+ g_value_get_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ICON_NAME)),
+ 0, /* Position */
+ app->dbus_name,
+ g_value_get_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_MENU)),
+ TRUE);
- return FALSE;
+ return;
}
-static gboolean
-_notification_watcher_server_protocol_version (CustomServiceAppstore * appstore, char ** version, gpointer user_data)
+void
+custom_service_appstore_application_add (CustomServiceAppstore * appstore, const gchar * dbus_name, const gchar * dbus_object)
{
+ g_return_if_fail(IS_CUSTOM_SERVICE_APPSTORE(appstore));
+ g_return_if_fail(dbus_name != NULL && dbus_name[0] != '\0');
+ g_return_if_fail(dbus_object != NULL && dbus_object[0] != '\0');
+ CustomServiceAppstorePrivate * priv = CUSTOM_SERVICE_APPSTORE_GET_PRIVATE(appstore);
- return FALSE;
+ Application * app = g_new(Application, 1);
+
+ app->dbus_name = g_strdup(dbus_name);
+ app->dbus_object = g_strdup(dbus_object);
+ app->appstore = appstore;
+
+ GError * error = NULL;
+ app->dbus_proxy = dbus_g_proxy_new_for_name_owner(priv->bus,
+ app->dbus_name,
+ app->dbus_object,
+ NOTIFICATION_ITEM_DBUS_IFACE,
+ &error);
+
+ if (error != NULL) {
+ g_warning("Unable to get notification item proxy for object '%s' on host '%s': %s", dbus_object, dbus_name, error->message);
+ g_error_free(error);
+ g_free(app);
+ return;
+ }
+
+ app->prop_proxy = dbus_g_proxy_new_for_name_owner(priv->bus,
+ app->dbus_name,
+ app->dbus_object,
+ DBUS_INTERFACE_PROPERTIES,
+ &error);
+
+ if (error != NULL) {
+ g_warning("Unable to get property proxy for object '%s' on host '%s': %s", dbus_object, dbus_name, error->message);
+ g_error_free(error);
+ g_object_unref(app->dbus_proxy);
+ g_free(app);
+ return;
+ }
+
+ org_freedesktop_DBus_Properties_get_all_async(app->prop_proxy,
+ NOTIFICATION_ITEM_DBUS_IFACE,
+ get_all_properties_cb,
+ app);
+
+ return;
}
-static gboolean
-_notification_watcher_server_register_notification_host (CustomServiceAppstore * appstore, const gchar * host, gpointer user_data)
+void
+custom_service_appstore_application_remove (CustomServiceAppstore * appstore, const gchar * dbus_name, const gchar * dbus_object)
{
+ g_return_if_fail(IS_CUSTOM_SERVICE_APPSTORE(appstore));
+ g_return_if_fail(dbus_name != NULL && dbus_name[0] != '\0');
+ g_return_if_fail(dbus_object != NULL && dbus_object[0] != '\0');
- return FALSE;
+
+ return;
}
+/* DBus Interface */
static gboolean
-_notification_watcher_server_is_notification_host_registered (CustomServiceAppstore * appstore, gboolean * haveHost, gpointer user_data)
+_custom_service_server_get_applications (CustomServiceAppstore * appstore, GArray ** apps)
{
return FALSE;
diff --git a/src/custom-service-appstore.h b/src/custom-service-appstore.h
index 48c9da9..7263617 100644
--- a/src/custom-service-appstore.h
+++ b/src/custom-service-appstore.h
@@ -22,9 +22,18 @@ struct _CustomServiceAppstoreClass {
struct _CustomServiceAppstore {
GObject parent;
+
+ void (*application_added) (CustomServiceAppstore * appstore, gchar *, gint, gchar *, gchar *, gpointer);
+ void (*application_removed) (CustomServiceAppstore * appstore, gint, gpointer);
};
-GType custom_service_appstore_get_type (void);
+GType custom_service_appstore_get_type (void);
+void custom_service_appstore_application_add (CustomServiceAppstore * appstore,
+ const gchar * dbus_name,
+ const gchar * dbus_object);
+void custom_service_appstore_application_remove (CustomServiceAppstore * appstore,
+ const gchar * dbus_name,
+ const gchar * dbus_object);
G_END_DECLS
diff --git a/src/custom-service-marshal.list b/src/custom-service-marshal.list
new file mode 100644
index 0000000..4056f53
--- /dev/null
+++ b/src/custom-service-marshal.list
@@ -0,0 +1 @@
+VOID: STRING, INT, STRING, STRING
diff --git a/src/custom-service-watcher.c b/src/custom-service-watcher.c
new file mode 100644
index 0000000..a0a1b27
--- /dev/null
+++ b/src/custom-service-watcher.c
@@ -0,0 +1,183 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include "custom-service-watcher.h"
+#include "dbus-shared.h"
+
+static gboolean _notification_watcher_server_register_service (CustomServiceWatcher * appwatcher, const gchar * service, DBusGMethodInvocation * method);
+static gboolean _notification_watcher_server_registered_services (CustomServiceWatcher * appwatcher, GArray ** apps);
+static gboolean _notification_watcher_server_protocol_version (CustomServiceWatcher * appwatcher, char ** version);
+static gboolean _notification_watcher_server_register_notification_host (CustomServiceWatcher * appwatcher, const gchar * host);
+static gboolean _notification_watcher_server_is_notification_host_registered (CustomServiceWatcher * appwatcher, gboolean * haveHost);
+
+#include "notification-watcher-server.h"
+
+/* Private Stuff */
+typedef struct _CustomServiceWatcherPrivate CustomServiceWatcherPrivate;
+struct _CustomServiceWatcherPrivate {
+ CustomServiceAppstore * appstore;
+};
+
+#define CUSTOM_SERVICE_WATCHER_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), CUSTOM_SERVICE_WATCHER_TYPE, CustomServiceWatcherPrivate))
+
+/* Signals Stuff */
+enum {
+ SERVICE_REGISTERED,
+ SERVICE_UNREGISTERED,
+ NOTIFICATION_HOST_REGISTERED,
+ NOTIFICATION_HOST_UNREGISTERED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* GObject stuff */
+static void custom_service_watcher_class_init (CustomServiceWatcherClass *klass);
+static void custom_service_watcher_init (CustomServiceWatcher *self);
+static void custom_service_watcher_dispose (GObject *object);
+static void custom_service_watcher_finalize (GObject *object);
+
+G_DEFINE_TYPE (CustomServiceWatcher, custom_service_watcher, G_TYPE_OBJECT);
+
+static void
+custom_service_watcher_class_init (CustomServiceWatcherClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (CustomServiceWatcherPrivate));
+
+ object_class->dispose = custom_service_watcher_dispose;
+ object_class->finalize = custom_service_watcher_finalize;
+
+ signals[SERVICE_REGISTERED] = g_signal_new ("service-registered",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CustomServiceWatcherClass, service_registered),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING, G_TYPE_NONE);
+ signals[SERVICE_UNREGISTERED] = g_signal_new ("service-unregistered",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CustomServiceWatcherClass, service_unregistered),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING, G_TYPE_NONE);
+ signals[NOTIFICATION_HOST_REGISTERED] = g_signal_new ("notification-host-registered",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CustomServiceWatcherClass, notification_host_registered),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0, G_TYPE_NONE);
+ signals[NOTIFICATION_HOST_UNREGISTERED] = g_signal_new ("notification-host-unregistered",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CustomServiceWatcherClass, notification_host_unregistered),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0, G_TYPE_NONE);
+
+ dbus_g_object_type_install_info(CUSTOM_SERVICE_WATCHER_TYPE,
+ &dbus_glib__notification_watcher_server_object_info);
+
+ return;
+}
+
+static void
+custom_service_watcher_init (CustomServiceWatcher *self)
+{
+ CustomServiceWatcherPrivate * priv = CUSTOM_SERVICE_WATCHER_GET_PRIVATE(self);
+
+ priv->appstore = NULL;
+
+ GError * error = NULL;
+ DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+ if (error != NULL) {
+ g_error("Unable to get session bus: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ dbus_g_connection_register_g_object(session_bus,
+ INDICATOR_CUSTOM_DBUS_OBJ "/more",
+ G_OBJECT(self));
+
+ return;
+}
+
+static void
+custom_service_watcher_dispose (GObject *object)
+{
+ CustomServiceWatcherPrivate * priv = CUSTOM_SERVICE_WATCHER_GET_PRIVATE(object);
+
+ if (priv->appstore != NULL) {
+ g_object_unref(G_OBJECT(priv->appstore));
+ priv->appstore = NULL;
+ }
+
+ G_OBJECT_CLASS (custom_service_watcher_parent_class)->dispose (object);
+ return;
+}
+
+static void
+custom_service_watcher_finalize (GObject *object)
+{
+
+ G_OBJECT_CLASS (custom_service_watcher_parent_class)->finalize (object);
+ return;
+}
+
+CustomServiceWatcher *
+custom_service_watcher_new (CustomServiceAppstore * appstore)
+{
+ GObject * obj = g_object_new(CUSTOM_SERVICE_WATCHER_TYPE, NULL);
+ CustomServiceWatcherPrivate * priv = CUSTOM_SERVICE_WATCHER_GET_PRIVATE(obj);
+ priv->appstore = appstore;
+ g_object_ref(G_OBJECT(priv->appstore));
+ return CUSTOM_SERVICE_WATCHER(obj);
+}
+
+static gboolean
+_notification_watcher_server_register_service (CustomServiceWatcher * appwatcher, const gchar * service, DBusGMethodInvocation * method)
+{
+ CustomServiceWatcherPrivate * priv = CUSTOM_SERVICE_WATCHER_GET_PRIVATE(appwatcher);
+
+ custom_service_appstore_application_add(priv->appstore, dbus_g_method_get_sender(method), service);
+
+ dbus_g_method_return(method, G_TYPE_NONE);
+ return TRUE;
+}
+
+static gboolean
+_notification_watcher_server_registered_services (CustomServiceWatcher * appwatcher, GArray ** apps)
+{
+
+ return FALSE;
+}
+
+static gboolean
+_notification_watcher_server_protocol_version (CustomServiceWatcher * appwatcher, char ** version)
+{
+ *version = g_strdup("Ayatana Version 1");
+ return TRUE;
+}
+
+static gboolean
+_notification_watcher_server_register_notification_host (CustomServiceWatcher * appwatcher, const gchar * host)
+{
+
+ return FALSE;
+}
+
+static gboolean
+_notification_watcher_server_is_notification_host_registered (CustomServiceWatcher * appwatcher, gboolean * haveHost)
+{
+ *haveHost = TRUE;
+ return TRUE;
+}
+
diff --git a/src/custom-service-watcher.h b/src/custom-service-watcher.h
new file mode 100644
index 0000000..1a037be
--- /dev/null
+++ b/src/custom-service-watcher.h
@@ -0,0 +1,40 @@
+#ifndef __CUSTOM_SERVICE_WATCHER_H__
+#define __CUSTOM_SERVICE_WATCHER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "custom-service-appstore.h"
+
+G_BEGIN_DECLS
+
+#define CUSTOM_SERVICE_WATCHER_TYPE (custom_service_watcher_get_type ())
+#define CUSTOM_SERVICE_WATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CUSTOM_SERVICE_WATCHER_TYPE, CustomServiceWatcher))
+#define CUSTOM_SERVICE_WATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CUSTOM_SERVICE_WATCHER_TYPE, CustomServiceWatcherClass))
+#define IS_CUSTOM_SERVICE_WATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CUSTOM_SERVICE_WATCHER_TYPE))
+#define IS_CUSTOM_SERVICE_WATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CUSTOM_SERVICE_WATCHER_TYPE))
+#define CUSTOM_SERVICE_WATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CUSTOM_SERVICE_WATCHER_TYPE, CustomServiceWatcherClass))
+
+typedef struct _CustomServiceWatcher CustomServiceWatcher;
+typedef struct _CustomServiceWatcherClass CustomServiceWatcherClass;
+
+struct _CustomServiceWatcherClass {
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*service_registered) (CustomServiceWatcher * watcher, gchar * object, gpointer data);
+ void (*service_unregistered) (CustomServiceWatcher * watcher, gchar * object, gpointer data);
+ void (*notification_host_registered) (CustomServiceWatcher * watcher, gpointer data);
+ void (*notification_host_unregistered) (CustomServiceWatcher * watcher, gpointer data);
+};
+
+struct _CustomServiceWatcher {
+ GObject parent;
+};
+
+GType custom_service_watcher_get_type (void);
+CustomServiceWatcher * custom_service_watcher_new (CustomServiceAppstore * appstore);
+
+G_END_DECLS
+
+#endif
diff --git a/src/custom-service.c b/src/custom-service.c
index df3d58a..3205bc2 100644
--- a/src/custom-service.c
+++ b/src/custom-service.c
@@ -2,10 +2,12 @@
#include "libindicator/indicator-service.h"
#include "notification-item-client.h"
#include "custom-service-appstore.h"
+#include "custom-service-watcher.h"
#include "dbus-shared.h"
static GMainLoop * mainloop = NULL;
static CustomServiceAppstore * appstore = NULL;
+static CustomServiceWatcher * watcher = NULL;
static IndicatorService * service = NULL;
int
@@ -15,6 +17,7 @@ main (int argc, char ** argv)
service = indicator_service_new(INDICATOR_CUSTOM_DBUS_ADDR);
appstore = CUSTOM_SERVICE_APPSTORE(g_object_new(CUSTOM_SERVICE_APPSTORE_TYPE, NULL));
+ watcher = custom_service_watcher_new(appstore);
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/src/dbus-properties.xml b/src/dbus-properties.xml
new file mode 100644
index 0000000..c172895
--- /dev/null
+++ b/src/dbus-properties.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/">
+ <interface name="org.freedesktop.DBus.Properties">
+
+ <method name="Get">
+ <arg direction="in" type="s" name="Interface_Name"/>
+ <arg direction="in" type="s" name="Property_Name"/>
+ <arg direction="out" type="v" name="Value"/>
+ </method>
+
+ <method name="Set">
+ <arg direction="in" type="s" name="Interface_Name"/>
+ <arg direction="in" type="s" name="Property_Name"/>
+ <arg direction="in" type="v" name="Value"/>
+ </method>
+
+ <method name="GetAll">
+ <arg direction="in" type="s" name="Interface_Name"/>
+ <arg direction="out" type="a{sv}" name="Properties"/>
+ </method>
+
+ </interface>
+</node>
diff --git a/src/dbus-shared.h b/src/dbus-shared.h
index 36436bd..364ac46 100644
--- a/src/dbus-shared.h
+++ b/src/dbus-shared.h
@@ -1,3 +1,10 @@
-#define INDICATOR_CUSTOM_DBUS_ADDR "org.ayatana.indicator.custom"
+#define INDICATOR_CUSTOM_DBUS_ADDR "org.ayatana.indicator.custom"
+#define INDICATOR_CUSTOM_DBUS_OBJ "/org/ayatana/indicator/custom/service"
+#define INDICATOR_CUSTOM_DBUS_IFACE "org.ayatana.indicator.custom.service"
+
+#define NOTIFICATION_WATCHER_DBUS_OBJ "/org/ayatana/indicator/custom/NotificationWatcher"
+#define NOTIFICATION_WATCHER_DBUS_IFACE "org.ayatana.indicator.custom.NotificationWatcher"
+
+#define NOTIFICATION_ITEM_DBUS_IFACE "org.ayatana.indicator.custom.NotificationItem"
diff --git a/src/indicator-custom.c b/src/indicator-custom.c
index d9763ea..7cb9142 100644
--- a/src/indicator-custom.c
+++ b/src/indicator-custom.c
@@ -1,42 +1,265 @@
+/* G Stuff */
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+/* DBus Stuff */
+#include <dbus/dbus-glib.h>
+#include <libdbusmenu-gtk/menu.h>
+
+/* Indicator Stuff */
#include <libindicator/indicator.h>
+#include <libindicator/indicator-object.h>
#include <libindicator/indicator-service-manager.h>
+
+/* Local Stuff */
#include "dbus-shared.h"
+#include "custom-service-client.h"
+
+#define INDICATOR_CUSTOM_TYPE (indicator_custom_get_type ())
+#define INDICATOR_CUSTOM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_CUSTOM_TYPE, IndicatorCustom))
+#define INDICATOR_CUSTOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_CUSTOM_TYPE, IndicatorCustomClass))
+#define IS_INDICATOR_CUSTOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_CUSTOM_TYPE))
+#define IS_INDICATOR_CUSTOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_CUSTOM_TYPE))
+#define INDICATOR_CUSTOM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_CUSTOM_TYPE, IndicatorCustomClass))
+
+typedef struct _IndicatorCustom IndicatorCustom;
+typedef struct _IndicatorCustomClass IndicatorCustomClass;
+
+struct _IndicatorCustomClass {
+ IndicatorObjectClass parent_class;
+};
+
+struct _IndicatorCustom {
+ IndicatorObject parent;
+};
+
+GType indicator_custom_get_type (void);
INDICATOR_SET_VERSION
-INDICATOR_SET_NAME("indicator-custom")
+INDICATOR_SET_TYPE(INDICATOR_CUSTOM_TYPE)
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+typedef struct _IndicatorCustomPrivate IndicatorCustomPrivate;
+struct _IndicatorCustomPrivate {
+ IndicatorServiceManager * sm;
+ DBusGConnection * bus;
+ DBusGProxy * service_proxy;
+ GList * applications;
+};
+
+typedef struct _ApplicationEntry ApplicationEntry;
+struct _ApplicationEntry {
+ guint position;
+ IndicatorObjectEntry entry;
+};
+
+#define INDICATOR_CUSTOM_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_CUSTOM_TYPE, IndicatorCustomPrivate))
+
+static void indicator_custom_class_init (IndicatorCustomClass *klass);
+static void indicator_custom_init (IndicatorCustom *self);
+static void indicator_custom_dispose (GObject *object);
+static void indicator_custom_finalize (GObject *object);
+static GList * get_entries (IndicatorObject * io);
+static void connected (IndicatorServiceManager * sm, gboolean connected, IndicatorCustom * custom);
+static void application_added (DBusGProxy * proxy, const gchar * iconname, gint position, const gchar * dbusaddress, const gchar * dbusobject, IndicatorCustom * custom);
+static void application_removed (DBusGProxy * proxy, gint position , IndicatorCustom * custom);
+static void get_applications (DBusGProxy *proxy, GPtrArray *OUT_applications, GError *error, gpointer userdata);
+
+G_DEFINE_TYPE (IndicatorCustom, indicator_custom, INDICATOR_OBJECT_TYPE);
+
+static void
+indicator_custom_class_init (IndicatorCustomClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
-IndicatorServiceManager * sm = NULL;
+ g_type_class_add_private (klass, sizeof (IndicatorCustomPrivate));
+
+ object_class->dispose = indicator_custom_dispose;
+ object_class->finalize = indicator_custom_finalize;
+
+ IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass);
+
+ io_class->get_entries = get_entries;
+
+ return;
+}
+
+static void
+indicator_custom_init (IndicatorCustom *self)
+{
+ IndicatorCustomPrivate * priv = INDICATOR_CUSTOM_GET_PRIVATE(self);
+
+ /* These are built in the connection phase */
+ priv->bus = NULL;
+ priv->service_proxy = NULL;
+
+ priv->sm = indicator_service_manager_new(INDICATOR_CUSTOM_DBUS_ADDR);
+ g_signal_connect(G_OBJECT(priv->sm), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connected), self);
+
+ priv->applications = NULL;
+
+ return;
+}
+
+static void
+indicator_custom_dispose (GObject *object)
+{
+ IndicatorCustomPrivate * priv = INDICATOR_CUSTOM_GET_PRIVATE(object);
+
+ while (priv->applications != NULL) {
+ application_removed(priv->service_proxy,
+ ((ApplicationEntry *)priv->applications->data)->position,
+ INDICATOR_CUSTOM(object));
+ }
+
+ if (priv->sm != NULL) {
+ g_object_unref(priv->sm);
+ priv->sm = NULL;
+ }
+
+ if (priv->bus != NULL) {
+ /* We're not incrementing the ref count on this one. */
+ priv->bus = NULL;
+ }
+
+ if (priv->service_proxy != NULL) {
+ g_object_unref(G_OBJECT(priv->service_proxy));
+ priv->service_proxy = NULL;
+ }
+
+ G_OBJECT_CLASS (indicator_custom_parent_class)->dispose (object);
+ return;
+}
+
+static void
+indicator_custom_finalize (GObject *object)
+{
+
+ G_OBJECT_CLASS (indicator_custom_parent_class)->finalize (object);
+ return;
+}
void
-connected (IndicatorServiceManager * sm, gboolean connected, gpointer not_used)
+connected (IndicatorServiceManager * sm, gboolean connected, IndicatorCustom * custom)
{
+ IndicatorCustomPrivate * priv = INDICATOR_CUSTOM_GET_PRIVATE(custom);
+ g_debug("Connected to Custom Indicator Service.");
+
+ GError * error = NULL;
+
+ /* Grab the session bus */
+ if (priv->bus == NULL) {
+ priv->bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+
+ if (error != NULL) {
+ g_error("Unable to get session bus: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+ }
+
+ /* Build the service proxy */
+ priv->service_proxy = dbus_g_proxy_new_for_name_owner(priv->bus,
+ INDICATOR_CUSTOM_DBUS_ADDR,
+ INDICATOR_CUSTOM_DBUS_OBJ,
+ INDICATOR_CUSTOM_DBUS_IFACE,
+ &error);
+
+ /* Set up proxy signals */
+ dbus_g_proxy_add_signal(priv->service_proxy,
+ "ApplicationAdded",
+ G_TYPE_STRING,
+ G_TYPE_INT,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_NONE);
+ dbus_g_proxy_add_signal(priv->service_proxy,
+ "ApplicationRemoved",
+ G_TYPE_INT,
+ G_TYPE_NONE);
+
+ dbus_g_proxy_connect_signal(priv->service_proxy,
+ "ApplicationAdded",
+ G_CALLBACK(application_added),
+ custom,
+ NULL /* Disconnection Signal */);
+ dbus_g_proxy_connect_signal(priv->service_proxy,
+ "ApplicationRemoved",
+ G_CALLBACK(application_removed),
+ custom,
+ NULL /* Disconnection Signal */);
+
+ /* Query it for existing applications */
+ org_ayatana_indicator_custom_service_get_applications_async(priv->service_proxy,
+ get_applications,
+ custom);
return;
}
-GtkLabel *
-get_label (void)
+/* Goes through the list of applications that we're maintaining and
+ pulls out the IndicatorObjectEntry and returns that in a list
+ for the caller. */
+static GList *
+get_entries (IndicatorObject * io)
{
- return NULL;
+ g_return_val_if_fail(IS_INDICATOR_CUSTOM(io), NULL);
+
+ IndicatorCustomPrivate * priv = INDICATOR_CUSTOM_GET_PRIVATE(io);
+ GList * retval = NULL;
+ GList * apppointer = NULL;
+
+ for (apppointer = priv->applications; apppointer != NULL; apppointer = g_list_next(apppointer)) {
+ IndicatorObjectEntry * entry = &(((ApplicationEntry *)apppointer->data)->entry);
+ retval = g_list_prepend(retval, entry);
+ }
+
+ if (retval != NULL) {
+ retval = g_list_reverse(retval);
+ }
+
+ return retval;
}
-GtkImage *
-get_icon (void)
+/* Here we respond to new applications by building up the
+ ApplicationEntry and signaling the indicator host that
+ we've got a new indicator. */
+static void
+application_added (DBusGProxy * proxy, const gchar * iconname, gint position, const gchar * dbusaddress, const gchar * dbusobject, IndicatorCustom * custom)
{
- return GTK_IMAGE(gtk_image_new());
+ IndicatorCustomPrivate * priv = INDICATOR_CUSTOM_GET_PRIVATE(custom);
+ ApplicationEntry * app = g_new(ApplicationEntry, 1);
+
+ app->position = position;
+ app->entry.image = GTK_IMAGE(gtk_image_new_from_icon_name(iconname, GTK_ICON_SIZE_MENU));
+ app->entry.label = NULL;
+ app->entry.menu = GTK_MENU(dbusmenu_gtkmenu_new((gchar *)dbusaddress, (gchar *)dbusobject));
+
+ priv->applications = g_list_prepend(priv->applications, app);
+
+ g_signal_emit(G_OBJECT(custom), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED_ID, 0, &(app->entry), TRUE);
+ return;
}
-GtkMenu *
-get_menu (void)
+static void
+application_removed (DBusGProxy * proxy, gint position , IndicatorCustom * custom)
{
- GtkMenu * main_menu = GTK_MENU(gtk_menu_new());
- GtkWidget * loading_item = gtk_menu_item_new_with_label("Loading...");
- gtk_menu_shell_append(GTK_MENU_SHELL(main_menu), loading_item);
- gtk_widget_show(GTK_WIDGET(loading_item));
- sm = indicator_service_manager_new(INDICATOR_CUSTOM_DBUS_ADDR);
- g_signal_connect(G_OBJECT(sm), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connected), NULL);
+ return;
+}
+
+/* This repsonds to the list of applications that the service
+ has and calls application_added on each one of them. */
+static void
+get_applications (DBusGProxy *proxy, GPtrArray *OUT_applications, GError *error, gpointer userdata)
+{
- return main_menu;
+ return;
}
diff --git a/src/notification-watcher.xml b/src/notification-watcher.xml
index 93acf74..7b034e7 100644
--- a/src/notification-watcher.xml
+++ b/src/notification-watcher.xml
@@ -7,6 +7,7 @@
<!-- Methods -->
<method name="RegisterService">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value="true" />
<arg type="s" name="service" direction="in" />
</method>
<method name="RegisteredServices">
@@ -31,7 +32,7 @@
</signal>
<signal name="NotificationHostRegistered">
</signal>
- <signal name="NotificationHostUnegistered">
+ <signal name="NotificationHostUnregistered">
</signal>
</interface>