aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen VanDine <ken.vandine@canonical.com>2010-01-08 22:17:33 -0500
committerKen VanDine <ken.vandine@canonical.com>2010-01-08 22:17:33 -0500
commit64df46b47e18de9c4cbf0ef87b9bae2853324637 (patch)
tree58d878cb2b30e583f0a0b87609e31478ba5a52d2
parent60e78aa5b49972bb34b5049d2d54e1be4b7ad992 (diff)
parentc1010b61c9097212c9631b6cbc4e85fd62539364 (diff)
downloadayatana-indicator-application-64df46b47e18de9c4cbf0ef87b9bae2853324637.tar.gz
ayatana-indicator-application-64df46b47e18de9c4cbf0ef87b9bae2853324637.tar.bz2
ayatana-indicator-application-64df46b47e18de9c4cbf0ef87b9bae2853324637.zip
* Upstream Release 0.0.7
* Making the Notification Watcher register for it's own DBus name to keep the service one unique. * Adding support for icons changing through the service and in the indicator. * Fixing the generated headers for DBus Properties calls * Fixing libappindicator set_icon to set the right icon. * Adding in icon path support. * Switching DBus interface to org.freedesktop * Adding check/radio support to menu parsing * Adding ChangeLog to dist * Adding check item support to menu parsing
-rw-r--r--.bzrignore43
-rw-r--r--Makefile.am3
-rw-r--r--configure.ac4
-rw-r--r--debian/changelog19
-rw-r--r--docs/reference/libappindicator-sections.txt1
-rw-r--r--docs/reference/tmpl/libappindicator-unused.sgml6
-rw-r--r--example/simple-client.c4
-rw-r--r--src/Makefile.am1
-rw-r--r--src/application-service-appstore.c368
-rw-r--r--src/application-service-appstore.h7
-rw-r--r--src/application-service-marshal.list3
-rw-r--r--src/application-service-watcher.c56
-rw-r--r--src/application-service.c2
-rw-r--r--src/application-service.xml5
-rw-r--r--src/dbus-properties-client.h139
-rw-r--r--src/dbus-shared.h8
-rw-r--r--src/indicator-application.c52
-rw-r--r--src/libappindicator/app-indicator.c114
-rw-r--r--src/libappindicator/app-indicator.h8
-rw-r--r--src/notification-item.xml7
-rw-r--r--src/notification-watcher.xml8
21 files changed, 786 insertions, 72 deletions
diff --git a/.bzrignore b/.bzrignore
index 4856033..977611c 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -44,3 +44,46 @@ src/libapplication_la-application-service-marshal.lo
src/libapplication_la-indicator-application.lo
src/libappindicator/app-indicator-enum-types.c
src/libappindicator/app-indicator-enum-types.h
+gtk-doc.make
+py-compile
+bindings/mono/appindicator-sharp-0.1.pc
+bindings/mono/appindicator-sharp.dll
+bindings/mono/appindicator-sharp.dll.config
+bindings/mono/generated
+bindings/mono/generated-stamp
+bindings/mono/libappindicator-api.raw
+bindings/mono/libappindicator-api.xml
+bindings/mono/examples/indicator-example
+bindings/python/.deps
+bindings/python/.libs
+bindings/python/_appindicator.la
+bindings/python/appindicator.c
+bindings/python/appindicator.lo
+bindings/python/appindicatormodule.lo
+docs/reference/.libs
+docs/reference/gtkdoc-in-srcdir
+docs/reference/html
+docs/reference/html-build.stamp
+docs/reference/html.stamp
+docs/reference/libappindicator-decl-list.txt
+docs/reference/libappindicator-decl.txt
+docs/reference/libappindicator-docs.sgml
+docs/reference/libappindicator-overrides.txt
+docs/reference/libappindicator-undeclared.txt
+docs/reference/libappindicator-undocumented.txt
+docs/reference/libappindicator-unused.txt
+docs/reference/libappindicator.args
+docs/reference/libappindicator.hierarchy
+docs/reference/libappindicator.interfaces
+docs/reference/libappindicator.prerequisites
+docs/reference/libappindicator.signals
+docs/reference/scan-build.stamp
+docs/reference/sgml-build.stamp
+docs/reference/sgml.stamp
+docs/reference/tmpl-build.stamp
+docs/reference/tmpl.stamp
+docs/reference/version.xml
+docs/reference/xml
+docs/reference/tmpl/app-indicator.sgml
+docs/reference/tmpl/app-indicator.sgml.bak
+src/libappindicator/appindicator-0.1.pc
diff --git a/Makefile.am b/Makefile.am
index a9b445c..4d38ef8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,7 +11,8 @@ EXTRA_DIST = \
xmldocs.make \
autogen.sh \
COPYING.LGPL.2.1 \
- COPYING.LGPL.3
+ COPYING.LGPL.3 \
+ ChangeLog
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-localinstall
diff --git a/configure.ac b/configure.ac
index 559c2b4..4bc18b2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,11 +1,11 @@
-AC_INIT(indicator-application, 0.0.6, ted@canonical.com)
+AC_INIT(indicator-application, 0.0.7, ted@canonical.com)
AC_COPYRIGHT([Copyright 2009 Canonical])
AC_PREREQ(2.53)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(indicator-application, 0.0.6)
+AM_INIT_AUTOMAKE(indicator-application, 0.0.7)
AM_MAINTAINER_MODE
diff --git a/debian/changelog b/debian/changelog
index 0801ab4..89635e7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,21 @@
-indicator-application (0.0.6-0ubuntu1) UNRELEASED; urgency=low
+indicator-application (0.0.7-0ubuntu1) lucid; urgency=low
+
+ * Upstream Release 0.0.7
+ * Making the Notification Watcher register for it's own DBus
+ name to keep the service one unique.
+ * Adding support for icons changing through the service and
+ in the indicator.
+ * Fixing the generated headers for DBus Properties calls
+ * Fixing libappindicator set_icon to set the right icon.
+ * Adding in icon path support.
+ * Switching DBus interface to org.freedesktop
+ * Adding check/radio support to menu parsing
+ * Adding ChangeLog to dist
+ * Adding check item support to menu parsing
+
+ -- Ted Gould <ted@ubuntu.com> Fri, 08 Jan 2010 16:05:39 -0600
+
+indicator-application (0.0.6-0ubuntu1) lucid; urgency=low
* Upstream release 0.0.6
* Include Python binding
diff --git a/docs/reference/libappindicator-sections.txt b/docs/reference/libappindicator-sections.txt
index b994297..68b120a 100644
--- a/docs/reference/libappindicator-sections.txt
+++ b/docs/reference/libappindicator-sections.txt
@@ -18,6 +18,7 @@ AppIndicator
AppIndicatorClass
app_indicator_get_type
app_indicator_new
+app_indicator_new_with_path
app_indicator_set_status
app_indicator_set_attention_icon
app_indicator_set_menu
diff --git a/docs/reference/tmpl/libappindicator-unused.sgml b/docs/reference/tmpl/libappindicator-unused.sgml
index e69de29..1428b51 100644
--- a/docs/reference/tmpl/libappindicator-unused.sgml
+++ b/docs/reference/tmpl/libappindicator-unused.sgml
@@ -0,0 +1,6 @@
+<!-- ##### ARG AppIndicator:icon-path ##### -->
+<para>
+
+</para>
+
+
diff --git a/example/simple-client.c b/example/simple-client.c
index ea4da9d..8ce9fba 100644
--- a/example/simple-client.c
+++ b/example/simple-client.c
@@ -53,12 +53,12 @@ main (int argc, char ** argv)
app_indicator_set_attention_icon(ci, "indicator-messages-new");
menu = gtk_menu_new ();
- GtkWidget *item = gtk_menu_item_new_with_label ("1");
+ GtkWidget *item = gtk_check_menu_item_new_with_label ("1");
g_signal_connect (item, "activate",
G_CALLBACK (item_clicked_cb), "1");
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- item = gtk_menu_item_new_with_label ("2");
+ item = gtk_radio_menu_item_new_with_label (NULL, "2");
g_signal_connect (item, "activate",
G_CALLBACK (item_clicked_cb), "2");
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
diff --git a/src/Makefile.am b/src/Makefile.am
index f101d12..d9b7963 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -101,7 +101,6 @@ libappindicator_la_LIBADD = \
DBUS_SPECS = \
application-service.xml \
- dbus-properties.xml \
notification-item.xml \
notification-watcher.xml
diff --git a/src/application-service-appstore.c b/src/application-service-appstore.c
index 1391d33..fa1b9d2 100644
--- a/src/application-service-appstore.c
+++ b/src/application-service-appstore.c
@@ -40,8 +40,13 @@ static gboolean _application_service_server_get_applications (ApplicationService
#define NOTIFICATION_ITEM_PROP_STATUS "Status"
#define NOTIFICATION_ITEM_PROP_ICON_NAME "IconName"
#define NOTIFICATION_ITEM_PROP_AICON_NAME "AttentionIconName"
+#define NOTIFICATION_ITEM_PROP_ICON_PATH "IconThemePath"
#define NOTIFICATION_ITEM_PROP_MENU "Menu"
+#define NOTIFICATION_ITEM_SIG_NEW_ICON "NewIcon"
+#define NOTIFICATION_ITEM_SIG_NEW_AICON "NewAttentionIcon"
+#define NOTIFICATION_ITEM_SIG_NEW_STATUS "NewStatus"
+
/* Private Stuff */
typedef struct _ApplicationServiceAppstorePrivate ApplicationServiceAppstorePrivate;
struct _ApplicationServiceAppstorePrivate {
@@ -49,6 +54,17 @@ struct _ApplicationServiceAppstorePrivate {
GList * applications;
};
+#define APP_STATUS_PASSIVE_STR "passive"
+#define APP_STATUS_ACTIVE_STR "active"
+#define APP_STATUS_ATTENTION_STR "attention"
+
+typedef enum _ApplicationStatus ApplicationStatus;
+enum _ApplicationStatus {
+ APP_STATUS_PASSIVE,
+ APP_STATUS_ACTIVE,
+ APP_STATUS_ATTENTION
+};
+
typedef struct _Application Application;
struct _Application {
gchar * dbus_name;
@@ -56,6 +72,13 @@ struct _Application {
ApplicationServiceAppstore * appstore; /* not ref'd */
DBusGProxy * dbus_proxy;
DBusGProxy * prop_proxy;
+ gboolean validated; /* Whether we've gotten all the parameters and they look good. */
+ ApplicationStatus status;
+ gchar * icon;
+ gchar * aicon;
+ gchar * menu;
+ gchar * icon_path;
+ gboolean currently_free;
};
#define APPLICATION_SERVICE_APPSTORE_GET_PRIVATE(o) \
@@ -65,6 +88,7 @@ struct _Application {
enum {
APPLICATION_ADDED,
APPLICATION_REMOVED,
+ APPLICATION_ICON_CHANGED,
LAST_SIGNAL
};
@@ -75,6 +99,8 @@ static void application_service_appstore_class_init (ApplicationServiceAppstoreC
static void application_service_appstore_init (ApplicationServiceAppstore *self);
static void application_service_appstore_dispose (GObject *object);
static void application_service_appstore_finalize (GObject *object);
+static ApplicationStatus string_to_status(const gchar * status_string);
+static void apply_status (Application * app, ApplicationStatus status);
G_DEFINE_TYPE (ApplicationServiceAppstore, application_service_appstore, G_TYPE_OBJECT);
@@ -91,18 +117,24 @@ application_service_appstore_class_init (ApplicationServiceAppstoreClass *klass)
signals[APPLICATION_ADDED] = g_signal_new ("application-added",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ApplicationServiceAppstore, application_added),
+ G_STRUCT_OFFSET (ApplicationServiceAppstoreClass, application_added),
NULL, NULL,
- _application_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);
+ _application_service_marshal_VOID__STRING_INT_STRING_STRING_STRING,
+ G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, 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 (ApplicationServiceAppstore, application_removed),
+ G_STRUCT_OFFSET (ApplicationServiceAppstoreClass, application_removed),
NULL, NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE, 1, G_TYPE_INT, G_TYPE_NONE);
-
+ signals[APPLICATION_ICON_CHANGED] = g_signal_new ("application-icon-changed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ApplicationServiceAppstoreClass, application_icon_changed),
+ NULL, NULL,
+ _application_service_marshal_VOID__INT_STRING,
+ G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING, G_TYPE_NONE);
dbus_g_object_type_install_info(APPLICATION_SERVICE_APPSTORE_TYPE,
&dbus_glib__application_service_server_object_info);
@@ -155,6 +187,9 @@ application_service_appstore_finalize (GObject *object)
return;
}
+/* Return from getting the properties from the item. We're looking at those
+ and making sure we have everythign that we need. If we do, then we'll
+ move on up to sending this onto the indicator. */
static void
get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data)
{
@@ -166,36 +201,77 @@ get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * err
Application * app = (Application *)data;
if (g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_MENU) == NULL ||
+ g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_STATUS) == 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;
}
- ApplicationServiceAppstorePrivate * priv = APPLICATION_SERVICE_APPSTORE_GET_PRIVATE(app->appstore);
- priv->applications = g_list_prepend(priv->applications, app);
-
- /* TODO: We need to have the position determined better. This
- would involve looking at the name and category and sorting
- it with the other entries. */
-
- 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);
+ app->validated = TRUE;
+
+ app->icon = g_value_dup_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ICON_NAME));
+ app->menu = g_value_dup_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_MENU));
+ if (g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_AICON_NAME) != NULL) {
+ app->aicon = g_value_dup_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ICON_NAME));
+ }
+
+ gpointer icon_path_data = g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ICON_PATH);
+ if (icon_path_data != NULL) {
+ app->icon_path = g_value_dup_string((GValue *)icon_path_data);
+ } else {
+ app->icon_path = g_strdup("");
+ }
+
+ apply_status(app, string_to_status(g_value_get_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_STATUS))));
return;
}
+/* Simple translation function -- could be optimized */
+static ApplicationStatus
+string_to_status(const gchar * status_string)
+{
+ if (!g_strcmp0(status_string, APP_STATUS_ACTIVE_STR))
+ return APP_STATUS_ACTIVE;
+ if (!g_strcmp0(status_string, APP_STATUS_ATTENTION_STR))
+ return APP_STATUS_ATTENTION;
+ return APP_STATUS_PASSIVE;
+}
+
+/* A small helper function to get the position of an application
+ in the app list. */
+static gint
+get_position (Application * app) {
+ ApplicationServiceAppstore * appstore = app->appstore;
+ ApplicationServiceAppstorePrivate * priv = APPLICATION_SERVICE_APPSTORE_GET_PRIVATE(appstore);
+
+ GList * applistitem = g_list_find(priv->applications, app);
+ if (applistitem == NULL) {
+ return -1;
+ }
+
+ return g_list_position(priv->applications, applistitem);
+}
+
/* A simple global function for dealing with freeing the information
in an Application structure */
static void
application_free (Application * app)
{
if (app == NULL) return;
+
+ /* Handle the case where this could be called by unref'ing one of
+ the proxy objects. */
+ if (app->currently_free) return;
+ app->currently_free = TRUE;
+
+ if (app->dbus_proxy) {
+ g_object_unref(app->dbus_proxy);
+ }
+ if (app->prop_proxy) {
+ g_object_unref(app->prop_proxy);
+ }
if (app->dbus_name != NULL) {
g_free(app->dbus_name);
@@ -203,6 +279,18 @@ application_free (Application * app)
if (app->dbus_object != NULL) {
g_free(app->dbus_object);
}
+ if (app->icon != NULL) {
+ g_free(app->icon);
+ }
+ if (app->aicon != NULL) {
+ g_free(app->aicon);
+ }
+ if (app->menu != NULL) {
+ g_free(app->menu);
+ }
+ if (app->icon_path != NULL) {
+ g_free(app->icon_path);
+ }
g_free(app);
return;
@@ -214,24 +302,198 @@ static void
application_removed_cb (DBusGProxy * proxy, gpointer userdata)
{
Application * app = (Application *)userdata;
+
+ /* Remove from the panel */
+ apply_status(app, APP_STATUS_PASSIVE);
+
+ /* Destroy the data */
+ application_free(app);
+ return;
+}
+
+/* Change the status of the application. If we're going passive
+ it removes it from the panel. If we're coming online, then
+ it add it to the panel. Otherwise it changes the icon. */
+static void
+apply_status (Application * app, ApplicationStatus status)
+{
+ if (app->status == status) {
+ return;
+ }
+ g_debug("Changing app status to: %d", status);
+
ApplicationServiceAppstore * appstore = app->appstore;
ApplicationServiceAppstorePrivate * priv = APPLICATION_SERVICE_APPSTORE_GET_PRIVATE(appstore);
- GList * applistitem = g_list_find(priv->applications, app);
- if (applistitem == NULL) {
- g_warning("Removing an application that isn't in the application list?");
+ /* This means we're going off line */
+ if (status == APP_STATUS_PASSIVE) {
+ gint position = get_position(app);
+ if (position == -1) return;
+
+ g_signal_emit(G_OBJECT(appstore),
+ signals[APPLICATION_REMOVED], 0,
+ position, TRUE);
+
+ priv->applications = g_list_remove(priv->applications, app);
+ } else {
+ /* Figure out which icon we should be using */
+ gchar * newicon = app->icon;
+ if (status == APP_STATUS_ATTENTION && app->aicon != NULL) {
+ newicon = app->aicon;
+ }
+
+ /* Determine whether we're already shown or not */
+ if (app->status == APP_STATUS_PASSIVE) {
+ /* Put on panel */
+ priv->applications = g_list_prepend(priv->applications, app);
+
+ /* TODO: We need to have the position determined better. This
+ would involve looking at the name and category and sorting
+ it with the other entries. */
+
+ g_signal_emit(G_OBJECT(app->appstore),
+ signals[APPLICATION_ADDED], 0,
+ newicon,
+ 0, /* Position */
+ app->dbus_name,
+ app->menu,
+ app->icon_path,
+ TRUE);
+ } else {
+ /* Icon update */
+ gint position = get_position(app);
+ if (position == -1) return;
+
+ g_signal_emit(G_OBJECT(appstore),
+ signals[APPLICATION_ICON_CHANGED], 0,
+ position, newicon, TRUE);
+ }
+ }
+
+ app->status = status;
+
+ return;
+}
+
+/* Gets the data back on an updated icon signal. Hopefully
+ a new fun icon. */
+static void
+new_icon_cb (DBusGProxy * proxy, GValue value, GError * error, gpointer userdata)
+{
+ /* Check for errors */
+ if (error != NULL) {
+ g_warning("Unable to get updated icon name: %s", error->message);
return;
}
- gint position = g_list_position(priv->applications, applistitem);
+ /* Grab the icon and make sure we have one */
+ const gchar * newicon = g_value_get_string(&value);
+ if (newicon == NULL) {
+ g_warning("Bad new icon :(");
+ return;
+ }
- g_signal_emit(G_OBJECT(appstore),
- signals[APPLICATION_REMOVED], 0,
- position, TRUE);
+ Application * app = (Application *) userdata;
- priv->applications = g_list_remove(priv->applications, app);
+ if (g_strcmp0(newicon, app->icon)) {
+ /* If the new icon is actually a new icon */
+ if (app->icon != NULL) g_free(app->icon);
+ app->icon = g_strdup(newicon);
+
+ if (app->status == APP_STATUS_ACTIVE) {
+ gint position = get_position(app);
+ if (position == -1) return;
+
+ g_signal_emit(G_OBJECT(app->appstore),
+ signals[APPLICATION_ICON_CHANGED], 0,
+ position, newicon, TRUE);
+ }
+ }
+
+ return;
+}
+
+/* Gets the data back on an updated aicon signal. Hopefully
+ a new fun icon. */
+static void
+new_aicon_cb (DBusGProxy * proxy, GValue value, GError * error, gpointer userdata)
+{
+ /* Check for errors */
+ if (error != NULL) {
+ g_warning("Unable to get updated icon name: %s", error->message);
+ return;
+ }
+
+ /* Grab the icon and make sure we have one */
+ const gchar * newicon = g_value_get_string(&value);
+ if (newicon == NULL) {
+ g_warning("Bad new icon :(");
+ return;
+ }
+
+ Application * app = (Application *) userdata;
+
+ if (g_strcmp0(newicon, app->aicon)) {
+ /* If the new icon is actually a new icon */
+ if (app->aicon != NULL) g_free(app->aicon);
+ app->aicon = g_strdup(newicon);
+
+ if (app->status == APP_STATUS_ATTENTION) {
+ gint position = get_position(app);
+ if (position == -1) return;
+
+ g_signal_emit(G_OBJECT(app->appstore),
+ signals[APPLICATION_ICON_CHANGED], 0,
+ position, newicon, TRUE);
+ }
+ }
+
+ return;
+}
+
+/* Called when the Notification Item signals that it
+ has a new icon. */
+static void
+new_icon (DBusGProxy * proxy, gpointer data)
+{
+ Application * app = (Application *)data;
+ if (!app->validated) return;
+
+ org_freedesktop_DBus_Properties_get_async(app->prop_proxy,
+ NOTIFICATION_ITEM_DBUS_IFACE,
+ NOTIFICATION_ITEM_PROP_ICON_NAME,
+ new_icon_cb,
+ app);
+ return;
+}
+
+/* Called when the Notification Item signals that it
+ has a new attention icon. */
+static void
+new_aicon (DBusGProxy * proxy, gpointer data)
+{
+ Application * app = (Application *)data;
+ if (!app->validated) return;
+
+ org_freedesktop_DBus_Properties_get_async(app->prop_proxy,
+ NOTIFICATION_ITEM_DBUS_IFACE,
+ NOTIFICATION_ITEM_PROP_AICON_NAME,
+ new_aicon_cb,
+ app);
+
+ return;
+}
+
+/* Called when the Notification Item signals that it
+ has a new status. */
+static void
+new_status (DBusGProxy * proxy, const gchar * status, gpointer data)
+{
+ Application * app = (Application *)data;
+ if (!app->validated) return;
+
+ apply_status(app, string_to_status(status));
- application_free(app);
return;
}
@@ -251,11 +513,18 @@ application_service_appstore_application_add (ApplicationServiceAppstore * appst
/* Build the application entry. This will be carried
along until we're sure we've got everything. */
- Application * app = g_new(Application, 1);
+ Application * app = g_new0(Application, 1);
+ app->validated = FALSE;
app->dbus_name = g_strdup(dbus_name);
app->dbus_object = g_strdup(dbus_object);
app->appstore = appstore;
+ app->status = APP_STATUS_PASSIVE;
+ app->icon = NULL;
+ app->aicon = NULL;
+ app->menu = NULL;
+ app->icon_path = NULL;
+ app->currently_free = FALSE;
/* Get the DBus proxy for the NotificationItem interface */
GError * error = NULL;
@@ -290,6 +559,34 @@ application_service_appstore_application_add (ApplicationServiceAppstore * appst
return;
}
+ /* Connect to signals */
+ dbus_g_proxy_add_signal(app->dbus_proxy,
+ NOTIFICATION_ITEM_SIG_NEW_ICON,
+ G_TYPE_INVALID);
+ dbus_g_proxy_add_signal(app->dbus_proxy,
+ NOTIFICATION_ITEM_SIG_NEW_AICON,
+ G_TYPE_INVALID);
+ dbus_g_proxy_add_signal(app->dbus_proxy,
+ NOTIFICATION_ITEM_SIG_NEW_STATUS,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+
+ dbus_g_proxy_connect_signal(app->dbus_proxy,
+ NOTIFICATION_ITEM_SIG_NEW_ICON,
+ G_CALLBACK(new_icon),
+ app,
+ NULL);
+ dbus_g_proxy_connect_signal(app->dbus_proxy,
+ NOTIFICATION_ITEM_SIG_NEW_AICON,
+ G_CALLBACK(new_aicon),
+ app,
+ NULL);
+ dbus_g_proxy_connect_signal(app->dbus_proxy,
+ NOTIFICATION_ITEM_SIG_NEW_STATUS,
+ G_CALLBACK(new_status),
+ app,
+ NULL);
+
/* Get all the propertiees */
org_freedesktop_DBus_Properties_get_all_async(app->prop_proxy,
NOTIFICATION_ITEM_DBUS_IFACE,
@@ -301,6 +598,8 @@ application_service_appstore_application_add (ApplicationServiceAppstore * appst
return;
}
+/* Removes an application. Currently only works for the apps
+ that are shown. /TODO Need to fix that. */
void
application_service_appstore_application_remove (ApplicationServiceAppstore * appstore, const gchar * dbus_name, const gchar * dbus_object)
{
@@ -308,6 +607,17 @@ application_service_appstore_application_remove (ApplicationServiceAppstore * ap
g_return_if_fail(dbus_name != NULL && dbus_name[0] != '\0');
g_return_if_fail(dbus_object != NULL && dbus_object[0] != '\0');
+ ApplicationServiceAppstorePrivate * priv = APPLICATION_SERVICE_APPSTORE_GET_PRIVATE(appstore);
+ GList * listpntr;
+
+ for (listpntr = priv->applications; listpntr != NULL; listpntr = g_list_next(listpntr)) {
+ Application * app = (Application *)listpntr->data;
+
+ if (!g_strcmp0(app->dbus_name, dbus_name) && !g_strcmp0(app->dbus_object, dbus_object)) {
+ application_removed_cb(NULL, app);
+ break; /* NOTE: Must break as the list will become inconsistent */
+ }
+ }
return;
}
diff --git a/src/application-service-appstore.h b/src/application-service-appstore.h
index edf1a37..6bd7a01 100644
--- a/src/application-service-appstore.h
+++ b/src/application-service-appstore.h
@@ -40,13 +40,14 @@ typedef struct _ApplicationServiceAppstoreClass ApplicationServiceAppstoreClass;
struct _ApplicationServiceAppstoreClass {
GObjectClass parent_class;
+
+ void (*application_added) (ApplicationServiceAppstore * appstore, gchar *, gint, gchar *, gchar *, gpointer);
+ void (*application_removed) (ApplicationServiceAppstore * appstore, gint, gpointer);
+ void (*application_icon_changed)(ApplicationServiceAppstore * appstore, gint, const gchar *, gpointer);
};
struct _ApplicationServiceAppstore {
GObject parent;
-
- void (*application_added) (ApplicationServiceAppstore * appstore, gchar *, gint, gchar *, gchar *, gpointer);
- void (*application_removed) (ApplicationServiceAppstore * appstore, gint, gpointer);
};
GType application_service_appstore_get_type (void);
diff --git a/src/application-service-marshal.list b/src/application-service-marshal.list
index a122bf8..4ac8398 100644
--- a/src/application-service-marshal.list
+++ b/src/application-service-marshal.list
@@ -16,4 +16,5 @@
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
-VOID: STRING, INT, STRING, STRING
+VOID: STRING, INT, STRING, STRING, STRING
+VOID: INT, STRING
diff --git a/src/application-service-watcher.c b/src/application-service-watcher.c
index 984b9d4..eff249d 100644
--- a/src/application-service-watcher.c
+++ b/src/application-service-watcher.c
@@ -26,14 +26,16 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib-bindings.h>
#include "application-service-watcher.h"
#include "dbus-shared.h"
-static gboolean _notification_watcher_server_register_service (ApplicationServiceWatcher * appwatcher, const gchar * service, DBusGMethodInvocation * method);
-static gboolean _notification_watcher_server_registered_services (ApplicationServiceWatcher * appwatcher, GArray ** apps);
+static gboolean _notification_watcher_server_register_status_notifier_item (ApplicationServiceWatcher * appwatcher, const gchar * service, DBusGMethodInvocation * method);
+static gboolean _notification_watcher_server_registered_status_notifier_items (ApplicationServiceWatcher * appwatcher, GArray ** apps);
static gboolean _notification_watcher_server_protocol_version (ApplicationServiceWatcher * appwatcher, char ** version);
static gboolean _notification_watcher_server_register_notification_host (ApplicationServiceWatcher * appwatcher, const gchar * host);
static gboolean _notification_watcher_server_is_notification_host_registered (ApplicationServiceWatcher * appwatcher, gboolean * haveHost);
+static void get_name_cb (DBusGProxy * proxy, guint status, GError * error, gpointer data);
#include "notification-watcher-server.h"
@@ -41,6 +43,7 @@ static gboolean _notification_watcher_server_is_notification_host_registered (Ap
typedef struct _ApplicationServiceWatcherPrivate ApplicationServiceWatcherPrivate;
struct _ApplicationServiceWatcherPrivate {
ApplicationServiceAppstore * appstore;
+ DBusGProxy * dbus_proxy;
};
#define APPLICATION_SERVICE_WATCHER_GET_PRIVATE(o) \
@@ -129,6 +132,23 @@ application_service_watcher_init (ApplicationServiceWatcher *self)
NOTIFICATION_WATCHER_DBUS_OBJ,
G_OBJECT(self));
+ priv->dbus_proxy = dbus_g_proxy_new_for_name_owner(session_bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ &error);
+ if (error != NULL) {
+ g_error("Ah, can't get proxy to dbus: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ org_freedesktop_DBus_request_name_async(priv->dbus_proxy,
+ NOTIFICATION_WATCHER_DBUS_ADDR,
+ DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ get_name_cb,
+ self);
+
return;
}
@@ -165,18 +185,26 @@ application_service_watcher_new (ApplicationServiceAppstore * appstore)
}
static gboolean
-_notification_watcher_server_register_service (ApplicationServiceWatcher * appwatcher, const gchar * service, DBusGMethodInvocation * method)
+_notification_watcher_server_register_status_notifier_item (ApplicationServiceWatcher * appwatcher, const gchar * service, DBusGMethodInvocation * method)
{
ApplicationServiceWatcherPrivate * priv = APPLICATION_SERVICE_WATCHER_GET_PRIVATE(appwatcher);
- application_service_appstore_application_add(priv->appstore, dbus_g_method_get_sender(method), service);
+ if (service[0] == '/') {
+ application_service_appstore_application_add(priv->appstore,
+ dbus_g_method_get_sender(method),
+ service);
+ } else {
+ application_service_appstore_application_add(priv->appstore,
+ service,
+ NOTIFICATION_ITEM_DEFAULT_OBJ);
+ }
dbus_g_method_return(method, G_TYPE_NONE);
return TRUE;
}
static gboolean
-_notification_watcher_server_registered_services (ApplicationServiceWatcher * appwatcher, GArray ** apps)
+_notification_watcher_server_registered_status_notifier_items (ApplicationServiceWatcher * appwatcher, GArray ** apps)
{
return FALSE;
@@ -203,3 +231,21 @@ _notification_watcher_server_is_notification_host_registered (ApplicationService
return TRUE;
}
+/* Function to handle the return of the get name. There isn't a whole
+ lot that can be done, but we're atleast going to tell people. */
+static void
+get_name_cb (DBusGProxy * proxy, guint status, GError * error, gpointer data)
+{
+ if (error != NULL) {
+ g_warning("Unable to get watcher name '%s' because: %s", NOTIFICATION_WATCHER_DBUS_ADDR, error->message);
+ return;
+ }
+
+ if (status != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER &&
+ status != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) {
+ g_warning("Unable to get watcher name '%s'", NOTIFICATION_WATCHER_DBUS_ADDR);
+ return;
+ }
+
+ return;
+}
diff --git a/src/application-service.c b/src/application-service.c
index 45295a1..351e9aa 100644
--- a/src/application-service.c
+++ b/src/application-service.c
@@ -57,7 +57,7 @@ main (int argc, char ** argv)
/* Bring us up as a basic indicator service */
service = indicator_service_new(INDICATOR_APPLICATION_DBUS_ADDR);
- g_signal_connect(G_OBJECT(service), "disconnected", G_CALLBACK(service_disconnected), NULL);
+ g_signal_connect(G_OBJECT(service), INDICATOR_SERVICE_SIGNAL_SHUTDOWN, G_CALLBACK(service_disconnected), NULL);
/* Building our app store */
appstore = APPLICATION_SERVICE_APPSTORE(g_object_new(APPLICATION_SERVICE_APPSTORE_TYPE, NULL));
diff --git a/src/application-service.xml b/src/application-service.xml
index fdd25bb..d74aaa9 100644
--- a/src/application-service.xml
+++ b/src/application-service.xml
@@ -35,10 +35,15 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
<arg type="i" name="position" direction="out" />
<arg type="s" name="dbusaddress" direction="out" />
<arg type="o" name="dbusobject" direction="out" />
+ <arg type="s" name="iconpath" direction="out" />
</signal>
<signal name="ApplicationRemoved">
<arg type="i" name="position" direction="out" />
</signal>
+ <signal name="ApplicationIconChanged">
+ <arg type="i" name="position" direction="out" />
+ <arg type="s" name="icon_name" direction="out" />
+ </signal>
</interface>
</node>
diff --git a/src/dbus-properties-client.h b/src/dbus-properties-client.h
new file mode 100644
index 0000000..dc9f299
--- /dev/null
+++ b/src/dbus-properties-client.h
@@ -0,0 +1,139 @@
+/* Generated by dbus-binding-tool; do not edit! */
+
+#include <glib.h>
+#include <dbus/dbus-glib.h>
+
+G_BEGIN_DECLS
+
+#ifndef _DBUS_GLIB_ASYNC_DATA_FREE
+#define _DBUS_GLIB_ASYNC_DATA_FREE
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+void
+_dbus_glib_async_data_free (gpointer stuff)
+{
+ g_slice_free (DBusGAsyncData, stuff);
+}
+#endif
+
+#ifndef DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_DBus_Properties
+#define DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_DBus_Properties
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_freedesktop_DBus_Properties_get (DBusGProxy *proxy, const char * IN_Interface_Name, const char * IN_Property_Name, GValue* OUT_Value, GError **error)
+
+{
+ return dbus_g_proxy_call (proxy, "Get", error, G_TYPE_STRING, IN_Interface_Name, G_TYPE_STRING, IN_Property_Name, G_TYPE_INVALID, G_TYPE_VALUE, OUT_Value, G_TYPE_INVALID);
+}
+
+typedef void (*org_freedesktop_DBus_Properties_get_reply) (DBusGProxy *proxy, GValue OUT_Value, GError *error, gpointer userdata);
+
+static void
+org_freedesktop_DBus_Properties_get_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+ DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+ GError *error = NULL;
+ GValue OUT_Value = {0};
+ dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_VALUE, &OUT_Value, G_TYPE_INVALID);
+ (*(org_freedesktop_DBus_Properties_get_reply)data->cb) (proxy, OUT_Value, error, data->userdata);
+ return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_freedesktop_DBus_Properties_get_async (DBusGProxy *proxy, const char * IN_Interface_Name, const char * IN_Property_Name, org_freedesktop_DBus_Properties_get_reply callback, gpointer userdata)
+
+{
+ DBusGAsyncData *stuff;
+ stuff = g_slice_new (DBusGAsyncData);
+ stuff->cb = G_CALLBACK (callback);
+ stuff->userdata = userdata;
+ return dbus_g_proxy_begin_call (proxy, "Get", org_freedesktop_DBus_Properties_get_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_Interface_Name, G_TYPE_STRING, IN_Property_Name, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_freedesktop_DBus_Properties_set (DBusGProxy *proxy, const char * IN_Interface_Name, const char * IN_Property_Name, const GValue* IN_Value, GError **error)
+
+{
+ return dbus_g_proxy_call (proxy, "Set", error, G_TYPE_STRING, IN_Interface_Name, G_TYPE_STRING, IN_Property_Name, G_TYPE_VALUE, IN_Value, G_TYPE_INVALID, G_TYPE_INVALID);
+}
+
+typedef void (*org_freedesktop_DBus_Properties_set_reply) (DBusGProxy *proxy, GError *error, gpointer userdata);
+
+static void
+org_freedesktop_DBus_Properties_set_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+ DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+ GError *error = NULL;
+ dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+ (*(org_freedesktop_DBus_Properties_set_reply)data->cb) (proxy, error, data->userdata);
+ return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_freedesktop_DBus_Properties_set_async (DBusGProxy *proxy, const char * IN_Interface_Name, const char * IN_Property_Name, const GValue* IN_Value, org_freedesktop_DBus_Properties_set_reply callback, gpointer userdata)
+
+{
+ DBusGAsyncData *stuff;
+ stuff = g_slice_new (DBusGAsyncData);
+ stuff->cb = G_CALLBACK (callback);
+ stuff->userdata = userdata;
+ return dbus_g_proxy_begin_call (proxy, "Set", org_freedesktop_DBus_Properties_set_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_Interface_Name, G_TYPE_STRING, IN_Property_Name, G_TYPE_VALUE, IN_Value, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_freedesktop_DBus_Properties_get_all (DBusGProxy *proxy, const char * IN_Interface_Name, GHashTable** OUT_Properties, GError **error)
+
+{
+ return dbus_g_proxy_call (proxy, "GetAll", error, G_TYPE_STRING, IN_Interface_Name, G_TYPE_INVALID, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), OUT_Properties, G_TYPE_INVALID);
+}
+
+typedef void (*org_freedesktop_DBus_Properties_get_all_reply) (DBusGProxy *proxy, GHashTable *OUT_Properties, GError *error, gpointer userdata);
+
+static void
+org_freedesktop_DBus_Properties_get_all_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+ DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+ GError *error = NULL;
+ GHashTable* OUT_Properties;
+ dbus_g_proxy_end_call (proxy, call, &error, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &OUT_Properties, G_TYPE_INVALID);
+ (*(org_freedesktop_DBus_Properties_get_all_reply)data->cb) (proxy, OUT_Properties, error, data->userdata);
+ return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_freedesktop_DBus_Properties_get_all_async (DBusGProxy *proxy, const char * IN_Interface_Name, org_freedesktop_DBus_Properties_get_all_reply callback, gpointer userdata)
+
+{
+ DBusGAsyncData *stuff;
+ stuff = g_slice_new (DBusGAsyncData);
+ stuff->cb = G_CALLBACK (callback);
+ stuff->userdata = userdata;
+ return dbus_g_proxy_begin_call (proxy, "GetAll", org_freedesktop_DBus_Properties_get_all_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_Interface_Name, G_TYPE_INVALID);
+}
+#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_DBus_Properties */
+
+G_END_DECLS
diff --git a/src/dbus-shared.h b/src/dbus-shared.h
index f888e02..b8dc016 100644
--- a/src/dbus-shared.h
+++ b/src/dbus-shared.h
@@ -24,8 +24,10 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define INDICATOR_APPLICATION_DBUS_OBJ "/org/ayatana/indicator/application/service"
#define INDICATOR_APPLICATION_DBUS_IFACE "org.ayatana.indicator.application.service"
-#define NOTIFICATION_WATCHER_DBUS_OBJ "/org/ayatana/indicator/application/NotificationWatcher"
-#define NOTIFICATION_WATCHER_DBUS_IFACE "org.ayatana.indicator.application.NotificationWatcher"
+#define NOTIFICATION_WATCHER_DBUS_ADDR "org.freedesktop.StatusNotifierWatcher"
+#define NOTIFICATION_WATCHER_DBUS_OBJ "/StatusNotifierWatcher"
+#define NOTIFICATION_WATCHER_DBUS_IFACE "org.freedesktop.StatusNotifierWatcher"
-#define NOTIFICATION_ITEM_DBUS_IFACE "org.ayatana.indicator.application.NotificationItem"
+#define NOTIFICATION_ITEM_DBUS_IFACE "org.freedesktop.StatusNotifierItem"
+#define NOTIFICATION_ITEM_DEFAULT_OBJ "/StatusNotifierItem"
diff --git a/src/indicator-application.c b/src/indicator-application.c
index f3566e4..c330645 100644
--- a/src/indicator-application.c
+++ b/src/indicator-application.c
@@ -80,6 +80,7 @@ struct _IndicatorApplicationPrivate {
typedef struct _ApplicationEntry ApplicationEntry;
struct _ApplicationEntry {
IndicatorObjectEntry entry;
+ gchar * icon_path;
};
#define INDICATOR_APPLICATION_GET_PRIVATE(o) \
@@ -91,8 +92,9 @@ static void indicator_application_dispose (GObject *object);
static void indicator_application_finalize (GObject *object);
static GList * get_entries (IndicatorObject * io);
static void connected (IndicatorServiceManager * sm, gboolean connected, IndicatorApplication * application);
-static void application_added (DBusGProxy * proxy, const gchar * iconname, gint position, const gchar * dbusaddress, const gchar * dbusobject, IndicatorApplication * application);
+static void application_added (DBusGProxy * proxy, const gchar * iconname, gint position, const gchar * dbusaddress, const gchar * dbusobject, const gchar * icon_path, IndicatorApplication * application);
static void application_removed (DBusGProxy * proxy, gint position , IndicatorApplication * application);
+static void application_icon_changed (DBusGProxy * proxy, gint position, const gchar * iconname, IndicatorApplication * application);
static void get_applications (DBusGProxy *proxy, GPtrArray *OUT_applications, GError *error, gpointer userdata);
G_DEFINE_TYPE (IndicatorApplication, indicator_application, INDICATOR_OBJECT_TYPE);
@@ -111,12 +113,18 @@ indicator_application_class_init (IndicatorApplicationClass *klass)
io_class->get_entries = get_entries;
- dbus_g_object_register_marshaller(_application_service_marshal_VOID__STRING_INT_STRING_STRING,
+ dbus_g_object_register_marshaller(_application_service_marshal_VOID__STRING_INT_STRING_STRING_STRING,
G_TYPE_NONE,
G_TYPE_STRING,
G_TYPE_INT,
G_TYPE_STRING,
G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_object_register_marshaller(_application_service_marshal_VOID__INT_STRING,
+ G_TYPE_NONE,
+ G_TYPE_INT,
+ G_TYPE_STRING,
G_TYPE_INVALID);
return;
@@ -211,11 +219,17 @@ connected (IndicatorServiceManager * sm, gboolean connected, IndicatorApplicatio
G_TYPE_INT,
G_TYPE_STRING,
G_TYPE_STRING,
+ G_TYPE_STRING,
G_TYPE_INVALID);
dbus_g_proxy_add_signal(priv->service_proxy,
"ApplicationRemoved",
G_TYPE_INT,
G_TYPE_INVALID);
+ dbus_g_proxy_add_signal(priv->service_proxy,
+ "ApplicationIconChanged",
+ G_TYPE_INT,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
/* Connect to them */
g_debug("Connect to them.");
@@ -229,6 +243,11 @@ connected (IndicatorServiceManager * sm, gboolean connected, IndicatorApplicatio
G_CALLBACK(application_removed),
application,
NULL /* Disconnection Signal */);
+ dbus_g_proxy_connect_signal(priv->service_proxy,
+ "ApplicationIconChanged",
+ G_CALLBACK(application_icon_changed),
+ application,
+ NULL /* Disconnection Signal */);
/* Query it for existing applications */
g_debug("Request current apps");
@@ -267,12 +286,19 @@ get_entries (IndicatorObject * io)
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, IndicatorApplication * application)
+application_added (DBusGProxy * proxy, const gchar * iconname, gint position, const gchar * dbusaddress, const gchar * dbusobject, const gchar * icon_path, IndicatorApplication * application)
{
g_debug("Building new application entry: %s with icon: %s", dbusaddress, iconname);
IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(application);
ApplicationEntry * app = g_new(ApplicationEntry, 1);
+ app->icon_path = NULL;
+ if (icon_path != NULL && icon_path[0] != '\0') {
+ app->icon_path = g_strdup(icon_path);
+ g_debug("\tAppending search path: %s", app->icon_path);
+ gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), app->icon_path);
+ }
+
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));
@@ -302,6 +328,9 @@ application_removed (DBusGProxy * proxy, gint position, IndicatorApplication * a
priv->applications = g_list_remove(priv->applications, app);
g_signal_emit(G_OBJECT(application), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED_ID, 0, &(app->entry), TRUE);
+ if (app->icon_path != NULL) {
+ g_free(app->icon_path);
+ }
if (app->entry.image != NULL) {
g_object_unref(G_OBJECT(app->entry.image));
}
@@ -317,6 +346,23 @@ application_removed (DBusGProxy * proxy, gint position, IndicatorApplication * a
return;
}
+/* The callback for the signal that the icon for an application
+ has changed. */
+static void
+application_icon_changed (DBusGProxy * proxy, gint position, const gchar * iconname, IndicatorApplication * application)
+{
+ IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(application);
+ ApplicationEntry * app = (ApplicationEntry *)g_list_nth_data(priv->applications, position);
+
+ if (app == NULL) {
+ g_warning("Unable to find application at position: %d", position);
+ return;
+ }
+
+ gtk_image_set_from_icon_name(app->entry.image, iconname, GTK_ICON_SIZE_MENU);
+ return;
+}
+
/* This repsonds to the list of applications that the service
has and calls application_added on each one of them. */
static void
diff --git a/src/libappindicator/app-indicator.c b/src/libappindicator/app-indicator.c
index bb68cb2..7560a97 100644
--- a/src/libappindicator/app-indicator.c
+++ b/src/libappindicator/app-indicator.c
@@ -63,6 +63,7 @@ struct _AppIndicatorPrivate {
AppIndicatorStatus status;
gchar *icon_name;
gchar *attention_icon_name;
+ gchar * icon_path;
DbusmenuServer *menuservice;
GtkWidget *menu;
@@ -91,6 +92,7 @@ enum {
PROP_STATUS,
PROP_ICON_NAME,
PROP_ATTENTION_ICON_NAME,
+ PROP_ICON_THEME_PATH,
PROP_MENU,
PROP_CONNECTED
};
@@ -101,6 +103,7 @@ enum {
#define PROP_STATUS_S "status"
#define PROP_ICON_NAME_S "icon-name"
#define PROP_ATTENTION_ICON_NAME_S "attention-icon-name"
+#define PROP_ICON_THEME_PATH_S "icon-theme-path"
#define PROP_MENU_S "menu"
#define PROP_CONNECTED_S "connected"
@@ -179,6 +182,14 @@ app_indicator_class_init (AppIndicatorClass *klass)
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property(object_class,
+ PROP_ICON_THEME_PATH,
+ g_param_spec_string (PROP_ICON_THEME_PATH_S,
+ "An additional path for custom icons.",
+ "An additional place to look for icon names that may be installed by the application.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
+
g_object_class_install_property(object_class,
PROP_MENU,
g_param_spec_string (PROP_MENU_S,
@@ -277,6 +288,7 @@ app_indicator_init (AppIndicator *self)
priv->status = APP_INDICATOR_STATUS_PASSIVE;
priv->icon_name = NULL;
priv->attention_icon_name = NULL;
+ priv->icon_path = NULL;
priv->menu = NULL;
priv->menuservice = NULL;
@@ -355,6 +367,11 @@ app_indicator_finalize (GObject *object)
priv->attention_icon_name = NULL;
}
+ if (priv->icon_path != NULL) {
+ g_free(priv->icon_path);
+ priv->icon_path = NULL;
+ }
+
G_OBJECT_CLASS (app_indicator_parent_class)->finalize (object);
return;
}
@@ -423,6 +440,13 @@ app_indicator_set_property (GObject * object, guint prop_id, const GValue * valu
g_value_get_string (value));
break;
+ case PROP_ICON_THEME_PATH:
+ if (priv->icon_path != NULL) {
+ g_free(priv->icon_path);
+ }
+ priv->icon_path = g_value_dup_string(value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -462,6 +486,10 @@ app_indicator_get_property (GObject * object, guint prop_id, GValue * value, GPa
g_value_set_string (value, priv->attention_icon_name);
break;
+ case PROP_ICON_THEME_PATH:
+ g_value_set_string (value, priv->icon_path);
+ break;
+
case PROP_MENU:
if (G_VALUE_HOLDS_STRING(value)) {
if (priv->menuservice != NULL) {
@@ -502,7 +530,7 @@ check_connect (AppIndicator *self)
GError * error = NULL;
priv->watcher_proxy = dbus_g_proxy_new_for_name_owner(priv->connection,
- INDICATOR_APPLICATION_DBUS_ADDR,
+ NOTIFICATION_WATCHER_DBUS_ADDR,
NOTIFICATION_WATCHER_DBUS_OBJ,
NOTIFICATION_WATCHER_DBUS_IFACE,
&error);
@@ -513,7 +541,7 @@ check_connect (AppIndicator *self)
return;
}
- org_ayatana_indicator_application_NotificationWatcher_register_service_async(priv->watcher_proxy, "/need/a/path", register_service_cb, self);
+ org_freedesktop_StatusNotifierWatcher_register_status_notifier_item_async(priv->watcher_proxy, "/need/a/path", register_service_cb, self);
return;
}
@@ -564,15 +592,45 @@ app_indicator_new (const gchar *id,
AppIndicatorCategory category)
{
AppIndicator *indicator = g_object_new (APP_INDICATOR_TYPE,
- "id", id,
- "category", category_from_enum (category),
- "icon-name", icon_name,
+ PROP_ID_S, id,
+ PROP_CATEGORY_S, category_from_enum (category),
+ PROP_ICON_NAME_S, icon_name,
NULL);
return indicator;
}
/**
+ app_indicator_new_with_path:
+ @id: The unique id of the indicator to create.
+ @icon_name: The icon name for this indicator
+ @category: The category of indicator.
+ @icon_path: A custom path for finding icons.
+
+ Creates a new #AppIndicator setting the properties:
+ #AppIndicator::id with @id, #AppIndicator::category
+ with @category, #AppIndicator::icon-name with
+ @icon_name and #AppIndicator::icon-theme-path with @icon_path.
+
+ Return value: A pointer to a new #AppIndicator object.
+ */
+AppIndicator *
+app_indicator_new_with_path (const gchar *id,
+ const gchar *icon_name,
+ AppIndicatorCategory category,
+ const gchar *icon_path)
+{
+ AppIndicator *indicator = g_object_new (APP_INDICATOR_TYPE,
+ PROP_ID_S, id,
+ PROP_CATEGORY_S, category_from_enum (category),
+ PROP_ICON_NAME_S, icon_name,
+ PROP_ICON_THEME_PATH_S, icon_path,
+ NULL);
+
+ return indicator;
+}
+
+/**
app_indicator_get_type:
Generates or returns the unique #GType for #AppIndicator.
@@ -640,14 +698,14 @@ app_indicator_set_icon (AppIndicator *self, const gchar *icon_name)
g_return_if_fail (IS_APP_INDICATOR (self));
g_return_if_fail (icon_name != NULL);
- if (g_strcmp0 (self->priv->attention_icon_name, icon_name) != 0)
+ if (g_strcmp0 (self->priv->icon_name, icon_name) != 0)
{
- if (self->priv->attention_icon_name)
- g_free (self->priv->attention_icon_name);
+ if (self->priv->icon_name)
+ g_free (self->priv->icon_name);
- self->priv->attention_icon_name = g_strdup (icon_name);
+ self->priv->icon_name = g_strdup (icon_name);
- g_signal_emit (self, signals[NEW_ATTENTION_ICON], 0, TRUE);
+ g_signal_emit (self, signals[NEW_ICON], 0, TRUE);
}
}
@@ -660,6 +718,14 @@ activate_menuitem (DbusmenuMenuitem *mi, gpointer user_data)
}
static void
+widget_toggled (GtkWidget *widget, DbusmenuMenuitem *mi)
+{
+ dbusmenu_menuitem_property_set (mi,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_CHECKED,
+ gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+}
+
+static void
menuitem_iterate (GtkWidget *widget,
gpointer data)
{
@@ -692,9 +758,33 @@ container_iterate (GtkWidget *widget,
}
else
{
- label = gtk_menu_item_get_label (GTK_MENU_ITEM (widget));
+ if (GTK_IS_CHECK_MENU_ITEM (widget))
+ {
+ GtkCheckMenuItem *check;
- if (GTK_IS_IMAGE_MENU_ITEM (widget))
+ check = GTK_CHECK_MENU_ITEM (widget);
+ label = gtk_menu_item_get_label (GTK_MENU_ITEM (widget));
+
+ dbusmenu_menuitem_property_set (child,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
+ GTK_IS_RADIO_MENU_ITEM (widget) ? DBUSMENU_MENUITEM_TOGGLE_RADIO : DBUSMENU_MENUITEM_TOGGLE_CHECK);
+
+ dbusmenu_menuitem_property_set (child,
+ DBUSMENU_MENUITEM_PROP_LABEL,
+ label);
+
+ label_set = TRUE;
+
+ dbusmenu_menuitem_property_set (child,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_CHECKED,
+ gtk_check_menu_item_get_active (check) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+
+ g_signal_connect (widget,
+ "toggled",
+ G_CALLBACK (widget_toggled),
+ child);
+ }
+ else if (GTK_IS_IMAGE_MENU_ITEM (widget))
{
GtkWidget *image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget));
diff --git a/src/libappindicator/app-indicator.h b/src/libappindicator/app-indicator.h
index e966a49..a680c33 100644
--- a/src/libappindicator/app-indicator.h
+++ b/src/libappindicator/app-indicator.h
@@ -128,8 +128,8 @@ typedef enum { /*< prefix=APP_INDICATOR_CATEGORY >*/
These are the states that the indicator can be on in
the user's panel. The indicator by default starts
- in the state @APP_INDICATOR_STATUS_OFF and can be
- shown by setting it to @APP_INDICATOR_STATUS_ON.
+ in the state @APP_INDICATOR_STATUS_PASSIVE and can be
+ shown by setting it to @APP_INDICATOR_STATUS_ACTIVE.
*/
typedef enum { /*< prefix=APP_INDICATOR_STATUS >*/
APP_INDICATOR_STATUS_PASSIVE,
@@ -202,6 +202,10 @@ GType app_indicator_get_type (void) G_GNUC_C
AppIndicator *app_indicator_new (const gchar *id,
const gchar *icon_name,
AppIndicatorCategory category);
+AppIndicator *app_indicator_new_with_path (const gchar *id,
+ const gchar *icon_name,
+ AppIndicatorCategory category,
+ const gchar *icon_path);
/* Set properties */
void app_indicator_set_status (AppIndicator *self,
diff --git a/src/notification-item.xml b/src/notification-item.xml
index c28cc54..bcc3a4a 100644
--- a/src/notification-item.xml
+++ b/src/notification-item.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<node name="/">
- <interface name="org.ayatana.indicator.application.NotificationItem">
+<node name="/StatusNotifierItem">
+ <interface name="org.freedesktop.StatusNotifierItem">
<!-- Properties -->
<property name="Id" type="s" access="read" />
@@ -8,6 +8,9 @@
<property name="Status" type="s" access="read" />
<property name="IconName" type="s" access="read" />
<property name="AttentionIconName" type="s" access="read" />
+ <!-- An additional path to add to the theme search path
+ to find the icons specified above. -->
+ <property name="IconThemePath" type="s" access="read" />
<property name="Menu" type="o" access="read" />
<!-- Methods -->
diff --git a/src/notification-watcher.xml b/src/notification-watcher.xml
index 2ef54a0..22ada5f 100644
--- a/src/notification-watcher.xml
+++ b/src/notification-watcher.xml
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
-<node name="/">
- <interface name="org.ayatana.indicator.application.NotificationWatcher">
+<node name="/StatusNotifierWatcher">
+ <interface name="org.freedesktop.StatusNotifierWatcher">
<!-- Properties -->
<!-- None currently -->
<!-- Methods -->
- <method name="RegisterService">
+ <method name="RegisterStatusNotifierItem">
<annotation name="org.freedesktop.DBus.GLib.Async" value="true" />
<arg type="s" name="service" direction="in" />
</method>
- <method name="RegisteredServices">
+ <method name="RegisteredStatusNotifierItems">
<arg type="as" name="services" direction="out" />
</method>
<method name="ProtocolVersion">