-static void luc_starter_constructed (GObject *object);
-static void luc_starter_finalize (GObject *object);
-static void luc_starter_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void luc_starter_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
+static void luc_starter_constructed (GObject *object);
+static void luc_starter_finalize (GObject *object);
+static void luc_starter_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void luc_starter_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static gint luc_starter_compare_luc_types (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data);
+static void luc_starter_start_next_group (LUCStarter *starter);
+static void luc_starter_start_app (const gchar *app,
+ LUCStarter *starter);
+static void luc_starter_start_app_finish (BootManagerService *service,
+ const gchar *unit,
+ const gchar *result,
+ GError *error,
+ gpointer user_data);
LUCHandler *luc_handler;
gchar **prioritised_types;
+
+ GList *start_order;
+ GHashTable *start_groups;
};
+static gint
+luc_starter_compare_luc_types (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
+{
+ LUCStarter *starter = LUC_STARTER (user_data);
+ gchar *type_a;
+ gchar *type_b;
+ gint n;
+ gint pos_a = G_MAXINT;
+ gint pos_b = G_MAXINT;
+
+ /* try to find the first type in the prioritised types list */
+ for (n = 0; pos_a < 0 && starter->prioritised_types[n] != NULL; n++)
+ if (g_strcmp0 (starter->prioritised_types[n], type_a) == 0)
+ pos_a = n;
+
+ /* try to find the second type in the prioritised types list */
+ for (n = 0; pos_b < 0 && starter->prioritised_types[n] != NULL; n++)
+ if (g_strcmp0 (starter->prioritised_types[n], type_b) == 0)
+ pos_b = n;
+
+ /* this statement has the following effect when sorting:
+ * - a and b are prioritised -> prioritization order is preserved
+ * - a is prioritised, b isn't -> negative return value, a comes first
+ * - b is prioritised, a isn't -> positive return value, b comes first
+ * - neither a nor b prioritised -> return value is 0, arbitrary order
+ */
+ return pos_a - pos_b;
+}
+
+
+
+static void
+luc_starter_start_next_group (LUCStarter *starter)
+{
+ const gchar *group_name;
+ GPtrArray *group;
+
+ g_return_if_fail (IS_LUC_STARTER (starter));
+ g_return_if_fail (starter->start_order != NULL);
+
+ group_name = starter->start_order->data;
+
+ g_debug ("start group '%s'", group_name);
+
+ /* look up the group with this name */
+ group = g_hash_table_lookup (starter->start_groups, group_name);
+ if (group != NULL)
+ {
+ /* launch all the applications in the group asynchronously */
+ g_ptr_array_foreach (group, (GFunc) luc_starter_start_app, starter);
+ }
+}
+
+
+
+static void
+luc_starter_start_app (const gchar *app,
+ LUCStarter *starter)
+{
+ g_return_if_fail (app != NULL && *app != '\0');
+ g_return_if_fail (IS_LUC_STARTER (starter));
+
+ g_debug ("start app '%s'", app);
+
+ boot_manager_service_start (starter->boot_manager, app, NULL,
+ luc_starter_start_app_finish,
+ starter);
+}
+
+
+
+static void
+luc_starter_start_app_finish (BootManagerService *service,
+ const gchar *unit,
+ const gchar *result,
+ GError *error,
+ gpointer user_data)
+{
+ const gchar *group_name;
+ LUCStarter *starter = LUC_STARTER (user_data);
+ GPtrArray *group;
+ gboolean app_found = FALSE;
+ guint n;
+
+ g_return_if_fail (BOOT_MANAGER_IS_SERVICE (service));
+ g_return_if_fail (unit != NULL && *unit != '\0');
+ g_return_if_fail (IS_LUC_STARTER (user_data));
+ g_return_if_fail (starter->start_order != NULL);
+
+ g_debug ("start app '%s' finish", unit);
+
+ /* get the current start group */
+ group_name = starter->start_order->data;
+
+ /* look up the apps for this group */
+ group = g_hash_table_lookup (starter->start_groups, group_name);
+ if (group != NULL)
+ {
+ /* try to find the current app in the group */
+ for (n = 0; !app_found && n < group->len; n++)
+ {
+ if (g_strcmp0 (unit, g_ptr_array_index (group, n)) == 0)
+ app_found = TRUE;
+ }
+
+ /* remove the app from the group */
+ if (app_found)
+ g_ptr_array_remove_index (group, n-1);
+
+ /* check if this was the last app in the group to be started */
+ if (group->len == 0)
+ {
+ g_debug ("start group %s finish", group_name);
+
+ /* remove the group from the groups and the order */
+ g_hash_table_remove (starter->start_groups, group_name);
+ starter->start_order = g_list_delete_link (starter->start_order,
+ starter->start_order);
+
+ /* start the next group if there are any left */
+ if (starter->start_order != NULL)
+ luc_starter_start_next_group (starter);
+ }
+ }
+}
+
+
+
LUCStarter *
luc_starter_new (BootManagerService *boot_manager,
LUCHandler *luc_handler)
void
luc_starter_start_groups (LUCStarter *starter)
{
- guint n;
-
- g_debug ("start LUC types in the following order:");
-
+ GVariantIter iter;
+ GPtrArray *group;
+ GVariant *context;
+ GList *lp;
+ gchar **apps;
+ gchar *type;
+ guint n;
+
+ g_debug ("prioritised types:");
for (n = 0; starter->prioritised_types[n] != NULL; n++)
g_debug (" %s", starter->prioritised_types[n]);
+
+ /* clear the start order */
+ if (starter->start_order != NULL)
+ {
+ g_list_free (starter->start_order);
+ starter->start_order = NULL;
+ }
+
+ /* clear the start groups */
+ if (starter->start_groups != NULL)
+ {
+ g_hash_table_remove_all (starter->start_groups);
+ }
+ else
+ {
+ starter->start_groups =
+ g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) g_ptr_array_free);
+ }
+
+ /* get the current last user context */
+ context = luc_handler_get_last_user_context (starter->luc_handler);
+ type = g_variant_print (context, TRUE);
+ g_debug ("context: %s", type);
+
+ /* create groups for all types in the LUC */
+ g_variant_iter_init (&iter, context);
+ while (g_variant_iter_loop (&iter, "{s^as}", &type, &apps))
+ {
+ group = g_ptr_array_new_with_free_func (g_free);
+
+ for (n = 0; apps != NULL && apps[n] != NULL; n++)
+ {
+ g_debug (" group %s app %s", type, apps[n]);
+ g_ptr_array_add (group, g_strdup (apps[n]));
+ }
+
+ g_hash_table_insert (starter->start_groups, g_strdup (type), group);
+ }
+
+ /* generate the start order by sorting the LUC types according to
+ * the prioritised types */
+ starter->start_order = g_hash_table_get_keys (starter->start_groups);
+ starter->start_order = g_list_sort_with_data (starter->start_order,
+ luc_starter_compare_luc_types,
+ starter);
+
+ g_debug ("start groups (ordered):");
+ for (lp = starter->start_order; lp != NULL; lp = lp->next)
+ g_debug (" %s", (gchar *)lp->data);
+
+ if (starter->start_order != NULL)
+ luc_starter_start_next_group (starter);
}