[Xfce4-commits] <xfce4-appfinder:master> Improve reloading of items and directories.

Nick Schermer noreply at xfce.org
Tue Dec 27 21:24:03 CET 2011


Updating branch refs/heads/master
         to 80158f7d30693d2196b5ea312a4c2b7478e6fcaf (commit)
       from 23f905b73a157c6d83a4ce905c0376da86cac76c (commit)

commit 80158f7d30693d2196b5ea312a4c2b7478e6fcaf
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Dec 27 21:18:39 2011 +0100

    Improve reloading of items and directories.

 src/appfinder-category-model.c |   39 +++++++-
 src/appfinder-model.c          |  194 ++++++++++++++++++++++++---------------
 src/appfinder-model.h          |    9 --
 src/appfinder-window.c         |   37 +++++---
 4 files changed, 178 insertions(+), 101 deletions(-)

diff --git a/src/appfinder-category-model.c b/src/appfinder-category-model.c
index 07613b9..bd30e9a 100644
--- a/src/appfinder-category-model.c
+++ b/src/appfinder-category-model.c
@@ -32,6 +32,10 @@
 
 
 
+typedef struct _CategoryItem CategoryItem;
+
+
+
 static void               xfce_appfinder_category_model_tree_model_init       (GtkTreeModelIface        *iface);
 static void               xfce_appfinder_category_model_get_property          (GObject                  *object,
                                                                                guint                     prop_id,
@@ -71,6 +75,7 @@ static gboolean           xfce_appfinder_category_model_iter_nth_child        (G
 static gboolean           xfce_appfinder_category_model_iter_parent           (GtkTreeModel             *tree_model,
                                                                                GtkTreeIter              *iter,
                                                                                GtkTreeIter              *child);
+static void               xfce_appfinder_category_category_free               (CategoryItem             *item);
 
 
 
@@ -91,6 +96,12 @@ struct _XfceAppfinderCategoryModel
   XfceAppfinderIconSize  icon_size;
 };
 
+struct _CategoryItem
+{
+  GarconMenuDirectory *directory;
+  GdkPixbuf           *pixbuf;
+};
+
 enum
 {
   PROP_0,
@@ -218,7 +229,7 @@ xfce_appfinder_category_model_finalize (GObject *object)
 
   /* clear the first three items */
   for (li = model->categories, n = 0; li != NULL && n < 3; li = li->next, n++)
-    xfce_appfinder_model_category_free (li->data);
+    xfce_appfinder_category_category_free (li->data);
   g_slist_free (model->categories);
 
   g_object_unref (G_OBJECT (model->all_applications));
@@ -446,6 +457,20 @@ xfce_appfinder_category_model_iter_parent (GtkTreeModel *tree_model,
 
 
 
+
+static void
+xfce_appfinder_category_category_free (CategoryItem *item)
+{
+  if (item->directory != NULL)
+    g_object_unref (G_OBJECT (item->directory));
+  if (item->pixbuf != NULL)
+    g_object_unref (G_OBJECT (item->pixbuf));
+  g_slice_free (CategoryItem, item);
+}
+
+
+
+
 XfceAppfinderCategoryModel *
 xfce_appfinder_category_model_new (void)
 {
@@ -482,13 +507,20 @@ xfce_appfinder_category_model_set_categories (XfceAppfinderCategoryModel *model,
 
      /* 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);
+       xfce_appfinder_category_category_free (li->data);
      g_slist_free (model->categories);
      model->categories = NULL;
     }
 
   appfinder_assert (model->categories == NULL);
 
+  for (li = categories; li != NULL; li = li->next)
+    {
+      item = g_slice_new0 (CategoryItem);
+      item->directory = g_object_ref (li->data);
+      model->categories = g_slist_prepend (model->categories, item);
+    }
+
   /* separator and the main categories */
   item = g_slice_new0 (CategoryItem);
   model->categories = g_slist_prepend (model->categories, item);
@@ -501,9 +533,6 @@ xfce_appfinder_category_model_set_categories (XfceAppfinderCategoryModel *model,
   item->directory = g_object_ref (G_OBJECT (model->all_applications));
   model->categories = g_slist_prepend (model->categories, item);
 
-  /* move the categories online */
-  model->categories = g_slist_concat (model->categories, g_slist_copy (categories));
-
   path = gtk_tree_path_new_first ();
   for (li = model->categories; li != NULL; li = lnext)
     {
diff --git a/src/appfinder-model.c b/src/appfinder-model.c
index 13f0f8f..edc232d 100644
--- a/src/appfinder-model.c
+++ b/src/appfinder-model.c
@@ -108,6 +108,7 @@ struct _XfceAppfinderModel
   GHashTable            *items_hash;
 
   GarconMenu            *menu;
+  guint                  menu_changed_idle_id;
 
   GdkPixbuf             *command_icon;
   GdkPixbuf             *command_icon_large;
@@ -310,6 +311,9 @@ xfce_appfinder_model_finalize (GObject *object)
   if (G_UNLIKELY (model->categories_changed_idle_id != 0))
     g_source_remove (model->categories_changed_idle_id);
 
+  if (G_UNLIKELY (model->menu_changed_idle_id != 0))
+    g_source_remove (model->menu_changed_idle_id);
+
   /* stop history file monitoring */
   xfce_appfinder_model_history_monitor_stop (model);
 
@@ -322,9 +326,9 @@ xfce_appfinder_model_finalize (GObject *object)
   g_slist_foreach (model->items, (GFunc) xfce_appfinder_model_item_free, model);
   g_slist_free (model->items);
 
-  g_slist_foreach (model->collect_categories, (GFunc) xfce_appfinder_model_category_free, NULL);
+  g_slist_foreach (model->collect_categories, (GFunc) g_object_unref, NULL);
   g_slist_free (model->collect_categories);
-  g_slist_foreach (model->categories, (GFunc) xfce_appfinder_model_category_free, NULL);
+  g_slist_foreach (model->categories, (GFunc) g_object_unref, NULL);
   g_slist_free (model->categories);
 
   g_hash_table_destroy (model->items_hash);
@@ -737,7 +741,7 @@ xfce_appfinder_model_collect_idle (gpointer user_data)
 
       xfce_appfinder_model_categories_changed (model);
 
-      g_slist_foreach (tmp, (GFunc) xfce_appfinder_model_category_free, NULL);
+      g_slist_foreach (tmp, (GFunc) g_object_unref, NULL);
       g_slist_free (tmp);
     }
 
@@ -1174,26 +1178,11 @@ static gint
 xfce_appfinder_model_category_compare (gconstpointer a,
                                        gconstpointer b)
 {
-  const CategoryItem *cat_a = a;
-  const CategoryItem *cat_b = b;
-
-  appfinder_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (cat_a->directory), 0);
-  appfinder_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (cat_b->directory), 0);
-
-  return g_utf8_collate (garcon_menu_directory_get_name (cat_a->directory),
-                         garcon_menu_directory_get_name (cat_b->directory));
-}
-
+  appfinder_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (a), 0);
+  appfinder_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (b), 0);
 
-
-void
-xfce_appfinder_model_category_free (CategoryItem *item)
-{
-  if (item->directory != NULL)
-    g_object_unref (G_OBJECT (item->directory));
-  if (item->pixbuf != NULL)
-    g_object_unref (G_OBJECT (item->pixbuf));
-  g_slice_free (CategoryItem, item);
+  return g_utf8_collate (garcon_menu_directory_get_name (GARCON_MENU_DIRECTORY (a)),
+                         garcon_menu_directory_get_name (GARCON_MENU_DIRECTORY (b)));
 }
 
 
@@ -1282,6 +1271,24 @@ xfce_appfinder_model_collect_item (const gchar    *desktop_id,
 
 
 
+static void
+xfce_appfinder_model_directory_changed (GarconMenu *menu)
+{
+  GarconMenu *parent;
+
+  appfinder_return_if_fail (GARCON_IS_MENU (menu));
+
+  while (menu != NULL)
+    {
+      parent = garcon_menu_get_parent (menu);
+      if (parent == NULL)
+        g_signal_emit_by_name (menu, "reload-required");
+      menu = parent;
+    }
+}
+
+
+
 static gboolean
 xfce_appfinder_model_collect_items (GarconMenu           *menu,
                                     GCancellable         *cancelled,
@@ -1293,7 +1300,6 @@ xfce_appfinder_model_collect_items (GarconMenu           *menu,
   GList               *menus, *li;
   GarconMenuDirectory *directory;
   gboolean             has_items = FALSE;
-  CategoryItem        *citem;
   GarconMenuItemPool  *pool;
   CollectContext      *context;
 
@@ -1318,6 +1324,9 @@ xfce_appfinder_model_collect_items (GarconMenu           *menu,
         category = directory;
     }
 
+  g_signal_connect (G_OBJECT (menu), "directory-changed",
+      G_CALLBACK (xfce_appfinder_model_directory_changed), NULL);
+
   /* collect all the items in the menu's pool. we walk
    * the pool directory to avoid the sorting of items
    * that is done within garcon for _get_elements and
@@ -1353,13 +1362,8 @@ xfce_appfinder_model_collect_items (GarconMenu           *menu,
     }
   g_list_free (menus);
 
-  if (directory != NULL
-      && has_items)
-    {
-      citem = g_slice_new0 (CategoryItem);
-      citem->directory = g_object_ref (G_OBJECT (directory));
-      *categories = g_slist_prepend (*categories, citem);
-    }
+  if (directory != NULL && has_items)
+    *categories = g_slist_prepend (*categories, g_object_ref (G_OBJECT (directory)));
 
   return has_items;
 }
@@ -1405,28 +1409,32 @@ xfce_appfinder_model_menu_changed_remove (gpointer key,
 
 
 
-static void
-xfce_appfinder_model_menu_changed (GarconMenu         *menu,
-                                   XfceAppfinderModel *model)
+static gboolean
+xfce_appfinder_model_menu_changed_idle (gpointer data)
 {
-  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;
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (data);
+  GarconMenu         *menu = model->menu;
+  GSList             *li, *lp;
+  GHashTable         *old_items;
+  ModelItem          *item;
+  ModelItem          *old_item;
+  const gchar        *desktop_id;
+  GSList             *collect_items = NULL;
+  GSList             *collect_categories = NULL;
+  GSList             *tmp;
+  guint               idx;
+  GtkTreeIter         iter;
+  GtkTreePath        *path;
+  GSList             *old_li;
+  GError             *error = NULL;
 
-  appfinder_return_if_fail (GARCON_IS_MENU (menu));
-  appfinder_return_if_fail (XFCE_IS_APPFINDER_MODEL (model));
-  appfinder_return_if_fail (model->menu == menu);
+  appfinder_return_val_if_fail (GARCON_IS_MENU (menu), FALSE);
+  appfinder_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
 
   APPFINDER_DEBUG ("menu changed");
 
+  model->menu_changed_idle_id = 0;
+
   /* 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)
@@ -1439,6 +1447,12 @@ xfce_appfinder_model_menu_changed (GarconMenu         *menu,
         }
     }
 
+  if (!garcon_menu_load (model->menu, NULL, &error))
+    {
+      g_warning ("Failed to reload the root menu: %s", error->message);
+      g_error_free (error);
+    }
+
   xfce_appfinder_model_collect_menu (menu, NULL, &collect_items, &collect_categories);
 
   for (li = collect_items; li != NULL; li = li->next)
@@ -1448,8 +1462,30 @@ xfce_appfinder_model_menu_changed (GarconMenu         *menu,
       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))
+
+      /* check if desktop id already exists */
+      old_li = g_hash_table_lookup (old_items, desktop_id);
+      if (old_li != NULL)
         {
+          /* check if the file location is still equal */
+          old_item = old_li->data;
+          if (!garcon_menu_element_equal (GARCON_MENU_ELEMENT (old_item->item),
+                                          GARCON_MENU_ELEMENT (item->item)))
+            {
+              APPFINDER_DEBUG ("%s file location changed", desktop_id);
+
+              /* do not remove from the hash table and insert the new item */
+              goto insert;
+            }
+
+          /* remove from the table */
+          g_hash_table_remove (old_items, desktop_id);
+
+          /* steal the categories */
+          g_ptr_array_unref (old_item->categories);
+          old_item->categories = item->categories;
+          item->categories = NULL;
+
           /* this is not interesting, since those items are also updated
            * by the GarconMenuItem::changed signal, so don't touch the
            * item in the model */
@@ -1457,6 +1493,8 @@ xfce_appfinder_model_menu_changed (GarconMenu         *menu,
         }
       else
         {
+          insert:
+
           /* insert new item in the list */
           model->items = g_slist_insert_sorted (model->items, item, xfce_appfinder_model_item_compare);
 
@@ -1476,10 +1514,10 @@ xfce_appfinder_model_menu_changed (GarconMenu         *menu,
 
           /* watch and add the command */
           g_signal_connect (G_OBJECT (item->item), "changed",
-                          G_CALLBACK (xfce_appfinder_model_item_changed), model);
+              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_hash_table_insert (model->items_hash, item->command, item);
         }
     }
 
@@ -1491,27 +1529,32 @@ xfce_appfinder_model_menu_changed (GarconMenu         *menu,
 
   /* 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;
+  /* swap lists */
+  tmp = model->categories;
+  model->categories = collect_categories;
 
-          xfce_appfinder_model_categories_changed (model);
+  /* always update the categories, because the pointers changed */
+  xfce_appfinder_model_categories_changed (model);
 
-          break;
-        }
-    }
+  g_slist_foreach (tmp, (GFunc) g_object_unref, NULL);
+  g_slist_free (tmp);
+
+  return FALSE;
+}
+
+
+
+static void
+xfce_appfinder_model_menu_changed (GarconMenu         *menu,
+                                   XfceAppfinderModel *model)
+{
+  appfinder_return_if_fail (GARCON_IS_MENU (menu));
+  appfinder_return_if_fail (XFCE_IS_APPFINDER_MODEL (model));
+  appfinder_return_if_fail (model->menu == menu);
 
-  g_slist_foreach (collect_categories, (GFunc) xfce_appfinder_model_category_free, NULL);
-  g_slist_free (collect_categories);
+  if (model->menu_changed_idle_id == 0)
+    model->menu_changed_idle_id = g_idle_add (xfce_appfinder_model_menu_changed_idle, model);
 }
 
 
@@ -1616,18 +1659,18 @@ xfce_appfinder_model_get (void)
 GSList *
 xfce_appfinder_model_get_categories (XfceAppfinderModel *model)
 {
-  GSList       *categories = NULL;
-  GSList       *li, *lp;
-  CategoryItem *category;
-  gboolean      visible;
-  ModelItem    *item;
+  GSList              *categories = NULL;
+  GSList              *li, *lp;
+  gboolean             visible;
+  ModelItem           *item;
+  GarconMenuDirectory *category;
 
   appfinder_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), NULL);
 
   for (li = model->categories; li != NULL; li = li->next)
     {
       category = li->data;
-      appfinder_assert (GARCON_IS_MENU_DIRECTORY (category->directory));
+      appfinder_assert (GARCON_IS_MENU_DIRECTORY (category));
       visible = FALSE;
 
       /* check if the category has a visible item */
@@ -1635,7 +1678,7 @@ xfce_appfinder_model_get_categories (XfceAppfinderModel *model)
         {
           item = lp->data;
           if (!item->not_visible
-              && xfce_appfinder_model_ptr_array_find (item->categories, category->directory))
+              && xfce_appfinder_model_ptr_array_find (item->categories, category))
             {
               visible = TRUE;
               break;
@@ -1648,7 +1691,8 @@ xfce_appfinder_model_get_categories (XfceAppfinderModel *model)
       categories = g_slist_prepend (categories, category);
     }
 
-  return g_slist_reverse (categories);
+  /* we return in reversed order here */
+  return categories;
 }
 
 
diff --git a/src/appfinder-model.h b/src/appfinder-model.h
index 480f03f..2b31cf8 100644
--- a/src/appfinder-model.h
+++ b/src/appfinder-model.h
@@ -62,13 +62,6 @@ XfceAppfinderIconSize;
 #define XFCE_APPFINDER_ICON_SIZE_DEFAULT_ITEM     XFCE_APPFINDER_ICON_SIZE_SMALL
 #define XFCE_APPFINDER_ICON_SIZE_48               XFCE_APPFINDER_ICON_SIZE_NORMAL
 
-typedef struct
-{
-  GarconMenuDirectory *directory;
-  GdkPixbuf           *pixbuf;
-}
-CategoryItem;
-
 
 
 GType                xfce_appfinder_model_get_type             (void) G_GNUC_CONST;
@@ -108,8 +101,6 @@ GarconMenuDirectory *xfce_appfinder_model_get_command_category (void);
 
 void                 xfce_appfinder_model_history_clear        (XfceAppfinderModel        *model);
 
-void                 xfce_appfinder_model_category_free        (CategoryItem              *category);
-
 G_END_DECLS
 
 #endif /* !__XFCE_APPFINDER_MODEL_H__ */
diff --git a/src/appfinder-window.c b/src/appfinder-window.c
index 06d9106..9c5fa92 100644
--- a/src/appfinder-window.c
+++ b/src/appfinder-window.c
@@ -79,7 +79,8 @@ static gboolean   xfce_appfinder_window_treeview_key_press_event      (GtkWidget
                                                                        XfceAppfinderWindow         *window);
 static void       xfce_appfinder_window_category_changed              (GtkTreeSelection            *selection,
                                                                        XfceAppfinderWindow         *window);
-static void       xfce_appfinder_window_category_set_categories       (XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_category_set_categories       (XfceAppfinderModel          *model,
+                                                                       XfceAppfinderWindow         *window);
 static void       xfce_appfinder_window_preferences                   (GtkWidget                   *button,
                                                                        XfceAppfinderWindow         *window);
 static void       xfce_appfinder_window_property_changed              (XfconfChannel               *channel,
@@ -353,10 +354,10 @@ xfce_appfinder_window_init (XfceAppfinderWindow *window)
       G_CALLBACK (xfce_appfinder_window_icon_theme_changed), window);
 
   /* load categories in the model */
-  xfce_appfinder_window_category_set_categories (window);
-  g_signal_connect_swapped (G_OBJECT (window->model), "categories-changed",
-                            G_CALLBACK (xfce_appfinder_window_category_set_categories),
-                            window);
+  xfce_appfinder_window_category_set_categories (NULL, window);
+  g_signal_connect (G_OBJECT (window->model), "categories-changed",
+                    G_CALLBACK (xfce_appfinder_window_category_set_categories),
+                    window);
 
   /* monitor xfconf property changes */
   window->property_watch_id =
@@ -990,23 +991,34 @@ xfce_appfinder_window_category_changed (GtkTreeSelection    *selection,
 
 
 static void
-xfce_appfinder_window_category_set_categories (XfceAppfinderWindow *window)
+xfce_appfinder_window_category_set_categories (XfceAppfinderModel  *signal_from_model,
+                                               XfceAppfinderWindow *window)
 {
-  GSList      *categories;
-  GtkTreePath *path;
-  gchar       *name;
+  GSList           *categories;
+  GtkTreePath      *path;
+  gchar            *name = NULL;
+  GtkTreeModel     *model;
+  GtkTreeIter       iter;
+  GtkTreeSelection *selection;
 
   appfinder_return_if_fail (GTK_IS_TREE_VIEW (window->sidepane));
 
+  if (signal_from_model != NULL)
+    {
+      /* reload from the model, make sure we restore the selected category */
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->sidepane));
+      if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        gtk_tree_model_get (model, &iter, XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME, &name, -1);
+    }
+
+  /* update the categories */
   categories = xfce_appfinder_model_get_categories (window->model);
   if (categories != NULL)
     xfce_appfinder_category_model_set_categories (window->category_model, categories);
   g_slist_free (categories);
 
-  if (xfconf_channel_get_bool (window->channel, "/remember-category", FALSE))
+  if (name == NULL && xfconf_channel_get_bool (window->channel, "/remember-category", FALSE))
     name = xfconf_channel_get_string (window->channel, "/last/category", NULL);
-  else
-    name = NULL;
 
   path = xfce_appfinder_category_model_find_category (window->category_model, name);
   if (path != NULL)
@@ -1014,6 +1026,7 @@ xfce_appfinder_window_category_set_categories (XfceAppfinderWindow *window)
       gtk_tree_view_set_cursor (GTK_TREE_VIEW (window->sidepane), path, NULL, FALSE);
       gtk_tree_path_free (path);
     }
+
   g_free (name);
 }
 


More information about the Xfce4-commits mailing list