From 0ff0866be738f1bd99862fa091daad34cd21fc19 Mon Sep 17 00:00:00 2001 From: TonCherAmi Date: Sun, 27 Jun 2021 10:28:21 +0300 Subject: [FileBrowser] Add sorting-method. (#1340) * [FileBrowser] Add sorting-method. * [FileBrowser] Convert -file-browser-directory to new config format. --- config/config.c | 3 - doc/rofi.1 | 20 +++++- doc/rofi.1.markdown | 19 ++++- include/settings.h | 3 - source/dialogs/filebrowser.c | 163 +++++++++++++++++++++++++++++++++++++++++-- source/xrmoptions.c | 3 - 6 files changed, 192 insertions(+), 19 deletions(-) diff --git a/config/config.c b/config/config.c index 8d6039cd..2ec105a6 100644 --- a/config/config.c +++ b/config/config.c @@ -118,9 +118,6 @@ Settings config = { /** Desktop Link launch command */ .drun_url_launcher = "xdg-open", - /** Directory the file browser starts in */ - .file_browser_directory = NULL, - /** Window fields to match in window mode*/ .window_match_fields = "all", /** Monitor */ diff --git a/doc/rofi.1 b/doc/rofi.1 index 8df9c1f4..e6e93fd7 100644 --- a/doc/rofi.1 +++ b/doc/rofi.1 @@ -1167,10 +1167,26 @@ Message can be multi\-line. .SS File browser settings .PP -\fB\fC\-filebrowser\-directory\fR \fIdirectory\fP +File browser behavior can be controlled via the following options: .PP -Directory the file browser starts in. +.RS + +.nf +configuration { + filebrowser { + /** Directory the file browser starts in. */ + directory: "/some/directory"; + /** + * Sorting method. Can be set to: + * - "name" + * - "mtime" (modification time) + * - "atime" (access time) + * - "ctime" (change time) + */ + sorting-method: "name"; + } +} .SS Other .PP diff --git a/doc/rofi.1.markdown b/doc/rofi.1.markdown index 107ef85a..20a14677 100644 --- a/doc/rofi.1.markdown +++ b/doc/rofi.1.markdown @@ -698,9 +698,24 @@ Message can be multi-line. ### File browser settings -`-filebrowser-directory` *directory* +File browser behavior can be controlled via the following options: -Directory the file browser starts in. +```css +configuration { + filebrowser { + /** Directory the file browser starts in. */ + directory: "/some/directory"; + /** + * Sorting method. Can be set to: + * - "name" + * - "mtime" (modification time) + * - "atime" (access time) + * - "ctime" (change time) + */ + sorting-method: "name"; + } +} +``` ### Other diff --git a/include/settings.h b/include/settings.h index 6f1cd9ca..abc9eb14 100644 --- a/include/settings.h +++ b/include/settings.h @@ -116,9 +116,6 @@ typedef struct /** Desktop Link launch command */ char * drun_url_launcher; - /** Directory the file browser starts in */ - char * file_browser_directory; - /** Search case sensitivity */ unsigned int case_sensitive; /** Cycle through in the element list */ diff --git a/source/dialogs/filebrowser.c b/source/dialogs/filebrowser.c index 6ec2a7fb..750ea97b 100644 --- a/source/dialogs/filebrowser.c +++ b/source/dialogs/filebrowser.c @@ -36,11 +36,11 @@ #include #include "mode.h" +#include "theme.h" #include "helper.h" #include "mode-private.h" #include "dialogs/filebrowser.h" #include "rofi.h" -#include "settings.h" #include "history.h" #include @@ -59,6 +59,26 @@ enum FBFileType RFILE, NUM_FILE_TYPES, }; + +/** + * Possible sorting methods + */ +enum FBSortingMethod +{ + FB_SORT_NAME, + FB_SORT_TIME, +}; + +/** + * Type of time to sort by + */ +enum FBSortingTime +{ + FB_MTIME, + FB_ATIME, + FB_CTIME, +}; + /** Icons to use for the file type */ const char *icon_name[NUM_FILE_TYPES] = { @@ -73,6 +93,7 @@ typedef struct enum FBFileType type; uint32_t icon_fetch_uid; gboolean link; + time_t time; } FBFile; typedef struct @@ -82,6 +103,15 @@ typedef struct unsigned int array_length; } FileBrowserModePrivateData; +struct +{ + enum FBSortingMethod sorting_method; + enum FBSortingTime sorting_time; +} file_browser_config = { + .sorting_method = FB_SORT_NAME, + .sorting_time = FB_MTIME, +}; + static void free_list ( FileBrowserModePrivateData *pd ) { for ( unsigned int i = 0; i < pd->array_length; i++ ) { @@ -96,10 +126,11 @@ static void free_list ( FileBrowserModePrivateData *pd ) #include #include -static gint compare ( gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer data ) +static gint compare_name ( gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer data ) { FBFile *fa = (FBFile *) a; FBFile *fb = (FBFile *) b; + if ( fa->type != fb->type ) { return fa->type - fb->type; } @@ -107,7 +138,74 @@ static gint compare ( gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer d return g_strcmp0 ( fa->name, fb->name ); } -static void get_file_browser ( Mode *sw ) +static gint compare_time ( gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer data ) +{ + FBFile *fa = (FBFile *) a; + FBFile *fb = (FBFile *) b; + + 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 ( file_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 struct stat *statbuf ) +{ + switch ( file_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 ) +{ + gchar* path = g_filename_from_utf8 ( file->path, -1, NULL, NULL, NULL ); + + struct stat statbuf; + + if ( stat ( path, &statbuf ) == 0 ) { + file->time = get_time ( &statbuf ); + } + else { + g_warning ( "Failed to stat file: %s, %s", path, strerror ( errno ) ); + } + + g_free ( path ); +} + +static void get_file_browser ( Mode *sw ) { FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw ); /** @@ -127,6 +225,7 @@ static void get_file_browser ( Mode *sw ) pd->array[pd->array_length].type = UP; pd->array[pd->array_length].icon_fetch_uid = 0; pd->array[pd->array_length].link = FALSE; + pd->array[pd->array_length].time = -1; pd->array_length++; continue; } @@ -152,6 +251,11 @@ static void get_file_browser ( Mode *sw ) 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].link = FALSE; + + if ( file_browser_config.sorting_method == FB_SORT_TIME ) { + set_time ( &pd->array[pd->array_length] ); + } + pd->array_length++; break; case DT_LNK: @@ -177,6 +281,10 @@ static void get_file_browser ( Mode *sw ) else if ( S_ISREG ( statbuf.st_mode ) ) { pd->array[pd->array_length].type = RFILE; } + + if ( file_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", file, strerror ( errno ) ); @@ -194,14 +302,56 @@ static void get_file_browser ( Mode *sw ) g_qsort_with_data ( pd->array, pd->array_length, sizeof ( FBFile ), compare, NULL ); } +static void file_browser_mode_init_config ( Mode *sw ) +{ + char *msg = NULL; + gboolean found_error = FALSE; + + ThemeWidget *wid = rofi_config_find_widget ( sw->name, NULL, TRUE ); + + Property *p = rofi_theme_find_property ( wid, P_STRING, "sorting-method", TRUE ); + if ( p != NULL && p->type == P_STRING ) { + if ( g_strcmp0 ( p->value.s, "name" ) == 0 ) { + file_browser_config.sorting_method = FB_SORT_NAME; + } + else if ( g_strcmp0 ( p->value.s, "mtime" ) == 0 ) { + file_browser_config.sorting_method = FB_SORT_TIME; + file_browser_config.sorting_time = FB_MTIME; + } + else if ( g_strcmp0 ( p->value.s, "atime" ) == 0 ) { + file_browser_config.sorting_method = FB_SORT_TIME; + file_browser_config.sorting_time = FB_ATIME; + } + else if ( g_strcmp0 ( p->value.s, "ctime" ) == 0 ) { + file_browser_config.sorting_method = FB_SORT_TIME; + file_browser_config.sorting_time = FB_CTIME; + } + else { + found_error = TRUE; + + msg = g_strdup_printf ( "\"%s\" is not a valid filebrowser sorting method", p->value.s ); + } + } + + if ( found_error ) { + rofi_view_error_dialog ( msg, FALSE ); + + g_free ( msg ); + } +} + static void file_browser_mode_init_current_dir ( Mode *sw ) { FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw ); - gboolean config_has_valid_dir = config.file_browser_directory != NULL - && g_file_test ( config.file_browser_directory, G_FILE_TEST_IS_DIR ); + ThemeWidget *wid = rofi_config_find_widget ( sw->name, NULL, TRUE ); + + Property *p = rofi_theme_find_property ( wid, P_STRING, "directory", TRUE ); + + gboolean config_has_valid_dir = p != NULL && p->type == P_STRING + && g_file_test ( p->value.s, G_FILE_TEST_IS_DIR ); if ( config_has_valid_dir ) { - pd->current_dir = g_file_new_for_path ( config.file_browser_directory ); + pd->current_dir = g_file_new_for_path ( p->value.s ); } else { char *current_dir = NULL; char *cache_file = g_build_filename ( cache_dir, FILEBROWSER_CACHE_FILE, NULL ); @@ -233,6 +383,7 @@ static int file_browser_mode_init ( Mode *sw ) FileBrowserModePrivateData *pd = g_malloc0 ( sizeof ( *pd ) ); mode_set_private_data ( sw, (void *) pd ); + file_browser_mode_init_config ( sw ); file_browser_mode_init_current_dir ( sw ); // Load content. diff --git a/source/xrmoptions.c b/source/xrmoptions.c index c2bb0187..aba59ee4 100644 --- a/source/xrmoptions.c +++ b/source/xrmoptions.c @@ -132,9 +132,6 @@ static XrmOption xrmOptions[] = { { xrm_String, "drun-url-launcher", { .str = &config.drun_url_launcher }, NULL, "Command to open a Desktop Entry that is a Link.", CONFIG_DEFAULT }, - { xrm_String, "filebrowser-directory", { .str = &config.file_browser_directory }, NULL, - "Directory the file browser starts in", CONFIG_DEFAULT }, - { xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL, "Disable history in run/ssh", CONFIG_DEFAULT }, { xrm_String, "ignored-prefixes", { .str = &config.ignored_prefixes }, NULL, -- cgit v1.2.3