diff options
author | Ted Gould <ted@gould.cx> | 2010-01-08 15:35:23 -0600 |
---|---|---|
committer | Ted Gould <ted@gould.cx> | 2010-01-08 15:35:23 -0600 |
commit | 98237f0789319b6133411618d505a2c945e669a5 (patch) | |
tree | ab1abf5193e2cddec2e6df706506d5043919e133 | |
parent | a5753822cc80f3f579aa61801b54134b3baa8076 (diff) | |
parent | bb71fc2d4c0b555f23940b8c9d4f6973307cbd20 (diff) | |
download | ayatana-indicator-application-98237f0789319b6133411618d505a2c945e669a5.tar.gz ayatana-indicator-application-98237f0789319b6133411618d505a2c945e669a5.tar.bz2 ayatana-indicator-application-98237f0789319b6133411618d505a2c945e669a5.zip |
Supporting icons changing and status changing.
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/application-service-appstore.c | 360 | ||||
-rw-r--r-- | src/application-service-appstore.h | 7 | ||||
-rw-r--r-- | src/application-service-marshal.list | 1 | ||||
-rw-r--r-- | src/application-service.c | 2 | ||||
-rw-r--r-- | src/application-service.xml | 4 | ||||
-rw-r--r-- | src/dbus-properties-client.h | 139 | ||||
-rw-r--r-- | src/indicator-application.c | 33 | ||||
-rw-r--r-- | src/libappindicator/app-indicator.c | 10 |
9 files changed, 517 insertions, 40 deletions
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 f76bbe2..fa1b9d2 100644 --- a/src/application-service-appstore.c +++ b/src/application-service-appstore.c @@ -43,6 +43,10 @@ static gboolean _application_service_server_get_applications (ApplicationService #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 { @@ -50,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; @@ -57,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) \ @@ -66,6 +88,7 @@ struct _Application { enum { APPLICATION_ADDED, APPLICATION_REMOVED, + APPLICATION_ICON_CHANGED, LAST_SIGNAL }; @@ -76,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); @@ -92,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_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); @@ -156,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) { @@ -167,45 +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. */ + 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)); + } - const gchar * icon_path = NULL; gpointer icon_path_data = g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ICON_PATH); if (icon_path_data != NULL) { - icon_path = g_value_get_string((GValue *)icon_path_data); + app->icon_path = g_value_dup_string((GValue *)icon_path_data); } else { - icon_path = ""; + app->icon_path = g_strdup(""); } - 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)), - icon_path, - TRUE); + 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); @@ -213,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; @@ -224,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; } @@ -261,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; @@ -300,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, @@ -311,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) { @@ -318,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 6cfbada..4ac8398 100644 --- a/src/application-service-marshal.list +++ b/src/application-service-marshal.list @@ -17,3 +17,4 @@ # 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, STRING +VOID: INT, STRING 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 d354943..d74aaa9 100644 --- a/src/application-service.xml +++ b/src/application-service.xml @@ -40,6 +40,10 @@ with this program. If not, see <http://www.gnu.org/licenses/>. <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/indicator-application.c b/src/indicator-application.c index fbfbd40..c330645 100644 --- a/src/indicator-application.c +++ b/src/indicator-application.c @@ -94,6 +94,7 @@ 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, 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); @@ -120,6 +121,11 @@ indicator_application_class_init (IndicatorApplicationClass *klass) 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; } @@ -219,6 +225,11 @@ connected (IndicatorServiceManager * sm, gboolean connected, IndicatorApplicatio "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."); @@ -232,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"); @@ -330,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 9a2e2a1..5868a4d 100644 --- a/src/libappindicator/app-indicator.c +++ b/src/libappindicator/app-indicator.c @@ -698,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); } } |