aboutsummaryrefslogtreecommitdiff
path: root/libindicator/indicator-ng.c
diff options
context:
space:
mode:
authorLars Uebernickel <lars.uebernickel@canonical.com>2013-02-06 15:37:38 -0500
committerLars Uebernickel <lars.uebernickel@canonical.com>2013-02-06 15:37:38 -0500
commitf9f86fbfa558e83d8591fbec43e95dcb5cc34584 (patch)
tree12dba699c331e5d0cb95ccc83d5b099daa98145f /libindicator/indicator-ng.c
parent8ff25e5375c3a0cb399fa687bf541f1cc0f4a020 (diff)
downloadlibayatana-indicator-f9f86fbfa558e83d8591fbec43e95dcb5cc34584.tar.gz
libayatana-indicator-f9f86fbfa558e83d8591fbec43e95dcb5cc34584.tar.bz2
libayatana-indicator-f9f86fbfa558e83d8591fbec43e95dcb5cc34584.zip
indicator-ng: try to restart the service when it crashes
This uses a (slightly) awkward heuristic: when the well-known name vanishes from the session bus, it only restarts the service when it didn't explicitly hide the indicator before.
Diffstat (limited to 'libindicator/indicator-ng.c')
-rw-r--r--libindicator/indicator-ng.c79
1 files changed, 74 insertions, 5 deletions
diff --git a/libindicator/indicator-ng.c b/libindicator/indicator-ng.c
index 6ec02b4..b2a95fe 100644
--- a/libindicator/indicator-ng.c
+++ b/libindicator/indicator-ng.c
@@ -11,16 +11,20 @@ struct _IndicatorNg
gchar *service_file;
gchar *name;
gchar *object_path;
+ gchar *bus_name;
gchar *profile;
gchar *header_action;
guint name_watch_id;
+ GDBusConnection *session_bus;
GActionGroup *actions;
GMenuModel *menu;
IndicatorObjectEntry entry;
gchar *accessible_desc;
+
+ gint64 last_service_restart;
};
static void indicator_ng_initable_iface_init (GInitableIface *initable);
@@ -111,6 +115,8 @@ indicator_ng_dispose (GObject *object)
self->name_watch_id = 0;
}
+ g_clear_object (&self->session_bus);
+
indicator_ng_free_actions_and_menu (self);
g_clear_object (&self->entry.label);
@@ -128,6 +134,7 @@ indicator_ng_finalize (GObject *object)
g_free (self->service_file);
g_free (self->name);
g_free (self->object_path);
+ g_free (self->bus_name);
g_free (self->accessible_desc);
g_free (self->header_action);
@@ -323,6 +330,8 @@ indicator_ng_service_appeared (GDBusConnection *connection,
g_assert (!self->actions);
g_assert (!self->menu);
+ self->session_bus = g_object_ref (connection);
+
self->actions = G_ACTION_GROUP (g_dbus_action_group_get (connection, name_owner, self->object_path));
gtk_widget_insert_action_group (GTK_WIDGET (self->entry.menu), "indicator", self->actions);
g_signal_connect_swapped (self->actions, "action-added", G_CALLBACK (indicator_ng_update_entry), self);
@@ -341,6 +350,41 @@ indicator_ng_service_appeared (GDBusConnection *connection,
}
static void
+indicator_ng_service_started (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IndicatorNg *self = user_data;
+ GError *error = NULL;
+ GVariant *reply;
+
+ reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), result, &error);
+ if (!reply)
+ {
+ g_warning ("Could not activate service '%s': %s", self->name, error->message);
+ indicator_object_set_visible (INDICATOR_OBJECT (self), FALSE);
+ g_error_free (error);
+ return;
+ }
+
+ switch (g_variant_get_uint32 (reply))
+ {
+ case 1: /* DBUS_START_REPLY_SUCCESS */
+ break;
+
+ case 2: /* DBUS_START_REPLY_ALREADY_RUNNING */
+ g_warning ("could not start service '%s': it is already running", self->name);
+ indicator_object_set_visible (INDICATOR_OBJECT (self), FALSE);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ g_variant_unref (reply);
+}
+
+static void
indicator_ng_service_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
@@ -349,7 +393,34 @@ indicator_ng_service_vanished (GDBusConnection *connection,
indicator_ng_free_actions_and_menu (self);
- indicator_object_set_visible (INDICATOR_OBJECT (self), FALSE);
+ /* Names may vanish because the service decided it doesn't need to
+ * show its indicator anymore, or because it crashed. Let's assume it
+ * crashes and restart it unless it explicitly hid its indicator. */
+
+ if (indicator_object_entry_is_visible (INDICATOR_OBJECT (self), &self->entry))
+ {
+ gint64 now;
+
+ /* take care not to start it if it repeatedly crashes */
+ now = g_get_monotonic_time ();
+ if (now - self->last_service_restart < 1 * G_USEC_PER_SEC)
+ return;
+
+ self->last_service_restart = now;
+
+ g_dbus_connection_call (self->session_bus,
+ "org.freedesktop.DBus",
+ "/",
+ "org.freedesktop.DBus",
+ "StartServiceByName",
+ g_variant_new ("(su)", self->bus_name, 0),
+ G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ indicator_ng_service_started,
+ self);
+ }
}
static gboolean
@@ -359,7 +430,6 @@ indicator_ng_initable_init (GInitable *initable,
{
IndicatorNg *self = INDICATOR_NG (initable);
GKeyFile *keyfile;
- gchar *bus_name = NULL;
keyfile = g_key_file_new ();
if (!g_key_file_load_from_file (keyfile, self->service_file, G_KEY_FILE_NONE, error))
@@ -370,21 +440,20 @@ indicator_ng_initable_init (GInitable *initable,
self->entry.name_hint = self->name;
- if (!(bus_name = g_key_file_get_string (keyfile, "Indicator Service", "BusName", error)))
+ if (!(self->bus_name = g_key_file_get_string (keyfile, "Indicator Service", "BusName", error)))
goto out;
if (!(self->object_path = g_key_file_get_string (keyfile, "Indicator Service", "ObjectPath", error)))
goto out;
self->name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
- bus_name,
+ self->bus_name,
G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
indicator_ng_service_appeared,
indicator_ng_service_vanished,
self, NULL);
out:
- g_free (bus_name);
g_key_file_free (keyfile);
return self->name_watch_id > 0;