mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-25 13:55:34 -05:00
Change how DRUN history is implemented to fix: #579
- This solution will correctly obey all priority rules as set in desktop files. - history only affects the application being sorted at top, not affects what desktop files refers to this. Possible issue is speed of this solution, it adds a sorting. (hopefully limited, as only history items need to be moved). and several lookups through the whole list of applications. This needs some profiling to see if it becomes an issue, several solutions can be applied to make this faster again. O(history_length*num_netries)+complexity(qsort) Fixes: #579
This commit is contained in:
parent
aa95f31bc3
commit
7929818be2
1 changed files with 47 additions and 22 deletions
|
@ -31,6 +31,7 @@
|
||||||
#ifdef ENABLE_DRUN
|
#ifdef ENABLE_DRUN
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -52,7 +53,7 @@
|
||||||
#include "nkutils-xdg-theme.h"
|
#include "nkutils-xdg-theme.h"
|
||||||
#include "xcb.h"
|
#include "xcb.h"
|
||||||
|
|
||||||
#define DRUN_CACHE_FILE "rofi2.druncache"
|
#define DRUN_CACHE_FILE "rofi3.druncache"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store extra information about the entry.
|
* Store extra information about the entry.
|
||||||
|
@ -83,6 +84,8 @@ typedef struct
|
||||||
char **categories;
|
char **categories;
|
||||||
|
|
||||||
GKeyFile *key_file;
|
GKeyFile *key_file;
|
||||||
|
|
||||||
|
gint sort_index;
|
||||||
} DRunModeEntry;
|
} DRunModeEntry;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -91,7 +94,6 @@ typedef struct
|
||||||
DRunModeEntry *entry_list;
|
DRunModeEntry *entry_list;
|
||||||
unsigned int cmd_list_length;
|
unsigned int cmd_list_length;
|
||||||
unsigned int cmd_list_length_actual;
|
unsigned int cmd_list_length_actual;
|
||||||
unsigned int history_length;
|
|
||||||
// List of disabled entries.
|
// List of disabled entries.
|
||||||
GHashTable *disabled_entries;
|
GHashTable *disabled_entries;
|
||||||
unsigned int disabled_entries_length;
|
unsigned int disabled_entries_length;
|
||||||
|
@ -207,9 +209,8 @@ static void exec_cmd_entry ( DRunModeEntry *e )
|
||||||
gboolean terminal = g_key_file_get_boolean ( e->key_file, "Desktop Entry", "Terminal", NULL );
|
gboolean terminal = g_key_file_get_boolean ( e->key_file, "Desktop Entry", "Terminal", NULL );
|
||||||
if ( helper_execute_command ( exec_path, fp, terminal, sn ? &context : NULL ) ) {
|
if ( helper_execute_command ( exec_path, fp, terminal, sn ? &context : NULL ) ) {
|
||||||
char *path = g_build_filename ( cache_dir, DRUN_CACHE_FILE, NULL );
|
char *path = g_build_filename ( cache_dir, DRUN_CACHE_FILE, NULL );
|
||||||
char *key = g_strdup_printf ( "%s:::%s", e->root, e->path );
|
// Store it based on the unique identifiers (app_id).
|
||||||
history_set ( path, key );
|
history_set ( path, e->app_id );
|
||||||
g_free ( key );
|
|
||||||
g_free ( path );
|
g_free ( path );
|
||||||
}
|
}
|
||||||
g_free ( wmclass );
|
g_free ( wmclass );
|
||||||
|
@ -317,10 +318,18 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c
|
||||||
pd->cmd_list_length_actual += 256;
|
pd->cmd_list_length_actual += 256;
|
||||||
pd->entry_list = g_realloc ( pd->entry_list, pd->cmd_list_length_actual * sizeof ( *( pd->entry_list ) ) );
|
pd->entry_list = g_realloc ( pd->entry_list, pd->cmd_list_length_actual * sizeof ( *( pd->entry_list ) ) );
|
||||||
}
|
}
|
||||||
pd->entry_list[pd->cmd_list_length].icon_size = 0;
|
// Make sure order is preserved, this will break when cmd_list_length is bigger then INT_MAX.
|
||||||
pd->entry_list[pd->cmd_list_length].root = g_strdup ( root );
|
// This is not likely to happen.
|
||||||
pd->entry_list[pd->cmd_list_length].path = g_strdup ( path );
|
if ( G_UNLIKELY ( pd->cmd_list_length > INT_MAX ) ) {
|
||||||
pd->entry_list[pd->cmd_list_length].app_id = g_strndup ( basename, strlen ( basename ) - strlen ( ".desktop" ) );
|
// Default to smallest value.
|
||||||
|
pd->entry_list[pd->cmd_list_length].sort_index = INT_MIN;
|
||||||
|
} else {
|
||||||
|
pd->entry_list[pd->cmd_list_length].sort_index = -pd->cmd_list_length;
|
||||||
|
}
|
||||||
|
pd->entry_list[pd->cmd_list_length].icon_size = 0;
|
||||||
|
pd->entry_list[pd->cmd_list_length].root = g_strdup ( root );
|
||||||
|
pd->entry_list[pd->cmd_list_length].path = g_strdup ( path );
|
||||||
|
pd->entry_list[pd->cmd_list_length].app_id = g_strndup ( basename, strlen ( basename ) - strlen ( ".desktop" ) );
|
||||||
gchar *n = g_key_file_get_locale_string ( kf, "Desktop Entry", "Name", NULL, NULL );
|
gchar *n = g_key_file_get_locale_string ( kf, "Desktop Entry", "Name", NULL, NULL );
|
||||||
pd->entry_list[pd->cmd_list_length].name = n;
|
pd->entry_list[pd->cmd_list_length].name = n;
|
||||||
gchar *gn = g_key_file_get_locale_string ( kf, "Desktop Entry", "GenericName", NULL, NULL );
|
gchar *gn = g_key_file_get_locale_string ( kf, "Desktop Entry", "GenericName", NULL, NULL );
|
||||||
|
@ -416,36 +425,45 @@ static void walk_dir ( DRunModePrivateData *pd, const char *root, const char *di
|
||||||
static void delete_entry_history ( const DRunModeEntry *entry )
|
static void delete_entry_history ( const DRunModeEntry *entry )
|
||||||
{
|
{
|
||||||
char *path = g_build_filename ( cache_dir, DRUN_CACHE_FILE, NULL );
|
char *path = g_build_filename ( cache_dir, DRUN_CACHE_FILE, NULL );
|
||||||
char *key = g_strdup_printf ( "%s:::%s", entry->root, entry->path );
|
history_remove ( path, entry->app_id );
|
||||||
history_remove ( path, key );
|
|
||||||
g_free ( key );
|
|
||||||
g_free ( path );
|
g_free ( path );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_apps_history ( DRunModePrivateData *pd )
|
static void get_apps_history ( DRunModePrivateData *pd )
|
||||||
{
|
{
|
||||||
|
TICK_N ( "Start drun history" );
|
||||||
unsigned int length = 0;
|
unsigned int length = 0;
|
||||||
gchar *path = g_build_filename ( cache_dir, DRUN_CACHE_FILE, NULL );
|
gchar *path = g_build_filename ( cache_dir, DRUN_CACHE_FILE, NULL );
|
||||||
gchar **retv = history_get_list ( path, &length );
|
gchar **retv = history_get_list ( path, &length );
|
||||||
for ( unsigned int index = 0; index < length; index++ ) {
|
for ( unsigned int index = 0; index < length; index++ ) {
|
||||||
char **st = g_strsplit ( retv[index], ":::", 2 );
|
for ( size_t i = 0; i < pd->cmd_list_length; i++ ) {
|
||||||
if ( st && st[0] && st[1] ) {
|
if ( g_strcmp0 ( pd->entry_list[i].app_id, retv[index] ) == 0 ) {
|
||||||
const gchar *basename = g_utf8_strrchr ( st[1], -1, G_DIR_SEPARATOR );
|
unsigned int sort_index = length-index;
|
||||||
if ( basename == NULL || !read_desktop_file ( pd, st[0], st[1], ++basename ) ) {
|
if ( G_LIKELY ( sort_index < INT_MAX ) ) {
|
||||||
history_remove ( path, retv[index] );
|
pd->entry_list[i].sort_index = sort_index;
|
||||||
|
} else {
|
||||||
|
// This won't sort right anymore, but never gonna hit it anyway.
|
||||||
|
pd->entry_list[i].sort_index = INT_MAX;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_strfreev ( st );
|
|
||||||
}
|
}
|
||||||
g_strfreev ( retv );
|
g_strfreev ( retv );
|
||||||
g_free ( path );
|
g_free ( path );
|
||||||
pd->history_length = pd->cmd_list_length;
|
TICK_N ( "Stop drun history" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint drun_int_sort_list ( gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer user_data )
|
||||||
|
{
|
||||||
|
DRunModeEntry *da = (DRunModeEntry *)a;
|
||||||
|
DRunModeEntry *db = (DRunModeEntry *)b;
|
||||||
|
|
||||||
|
return db->sort_index - da->sort_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_apps ( DRunModePrivateData *pd )
|
static void get_apps ( DRunModePrivateData *pd )
|
||||||
{
|
{
|
||||||
TICK_N ( "Get Desktop apps (start)" );
|
TICK_N ( "Get Desktop apps (start)" );
|
||||||
get_apps_history ( pd );
|
|
||||||
|
|
||||||
gchar *dir;
|
gchar *dir;
|
||||||
// First read the user directory.
|
// First read the user directory.
|
||||||
|
@ -471,6 +489,12 @@ static void get_apps ( DRunModePrivateData *pd )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TICK_N ( "Get Desktop apps (system dirs)" );
|
TICK_N ( "Get Desktop apps (system dirs)" );
|
||||||
|
get_apps_history ( pd );
|
||||||
|
|
||||||
|
|
||||||
|
g_qsort_with_data ( pd->entry_list, pd->cmd_list_length, sizeof ( DRunModeEntry ) , drun_int_sort_list, NULL );
|
||||||
|
|
||||||
|
TICK_N ( "Sorting done." );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drun_icon_fetch ( gpointer data, gpointer user_data )
|
static void drun_icon_fetch ( gpointer data, gpointer user_data )
|
||||||
|
@ -581,7 +605,8 @@ static ModeMode drun_mode_result ( Mode *sw, int mretv, char **input, unsigned i
|
||||||
helper_execute_command ( NULL, *input, run_in_term, run_in_term ? &context : NULL );
|
helper_execute_command ( NULL, *input, run_in_term, run_in_term ? &context : NULL );
|
||||||
}
|
}
|
||||||
else if ( ( mretv & MENU_ENTRY_DELETE ) && selected_line < rmpd->cmd_list_length ) {
|
else if ( ( mretv & MENU_ENTRY_DELETE ) && selected_line < rmpd->cmd_list_length ) {
|
||||||
if ( selected_line < rmpd->history_length ) {
|
// Possitive sort index means it is in history.
|
||||||
|
if ( rmpd->entry_list[selected_line].sort_index >= 0 ) {
|
||||||
if ( rmpd->pool ) {
|
if ( rmpd->pool ) {
|
||||||
g_thread_pool_free ( rmpd->pool, TRUE, TRUE );
|
g_thread_pool_free ( rmpd->pool, TRUE, TRUE );
|
||||||
rmpd->pool = NULL;
|
rmpd->pool = NULL;
|
||||||
|
@ -684,7 +709,7 @@ static int drun_token_match ( const Mode *data, rofi_int_matcher **tokens, unsig
|
||||||
test = helper_token_match ( ftokens, rmpd->entry_list[index].generic_name );
|
test = helper_token_match ( ftokens, rmpd->entry_list[index].generic_name );
|
||||||
}
|
}
|
||||||
// Match executable name.
|
// Match executable name.
|
||||||
if ( test == tokens[j]->invert ) {
|
if ( test == tokens[j]->invert ) {
|
||||||
test = helper_token_match ( ftokens, rmpd->entry_list[index].exec );
|
test = helper_token_match ( ftokens, rmpd->entry_list[index].exec );
|
||||||
}
|
}
|
||||||
// Match against category.
|
// Match against category.
|
||||||
|
|
Loading…
Reference in a new issue