Commit ddea0a25 authored by Mahmoud Khalil's avatar Mahmoud Khalil Committed by Andre Miranda
Browse files

Sort by frecency (Bug #9265)



Co-authored-by: default avatarAndre Miranda <andreldm@xfce.org>
parent 84370279
Loading
Loading
Loading
Loading
Loading
+294 −5
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@

#define HISTORY_PATH   "xfce4/xfce4-appfinder/history"
#define BOOKMARKS_PATH "xfce4/appfinder/bookmarks"
#define FRECENCY_PATH  "xfce4/appfinder/frecency"


static void               xfce_appfinder_model_tree_model_init        (GtkTreeModelIface        *iface);
@@ -102,6 +103,12 @@ static void xfce_appfinder_model_bookmarks_monitor (XfceAppfi

static gboolean           xfce_appfinder_model_fuzzy_match            (const gchar              *source,
                                                                       const gchar              *token);
static gint               xfce_appfinder_model_item_compare_frecency  (gconstpointer             a,
                                                                       gconstpointer             b,
                                                                       gpointer                  data);
static void               xfce_appfinder_model_frecency_collect       (XfceAppfinderModel       *model,
                                                                       GMappedFile              *mmap);
static void               xfce_appfinder_model_frecency_free          (gpointer                  data);


struct _XfceAppfinderModelClass
@@ -119,6 +126,7 @@ struct _XfceAppfinderModel
  GHashTable            *items_hash;

  GHashTable            *bookmarks_hash;
  GHashTable            *frecencies_hash;

  GFileMonitor          *bookmarks_monitor;
  GFile                 *bookmarks_file;
@@ -144,9 +152,18 @@ struct _XfceAppfinderModel
  GFile                 *history_file;
  guint64                history_mtime;

  gboolean               sort_by_frecency;

  XfceAppfinderIconSize  icon_size;
};

typedef struct
{
  guint   frequency;
  guint64 recency;
}
Frecency;

typedef struct
{
  GarconMenuItem *item;
@@ -158,6 +175,8 @@ typedef struct
  guint           not_visible : 1;
  guint           is_bookmark : 1;

  Frecency       *frecency; /* owned by frecencies_hash */

  GdkPixbuf      *icon;
  GdkPixbuf      *icon_large;
}
@@ -180,7 +199,8 @@ enum
enum
{
  PROP_0,
  PROP_ICON_SIZE
  PROP_ICON_SIZE,
  PROP_SORT_BY_FRECENCY
};


@@ -212,6 +232,12 @@ xfce_appfinder_model_class_init (XfceAppfinderModelClass *klass)
                                                      XFCE_APPFINDER_ICON_SIZE_DEFAULT_ITEM,
                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_class,
                                   PROP_SORT_BY_FRECENCY,
                                   g_param_spec_boolean ("sort-by-frecency", NULL, NULL,
                                                         FALSE,
                                                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));

  model_signals[CATEGORIES_CHANGED] =
    g_signal_new (g_intern_static_string ("categories-changed"),
                  G_TYPE_FROM_CLASS (gobject_class),
@@ -230,6 +256,7 @@ xfce_appfinder_model_init (XfceAppfinderModel *model)
  model->stamp = g_random_int ();
  model->items_hash = g_hash_table_new (g_str_hash, g_str_equal);
  model->bookmarks_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
  model->frecencies_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, xfce_appfinder_model_frecency_free);
  model->icon_size = XFCE_APPFINDER_ICON_SIZE_DEFAULT_ITEM;
  model->command_icon = xfce_appfinder_model_load_pixbuf (XFCE_APPFINDER_STOCK_EXECUTE, model->icon_size);
  model->command_icon_large = xfce_appfinder_model_load_pixbuf (XFCE_APPFINDER_STOCK_EXECUTE, XFCE_APPFINDER_ICON_SIZE_48);
@@ -281,6 +308,10 @@ xfce_appfinder_model_get_property (GObject *object,
      g_value_set_uint (value, model->icon_size);
      break;

    case PROP_SORT_BY_FRECENCY:
      g_value_set_boolean (value, model->sort_by_frecency);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
@@ -311,6 +342,10 @@ xfce_appfinder_model_set_property (GObject *object,
        }
      break;

    case PROP_SORT_BY_FRECENCY:
      model->sort_by_frecency = g_value_get_boolean (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
@@ -362,6 +397,7 @@ xfce_appfinder_model_finalize (GObject *object)

  g_hash_table_destroy (model->items_hash);
  g_hash_table_destroy (model->bookmarks_hash);
  g_hash_table_destroy (model->frecencies_hash);

  g_object_unref (G_OBJECT (model->command_icon_large));
  g_object_unref (G_OBJECT (model->command_icon));
@@ -410,6 +446,12 @@ xfce_appfinder_model_get_column_type (GtkTreeModel *tree_model,
    case XFCE_APPFINDER_MODEL_COLUMN_BOOKMARK:
      return G_TYPE_BOOLEAN;

    case XFCE_APPFINDER_MODEL_COLUMN_FREQUENCY:
      return G_TYPE_UINT;

    case XFCE_APPFINDER_MODEL_COLUMN_RECENCY:
      return G_TYPE_UINT64;

    default:
      g_assert_not_reached ();
      return G_TYPE_INVALID;
@@ -598,6 +640,16 @@ xfce_appfinder_model_get_value (GtkTreeModel *tree_model,
      g_value_set_boolean (value, item->is_bookmark);
      break;

    case XFCE_APPFINDER_MODEL_COLUMN_FREQUENCY:
      g_value_init (value, G_TYPE_UINT);
      g_value_set_uint (value, item->frecency ? item->frecency->frequency : 0);
      break;

    case XFCE_APPFINDER_MODEL_COLUMN_RECENCY:
      g_value_init (value, G_TYPE_UINT64);
      g_value_set_uint64 (value, item->frecency ? item->frecency->recency : 0);
      break;

    default:
      g_assert_not_reached ();
      break;
@@ -771,6 +823,7 @@ xfce_appfinder_model_collect_idle (gpointer user_data)

          desktop_id = garcon_menu_item_get_desktop_id (item->item);
          item->is_bookmark = g_hash_table_lookup (model->bookmarks_hash, desktop_id) != NULL;
          item->frecency = g_hash_table_lookup (model->frecencies_hash, desktop_id);
        }

      /* insert in hash table */
@@ -939,7 +992,10 @@ xfce_appfinder_model_item_changed (GarconMenuItem *menu_item,
          /* check if the item should be a bookmark */
          desktop_id = garcon_menu_item_get_desktop_id (menu_item);
          if (desktop_id != NULL)
            {
              item->is_bookmark = g_hash_table_lookup (model->bookmarks_hash, desktop_id) != NULL;
              item->frecency = g_hash_table_lookup (model->frecencies_hash, desktop_id);
            }
          else
            item->is_bookmark = FALSE;

@@ -1892,10 +1948,35 @@ xfce_appfinder_model_collect_thread (gpointer user_data)
      g_free (filename);
    }

  /* load frecencies */
  filename = xfce_resource_lookup (XFCE_RESOURCE_CACHE, FRECENCY_PATH);
  if (G_LIKELY (filename != NULL))
    {
      APPFINDER_DEBUG ("load frecencies from %s", filename);

      mmap = g_mapped_file_new (filename, FALSE, &error);
      if (G_LIKELY (mmap != NULL))
        {
          xfce_appfinder_model_frecency_collect (model, mmap);
          g_mapped_file_unref (mmap);
        }
      else
        {
          g_warning ("Failed to open frecencies file: %s", error->message);
          g_clear_error (&error);
        }

      g_free (filename);
    }

  if (model->collect_items != NULL
      && !g_cancellable_is_cancelled (model->collect_cancelled))
    {
      if (model->sort_by_frecency)
        model->collect_items = g_slist_sort_with_data (model->collect_items, xfce_appfinder_model_item_compare_frecency, model);
      else
        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);

      model->collect_idle_id = gdk_threads_add_idle_full (G_PRIORITY_LOW, xfce_appfinder_model_collect_idle,
@@ -1915,8 +1996,214 @@ xfce_appfinder_model_collect_thread (gpointer user_data)



static gint
xfce_appfinder_model_item_compare_frecency (gconstpointer a,
                                            gconstpointer b,
                                            gpointer      data)
{
  const ModelItem    *item_a = a, *item_b = b;
  const gchar        *desktop_id_a, *desktop_id_b;
  XfceAppfinderModel *model;
  Frecency           *frecency_a, *frecency_b;
  guint               freq_a, freq_b, res_a, res_b;
  guint64             rec_a, rec_b;

  if (item_a->item != NULL && item_b->item != NULL)
    {
      desktop_id_a = garcon_menu_item_get_desktop_id (item_a->item);
      desktop_id_b = garcon_menu_item_get_desktop_id (item_b->item);

      if (desktop_id_a != NULL && desktop_id_b != NULL)
        {
          model = (XfceAppfinderModel *) data;

          frecency_a = g_hash_table_lookup (model->frecencies_hash, desktop_id_a);
          frecency_b = g_hash_table_lookup (model->frecencies_hash, desktop_id_b);

          freq_a = frecency_a ? frecency_a->frequency : 0;
          freq_b = frecency_b ? frecency_b->frequency : 0;

          rec_a = frecency_a ? frecency_a->recency : 0;
          rec_b = frecency_b ? frecency_b->recency : 0;

          res_a = xfce_appfinder_model_calculate_frecency (freq_a, rec_a);
          res_b = xfce_appfinder_model_calculate_frecency (freq_b, rec_b);

          if (res_b - res_a != 0)
            return res_b - res_a;
        }
    }

  /* fallback to alphabetical order if desktop files are invalid
   * or items have the same frecency */
  return xfce_appfinder_model_item_compare (a, b);
}



static void
xfce_appfinder_model_frecency_collect (XfceAppfinderModel  *model,
                                       GMappedFile         *mmap)
{
  gchar       *line;
  gchar      **tokens;
  gchar       *end;
  gchar       *contents;
  Frecency    *frecency;

  contents = g_mapped_file_get_contents (mmap);
  if (contents == NULL)
    return;

  /* walk the file */
  for (; !g_cancellable_is_cancelled (model->collect_cancelled);)
    {
      end = strchr (contents, '\n');
      if (G_UNLIKELY (end == NULL))
        break;

      if (end != contents)
        {
          line = g_strndup (contents, end - contents);
          tokens = g_strsplit (line, ":", 3);
          if (g_strv_length (tokens) == 3 && tokens[0] != NULL && tokens[1] != NULL && tokens[2] != NULL)
            {
              frecency = g_slice_new0 (Frecency);
              frecency->frequency = g_ascii_strtoull (tokens[1], NULL, 0);
              frecency->recency = g_ascii_strtoull (tokens[2], NULL, 0);
              g_hash_table_insert (model->frecencies_hash, g_strdup (tokens[0]), frecency);
            }
          g_free (line);
          g_strfreev (tokens);
        }
      contents = end + 1;
    }
}



static void
xfce_appfinder_model_frecency_free (gpointer data)
{
  g_slice_free (Frecency, data);
}



guint
xfce_appfinder_model_calculate_frecency (guint   frequency,
                                         guint64 recency)
{
  GDateTime *date_time_now;
  guint64    unix_time_now;
  guint64    diff;

  /* get the current timestamp */
  date_time_now = g_date_time_new_now_local ();
  unix_time_now = g_date_time_to_unix (date_time_now);
  g_date_time_unref (date_time_now);

  diff = unix_time_now - recency;

  /* return frecency according to the frequency and how recent the item is */
  if (diff < 3600) return frequency * 4;
  if (diff < 86400) return frequency * 2;
  if (diff < 604800) return frequency / 2;
  return frequency / 4;
}



void
xfce_appfinder_model_update_frecency (XfceAppfinderModel *model,
                                      const gchar        *desktop_id,
                                      GError            **error)
{
  ModelItem    *item;
  GSList       *li;
  const gchar  *item_desktop_id;
  GString      *frecency_contents;
  gchar        *filename;
  GtkTreePath  *path;
  gint          idx;
  GtkTreeIter   iter;
  GDateTime    *now;

  appfinder_return_if_fail (XFCE_IS_APPFINDER_MODEL (model));
  appfinder_return_if_fail (error == NULL || *error == NULL);
  appfinder_return_if_fail (desktop_id != NULL);

  frecency_contents = g_string_sized_new (0);

  /* update the model items */
  for (idx = 0, li = model->items; li != NULL; li = li->next, idx++)
    {
      item = li->data;
      if (item->item == NULL)
        continue;

      item_desktop_id = garcon_menu_item_get_desktop_id (item->item);
      if (item_desktop_id == NULL)
        continue;

      if (item->frecency == NULL)
        item->frecency = g_hash_table_lookup (model->frecencies_hash, item_desktop_id);

      if (item->frecency == NULL)
        {
          item->frecency = g_slice_new0 (Frecency);
          item->frecency->frequency = 0;
          item->frecency->recency = 0;
          g_hash_table_insert (model->frecencies_hash, g_strdup (item_desktop_id), item->frecency);
        }

      /* find the item we're trying to add/remove */
      if (desktop_id != NULL && g_strcmp0 (item_desktop_id, desktop_id) == 0)
        {
          /* update frequency */
          item->frecency->frequency++;

          /* update recency */
          now = g_date_time_new_now_local ();
          item->frecency->recency = g_date_time_to_unix (now);
          g_date_time_unref (now);

          /* stop searching, continue collecting */
          desktop_id = NULL;

          /* update model */
          path = gtk_tree_path_new_from_indices (idx, -1);
          ITER_INIT (iter, model->stamp, li);
          gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
          gtk_tree_path_free (path);
        }

      /* collect items' frecency */
      g_string_append (frecency_contents, g_strdup_printf (
        "%s:%" G_GUINT32_FORMAT ":%" G_GUINT64_FORMAT,
        item_desktop_id,
        item->frecency->frequency,
        item->frecency->recency));
      g_string_append_c (frecency_contents, '\n');
    }

  APPFINDER_DEBUG ("saving frecencies");

  /* write new frecencies */
  filename = xfce_resource_save_location (XFCE_RESOURCE_CACHE, FRECENCY_PATH, TRUE);
  if (G_LIKELY (filename != NULL))
    g_file_set_contents (filename, frecency_contents->str, frecency_contents->len, NULL);
  else
    g_set_error_literal (error, 0, 0, "Unable to create frecencies file");

  g_free (filename);
  g_string_free (frecency_contents, TRUE);
}



XfceAppfinderModel *
xfce_appfinder_model_get (void)
xfce_appfinder_model_get (gboolean sort_by_frecency)
{
  static XfceAppfinderModel *model = NULL;

@@ -1926,7 +2213,9 @@ xfce_appfinder_model_get (void)
    }
  else
    {
      model = g_object_new (XFCE_TYPE_APPFINDER_MODEL, NULL);
      model = g_object_new (XFCE_TYPE_APPFINDER_MODEL,
                            "sort-by-frecency", sort_by_frecency,
                            NULL);
      g_object_add_weak_pointer (G_OBJECT (model), (gpointer) &model);
      appfinder_refcount_debug_add (G_OBJECT (model), "appfinder-model");
      APPFINDER_DEBUG ("allocate new model");
+8 −1
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ enum
  XFCE_APPFINDER_MODEL_COLUMN_COMMAND,
  XFCE_APPFINDER_MODEL_COLUMN_URI,
  XFCE_APPFINDER_MODEL_COLUMN_BOOKMARK,
  XFCE_APPFINDER_MODEL_COLUMN_FREQUENCY,
  XFCE_APPFINDER_MODEL_COLUMN_RECENCY,
  XFCE_APPFINDER_MODEL_COLUMN_TOOLTIP,
  XFCE_APPFINDER_MODEL_N_COLUMNS,
};
@@ -67,7 +69,7 @@ XfceAppfinderIconSize;

GType                xfce_appfinder_model_get_type               (void) G_GNUC_CONST;

XfceAppfinderModel  *xfce_appfinder_model_get                    (void) G_GNUC_MALLOC;
XfceAppfinderModel  *xfce_appfinder_model_get                    (gboolean                   sort_by_frecency) G_GNUC_MALLOC;

GSList              *xfce_appfinder_model_get_categories         (XfceAppfinderModel        *model);

@@ -108,6 +110,11 @@ gboolean xfce_appfinder_model_bookmark_toggle (XfceAppfinderM
GarconMenuDirectory *xfce_appfinder_model_get_command_category   (void);

GarconMenuDirectory *xfce_appfinder_model_get_bookmarks_category (void);
void                 xfce_appfinder_model_update_frecency        (XfceAppfinderModel       *model,
                                                                  const gchar              *desktop_id,
                                                                  GError                  **error);
guint                xfce_appfinder_model_calculate_frecency     (guint                     frequency,
                                                                  guint64                   recency);

G_END_DECLS

+5 −1
Original line number Diff line number Diff line
@@ -134,6 +134,10 @@ xfce_appfinder_preferences_init (XfceAppfinderPreferences *preferences)
      G_CALLBACK (xfce_appfinder_preferences_single_window_sensitive), object);
  xfce_appfinder_preferences_single_window_sensitive (GTK_WIDGET (previous), GTK_WIDGET (object));

  object = gtk_builder_get_object (GTK_BUILDER (preferences), "sort-by-frecency");
  xfconf_g_property_bind (preferences->channel, "/sort-by-frecency", G_TYPE_BOOLEAN,
                          G_OBJECT (object), "active");

  previous = gtk_builder_get_object (GTK_BUILDER (preferences), "icon-view");
  xfconf_g_property_bind (preferences->channel, "/icon-view", G_TYPE_BOOLEAN,
                          G_OBJECT (previous), "active");
@@ -259,7 +263,7 @@ xfce_appfinder_preferences_clear_history (XfceAppfinderPreferences *preferences)
                           _("This will permanently clear the custom command history."),
                           _("Are you sure you want to clear the command history?")))
    {
      model = xfce_appfinder_model_get ();
      model = xfce_appfinder_model_get (xfconf_channel_get_bool (preferences->channel, "/sort-by-frecency", FALSE));
      xfce_appfinder_model_history_clear (model);
      g_object_unref (G_OBJECT (model));
    }
+17 −0
Original line number Diff line number Diff line
@@ -224,6 +224,23 @@
                                <property name="position">3</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkCheckButton" id="sort-by-frecency">
                                <property name="label" translatable="yes">Sort recently used items first</property>
                                <property name="use_action_appearance">False</property>
                                <property name="visible">True</property>
                                <property name="can_focus">True</property>
                                <property name="receives_default">False</property>
                                <property name="tooltip_text" translatable="yes">Order items, such that items that are most recently used are always on the top.</property>
                                <property name="use_underline">True</property>
                                <property name="draw_indicator">True</property>
                              </object>
                              <packing>
                                <property name="expand">True</property>
                                <property name="fill">True</property>
                                <property name="position">4</property>
                              </packing>
                            </child>
                          </object>
                        </child>
                      </object>
+70 −2
Original line number Diff line number Diff line
@@ -117,6 +117,13 @@ static gint xfce_appfinder_window_sort_items (GtkTreeMo
                                                                       GtkTreeIter                 *b,
                                                                       gpointer                     data);
static gboolean   xfce_appfinder_should_sort_icon_view                (void);
static void       xfce_appfinder_window_update_frecency               (XfceAppfinderWindow         *window,
                                                                       GtkTreeModel                *model,
                                                                       const gchar                 *uri);
static gint       xfce_appfinder_window_sort_items_frecency           (GtkTreeModel                *model,
                                                                       GtkTreeIter                 *a,
                                                                       GtkTreeIter                 *b,
                                                                       gpointer                     data);

struct _XfceAppfinderWindowClass
{
@@ -218,7 +225,7 @@ xfce_appfinder_window_init (XfceAppfinderWindow *window)
  xfconf_g_property_bind (window->channel, "/category-icon-size", G_TYPE_UINT,
                          G_OBJECT (window->category_model), "icon-size");

  window->model = xfce_appfinder_model_get ();
  window->model = xfce_appfinder_model_get (xfconf_channel_get_bool (window->channel, "/sort-by-frecency", FALSE));
  xfconf_g_property_bind (window->channel, "/item-icon-size", G_TYPE_UINT,
                          G_OBJECT (window->model), "icon-size");

@@ -702,6 +709,9 @@ xfce_appfinder_window_view (XfceAppfinderWindow *window)
  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (window->filter_model), xfce_appfinder_window_item_visible, window, NULL);

  window->sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (window->filter_model));
  if (xfconf_channel_get_bool (window->channel, "/sort-by-frecency", FALSE))
    gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (window->sort_model), xfce_appfinder_window_sort_items_frecency, window->entry, NULL);
  else
    gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (window->sort_model), xfce_appfinder_window_sort_items, window->entry, NULL);

  if (icon_view)
@@ -1817,6 +1827,7 @@ xfce_appfinder_window_execute (XfceAppfinderWindow *window,
  gboolean      regular_command = FALSE;
  gboolean      save_cmd;
  gboolean      only_custom_cmd = FALSE;
  const gchar  *uri;

  screen = gtk_window_get_screen (GTK_WINDOW (window));
  if (gtk_widget_get_visible (window->paned))
@@ -1830,6 +1841,7 @@ xfce_appfinder_window_execute (XfceAppfinderWindow *window,
      if (xfce_appfinder_window_view_get_selected (window, &model, &iter))
        {
          child_model = model;
          gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_URI, &uri, -1);

          if (GTK_IS_TREE_MODEL_SORT (model) || xfce_appfinder_should_sort_icon_view ())
            {
@@ -1841,6 +1853,7 @@ xfce_appfinder_window_execute (XfceAppfinderWindow *window,
          gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (child_model), &child_iter, &iter);
          result = xfce_appfinder_model_execute (window->model, &child_iter, screen, &regular_command, &error);

          xfce_appfinder_window_update_frecency (window, model, uri);
          if (!result && regular_command)
            {
              gtk_tree_model_get (model, &child_iter, XFCE_APPFINDER_MODEL_COLUMN_COMMAND, &cmd, -1);
@@ -1888,6 +1901,32 @@ xfce_appfinder_window_execute (XfceAppfinderWindow *window,



static void
xfce_appfinder_window_update_frecency (XfceAppfinderWindow *window,
                                        GtkTreeModel        *model,
                                        const gchar         *uri)
{
  GFile      *gfile;
  gchar      *desktop_id;
  GError     *error = NULL;

  if (uri != NULL)
    {
      gfile = g_file_new_for_uri (uri);
      desktop_id = g_file_get_basename (gfile);
      g_object_unref (G_OBJECT (gfile));
      APPFINDER_DEBUG ("desktop : %s", desktop_id);

      model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (window->filter_model));
      xfce_appfinder_model_update_frecency (XFCE_APPFINDER_MODEL (model), desktop_id, &error);

      g_free (desktop_id);
      g_free (error);
    }
}



void
xfce_appfinder_window_set_expanded (XfceAppfinderWindow *window,
                                    gboolean             expanded)
@@ -1985,6 +2024,35 @@ xfce_appfinder_window_sort_items (GtkTreeModel *model,



static gint
xfce_appfinder_window_sort_items_frecency  (GtkTreeModel *model,
                                            GtkTreeIter  *a,
                                            GtkTreeIter  *b,
                                            gpointer      data)
{
  guint        a_freq, b_freq;
  guint64      a_rec, b_rec;
  guint        a_res, b_res;

  gtk_tree_model_get (model, a, XFCE_APPFINDER_MODEL_COLUMN_FREQUENCY, &a_freq, -1);
  gtk_tree_model_get (model, b, XFCE_APPFINDER_MODEL_COLUMN_FREQUENCY, &b_freq, -1);

  gtk_tree_model_get (model, a, XFCE_APPFINDER_MODEL_COLUMN_RECENCY, &a_rec, -1);
  gtk_tree_model_get (model, b, XFCE_APPFINDER_MODEL_COLUMN_RECENCY, &b_rec, -1);

  a_res = xfce_appfinder_model_calculate_frecency (a_freq, a_rec);
  b_res = xfce_appfinder_model_calculate_frecency (b_freq, b_rec);

  /* Sort according the frecency */
  if (b_res - a_res != 0)
    return b_res - a_res;

  /* If they have the same frecency, fallback to the alphabetical order */
  return xfce_appfinder_window_sort_items (model, a, b, data);
}



/*
 * Checks for gtk => 3.22.27 during runtime.
 * This is necessary because sort model for icon view did not work as expected.
Loading