mirror of https://github.com/davatorium/rofi.git
(re-implement) Do lazy loading for icons.
- Fetch only when requested - Fetch the right size, instead of estimation.
This commit is contained in:
parent
2578817db7
commit
b3b01b1973
|
@ -54,7 +54,6 @@
|
||||||
|
|
||||||
#define DRUN_CACHE_FILE "rofi2.druncache"
|
#define DRUN_CACHE_FILE "rofi2.druncache"
|
||||||
|
|
||||||
#define GET_CAT_PARSE_TIME
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store extra information about the entry.
|
* Store extra information about the entry.
|
||||||
|
@ -67,6 +66,7 @@ typedef struct
|
||||||
/* Path to desktop file */
|
/* Path to desktop file */
|
||||||
char *path;
|
char *path;
|
||||||
/* Icon stuff */
|
/* Icon stuff */
|
||||||
|
int icon_size;
|
||||||
char *icon_name;
|
char *icon_name;
|
||||||
cairo_surface_t *icon;
|
cairo_surface_t *icon;
|
||||||
/* Executable */
|
/* Executable */
|
||||||
|
@ -75,9 +75,7 @@ typedef struct
|
||||||
char *name;
|
char *name;
|
||||||
/* Generic Name */
|
/* Generic Name */
|
||||||
char *generic_name;
|
char *generic_name;
|
||||||
#ifdef GET_CAT_PARSE_TIME
|
|
||||||
char **categories;
|
char **categories;
|
||||||
#endif
|
|
||||||
|
|
||||||
GKeyFile *key_file;
|
GKeyFile *key_file;
|
||||||
} DRunModeEntry;
|
} DRunModeEntry;
|
||||||
|
@ -93,8 +91,10 @@ typedef struct
|
||||||
GHashTable *disabled_entries;
|
GHashTable *disabled_entries;
|
||||||
unsigned int disabled_entries_length;
|
unsigned int disabled_entries_length;
|
||||||
GThread *thread;
|
GThread *thread;
|
||||||
|
GAsyncQueue *icon_fetch_queue;
|
||||||
|
|
||||||
unsigned int expected_line_height;
|
unsigned int expected_line_height;
|
||||||
|
DRunModeEntry quit_entry;
|
||||||
} DRunModePrivateData;
|
} DRunModePrivateData;
|
||||||
|
|
||||||
struct RegexEvalArg
|
struct RegexEvalArg
|
||||||
|
@ -283,9 +283,7 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c
|
||||||
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 );
|
||||||
pd->entry_list[pd->cmd_list_length].generic_name = gn;
|
pd->entry_list[pd->cmd_list_length].generic_name = gn;
|
||||||
#ifdef GET_CAT_PARSE_TIME
|
|
||||||
pd->entry_list[pd->cmd_list_length].categories = g_key_file_get_locale_string_list ( kf, "Desktop Entry", "Categories", NULL, NULL, NULL );
|
pd->entry_list[pd->cmd_list_length].categories = g_key_file_get_locale_string_list ( kf, "Desktop Entry", "Categories", NULL, NULL, NULL );
|
||||||
#endif
|
|
||||||
pd->entry_list[pd->cmd_list_length].exec = g_key_file_get_string ( kf, "Desktop Entry", "Exec", NULL );
|
pd->entry_list[pd->cmd_list_length].exec = g_key_file_get_string ( kf, "Desktop Entry", "Exec", NULL );
|
||||||
|
|
||||||
if ( config.show_icons ) {
|
if ( config.show_icons ) {
|
||||||
|
@ -422,32 +420,32 @@ static void get_apps ( DRunModePrivateData *pd )
|
||||||
TICK_N ( "Get Desktop apps (system dirs)" );
|
TICK_N ( "Get Desktop apps (system dirs)" );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drun_icon_fetch ( gpointer data )
|
static gpointer drun_icon_fetch ( gpointer data )
|
||||||
{
|
{
|
||||||
// as long as dr->icon is updated atomicly.. (is a pointer write atomic?)
|
// as long as dr->icon is updated atomicly.. (is a pointer write atomic?)
|
||||||
// this should be fine running in another thread.
|
// this should be fine running in another thread.
|
||||||
GTimer *t = g_timer_new ();
|
|
||||||
DRunModePrivateData *pd = (DRunModePrivateData *) data;
|
DRunModePrivateData *pd = (DRunModePrivateData *) data;
|
||||||
for ( size_t i = 0; i < pd->cmd_list_length; i++ ) {
|
DRunModeEntry *dr;
|
||||||
DRunModeEntry *dr = &( pd->entry_list[i] );
|
while ( ( dr = g_async_queue_pop ( pd->icon_fetch_queue )) != &(pd->quit_entry) )
|
||||||
|
{
|
||||||
if ( dr->icon_name == NULL ) {
|
if ( dr->icon_name == NULL ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
gchar *icon_path = nk_xdg_theme_get_icon ( pd->xdg_context, NULL, "Applications", dr->icon_name, pd->expected_line_height, 1, TRUE );
|
gchar *icon_path = nk_xdg_theme_get_icon ( pd->xdg_context, NULL, "Applications", dr->icon_name, dr->icon_size, 1, TRUE );
|
||||||
if ( icon_path == NULL ) {
|
if ( icon_path == NULL ) {
|
||||||
g_free ( dr->icon_name );
|
g_free ( dr->icon_name );
|
||||||
dr->icon_name = NULL;
|
dr->icon_name = NULL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Found Icon %s(%d): %s", dr->icon_name, pd->expected_line_height, icon_path );
|
g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Found Icon %s(%d): %s", dr->icon_name, dr->icon_size, icon_path );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( g_str_has_suffix ( icon_path, ".png" ) ) {
|
if ( g_str_has_suffix ( icon_path, ".png" ) ) {
|
||||||
dr->icon = cairo_image_surface_create_from_png ( icon_path );
|
dr->icon = cairo_image_surface_create_from_png ( icon_path );
|
||||||
}
|
}
|
||||||
else if ( g_str_has_suffix ( icon_path, ".svg" ) ) {
|
else if ( g_str_has_suffix ( icon_path, ".svg" ) ) {
|
||||||
dr->icon = cairo_image_surface_create_from_svg ( icon_path, pd->expected_line_height );
|
dr->icon = cairo_image_surface_create_from_svg ( icon_path, dr->icon_size);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Icon type not yet supported: %s", icon_path );
|
g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Icon type not yet supported: %s", icon_path );
|
||||||
|
@ -458,20 +456,18 @@ static void drun_icon_fetch ( gpointer data )
|
||||||
g_free ( icon_path );
|
g_free ( icon_path );
|
||||||
rofi_view_reload ();
|
rofi_view_reload ();
|
||||||
}
|
}
|
||||||
g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "elapsed: %f\n", g_timer_elapsed ( t, NULL ) );
|
return NULL;
|
||||||
g_timer_destroy ( t );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int drun_mode_init ( Mode *sw )
|
static int drun_mode_init ( Mode *sw )
|
||||||
{
|
{
|
||||||
if ( mode_get_private_data ( sw ) == NULL ) {
|
if ( mode_get_private_data ( sw ) == NULL ) {
|
||||||
DRunModePrivateData *pd = g_malloc0 ( sizeof ( *pd ) );
|
DRunModePrivateData *pd = g_malloc0 ( sizeof ( *pd ) );
|
||||||
pd->expected_line_height = ceil ( textbox_get_estimated_char_height ( ) );
|
|
||||||
pd->disabled_entries = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, NULL );
|
pd->disabled_entries = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, NULL );
|
||||||
mode_set_private_data ( sw, (void *) pd );
|
mode_set_private_data ( sw, (void *) pd );
|
||||||
pd->xdg_context = nk_xdg_theme_context_new ();
|
pd->xdg_context = nk_xdg_theme_context_new ();
|
||||||
get_apps ( pd );
|
get_apps ( pd );
|
||||||
pd->thread = g_thread_new ( "icon-fetch-drun", drun_icon_fetch, pd );
|
pd->icon_fetch_queue = g_async_queue_new ( );
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -486,9 +482,7 @@ static void drun_entry_clear ( DRunModeEntry *e )
|
||||||
g_free ( e->exec );
|
g_free ( e->exec );
|
||||||
g_free ( e->name );
|
g_free ( e->name );
|
||||||
g_free ( e->generic_name );
|
g_free ( e->generic_name );
|
||||||
#ifdef GET_CAT_PARSE_TIME
|
|
||||||
g_strfreev ( e->categories );
|
g_strfreev ( e->categories );
|
||||||
#endif
|
|
||||||
g_key_file_free ( e->key_file );
|
g_key_file_free ( e->key_file );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,8 +511,13 @@ static ModeMode drun_mode_result ( Mode *sw, int mretv, char **input, unsigned i
|
||||||
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 ) {
|
if ( selected_line < rmpd->history_length ) {
|
||||||
if ( rmpd->thread ) {
|
if ( rmpd->thread ) {
|
||||||
g_thread_join ( rmpd->thread );
|
g_async_queue_lock ( rmpd->icon_fetch_queue );
|
||||||
rmpd->thread = NULL;
|
DRunModeEntry *dr;
|
||||||
|
while ( (dr = g_async_queue_try_pop_unlocked ( rmpd->icon_fetch_queue )) != NULL ){
|
||||||
|
// Reset for possible re-fetch.
|
||||||
|
dr->icon_size = 0;
|
||||||
|
}
|
||||||
|
g_async_queue_unlock ( rmpd->icon_fetch_queue );
|
||||||
}
|
}
|
||||||
delete_entry_history ( &( rmpd->entry_list[selected_line] ) );
|
delete_entry_history ( &( rmpd->entry_list[selected_line] ) );
|
||||||
drun_entry_clear ( &( rmpd->entry_list[selected_line] ) );
|
drun_entry_clear ( &( rmpd->entry_list[selected_line] ) );
|
||||||
|
@ -535,9 +534,18 @@ static void drun_mode_destroy ( Mode *sw )
|
||||||
DRunModePrivateData *rmpd = (DRunModePrivateData *) mode_get_private_data ( sw );
|
DRunModePrivateData *rmpd = (DRunModePrivateData *) mode_get_private_data ( sw );
|
||||||
if ( rmpd != NULL ) {
|
if ( rmpd != NULL ) {
|
||||||
if ( rmpd->thread ) {
|
if ( rmpd->thread ) {
|
||||||
|
g_async_queue_lock ( rmpd->icon_fetch_queue );
|
||||||
|
while ( g_async_queue_try_pop_unlocked ( rmpd->icon_fetch_queue ) );
|
||||||
|
// Make the thread quit.
|
||||||
|
g_async_queue_push_front_unlocked ( rmpd->icon_fetch_queue, (gpointer) &(rmpd->quit_entry));
|
||||||
|
g_async_queue_unlock ( rmpd->icon_fetch_queue );
|
||||||
g_thread_join ( rmpd->thread );
|
g_thread_join ( rmpd->thread );
|
||||||
rmpd->thread = NULL;
|
rmpd->thread = NULL;
|
||||||
}
|
}
|
||||||
|
if ( rmpd->icon_fetch_queue ) {
|
||||||
|
g_async_queue_unref ( rmpd->icon_fetch_queue );
|
||||||
|
rmpd->icon_fetch_queue = NULL;
|
||||||
|
}
|
||||||
for ( size_t i = 0; i < rmpd->cmd_list_length; i++ ) {
|
for ( size_t i = 0; i < rmpd->cmd_list_length; i++ ) {
|
||||||
drun_entry_clear ( &( rmpd->entry_list[i] ) );
|
drun_entry_clear ( &( rmpd->entry_list[i] ) );
|
||||||
}
|
}
|
||||||
|
@ -576,6 +584,13 @@ static cairo_surface_t *_get_icon ( const Mode *sw, unsigned int selected_line,
|
||||||
DRunModePrivateData *pd = (DRunModePrivateData *) mode_get_private_data ( sw );
|
DRunModePrivateData *pd = (DRunModePrivateData *) mode_get_private_data ( sw );
|
||||||
g_return_val_if_fail ( pd->entry_list != NULL, NULL );
|
g_return_val_if_fail ( pd->entry_list != NULL, NULL );
|
||||||
DRunModeEntry *dr = &( pd->entry_list[selected_line] );
|
DRunModeEntry *dr = &( pd->entry_list[selected_line] );
|
||||||
|
if ( pd->thread == NULL ) {
|
||||||
|
pd->thread = g_thread_new ( "icon-fetch-drun", drun_icon_fetch, pd );
|
||||||
|
}
|
||||||
|
if ( dr->icon_size == 0 && dr->icon_name ) {
|
||||||
|
dr->icon_size = height;
|
||||||
|
g_async_queue_push ( pd->icon_fetch_queue, dr );
|
||||||
|
}
|
||||||
return dr->icon;
|
return dr->icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -616,18 +631,10 @@ static int drun_token_match ( const Mode *data, GRegex **tokens, unsigned int in
|
||||||
}
|
}
|
||||||
// Match against category.
|
// Match against category.
|
||||||
if ( !test ) {
|
if ( !test ) {
|
||||||
#ifdef GET_CAT_PARSE_TIME
|
|
||||||
gchar **list = rmpd->entry_list[index].categories;
|
gchar **list = rmpd->entry_list[index].categories;
|
||||||
for ( int iter = 0; !test && list && list[iter]; iter++ ) {
|
for ( int iter = 0; !test && list && list[iter]; iter++ ) {
|
||||||
test = helper_token_match ( ftokens, list[iter] );
|
test = helper_token_match ( ftokens, list[iter] );
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
gchar **list = g_key_file_get_locale_string_list ( rmpd->entry_list[index].key_file, "Desktop Entry", "Categories", NULL, NULL, NULL );
|
|
||||||
for ( int iter = 0; !test && list && list[iter]; iter++ ) {
|
|
||||||
test = helper_token_match ( ftokens, list[iter] );
|
|
||||||
}
|
|
||||||
g_strfreev ( list );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if ( test == 0 ) {
|
if ( test == 0 ) {
|
||||||
match = 0;
|
match = 0;
|
||||||
|
|
Loading…
Reference in New Issue