summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMahmoud Khalil <mahmoudkhalil11@gmail.com>2020-02-16 23:57:46 +0200
committerAndre Miranda <andreldm@xfce.org>2020-05-21 23:39:06 -0300
commitddea0a250d36b66942ff514d8ca2c2b3557eaa5b (patch)
tree3b642e838e25140c16342fd6a4920d0437fdc2f4 /src
parent84370279a53999e0de970eb7ae69464cecc90ee3 (diff)
downloadxfce4-appfinder-ddea0a250d36b66942ff514d8ca2c2b3557eaa5b.tar.gz
Sort by frecency (Bug #9265)
Co-authored-by: Andre Miranda <andreldm@xfce.org>
Diffstat (limited to 'src')
-rw-r--r--src/appfinder-model.c299
-rw-r--r--src/appfinder-model.h9
-rw-r--r--src/appfinder-preferences.c6
-rw-r--r--src/appfinder-preferences.glade17
-rw-r--r--src/appfinder-window.c72
-rw-r--r--src/main.c3
6 files changed, 396 insertions, 10 deletions
diff --git a/src/appfinder-model.c b/src/appfinder-model.c
index 7a2bb7b..35c34cd 100644
--- a/src/appfinder-model.c
+++ b/src/appfinder-model.c
@@ -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,11 +152,20 @@ 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;
gchar *key;
gchar *abstract;
@@ -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->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))
{
- model->collect_items = g_slist_sort (model->collect_items, xfce_appfinder_model_item_compare);
+ 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");
diff --git a/src/appfinder-model.h b/src/appfinder-model.h
index 0db7233..1038611 100644
--- a/src/appfinder-model.h
+++ b/src/appfinder-model.h
@@ -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
diff --git a/src/appfinder-preferences.c b/src/appfinder-preferences.c
index f3450fa..cdb69c4 100644
--- a/src/appfinder-preferences.c
+++ b/src/appfinder-preferences.c
@@ -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));
}
diff --git a/src/appfinder-preferences.glade b/src/appfinder-preferences.glade
index 10ac1c8..9755a0d 100644
--- a/src/appfinder-preferences.glade
+++ b/src/appfinder-preferences.glade
@@ -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>
diff --git a/src/appfinder-window.c b/src/appfinder-window.c
index ac309a5..942cf29 100644
--- a/src/appfinder-window.c
+++ b/src/appfinder-window.c
@@ -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,7 +709,10 @@ 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));
- gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (window->sort_model), xfce_appfinder_window_sort_items, window->entry, NULL);
+ 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.
diff --git a/src/main.c b/src/main.c
index c958a80..679dfe5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -145,7 +145,8 @@ appfinder_window_destroyed (GtkWidget *window)
if (model_cache == NULL)
{
APPFINDER_DEBUG ("main took reference on the main model");
- model_cache = xfce_appfinder_model_get ();
+ channel = xfconf_channel_get ("xfce4-appfinder");
+ model_cache = xfce_appfinder_model_get (xfconf_channel_get_bool (channel, "/sort-by-frecency", FALSE));
}
/* remove from internal list */