summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Davenport <qball@blame.services>2023-05-10 17:49:16 +0200
committerDave Davenport <qball@blame.services>2023-05-10 17:49:16 +0200
commit848277001fc8cf9afc538067f2afa24a174f8c7f (patch)
tree4e4082c1e59162a2b04abd83630bc5d336ce300c
parentf369a7f63f618bbcad10c18e73f7e2b117c515f1 (diff)
[RB] Pull the scanning into a separate thread.
-rw-r--r--source/modes/recursivebrowser.c437
1 files changed, 164 insertions, 273 deletions
diff --git a/source/modes/recursivebrowser.c b/source/modes/recursivebrowser.c
index 5a69bc31..a8b49450 100644
--- a/source/modes/recursivebrowser.c
+++ b/source/modes/recursivebrowser.c
@@ -103,6 +103,13 @@ typedef struct {
FBFile *array;
unsigned int array_length;
unsigned int array_length_real;
+
+ GThread *reading_thread;
+ GAsyncQueue *async_queue;
+ guint wake_source;
+ guint end_thread;
+ gboolean loading;
+ int pipefd2[2];
} FileBrowserModePrivateData;
/**
@@ -138,220 +145,14 @@ static void free_list(FileBrowserModePrivateData *pd) {
#include <dirent.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) {
if ((pd->array_length + 1) > pd->array_length_real) {
- pd->array_length_real += 1024;
+ pd->array_length_real += 10240;
pd->array =
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) {
FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw);
@@ -376,8 +177,8 @@ static void recursive_browser_mode_init_config(Mode *sw) {
} else {
found_error = TRUE;
- msg = g_strdup_printf("\"%s\" is not a valid recursivebrowser sorting method",
- p->value.s);
+ msg = g_strdup_printf(
+ "\"%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) {
/**
* 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);
// 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;
}
@@ -463,7 +396,7 @@ static unsigned int recursive_browser_mode_get_num_entries(const Mode *sw) {
}
static ModeMode recursive_browser_mode_result(Mode *sw, int mretv, char **input,
- unsigned int selected_line) {
+ unsigned int selected_line) {
ModeMode retv = MODE_EXIT;
FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw);
@@ -489,18 +422,7 @@ static ModeMode recursive_browser_mode_result(Mode *sw, int mretv, char **input,
retv = (mretv & MENU_LOWER_MASK);
} else if ((mretv & MENU_OK)) {
if (selected_line < pd->array_length) {
- if (pd->array[selected_line].type == UP) {
- 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)) {
+ if (pd->array[selected_line].type == RFILE) {
char *d_esc = g_shell_quote(pd->array[selected_line].path);
char *cmd = g_strdup_printf("%s %s", pd->command, 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(cmd);
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;
} 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) {
- recursive_browser_config.show_hidden = !recursive_browser_config.show_hidden;
- free_list(pd);
- get_recursive_browser(sw,pd->current_dir);
retv = RELOAD_DIALOG;
}
return retv;
@@ -563,6 +446,10 @@ static void recursive_browser_mode_destroy(Mode *sw) {
FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw);
if (pd != NULL) {
+ if (pd->reading_thread) {
+ pd->end_thread = TRUE;
+ g_thread_join(pd->reading_thread);
+ }
g_object_unref(pd->current_dir);
g_free(pd->command);
free_list(pd);
@@ -600,8 +487,9 @@ static char *_get_display_value(const Mode *sw, unsigned int selected_line,
*
* @returns try when a match.
*/
-static int recursive_browser_token_match(const Mode *sw, rofi_int_matcher **tokens,
- unsigned int index) {
+static int recursive_browser_token_match(const Mode *sw,
+ rofi_int_matcher **tokens,
+ unsigned int index) {
FileBrowserModePrivateData *pd =
(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)) {
dr->icon_fetch_uid = rofi_icon_fetcher_query(dr->path, height);
} 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;
return rofi_icon_fetcher_get(dr->icon_fetch_uid);
@@ -657,9 +546,10 @@ Mode *create_new_recursive_browser(void) {
return sw;
}
-#if 1
+#if 0
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;
FileBrowserModePrivateData *pd =
(FileBrowserModePrivateData *)mode_get_private_data(sw);
@@ -677,7 +567,7 @@ ModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input,
g_object_unref(pd->current_dir);
pd->current_dir = new;
free_list(pd);
- get_recursive_browser(sw,pd->current_dir);
+ get_recursive_browser(sw, pd->current_dir);
return RESET_DIALOG;
}
} else if (pd->array[selected_line].type == DIRECTORY) {
@@ -685,7 +575,7 @@ ModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input,
g_object_unref(pd->current_dir);
pd->current_dir = new;
free_list(pd);
- get_recursive_browser(sw,pd->current_dir);
+ get_recursive_browser(sw, pd->current_dir);
return RESET_DIALOG;
} else if (pd->array[selected_line].type == RFILE) {
*path = g_strescape(pd->array[selected_line].path, NULL);
@@ -703,16 +593,17 @@ ModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input,
pd->current_dir = g_file_new_for_path(dir);
g_free(dir);
free_list(pd);
- get_recursive_browser(sw,pd->current_dir);
+ get_recursive_browser(sw, pd->current_dir);
return RESET_DIALOG;
}
}
g_free(dir);
retv = RELOAD_DIALOG;
} 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);
- get_recursive_browser(sw,pd->current_dir);
+ get_recursive_browser(sw, pd->current_dir);
retv = RELOAD_DIALOG;
}
return retv;