aboutsummaryrefslogtreecommitdiff
path: root/src/indicator-application.c
diff options
context:
space:
mode:
authorTed Gould <ted@gould.cx>2010-02-08 09:33:13 -0600
committerTed Gould <ted@gould.cx>2010-02-08 09:33:13 -0600
commit89972d214c5a8e65783cd83e82ac3ef9c1b915c8 (patch)
treee031e730ac8d7e80a51aa4a9e6e41de1b164873b /src/indicator-application.c
parent08f04e0260f602442bf7bae6ad113c8f53b8dd96 (diff)
parente6056c5c268be7056a79bb6c5fc0b5408dea2994 (diff)
downloadlibayatana-appindicator-89972d214c5a8e65783cd83e82ac3ef9c1b915c8.tar.gz
libayatana-appindicator-89972d214c5a8e65783cd83e82ac3ef9c1b915c8.tar.bz2
libayatana-appindicator-89972d214c5a8e65783cd83e82ac3ef9c1b915c8.zip
* Upstream Merge
* Handling the service restarting better by removing the icons after a small delay to ensure they don't return. * Fixing a crash where a proxy was created while the previous one was being destroyed.
Diffstat (limited to 'src/indicator-application.c')
-rw-r--r--src/indicator-application.c216
1 files changed, 170 insertions, 46 deletions
diff --git a/src/indicator-application.c b/src/indicator-application.c
index 269150a..170e0d4 100644
--- a/src/indicator-application.c
+++ b/src/indicator-application.c
@@ -78,12 +78,16 @@ struct _IndicatorApplicationPrivate {
DBusGProxy * service_proxy;
GList * applications;
GHashTable * theme_dirs;
+ guint disconnect_kill;
};
typedef struct _ApplicationEntry ApplicationEntry;
struct _ApplicationEntry {
IndicatorObjectEntry entry;
gchar * icon_path;
+ gboolean old_service;
+ gchar * dbusobject;
+ gchar * dbusaddress;
};
#define INDICATOR_APPLICATION_GET_PRIVATE(o) \
@@ -95,7 +99,12 @@ static void indicator_application_dispose (GObject *object);
static void indicator_application_finalize (GObject *object);
static GList * get_entries (IndicatorObject * io);
static guint get_location (IndicatorObject * io, IndicatorObjectEntry * entry);
-static void connected (IndicatorServiceManager * sm, gboolean connected, IndicatorApplication * application);
+void connection_changed (IndicatorServiceManager * sm, gboolean connected, IndicatorApplication * application);
+static void connected (IndicatorApplication * application);
+static void disconnected (IndicatorApplication * application);
+static void disconnected_helper (gpointer data, gpointer user_data);
+static gboolean disconnected_kill (gpointer user_data);
+static void disconnected_kill_helper (gpointer data, gpointer user_data);
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);
@@ -147,9 +156,10 @@ indicator_application_init (IndicatorApplication *self)
priv->bus = NULL;
priv->service_proxy = NULL;
priv->theme_dirs = NULL;
+ priv->disconnect_kill = 0;
priv->sm = indicator_service_manager_new(INDICATOR_APPLICATION_DBUS_ADDR);
- g_signal_connect(G_OBJECT(priv->sm), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connected), self);
+ g_signal_connect(G_OBJECT(priv->sm), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connection_changed), self);
priv->applications = NULL;
@@ -163,6 +173,10 @@ indicator_application_dispose (GObject *object)
{
IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(object);
+ if (priv->disconnect_kill != 0) {
+ g_source_remove(priv->disconnect_kill);
+ }
+
while (priv->applications != NULL) {
application_removed(priv->service_proxy,
0,
@@ -205,8 +219,24 @@ indicator_application_finalize (GObject *object)
return;
}
+/* Responds to connection change event from the service manager and
+ splits it into two. */
void
-connected (IndicatorServiceManager * sm, gboolean connected, IndicatorApplication * application)
+connection_changed (IndicatorServiceManager * sm, gboolean connect, IndicatorApplication * application)
+{
+ g_return_if_fail(IS_INDICATOR_APPLICATION(application));
+ if (connect) {
+ connected(application);
+ } else {
+ disconnected(application);
+ }
+ return;
+}
+
+/* Brings up the connection to a service that has just come onto the
+ bus, or is atleast new to us. */
+void
+connected (IndicatorApplication * application)
{
IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(application);
g_debug("Connected to Application Indicator Service.");
@@ -224,50 +254,51 @@ connected (IndicatorServiceManager * sm, gboolean connected, IndicatorApplicatio
}
}
+ if (priv->service_proxy == NULL) {
/* Build the service proxy */
- priv->service_proxy = dbus_g_proxy_new_for_name_owner(priv->bus,
- INDICATOR_APPLICATION_DBUS_ADDR,
- INDICATOR_APPLICATION_DBUS_OBJ,
- INDICATOR_APPLICATION_DBUS_IFACE,
- &error);
-
- /* Set up proxy signals */
- g_debug("Setup 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_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.");
- dbus_g_proxy_connect_signal(priv->service_proxy,
- "ApplicationAdded",
- G_CALLBACK(application_added),
- application,
- NULL /* Disconnection Signal */);
- dbus_g_proxy_connect_signal(priv->service_proxy,
- "ApplicationRemoved",
- 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 */);
+ priv->service_proxy = dbus_g_proxy_new_for_name(priv->bus,
+ INDICATOR_APPLICATION_DBUS_ADDR,
+ INDICATOR_APPLICATION_DBUS_OBJ,
+ INDICATOR_APPLICATION_DBUS_IFACE);
+
+ /* Set up proxy signals */
+ g_debug("Setup 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_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.");
+ dbus_g_proxy_connect_signal(priv->service_proxy,
+ "ApplicationAdded",
+ G_CALLBACK(application_added),
+ application,
+ NULL /* Disconnection Signal */);
+ dbus_g_proxy_connect_signal(priv->service_proxy,
+ "ApplicationRemoved",
+ 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");
@@ -278,6 +309,57 @@ connected (IndicatorServiceManager * sm, gboolean connected, IndicatorApplicatio
return;
}
+/* Marks every current application as belonging to the old
+ service so that we can delete it if it doesn't come back.
+ Also, sets up a timeout on comming back. */
+static void
+disconnected (IndicatorApplication * application)
+{
+ IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(application);
+ g_list_foreach(priv->applications, disconnected_helper, application);
+ /* I'll like this to be a little shorter, but it's a bit
+ inpractical to make it so. This means that the user will
+ probably notice a visible glitch. Though, if applications
+ are disappearing there isn't much we can do. */
+ priv->disconnect_kill = g_timeout_add(250, disconnected_kill, application);
+ return;
+}
+
+/* Marks an entry as being from the old service */
+static void
+disconnected_helper (gpointer data, gpointer user_data)
+{
+ ApplicationEntry * entry = (ApplicationEntry *)data;
+ entry->old_service = TRUE;
+ return;
+}
+
+/* Makes sure the old applications that don't come back
+ get dropped. */
+static gboolean
+disconnected_kill (gpointer user_data)
+{
+ g_return_val_if_fail(IS_INDICATOR_APPLICATION(user_data), FALSE);
+ IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(user_data);
+ priv->disconnect_kill = 0;
+ g_list_foreach(priv->applications, disconnected_kill_helper, user_data);
+ return FALSE;
+}
+
+/* Looks for entries that are still associated with the
+ old service and removes them. */
+static void
+disconnected_kill_helper (gpointer data, gpointer user_data)
+{
+ g_return_if_fail(IS_INDICATOR_APPLICATION(user_data));
+ IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(user_data);
+ ApplicationEntry * entry = (ApplicationEntry *)data;
+ if (entry->old_service) {
+ application_removed(NULL, g_list_index(priv->applications, data), INDICATOR_APPLICATION(user_data));
+ }
+ return;
+}
+
/* Goes through the list of applications that we're maintaining and
pulls out the IndicatorObjectEntry and returns that in a list
for the caller. */
@@ -311,22 +393,57 @@ get_location (IndicatorObject * io, IndicatorObjectEntry * entry)
return g_list_index(priv->applications, entry);
}
+/* Searching for ApplicationEntries where the dbusobject and
+ address are the same. */
+static gint
+application_added_search (gconstpointer a, gconstpointer b)
+{
+ ApplicationEntry * appa = (ApplicationEntry *)a;
+ ApplicationEntry * appb = (ApplicationEntry *)b;
+
+ if (g_strcmp0(appa->dbusaddress, appb->dbusaddress) == 0 &&
+ g_strcmp0(appa->dbusobject, appb->dbusobject) == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
/* 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, const gchar * icon_path, IndicatorApplication * application)
{
+ g_return_if_fail(IS_INDICATOR_APPLICATION(application));
g_debug("Building new application entry: %s with icon: %s", dbusaddress, iconname);
IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(application);
+
+ /* First search to see if we already have this entry */
+ ApplicationEntry searchapp;
+ searchapp.dbusaddress = (gchar *)dbusaddress; /* Casting off const, but it's okay, we're not changing it */
+ searchapp.dbusobject = (gchar *)dbusobject; /* Casting off const, but it's okay, we're not changing it */
+
+ GList * searchpointer = g_list_find_custom(priv->applications, &searchapp, application_added_search);
+ if (searchpointer != NULL) {
+ g_debug("\t...Already have that one.");
+ ApplicationEntry * app = (ApplicationEntry *)searchpointer->data;
+ app->old_service = FALSE;
+ return;
+ }
+
ApplicationEntry * app = g_new(ApplicationEntry, 1);
+ app->old_service = FALSE;
app->icon_path = NULL;
if (icon_path != NULL && icon_path[0] != '\0') {
app->icon_path = g_strdup(icon_path);
theme_dir_ref(application, icon_path);
}
+ app->dbusaddress = g_strdup(dbusaddress);
+ app->dbusobject = g_strdup(dbusobject);
+
/* We make a long name using the suffix, and if that
icon is available we want to use it. Otherwise we'll
just use the name we were given. */
@@ -359,6 +476,7 @@ application_added (DBusGProxy * proxy, const gchar * iconname, gint position, co
static void
application_removed (DBusGProxy * proxy, gint position, IndicatorApplication * application)
{
+ g_return_if_fail(IS_INDICATOR_APPLICATION(application));
IndicatorApplicationPrivate * priv = INDICATOR_APPLICATION_GET_PRIVATE(application);
ApplicationEntry * app = (ApplicationEntry *)g_list_nth_data(priv->applications, position);
@@ -374,6 +492,12 @@ application_removed (DBusGProxy * proxy, gint position, IndicatorApplication * a
theme_dir_unref(application, app->icon_path);
g_free(app->icon_path);
}
+ if (app->dbusaddress != NULL) {
+ g_free(app->dbusaddress);
+ }
+ if (app->dbusobject != NULL) {
+ g_free(app->dbusobject);
+ }
if (app->entry.image != NULL) {
g_object_unref(G_OBJECT(app->entry.image));
}