26#define G_LOG_DOMAIN "Modes.RecursiveBrowser"
42#include <glib/gstdio.h>
60#define DEFAULT_OPEN "xdg-open"
78 uint32_t icon_fetch_uid;
79 uint32_t icon_fetch_size;
80 guint icon_fetch_scale;
89 unsigned int array_length;
90 unsigned int array_length_real;
113#include <sys/types.h>
127 gboolean found_error = FALSE;
138 GError *error = NULL;
139 g_debug(
"compile regex: %s\n", p->
value.
s);
142 msg = g_strdup_printf(
"\"%s\" is not a valid regex for filtering: %s",
143 p->
value.
s, error->message);
149 g_debug(
"compile default regex\n");
150 pd->
filter_regex = g_regex_new(
"^(\\..*)", G_REGEX_OPTIMIZE, 0, NULL);
174 gboolean config_has_valid_dir = p != NULL && p->
type ==
P_STRING &&
175 g_file_test(p->
value.
s, G_FILE_TEST_IS_DIR);
177 if (config_has_valid_dir) {
181 pd->
current_dir = g_file_new_for_path(g_get_home_dir());
186 GQueue *dirs_to_scan = g_queue_new();
187 GHashTable *dirs_scanned =
188 g_hash_table_new_full(g_str_hash, g_int_equal, g_free, NULL);
189 g_queue_push_tail(dirs_to_scan, g_object_ref(path));
190 GFile *dir_to_scan = NULL;
191 while ((dir_to_scan = g_queue_pop_head(dirs_to_scan)) != NULL) {
192 char *cdir = g_file_get_path(dir_to_scan);
194 if (g_hash_table_lookup_extended(dirs_scanned, cdir, NULL, NULL)) {
198 g_hash_table_insert(dirs_scanned, g_strdup(cdir), NULL);
199 DIR *dir = opendir(cdir);
200 g_object_unref(dir_to_scan);
202 struct dirent *rd = NULL;
203 while (pd->
end_thread == FALSE && (rd = readdir(dir)) != NULL) {
204 if (g_strcmp0(rd->d_name,
"..") == 0) {
207 if (g_strcmp0(rd->d_name,
".") == 0) {
214 switch (rd->d_type) {
224 f->
path = g_build_filename(cdir, rd->d_name, NULL);
225 f->
name = g_filename_to_utf8(f->
path, -1, NULL, NULL, NULL);
226 if (f->
name == NULL) {
229 if (f->
name == NULL) {
230 f->
name = g_strdup(
"n/a");
239 if (g_async_queue_length(pd->
async_queue) > 10000) {
245 char *d = g_build_filename(cdir, rd->d_name, NULL);
246 GFile *dirp = g_file_new_for_path(d);
247 g_queue_push_tail(dirs_to_scan, dirp);
255 f->
path = g_build_filename(cdir, rd->d_name, NULL);
256 f->
name = g_filename_to_utf8(f->
path, -1, NULL, NULL, NULL);
257 if (f->
name == NULL) {
260 if (f->
name == NULL) {
261 f->
name = g_strdup(
"n/a");
268 if (rd->d_type == DT_LNK) {
285 if (g_stat(f->
path, &statbuf) == 0) {
286 if (S_ISDIR(statbuf.st_mode)) {
287 char *new_full_path =
288 g_build_filename(cdir, rd->d_name, NULL);
294 char *sym = g_file_read_link(new_full_path, NULL);
296 GFile *dirp = g_file_new_for_path(sym);
297 g_queue_push_tail(dirs_to_scan, dirp);
300 g_free(new_full_path);
302 }
else if (S_ISREG(statbuf.st_mode)) {
307 g_warning(
"Failed to stat file: %s, %s", f->
path,
314 if (g_async_queue_length(pd->
async_queue) > 10000) {
326 g_hash_table_destroy(dirs_scanned);
328 g_queue_free(dirs_to_scan);
332 GTimer *t = g_timer_new();
333 g_debug(
"Start scan.\n");
337 double f = g_timer_elapsed(t, NULL);
338 g_debug(
"End scan: %f\n", f);
343 GIOCondition condition,
344 gpointer user_data) {
348 if ((condition & G_IO_IN) != G_IO_IN) {
349 return G_SOURCE_CONTINUE;
352 if (read(fd, &command, 1) == 1) {
353 if (command ==
'r') {
355 gboolean changed = FALSE;
358 while ((block = g_async_queue_try_pop(pd->
async_queue)) != NULL) {
369 }
else if (command ==
'q') {
376 return G_SOURCE_CONTINUE;
392 g_error(
"Failed to create pipe");
401 g_thread_new(
"recursivebrowser-read",
414 G_GNUC_UNUSED
char **input,
415 unsigned int selected_line) {
432 }
else if ((mretv &
MENU_OK)) {
433 if (selected_line < pd->array_length) {
435 char *d_esc = g_shell_quote(pd->
array[selected_line].
path);
436 char *cmd = g_strdup_printf(
"%s %s", pd->
command, d_esc);
474 G_GNUC_UNUSED
int *state,
475 G_GNUC_UNUSED GList **attr_list,
485 return g_strdup(
" ..");
488 return g_strconcat(
"@", pd->
array[selected_line].
name, NULL);
490 return g_strdup(pd->
array[selected_line].
name);
504 unsigned int index) {
512static cairo_surface_t *
_get_icon(
const Mode *sw,
unsigned int selected_line,
513 unsigned int height) {
517 g_return_val_if_fail(pd->
array != NULL, NULL);
522 gchar *_path = g_strconcat(
"thumbnail://", dr->
path, NULL);
538 char *dirname = g_file_get_parse_name(pd->
current_dir);
540 g_markup_printf_escaped(
"<b>Current directory:</b> %s", dirname);
551 char *d = g_strescape(pd->
array[index].
path, NULL);
566 unsigned int selected_line,
572 if (selected_line < pd->array_length) {
574 *path = g_strescape(pd->
array[selected_line].
path, NULL);
589 .display_name = NULL,
591 .name =
"recursivebrowser",
592 .cfg_name_key =
"display-recursivebrowser",
602 ._preprocess_input = NULL,
605 .private_data = NULL,
guint display_scale(void)
static char * _get_message(const Mode *sw)
static void free_list(FileBrowserModePrivateData *pd)
static char * _get_completion(const Mode *sw, unsigned int index)
static void fb_resize_array(FileBrowserModePrivateData *pd)
ModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input, unsigned int selected_line, char **path)
Mode recursive_browser_mode
Mode * create_new_recursive_browser(void)
Property * rofi_theme_find_property(ThemeWidget *wid, PropertyType type, const char *property, gboolean exact)
gboolean helper_execute_command(const char *wd, const char *cmd, gboolean run_in_term, RofiHelperExecuteContext *context)
ThemeWidget * rofi_config_find_widget(const char *name, const char *state, gboolean exact)
int helper_token_match(rofi_int_matcher *const *tokens, const char *input)
char * rofi_force_utf8(const gchar *data, ssize_t length)
gboolean rofi_icon_fetcher_file_is_image(const char *const path)
cairo_surface_t * rofi_icon_fetcher_get(const uint32_t uid)
uint32_t rofi_icon_fetcher_query(const char *name, const int size)
void * mode_get_private_data(const Mode *mode)
void mode_set_private_data(Mode *mode, void *pd)
void rofi_set_return_code(int code)
void rofi_view_reload(void)
int rofi_view_error_dialog(const char *msg, int markup)
static gboolean recursive_browser_async_read_proc(gint fd, GIOCondition condition, gpointer user_data)
const char * rb_icon_name[NUM_FILE_TYPES]
static void scan_dir(FileBrowserModePrivateData *pd, GFile *path)
static int recursive_browser_token_match(const Mode *sw, rofi_int_matcher **tokens, unsigned int index)
static cairo_surface_t * _get_icon(const Mode *sw, unsigned int selected_line, unsigned int height)
static void recursive_browser_mode_init_current_dir(Mode *sw)
static void recursive_browser_mode_init_config(Mode *sw)
static unsigned int recursive_browser_mode_get_num_entries(const Mode *sw)
static char * _get_display_value(const Mode *sw, unsigned int selected_line, G_GNUC_UNUSED int *state, G_GNUC_UNUSED GList **attr_list, int get_entry)
static void recursive_browser_mode_destroy(Mode *sw)
static gpointer recursive_browser_input_thread(gpointer userdata)
static ModeMode recursive_browser_mode_result(Mode *sw, int mretv, G_GNUC_UNUSED char **input, unsigned int selected_line)
static int recursive_browser_mode_init(Mode *sw)
struct rofi_int_matcher_t rofi_int_matcher
GAsyncQueue * async_queue
unsigned int array_length_real
unsigned int array_length
_mode_completer_result _completer_result