diff options
-rw-r--r-- | .bzrignore | 5 | ||||
-rw-r--r-- | Makefile.am.marshal | 4 | ||||
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | src/Makefile.am | 10 | ||||
-rw-r--r-- | src/custom-service-appstore.c | 177 | ||||
-rw-r--r-- | src/custom-service-appstore.h | 11 | ||||
-rw-r--r-- | src/custom-service-marshal.list | 1 | ||||
-rw-r--r-- | src/custom-service-watcher.c | 183 | ||||
-rw-r--r-- | src/custom-service-watcher.h | 40 | ||||
-rw-r--r-- | src/custom-service.c | 3 | ||||
-rw-r--r-- | src/dbus-properties.xml | 23 | ||||
-rw-r--r-- | src/dbus-shared.h | 9 | ||||
-rw-r--r-- | src/indicator-custom.c | 259 | ||||
-rw-r--r-- | src/notification-watcher.xml | 3 |
14 files changed, 675 insertions, 59 deletions
@@ -26,3 +26,8 @@ tests/libcustomindicator-tests tests/test-libcustomindicator-dbus src/custom-service-client.h src/custom-service-server.h +src/custom-service-marshal.c +src/custom-service-marshal.h +src/stamp-marshal +src/dbus-properties-client.h +src/dbus-properties-server.h diff --git a/Makefile.am.marshal b/Makefile.am.marshal index 8b30d4f..a6ab024 100644 --- a/Makefile.am.marshal +++ b/Makefile.am.marshal @@ -26,7 +26,7 @@ stamp-marshal: $(glib_marshal_list) $(QUIET_GEN)$(GLIB_GENMARSHAL) \ --prefix=$(glib_marshal_prefix) \ --header \ - $(glib_marshal_list) > xgen-mh \ + $(srcdir)/$(glib_marshal_list) > xgen-mh \ && (cmp -s xgen-mh $(marshal_h) || cp -f xgen-mh $(marshal_h)) \ && rm -f xgen-mh \ && echo timestamp > $(@F) @@ -39,7 +39,7 @@ $(marshal_c): $(marshal_h) $(GLIB_GENMARSHAL) \ --prefix=$(glib_marshal_prefix) \ --body \ - $(glib_marshal_list)) > xgen-mc \ + $(srcdir)/$(glib_marshal_list)) > xgen-mc \ && cp xgen-mc $(marshal_c) \ && rm -f xgen-mc diff --git a/debian/changelog b/debian/changelog index c37028a..a479c64 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +indicator-custom (0.0.1-0ubuntu3~ppa1~service2) UNRELEASED; urgency=low + + * Building the service and getting things in better shape. + + -- Ted Gould <ted@ubuntu.com> Sun, 08 Nov 2009 23:03:10 -0600 + indicator-custom (0.0.1-0ubuntu3~ppa1~service1) karmic; urgency=low * Grabbing from the service development branch 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> |