static void on_settings_tree_changed_cb (GMenuTree *tree, gpointer user_data) { CinnamonAppSystem *self = CINNAMON_APP_SYSTEM (user_data); GError *error = NULL; GHashTable *new_settings; GHashTableIter iter; gpointer key, value; g_assert (tree == self->priv->settings_tree); g_hash_table_remove_all (self->priv->setting_id_to_app); if (!gmenu_tree_load_sync (self->priv->settings_tree, &error)) { g_warning ("Failed to load settings: %s", error->message); return; } new_settings = get_flattened_entries_from_tree (tree); g_hash_table_iter_init (&iter, new_settings); while (g_hash_table_iter_next (&iter, &key, &value)) { const char *id = key; GMenuTreeEntry *entry = value; CinnamonApp *app; app = _cinnamon_app_new (entry); g_hash_table_replace (self->priv->setting_id_to_app, (char*)id, app); } g_hash_table_destroy (new_settings); }
static void on_apps_tree_changed_cb (GMenuTree *tree, gpointer user_data) { CinnamonAppSystem *self = CINNAMON_APP_SYSTEM (user_data); GError *error = NULL; GHashTable *new_apps; GHashTableIter iter; gpointer key, value; GSList *removed_apps = NULL; GSList *removed_node; g_assert (tree == self->priv->apps_tree); g_slist_foreach (self->priv->known_vendor_prefixes, (GFunc)g_free, NULL); g_slist_free (self->priv->known_vendor_prefixes); self->priv->known_vendor_prefixes = NULL; if (!gmenu_tree_load_sync (self->priv->apps_tree, &error)) { g_warning ("Failed to load apps: %s", error->message); return; } new_apps = get_flattened_entries_from_tree (self->priv->apps_tree); g_hash_table_iter_init (&iter, new_apps); while (g_hash_table_iter_next (&iter, &key, &value)) { const char *id = key; GMenuTreeEntry *entry = value; GMenuTreeEntry *old_entry; char *prefix; CinnamonApp *app; prefix = get_prefix_for_entry (entry); if (prefix != NULL && !g_slist_find_custom (self->priv->known_vendor_prefixes, prefix, (GCompareFunc)g_strcmp0)) self->priv->known_vendor_prefixes = g_slist_append (self->priv->known_vendor_prefixes, prefix); else g_free (prefix); app = g_hash_table_lookup (self->priv->id_to_app, id); if (app != NULL) { /* We hold a reference to the original entry temporarily, * because otherwise the hash table would be referencing * potentially free'd memory until we replace it below with * the new data. */ old_entry = cinnamon_app_get_tree_entry (app); gmenu_tree_item_ref (old_entry); _cinnamon_app_set_entry (app, entry); g_object_ref (app); /* Extra ref, removed in _replace below */ } else { old_entry = NULL; app = _cinnamon_app_new (entry); } /* Note that "id" is owned by app->entry. Since we're always * setting a new entry, even if the app already exists in the * hash table we need to replace the key so that the new id * string is pointed to. */ g_hash_table_replace (self->priv->id_to_app, (char*)id, app); if (old_entry) gmenu_tree_item_unref (old_entry); } /* Now iterate over the apps again; we need to unreference any apps * which have been removed. The JS code may still be holding a * reference; that's fine. */ g_hash_table_iter_init (&iter, self->priv->id_to_app); while (g_hash_table_iter_next (&iter, &key, &value)) { const char *id = key; if (!g_hash_table_lookup (new_apps, id)) removed_apps = g_slist_prepend (removed_apps, (char*)id); } for (removed_node = removed_apps; removed_node; removed_node = removed_node->next) { const char *id = removed_node->data; g_hash_table_remove (self->priv->id_to_app, id); } g_slist_free (removed_apps); g_hash_table_destroy (new_apps); g_signal_emit (self, signals[INSTALLED_CHANGED], 0); }