[Xfce4-commits] <xfce4-appfinder:master> Full support for menu reloading.
Nick Schermer
noreply at xfce.org
Sat Jul 9 16:18:10 CEST 2011
Updating branch refs/heads/master
to 00a875654fa7285e46882af34506d1936fb5eeb9 (commit)
from a0b01810f1d66d6fa905b7c23d780589763e87f8 (commit)
commit 00a875654fa7285e46882af34506d1936fb5eeb9
Author: Nick Schermer <nick at xfce.org>
Date: Sat Jun 25 19:47:11 2011 +0200
Full support for menu reloading.
src/appfinder-category-model.c | 33 +++--
src/appfinder-model.c | 267 +++++++++++++++++++++++++++++++---------
2 files changed, 228 insertions(+), 72 deletions(-)
diff --git a/src/appfinder-category-model.c b/src/appfinder-category-model.c
index ca69485..51dc156 100644
--- a/src/appfinder-category-model.c
+++ b/src/appfinder-category-model.c
@@ -144,6 +144,8 @@ xfce_appfinder_category_model_finalize (GObject *object)
g_object_unref (G_OBJECT (model->all_applications));
+ APPFINDER_DEBUG ("category model finalized");
+
(*G_OBJECT_CLASS (xfce_appfinder_category_model_parent_class)->finalize) (object);
}
@@ -379,26 +381,31 @@ xfce_appfinder_category_model_set_categories (XfceAppfinderCategoryModel *model,
{
CategoryItem *item;
GSList *li, *lnext;
- gint idx;
GtkTreePath *path;
GtkTreeIter iter;
+ guint children, i;
APPFINDER_DEBUG ("insert %d categories", g_slist_length (categories));
/* remove items from the model */
- for (li = model->categories, idx = 0; li != NULL; li = lnext, idx++)
+ if (model->categories != NULL)
{
- lnext = li->next;
-
- model->categories = g_slist_delete_link (model->categories, li);
-
- /* remove the items we own */
- if (idx < 3)
- xfce_appfinder_model_category_free (li->data);
+ /* reverse remove all the items */
+ children = g_slist_length (model->categories);
+ path = gtk_tree_path_new_from_indices (children, -1);
+ for (;;)
+ {
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ if (!gtk_tree_path_prev (path))
+ break;
+ }
+ gtk_tree_path_free (path);
- path = gtk_tree_path_new_from_indices (idx, -1);
- gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
- gtk_tree_path_free (path);
+ /* clean the first three categories and drop the list */
+ for (i = 0, li = model->categories; i < 3 && li != NULL; i++, li = li->next)
+ xfce_appfinder_model_category_free (li->data);
+ g_slist_free (model->categories);
+ model->categories = NULL;
}
g_assert (model->categories == NULL);
@@ -419,7 +426,7 @@ xfce_appfinder_category_model_set_categories (XfceAppfinderCategoryModel *model,
model->categories = g_slist_concat (model->categories, g_slist_copy (categories));
path = gtk_tree_path_new_first ();
- for (li = model->categories; li != NULL; li = li->next)
+ for (li = model->categories; li != NULL; li = lnext)
{
/* remember the next item */
lnext = li->next;
diff --git a/src/appfinder-model.c b/src/appfinder-model.c
index 4744e90..f2232a1 100644
--- a/src/appfinder-model.c
+++ b/src/appfinder-model.c
@@ -72,7 +72,8 @@ static void xfce_appfinder_model_menu_changed (GarconMenu
static gpointer xfce_appfinder_model_collect_thread (gpointer user_data);
static void xfce_appfinder_model_item_free (gpointer data,
XfceAppfinderModel *model);
-
+static void xfce_appfinder_model_item_changed (GarconMenuItem *menu_item,
+ XfceAppfinderModel *model);
struct _XfceAppfinderModelClass
@@ -100,8 +101,7 @@ struct _XfceAppfinderModel
GSList *collect_items;
GSList *collect_categories;
GThread *collect_thread;
- volatile gboolean collect_cancelled;
- GHashTable *collect_desktop_ids;
+ GCancellable *collect_cancelled;
};
typedef struct
@@ -163,6 +163,7 @@ xfce_appfinder_model_init (XfceAppfinderModel *model)
model->command_icon_small = xfce_appfinder_model_load_pixbuf (GTK_STOCK_EXECUTE, ICON_SMALL);
model->command_icon_large = xfce_appfinder_model_load_pixbuf (GTK_STOCK_EXECUTE, ICON_LARGE);
model->command_category = xfce_appfinder_model_get_command_category ();
+ model->collect_cancelled = g_cancellable_new ();
model->menu = garcon_menu_new_applications ();
model->collect_thread = g_thread_create (xfce_appfinder_model_collect_thread, model, TRUE, NULL);
@@ -195,8 +196,9 @@ xfce_appfinder_model_finalize (GObject *object)
XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (object);
/* join the collector thread */
- model->collect_cancelled = TRUE;
+ g_cancellable_cancel (model->collect_cancelled);
g_thread_join (model->collect_thread);
+ g_object_unref (G_OBJECT (model->collect_cancelled));
/* cancel any pending collect idle source */
if (G_UNLIKELY (model->collect_idle_id != 0))
@@ -217,15 +219,13 @@ xfce_appfinder_model_finalize (GObject *object)
g_slist_foreach (model->categories, (GFunc) xfce_appfinder_model_category_free, NULL);
g_slist_free (model->categories);
- if (model->collect_desktop_ids != NULL)
- g_hash_table_destroy (model->collect_desktop_ids);
g_hash_table_destroy (model->items_hash);
g_object_unref (G_OBJECT (model->command_icon_large));
g_object_unref (G_OBJECT (model->command_icon_small));
g_object_unref (G_OBJECT (model->command_category));
- APPFINDER_DEBUG ("model cleared");
+ APPFINDER_DEBUG ("model finalized");
(*G_OBJECT_CLASS (xfce_appfinder_model_parent_class)->finalize) (object);
}
@@ -532,6 +532,7 @@ xfce_appfinder_model_collect_idle (gpointer user_data)
GtkTreeIter iter;
GSList *li, *lnext;
GSList *tmp;
+ ModelItem *item;
g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
g_return_val_if_fail (model->items == NULL, FALSE);
@@ -563,6 +564,16 @@ xfce_appfinder_model_collect_idle (gpointer user_data)
/* reset the next item */
li->next = lnext;
+
+ /* watch changes */
+ item = li->data;
+ if (item->item != NULL)
+ g_signal_connect (G_OBJECT (item->item), "changed",
+ G_CALLBACK (xfce_appfinder_model_item_changed), model);
+
+ /* insert in hash table */
+ if (G_LIKELY (item->command != NULL))
+ g_hash_table_insert (model->items_hash, item->command, item);
}
gtk_tree_path_free (path);
@@ -711,7 +722,6 @@ xfce_appfinder_model_item_changed (GarconMenuItem *menu_item,
APPFINDER_DEBUG ("update item %s", garcon_menu_item_get_desktop_id (menu_item));
- g_hash_table_remove (model->items_hash, item->command);
xfce_appfinder_model_item_free (item, model);
item = xfce_appfinder_model_item_new (menu_item);
@@ -743,10 +753,13 @@ xfce_appfinder_model_item_free (gpointer data,
if (item->item != NULL)
{
- g_signal_handlers_disconnect_by_func (G_OBJECT (item->item),
- G_CALLBACK (xfce_appfinder_model_item_changed), model);
+ if (model != NULL)
+ g_signal_handlers_disconnect_by_func (G_OBJECT (item->item),
+ G_CALLBACK (xfce_appfinder_model_item_changed), model);
g_object_unref (G_OBJECT (item->item));
}
+ if (model != NULL && item->command != NULL)
+ g_hash_table_remove (model->items_hash, item->command);
if (item->icon_small != NULL)
g_object_unref (G_OBJECT (item->icon_small));
if (item->icon_large != NULL)
@@ -762,7 +775,6 @@ xfce_appfinder_model_item_free (gpointer data,
-
static gint
xfce_appfinder_model_category_compare (gconstpointer a,
gconstpointer b)
@@ -807,10 +819,47 @@ xfce_appfinder_model_ptr_array_find (GPtrArray *array,
+static void
+xfce_appfinder_model_collect_history (XfceAppfinderModel *model,
+ GMappedFile *history)
+{
+ gchar *contents, *end;
+ gsize len;
+ ModelItem *item;
+
+ contents = g_mapped_file_get_contents (history);
+ if (contents == NULL)
+ return;
+
+ for (;!model->collect_cancelled;)
+ {
+ end = strchr (contents, '\n');
+ if (G_UNLIKELY (end == NULL))
+ break;
+
+ len = end - contents;
+ if (len > 0)
+ {
+ item = g_slice_new0 (ModelItem);
+ item->command = g_strndup (contents, len);
+ item->icon_small = g_object_ref (G_OBJECT (model->command_icon_small));
+ item->icon_large = g_object_ref (G_OBJECT (model->command_icon_large));
+ model->collect_items = g_slist_prepend (model->collect_items, item);
+ }
+
+ contents += len + 1;
+ }
+}
+
+
+
static gboolean
-xfce_appfinder_model_collect_items (XfceAppfinderModel *model,
- GarconMenu *menu,
- GarconMenuDirectory *category)
+xfce_appfinder_model_collect_items (GarconMenu *menu,
+ GCancellable *cancelled,
+ GarconMenuDirectory *category,
+ GSList **items,
+ GSList **categories,
+ GHashTable *desktop_ids)
{
GList *elements, *li;
GarconMenuDirectory *directory;
@@ -820,7 +869,11 @@ xfce_appfinder_model_collect_items (XfceAppfinderModel *model,
CategoryItem *citem;
g_return_val_if_fail (GARCON_IS_MENU (menu), FALSE);
+ g_return_val_if_fail (cancelled == NULL || G_IS_CANCELLABLE (cancelled), FALSE);
g_return_val_if_fail (category == NULL || GARCON_IS_MENU_DIRECTORY (category), FALSE);
+ g_return_val_if_fail (items != NULL, FALSE);
+ g_return_val_if_fail (categories != NULL, FALSE);
+ g_return_val_if_fail (desktop_ids != NULL, FALSE);
directory = garcon_menu_get_directory (menu);
if (directory != NULL)
@@ -835,7 +888,7 @@ xfce_appfinder_model_collect_items (XfceAppfinderModel *model,
/* collect all the elements in this menu and its sub menus */
elements = garcon_menu_get_elements (menu);
- for (li = elements; li != NULL && !model->collect_cancelled; li = li->next)
+ for (li = elements; li != NULL && !g_cancellable_is_cancelled (cancelled); li = li->next)
{
if (GARCON_IS_MENU_ITEM (li->data))
{
@@ -843,7 +896,7 @@ xfce_appfinder_model_collect_items (XfceAppfinderModel *model,
continue;
desktop_id = garcon_menu_item_get_desktop_id (li->data);
- item = g_hash_table_lookup (model->collect_desktop_ids, desktop_id);
+ item = g_hash_table_lookup (desktop_ids, desktop_id);
if (G_LIKELY (item == NULL))
{
item = xfce_appfinder_model_item_new (li->data);
@@ -852,13 +905,8 @@ xfce_appfinder_model_collect_items (XfceAppfinderModel *model,
if (category != NULL)
g_ptr_array_add (item->categories, g_object_ref (G_OBJECT (category)));
- model->collect_items = g_slist_prepend (model->collect_items, item);
- g_hash_table_insert (model->collect_desktop_ids, (gchar *) desktop_id, item);
- if (G_LIKELY (item->command != NULL))
- g_hash_table_insert (model->items_hash, item->command, item);
-
- g_signal_connect (G_OBJECT (item->item), "changed",
- G_CALLBACK (xfce_appfinder_model_item_changed), model);
+ *items = g_slist_prepend (*items, item);
+ g_hash_table_insert (desktop_ids, (gchar *) desktop_id, item);
}
else if (category != NULL
&& !xfce_appfinder_model_ptr_array_find (item->categories, category))
@@ -872,17 +920,19 @@ xfce_appfinder_model_collect_items (XfceAppfinderModel *model,
}
else if (GARCON_IS_MENU (li->data))
{
- if (xfce_appfinder_model_collect_items (model, li->data, category))
+ if (xfce_appfinder_model_collect_items (li->data, cancelled, category, items,
+ categories, desktop_ids))
has_items = TRUE;
}
}
g_list_free (elements);
- if (directory != NULL && has_items)
+ if (directory != NULL
+ && has_items)
{
citem = g_slice_new0 (CategoryItem);
citem->directory = g_object_ref (G_OBJECT (directory));
- model->collect_categories = g_slist_prepend (model->collect_categories, citem);
+ *categories = g_slist_prepend (*categories, citem);
}
return has_items;
@@ -891,37 +941,40 @@ xfce_appfinder_model_collect_items (XfceAppfinderModel *model,
static void
-xfce_appfinder_model_collect_history (XfceAppfinderModel *model,
- GMappedFile *history)
+xfce_appfinder_model_collect_menu (GarconMenu *menu,
+ GCancellable *cancelled,
+ GSList **items,
+ GSList **categories)
{
- gchar *contents, *end;
- gsize len;
- ModelItem *item;
+ GHashTable *desktop_ids;
- contents = g_mapped_file_get_contents (history);
- if (contents == NULL)
- return;
+ desktop_ids = g_hash_table_new (g_str_hash, g_str_equal);
+ xfce_appfinder_model_collect_items (menu, cancelled, NULL, items,
+ categories, desktop_ids);
+ g_hash_table_destroy (desktop_ids);
+}
- for (;!model->collect_cancelled;)
- {
- end = strchr (contents, '\n');
- if (G_UNLIKELY (end == NULL))
- break;
- len = end - contents;
- if (len > 0)
- {
- item = g_slice_new0 (ModelItem);
- item->command = g_strndup (contents, len);
- item->icon_small = g_object_ref (G_OBJECT (model->command_icon_small));
- item->icon_large = g_object_ref (G_OBJECT (model->command_icon_large));
- model->collect_items = g_slist_prepend (model->collect_items, item);
- g_hash_table_insert (model->items_hash, item->command, item);
- }
+static void
+xfce_appfinder_model_menu_changed_remove (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (user_data);
+ GSList *li = value;
+ GtkTreePath *path;
+ gint position;
- contents += len + 1;
- }
+ APPFINDER_DEBUG ("remove %s from the model", (gchar *) key);
+
+ position = g_slist_position (model->items, li);
+ xfce_appfinder_model_item_free (li->data, model);
+ model->items = g_slist_delete_link (model->items, li);
+
+ path = gtk_tree_path_new_from_indices (position, -1);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_free (path);
}
@@ -930,11 +983,109 @@ static void
xfce_appfinder_model_menu_changed (GarconMenu *menu,
XfceAppfinderModel *model)
{
+ GSList *li, *lp;
+ GHashTable *old_items;
+ ModelItem *item;
+ const gchar *desktop_id;
+ GSList *collect_items = NULL;
+ GSList *collect_categories = NULL;
+ GSList *tmp;
+ guint idx;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ CategoryItem *cat_a, *cat_b;
+
g_return_if_fail (GARCON_IS_MENU (menu));
g_return_if_fail (XFCE_IS_APPFINDER_MODEL (model));
+ g_return_if_fail (model->menu == menu);
- /* TODO */
APPFINDER_DEBUG ("menu changed");
+
+ /* add all the old items in a garcon database */
+ old_items = g_hash_table_new (g_str_hash, g_str_equal);
+ for (li = model->items; li != NULL; li = li->next)
+ {
+ item = li->data;
+ if (item->item != NULL)
+ {
+ desktop_id = garcon_menu_item_get_desktop_id (item->item);
+ g_hash_table_insert (old_items, (gchar *) desktop_id, li);
+ }
+ }
+
+ xfce_appfinder_model_collect_menu (menu, NULL, &collect_items, &collect_categories);
+
+ for (li = collect_items; li != NULL; li = li->next)
+ {
+ item = li->data;
+
+ g_assert (GARCON_IS_MENU_ITEM (item->item));
+
+ desktop_id = garcon_menu_item_get_desktop_id (item->item);
+ if (g_hash_table_remove (old_items, desktop_id))
+ {
+ /* this is not interesting, since those items are also updated
+ * by the GarconMenuItem::changed signal, so don't touch the
+ * item in the model */
+ xfce_appfinder_model_item_free (item, NULL);
+ }
+ else
+ {
+ /* insert new item in the list */
+ model->items = g_slist_insert_sorted (model->items, item, xfce_appfinder_model_item_compare);
+
+ /* find the item and the position */
+ for (lp = model->items, idx = 0; lp != NULL; lp = lp->next, idx++)
+ if (lp->data == item)
+ break;
+ g_assert (lp != NULL);
+
+ APPFINDER_DEBUG ("insert %s in the model", desktop_id);
+
+ /* emit the insert-row signal */
+ path = gtk_tree_path_new_from_indices (idx, -1);
+ ITER_INIT (iter, model->stamp, lp);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+
+ /* watch and add the command */
+ g_signal_connect (G_OBJECT (item->item), "changed",
+ G_CALLBACK (xfce_appfinder_model_item_changed), model);
+
+ if (G_LIKELY (item->command != NULL))
+ g_hash_table_insert (model->items_hash, item->command, item);
+ }
+ }
+
+ g_slist_free (collect_items);
+
+ /* remove remaining items from the model */
+ g_hash_table_foreach (old_items, xfce_appfinder_model_menu_changed_remove, model);
+ g_hash_table_destroy (old_items);
+
+ /* update the new categories */
+ collect_categories = g_slist_sort (collect_categories, xfce_appfinder_model_category_compare);
+ for (li = collect_categories, lp = model->categories; li != NULL && lp != NULL; li = li->next, lp = lp->next)
+ {
+ cat_a = li->data;
+ cat_b = lp->data;
+
+ /* different items or the list length is different */
+ if (!garcon_menu_directory_equal (cat_a->directory, cat_b->directory)
+ || ((li->next == NULL) != (lp->next == NULL)))
+ {
+ tmp = model->categories;
+ model->categories = collect_categories;
+ collect_categories = tmp;
+
+ g_signal_emit (G_OBJECT (model), model_signals[CATEGORIES_CHANGED], 0);
+
+ break;
+ }
+ }
+
+ g_slist_foreach (collect_categories, (GFunc) xfce_appfinder_model_category_free, NULL);
+ g_slist_free (collect_categories);
}
@@ -949,19 +1100,17 @@ xfce_appfinder_model_collect_thread (gpointer user_data)
g_return_val_if_fail (GARCON_IS_MENU (model->menu), NULL);
g_return_val_if_fail (model->collect_items == NULL, NULL);
- g_return_val_if_fail (model->collect_desktop_ids == NULL, NULL);
+ g_return_val_if_fail (model->collect_categories == NULL, NULL);
APPFINDER_DEBUG ("collect thread start");
/* load menu data */
if (G_LIKELY (model->menu != NULL))
{
- if (garcon_menu_load (model->menu, NULL, &error))
+ if (garcon_menu_load (model->menu, model->collect_cancelled, &error))
{
- model->collect_desktop_ids = g_hash_table_new (g_str_hash, g_str_equal);
- xfce_appfinder_model_collect_items (model, model->menu, NULL);
- g_hash_table_destroy (model->collect_desktop_ids);
- model->collect_desktop_ids = NULL;
+ xfce_appfinder_model_collect_menu (model->menu, model->collect_cancelled,
+ &model->collect_items, &model->collect_categories);
}
else
{
@@ -988,7 +1137,7 @@ xfce_appfinder_model_collect_thread (gpointer user_data)
}
if (model->collect_items != NULL
- && !model->collect_cancelled)
+ && !g_cancellable_is_cancelled (model->collect_cancelled))
{
model->collect_items = g_slist_sort (model->collect_items, xfce_appfinder_model_item_compare);
model->collect_categories = g_slist_sort (model->collect_categories, xfce_appfinder_model_category_compare);
More information about the Xfce4-commits
mailing list