1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2024-11-18 13:54:36 -05:00

[RB] Pull the scanning into a separate thread.

This commit is contained in:
Dave Davenport 2023-05-10 17:49:16 +02:00
parent f369a7f63f
commit 848277001f

View file

@ -103,6 +103,13 @@ typedef struct {
FBFile *array; FBFile *array;
unsigned int array_length; unsigned int array_length;
unsigned int array_length_real; unsigned int array_length_real;
GThread *reading_thread;
GAsyncQueue *async_queue;
guint wake_source;
guint end_thread;
gboolean loading;
int pipefd2[2];
} FileBrowserModePrivateData; } FileBrowserModePrivateData;
/** /**
@ -138,220 +145,14 @@ static void free_list(FileBrowserModePrivateData *pd) {
#include <dirent.h> #include <dirent.h>
#include <sys/types.h> #include <sys/types.h>
static gint compare_name(gconstpointer a, gconstpointer b,
G_GNUC_UNUSED gpointer data) {
FBFile *fa = (FBFile *)a;
FBFile *fb = (FBFile *)b;
if (recursive_browser_config.directories_first && fa->type != fb->type) {
return fa->type - fb->type;
}
return g_strcmp0(fa->name, fb->name);
}
static gint compare_time(gconstpointer a, gconstpointer b,
G_GNUC_UNUSED gpointer data) {
FBFile *fa = (FBFile *)a;
FBFile *fb = (FBFile *)b;
if (recursive_browser_config.directories_first && fa->type != fb->type) {
return fa->type - fb->type;
}
if (fa->time < 0) {
return -1;
}
if (fb->time < 0) {
return 1;
}
return fb->time - fa->time;
}
static gint compare(gconstpointer a, gconstpointer b, gpointer data) {
GCompareDataFunc comparator = NULL;
switch (recursive_browser_config.sorting_method) {
case FB_SORT_NAME:
comparator = compare_name;
break;
case FB_SORT_TIME:
comparator = compare_time;
break;
default:
comparator = compare_name;
break;
}
return comparator(a, b, data);
}
static time_t get_time(const GStatBuf *statbuf) {
switch (recursive_browser_config.sorting_time) {
case FB_MTIME:
return statbuf->st_mtim.tv_sec;
case FB_ATIME:
return statbuf->st_atim.tv_sec;
case FB_CTIME:
return statbuf->st_ctim.tv_sec;
default:
return 0;
}
}
static void set_time(FBFile *file) {
// GError *error = NULL;
// gchar *path = g_filename_from_utf8(file->path, -1, NULL, NULL, &error);
// if (error) {
// g_warning("Failed to convert filename: %s: %s", file->path,
// error->message); g_error_free(error); return;
// }
GStatBuf statbuf;
if (g_lstat(file->path, &statbuf) == 0) {
file->time = get_time(&statbuf);
} else {
g_warning("Failed to stat file: %s, %s", file->path, strerror(errno));
}
// g_free(path);
}
inline static void fb_resize_array(FileBrowserModePrivateData *pd) { inline static void fb_resize_array(FileBrowserModePrivateData *pd) {
if ((pd->array_length + 1) > pd->array_length_real) { if ((pd->array_length + 1) > pd->array_length_real) {
pd->array_length_real += 1024; pd->array_length_real += 10240;
pd->array = pd->array =
g_realloc(pd->array, (pd->array_length_real + 1) * sizeof(FBFile)); g_realloc(pd->array, (pd->array_length_real + 1) * sizeof(FBFile));
} }
} }
static void get_recursive_browser(Mode *sw, GFile *scan_dir) {
FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw);
/**
* Get the entries to display.
* this gets called on plugin initialization.
*/
char *cdir = g_file_get_path(scan_dir);
DIR *dir = opendir(cdir);
if (dir) {
struct dirent *rd = NULL;
while ((rd = readdir(dir)) != NULL) {
if (g_strcmp0(rd->d_name, "..") == 0) {
continue;
//fb_resize_array(pd);
//// Rofi expects utf-8, so lets convert the filename.
//pd->array[pd->array_length].name = g_strdup("..");
//pd->array[pd->array_length].path = NULL;
//pd->array[pd->array_length].type = UP;
//pd->array[pd->array_length].icon_fetch_uid = 0;
//pd->array[pd->array_length].icon_fetch_size = 0;
//pd->array[pd->array_length].link = FALSE;
//pd->array[pd->array_length].time = -1;
//pd->array_length++;
}
if (g_strcmp0(rd->d_name, ".") == 0) {
continue;
}
if (rd->d_name[0] == '.' && recursive_browser_config.show_hidden == FALSE) {
continue;
}
switch (rd->d_type) {
case DT_BLK:
case DT_CHR:
case DT_FIFO:
case DT_UNKNOWN:
case DT_SOCK:
default:
break;
case DT_REG:
fb_resize_array(pd);
// Rofi expects utf-8, so lets convert the filename.
pd->array[pd->array_length].path =
g_build_filename(cdir, rd->d_name, NULL);
pd->array[pd->array_length].name =
g_filename_to_utf8(pd->array[pd->array_length].path, -1, NULL, NULL, NULL);
if (pd->array[pd->array_length].name == NULL) {
pd->array[pd->array_length].name = rofi_force_utf8(rd->d_name, -1);
}
pd->array[pd->array_length].type =
(rd->d_type == DT_DIR) ? DIRECTORY : RFILE;
pd->array[pd->array_length].icon_fetch_uid = 0;
pd->array[pd->array_length].icon_fetch_size = 0;
pd->array[pd->array_length].link = FALSE;
if (recursive_browser_config.sorting_method == FB_SORT_TIME) {
set_time(&pd->array[pd->array_length]);
}
pd->array_length++;
break;
case DT_DIR:
char *d = g_build_filename(cdir, rd->d_name, NULL);
GFile *dirp = g_file_new_for_path(d);
get_recursive_browser(sw,dirp);
g_object_unref(dirp);
g_free(d);
break;
case DT_LNK:
fb_resize_array(pd);
// Rofi expects utf-8, so lets convert the filename.
pd->array[pd->array_length].name =
g_filename_to_utf8(rd->d_name, -1, NULL, NULL, NULL);
if (pd->array[pd->array_length].name == NULL) {
pd->array[pd->array_length].name = rofi_force_utf8(rd->d_name, -1);
}
pd->array[pd->array_length].path =
g_build_filename(cdir, rd->d_name, NULL);
pd->array[pd->array_length].icon_fetch_uid = 0;
pd->array[pd->array_length].icon_fetch_size = 0;
pd->array[pd->array_length].link = TRUE;
// Default to file.
pd->array[pd->array_length].type = RFILE;
if (0){
// If we have link, use a stat to fine out what it is, if we fail, we
// mark it as file.
// TODO have a 'broken link' mode?
// Convert full path to right encoding.
// DD: Path should be in file encoding, not utf-8
// char *file =
// g_filename_from_utf8(pd->array[pd->array_length].path,
// -1, NULL, NULL, NULL);
if (pd->array[pd->array_length].path) {
GStatBuf statbuf;
if (g_stat(pd->array[pd->array_length].path, &statbuf) == 0) {
if (S_ISDIR(statbuf.st_mode)) {
pd->array[pd->array_length].type = DIRECTORY;
} else if (S_ISREG(statbuf.st_mode)) {
pd->array[pd->array_length].type = RFILE;
}
if (recursive_browser_config.sorting_method == FB_SORT_TIME) {
pd->array[pd->array_length].time = get_time(&statbuf);
}
} else {
g_warning("Failed to stat file: %s, %s",
pd->array[pd->array_length].path, strerror(errno));
}
// g_free(file);
}
}
pd->array_length++;
break;
}
}
closedir(dir);
}
g_free(cdir);
//g_qsort_with_data(pd->array, pd->array_length, sizeof(FBFile), compare, NULL);
}
static void recursive_browser_mode_init_config(Mode *sw) { static void recursive_browser_mode_init_config(Mode *sw) {
FileBrowserModePrivateData *pd = FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw); (FileBrowserModePrivateData *)mode_get_private_data(sw);
@ -376,8 +177,8 @@ static void recursive_browser_mode_init_config(Mode *sw) {
} else { } else {
found_error = TRUE; found_error = TRUE;
msg = g_strdup_printf("\"%s\" is not a valid recursivebrowser sorting method", msg = g_strdup_printf(
p->value.s); "\"%s\" is not a valid recursivebrowser sorting method", p->value.s);
} }
} }
@ -440,6 +241,127 @@ static void recursive_browser_mode_init_current_dir(Mode *sw) {
} }
} }
static void scan_dir(FileBrowserModePrivateData *pd, GFile *path) {
char *cdir = g_file_get_path(path);
DIR *dir = opendir(cdir);
if (dir) {
struct dirent *rd = NULL;
while (pd->end_thread == FALSE && (rd = readdir(dir)) != NULL) {
if (g_strcmp0(rd->d_name, "..") == 0) {
continue;
}
if (g_strcmp0(rd->d_name, ".") == 0) {
continue;
}
if (rd->d_name[0] == '.') {
continue;
}
switch (rd->d_type) {
case DT_BLK:
case DT_CHR:
case DT_FIFO:
case DT_UNKNOWN:
case DT_SOCK:
default:
break;
case DT_REG: {
FBFile *f = g_malloc0(sizeof(FBFile));
// Rofi expects utf-8, so lets convert the filename.
f->path = g_build_filename(cdir, rd->d_name, NULL);
f->name = g_filename_to_utf8(f->path, -1, NULL, NULL, NULL);
if (f->name == NULL) {
f->name = rofi_force_utf8(rd->d_name, -1);
}
f->type = (rd->d_type == DT_DIR) ? DIRECTORY : RFILE;
f->icon_fetch_uid = 0;
f->icon_fetch_size = 0;
f->link = FALSE;
g_async_queue_push(pd->async_queue, f);
if (g_async_queue_length(pd->async_queue) > 10000) {
write(pd->pipefd2[1], "r", 1);
}
break;
}
case DT_DIR: {
char *d = g_build_filename(cdir, rd->d_name, NULL);
GFile *dirp = g_file_new_for_path(d);
scan_dir(pd, dirp);
g_object_unref(dirp);
g_free(d);
break;
}
case DT_LNK: {
FBFile *f = g_malloc0(sizeof(FBFile));
// Rofi expects utf-8, so lets convert the filename.
f->name = g_filename_to_utf8(rd->d_name, -1, NULL, NULL, NULL);
if (f->name == NULL) {
f->name = rofi_force_utf8(rd->d_name, -1);
}
f->path = g_build_filename(cdir, rd->d_name, NULL);
f->icon_fetch_uid = 0;
f->icon_fetch_size = 0;
f->link = TRUE;
// Default to file.
f->type = RFILE;
g_async_queue_push(pd->async_queue, f);
if (g_async_queue_length(pd->async_queue) > 10000) {
write(pd->pipefd2[1], "r", 1);
}
break;
}
}
}
closedir(dir);
}
g_free(cdir);
}
static gpointer recursive_browser_input_thread(gpointer userdata) {
FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *)userdata;
printf("Start scan.\n");
scan_dir(pd, pd->current_dir);
write(pd->pipefd2[1], "r", 1);
write(pd->pipefd2[1], "q", 1);
printf("End scan.\n");
return NULL;
}
static gboolean recursive_browser_async_read_proc(gint fd,
GIOCondition condition,
gpointer user_data) {
FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *)user_data;
char command;
// Only interrested in read events.
if ((condition & G_IO_IN) != G_IO_IN) {
return G_SOURCE_CONTINUE;
}
// Read the entry from the pipe that was used to signal this action.
if (read(fd, &command, 1) == 1) {
if (command == 'r') {
FBFile *block = NULL;
gboolean changed = FALSE;
// Empty out the AsyncQueue (that is thread safe) from all blocks pushed
// into it.
while ((block = g_async_queue_try_pop(pd->async_queue)) != NULL) {
fb_resize_array(pd);
pd->array[pd->array_length] = *block;
pd->array_length++;
g_free(block);
changed = TRUE;
}
if (changed) {
rofi_view_reload();
}
} else if (command == 'q') {
if (pd->loading) {
rofi_view_set_overlay(rofi_view_get_active(), NULL);
}
}
}
return G_SOURCE_CONTINUE;
}
static int recursive_browser_mode_init(Mode *sw) { static int recursive_browser_mode_init(Mode *sw) {
/** /**
* Called on startup when enabled (in modes list) * Called on startup when enabled (in modes list)
@ -452,7 +374,18 @@ static int recursive_browser_mode_init(Mode *sw) {
recursive_browser_mode_init_current_dir(sw); recursive_browser_mode_init_current_dir(sw);
// Load content. // Load content.
get_recursive_browser(sw,pd->current_dir); if (pipe(pd->pipefd2) == -1) {
g_error("Failed to create pipe");
}
pd->wake_source = g_unix_fd_add(pd->pipefd2[0], G_IO_IN,
recursive_browser_async_read_proc, pd);
// Create the message passing queue to the UI thread.
pd->async_queue = g_async_queue_new();
pd->end_thread = FALSE;
pd->reading_thread = g_thread_new(
"dmenu-read", (GThreadFunc)recursive_browser_input_thread, pd);
pd->loading = TRUE;
} }
return TRUE; return TRUE;
} }
@ -489,18 +422,7 @@ static ModeMode recursive_browser_mode_result(Mode *sw, int mretv, char **input,
retv = (mretv & MENU_LOWER_MASK); retv = (mretv & MENU_LOWER_MASK);
} else if ((mretv & MENU_OK)) { } else if ((mretv & MENU_OK)) {
if (selected_line < pd->array_length) { if (selected_line < pd->array_length) {
if (pd->array[selected_line].type == UP) { if (pd->array[selected_line].type == RFILE) {
GFile *new = g_file_get_parent(pd->current_dir);
if (new) {
g_object_unref(pd->current_dir);
pd->current_dir = new;
free_list(pd);
get_recursive_browser(sw,pd->current_dir);
return RESET_DIALOG;
}
} else if ((pd->array[selected_line].type == RFILE) ||
(pd->array[selected_line].type == DIRECTORY &&
special_command)) {
char *d_esc = g_shell_quote(pd->array[selected_line].path); char *d_esc = g_shell_quote(pd->array[selected_line].path);
char *cmd = g_strdup_printf("%s %s", pd->command, d_esc); char *cmd = g_strdup_printf("%s %s", pd->command, d_esc);
g_free(d_esc); g_free(d_esc);
@ -509,51 +431,12 @@ static ModeMode recursive_browser_mode_result(Mode *sw, int mretv, char **input,
g_free(cdir); g_free(cdir);
g_free(cmd); g_free(cmd);
return MODE_EXIT; return MODE_EXIT;
} else if (pd->array[selected_line].type == DIRECTORY) {
char *path = g_build_filename(cache_dir, FILEBROWSER_CACHE_FILE, NULL);
g_file_set_contents(path, pd->array[selected_line].path, -1, NULL);
g_free(path);
GFile *new = g_file_new_for_path(pd->array[selected_line].path);
g_object_unref(pd->current_dir);
pd->current_dir = new;
free_list(pd);
get_recursive_browser(sw,pd->current_dir);
return RESET_DIALOG;
} }
} }
retv = RELOAD_DIALOG; retv = RELOAD_DIALOG;
} else if ((mretv & MENU_CUSTOM_INPUT)) { } else if ((mretv & MENU_CUSTOM_INPUT)) {
if (special_command) {
GFile *new = g_file_get_parent(pd->current_dir);
if (new) {
g_object_unref(pd->current_dir);
pd->current_dir = new;
free_list(pd);
get_recursive_browser(sw,pd->current_dir);
}
return RESET_DIALOG;
}
if (*input) {
char *p = rofi_expand_path(*input);
char *dir = g_filename_from_utf8(p, -1, NULL, NULL, NULL);
g_free(p);
if (g_file_test(dir, G_FILE_TEST_EXISTS)) {
if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
g_object_unref(pd->current_dir);
pd->current_dir = g_file_new_for_path(dir);
g_free(dir);
free_list(pd);
get_recursive_browser(sw,pd->current_dir);
return RESET_DIALOG;
}
}
g_free(dir);
retv = RELOAD_DIALOG; retv = RELOAD_DIALOG;
}
} else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) { } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {
recursive_browser_config.show_hidden = !recursive_browser_config.show_hidden;
free_list(pd);
get_recursive_browser(sw,pd->current_dir);
retv = RELOAD_DIALOG; retv = RELOAD_DIALOG;
} }
return retv; return retv;
@ -563,6 +446,10 @@ static void recursive_browser_mode_destroy(Mode *sw) {
FileBrowserModePrivateData *pd = FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw); (FileBrowserModePrivateData *)mode_get_private_data(sw);
if (pd != NULL) { if (pd != NULL) {
if (pd->reading_thread) {
pd->end_thread = TRUE;
g_thread_join(pd->reading_thread);
}
g_object_unref(pd->current_dir); g_object_unref(pd->current_dir);
g_free(pd->command); g_free(pd->command);
free_list(pd); free_list(pd);
@ -600,7 +487,8 @@ static char *_get_display_value(const Mode *sw, unsigned int selected_line,
* *
* @returns try when a match. * @returns try when a match.
*/ */
static int recursive_browser_token_match(const Mode *sw, rofi_int_matcher **tokens, static int recursive_browser_token_match(const Mode *sw,
rofi_int_matcher **tokens,
unsigned int index) { unsigned int index) {
FileBrowserModePrivateData *pd = FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw); (FileBrowserModePrivateData *)mode_get_private_data(sw);
@ -621,7 +509,8 @@ static cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,
if (rofi_icon_fetcher_file_is_image(dr->path)) { if (rofi_icon_fetcher_file_is_image(dr->path)) {
dr->icon_fetch_uid = rofi_icon_fetcher_query(dr->path, height); dr->icon_fetch_uid = rofi_icon_fetcher_query(dr->path, height);
} else { } else {
dr->icon_fetch_uid = rofi_icon_fetcher_query(rb_icon_name[dr->type], height); dr->icon_fetch_uid =
rofi_icon_fetcher_query(rb_icon_name[dr->type], height);
} }
dr->icon_fetch_size = height; dr->icon_fetch_size = height;
return rofi_icon_fetcher_get(dr->icon_fetch_uid); return rofi_icon_fetcher_get(dr->icon_fetch_uid);
@ -657,9 +546,10 @@ Mode *create_new_recursive_browser(void) {
return sw; return sw;
} }
#if 1 #if 0
ModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input, ModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input,
unsigned int selected_line, char **path) { unsigned int selected_line,
char **path) {
ModeMode retv = MODE_EXIT; ModeMode retv = MODE_EXIT;
FileBrowserModePrivateData *pd = FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw); (FileBrowserModePrivateData *)mode_get_private_data(sw);
@ -710,7 +600,8 @@ ModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input,
g_free(dir); g_free(dir);
retv = RELOAD_DIALOG; retv = RELOAD_DIALOG;
} else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) { } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {
recursive_browser_config.show_hidden = !recursive_browser_config.show_hidden; recursive_browser_config.show_hidden =
!recursive_browser_config.show_hidden;
free_list(pd); free_list(pd);
get_recursive_browser(sw, pd->current_dir); get_recursive_browser(sw, pd->current_dir);
retv = RELOAD_DIALOG; retv = RELOAD_DIALOG;