From 5df711cbae423ed2b51b84d12a1e92f07de50de3 Mon Sep 17 00:00:00 2001 From: guns Date: Sat, 28 May 2016 00:19:45 -0500 Subject: Add --sort mtime to menu and fix menu when sorting by mtime We did not preload when SORT_MTIME, so check opt.sort > SORT_MTIME before offering to sort by file size. The CB_* enum block was run through s/, /,\n\t/g for legibility. --- src/menu.c | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/menu.c b/src/menu.c index 9a83f08..f315093 100644 --- a/src/menu.c +++ b/src/menu.c @@ -49,14 +49,38 @@ void feh_menu_cb(feh_menu * m, feh_menu_item * i, int action, unsigned short dat void feh_menu_cb_opt_fullscreen(feh_menu * m, feh_menu_item * i); enum { - CB_CLOSE = 1, CB_EXIT, CB_RELOAD, CB_REMOVE, CB_DELETE, CB_RESET, - CB_REMOVE_THUMB, CB_DELETE_THUMB, CB_BG_TILED, CB_BG_SCALED, - CB_BG_CENTERED, CB_BG_FILLED, CB_BG_TILED_NOFILE, - CB_BG_SCALED_NOFILE, CB_BG_CENTERED_NOFILE, CB_BG_FILLED_NOFILE, - CB_SORT_FILENAME, CB_SORT_IMAGENAME, CB_SORT_FILESIZE, CB_SORT_RANDOMIZE, - CB_SAVE_IMAGE, CB_SAVE_FILELIST, CB_FIT, CB_OPT_DRAW_FILENAME, - CB_OPT_DRAW_ACTIONS, CB_OPT_KEEP_HTTP, CB_OPT_FREEZE_WINDOW, - CB_OPT_FULLSCREEN, CB_EDIT_ROTATE, CB_OPT_AUTO_ZOOM, CB_OPT_KEEP_ZOOM_VP + CB_CLOSE = 1, + CB_EXIT, + CB_RELOAD, + CB_REMOVE, + CB_DELETE, + CB_RESET, + CB_REMOVE_THUMB, + CB_DELETE_THUMB, + CB_BG_TILED, + CB_BG_SCALED, + CB_BG_CENTERED, + CB_BG_FILLED, + CB_BG_TILED_NOFILE, + CB_BG_SCALED_NOFILE, + CB_BG_CENTERED_NOFILE, + CB_BG_FILLED_NOFILE, + CB_SORT_FILENAME, + CB_SORT_IMAGENAME, + CB_SORT_MTIME, + CB_SORT_FILESIZE, + CB_SORT_RANDOMIZE, + CB_SAVE_IMAGE, + CB_SAVE_FILELIST, + CB_FIT, + CB_OPT_DRAW_FILENAME, + CB_OPT_DRAW_ACTIONS, + CB_OPT_KEEP_HTTP, + CB_OPT_FREEZE_WINDOW, + CB_OPT_FULLSCREEN, + CB_EDIT_ROTATE, + CB_OPT_AUTO_ZOOM, + CB_OPT_KEEP_ZOOM_VP }; feh_menu *feh_menu_new(void) @@ -923,7 +947,8 @@ void feh_menu_init_common() feh_menu_add_entry(m, "By File Name", NULL, CB_SORT_FILENAME, 0, NULL); feh_menu_add_entry(m, "By Image Name", NULL, CB_SORT_IMAGENAME, 0, NULL); - if (opt.preload || (opt.sort > SORT_FILENAME)) + feh_menu_add_entry(m, "By Modification Date", NULL, CB_SORT_MTIME, 0, NULL); + if (opt.preload || (opt.sort > SORT_MTIME)) feh_menu_add_entry(m, "By File Size", NULL, CB_SORT_FILESIZE, 0, NULL); feh_menu_add_entry(m, "Randomize", NULL, CB_SORT_RANDOMIZE, 0, NULL); @@ -1252,6 +1277,12 @@ void feh_menu_cb(feh_menu * m, feh_menu_item * i, int action, unsigned short dat slideshow_change_image(m->fehwin, SLIDE_FIRST, 1); } break; + case CB_SORT_MTIME: + filelist = gib_list_sort(filelist, feh_cmp_mtime); + if (opt.jump_on_resort) { + slideshow_change_image(m->fehwin, SLIDE_FIRST, 1); + } + break; case CB_SORT_FILESIZE: filelist = gib_list_sort(filelist, feh_cmp_size); if (opt.jump_on_resort) { -- cgit v1.2.3 From 7db8895f8cfb3d58b8e9b4c7a5a64a4df9bb1af0 Mon Sep 17 00:00:00 2001 From: guns Date: Sat, 28 May 2016 00:29:28 -0500 Subject: New sort option: dirname Sort filelist by dirname, then by name. This results in file entries sorting before subdirectory entries. Useful in conjunction with upcoming prev_dir and next_dir navigation actions. --- man/feh.pre | 8 ++++---- src/filelist.c | 28 ++++++++++++++++++++++++++++ src/filelist.h | 14 ++++++++++++-- src/menu.c | 8 ++++++++ src/options.c | 2 ++ 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/man/feh.pre b/man/feh.pre index 9d652b9..609ef57 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -600,10 +600,10 @@ in paused mode. . .It Cm -S , --sort Ar sort_type . -The file list may be sorted according to image parameters. Allowed sort -types are: name, filename, mtime, width, height, pixels, size, format. For sort -modes other than name, filename, or mtime, a preload run will be necessary, -causing a delay proportional to the number of images in the list. +The file list may be sorted according to image parameters. Allowed sort types +are: name, filename, dirname, mtime, width, height, pixels, size, format. For +sort modes other than name, filename, dirname, or mtime, a preload run will be +necessary, causing a delay proportional to the number of images in the list. . .Pp . diff --git a/src/filelist.c b/src/filelist.c index 7e9dcbe..8956238 100644 --- a/src/filelist.c +++ b/src/filelist.c @@ -383,6 +383,20 @@ int feh_file_info_load(feh_file * file, Imlib_Image im) return(0); } +void feh_file_dirname(char *dst, feh_file * f, int maxlen) +{ + int n = strlen(f->filename) - strlen(f->name); + + /* Give up on long dirnames */ + if (n <= 0 || n >= maxlen) { + dst[0] = '\0'; + return; + } + + strncpy(dst, f->filename, n); + dst[n] = '\0'; +} + int feh_cmp_filename(void *file1, void *file2) { return(strcmp(FEH_FILE(file1)->filename, FEH_FILE(file2)->filename)); @@ -393,6 +407,17 @@ int feh_cmp_name(void *file1, void *file2) return(strcmp(FEH_FILE(file1)->name, FEH_FILE(file2)->name)); } +int feh_cmp_dirname(void *file1, void *file2) +{ + char dir1[FEH_MAX_DIRNAME_LEN], dir2[FEH_MAX_DIRNAME_LEN]; + int cmp; + feh_file_dirname(dir1, FEH_FILE(file1), FEH_MAX_DIRNAME_LEN); + feh_file_dirname(dir2, FEH_FILE(file2), FEH_MAX_DIRNAME_LEN); + if ((cmp = strcmp(dir1, dir2)) != 0) + return(cmp); + return(feh_cmp_name(file1, file2)); +} + /* Return -1 if file1 is _newer_ than file2 */ int feh_cmp_mtime(void *file1, void *file2) { @@ -465,6 +490,9 @@ void feh_prepare_filelist(void) case SORT_FILENAME: filelist = gib_list_sort(filelist, feh_cmp_filename); break; + case SORT_DIRNAME: + filelist = gib_list_sort(filelist, feh_cmp_dirname); + break; case SORT_MTIME: filelist = gib_list_sort(filelist, feh_cmp_mtime); break; diff --git a/src/filelist.h b/src/filelist.h index 7bfd518..79d1e62 100644 --- a/src/filelist.h +++ b/src/filelist.h @@ -53,13 +53,21 @@ struct __feh_file_info { }; #define FEH_FILE(l) ((feh_file *) l) +#define FEH_MAX_DIRNAME_LEN 4096 enum filelist_recurse { FILELIST_FIRST, FILELIST_CONTINUE, FILELIST_LAST }; -enum sort_type { SORT_NONE, SORT_NAME, SORT_FILENAME, SORT_MTIME, SORT_WIDTH, +enum sort_type { + SORT_NONE, + SORT_NAME, + SORT_FILENAME, + SORT_DIRNAME, + SORT_MTIME, + SORT_WIDTH, SORT_HEIGHT, SORT_PIXELS, - SORT_SIZE, SORT_FORMAT + SORT_SIZE, + SORT_FORMAT }; feh_file *feh_file_new(char *filename); @@ -73,6 +81,7 @@ void add_file_to_rm_filelist(char *file); void delete_rm_files(void); gib_list *feh_file_info_preload(gib_list * list); int feh_file_info_load(feh_file * file, Imlib_Image im); +void feh_file_dirname(char *dst, feh_file * f, int maxlen); void feh_prepare_filelist(void); int feh_write_filelist(gib_list * list, char *filename); gib_list *feh_read_filelist(char *filename); @@ -81,6 +90,7 @@ gib_list *feh_file_remove_from_list(gib_list * list, gib_list * l); void feh_save_filelist(); int feh_cmp_name(void *file1, void *file2); +int feh_cmp_dirname(void *file1, void *file2); int feh_cmp_filename(void *file1, void *file2); int feh_cmp_mtime(void *file1, void *file2); int feh_cmp_width(void *file1, void *file2); diff --git a/src/menu.c b/src/menu.c index f315093..ddb2db1 100644 --- a/src/menu.c +++ b/src/menu.c @@ -67,6 +67,7 @@ enum { CB_BG_FILLED_NOFILE, CB_SORT_FILENAME, CB_SORT_IMAGENAME, + CB_SORT_DIRNAME, CB_SORT_MTIME, CB_SORT_FILESIZE, CB_SORT_RANDOMIZE, @@ -947,6 +948,7 @@ void feh_menu_init_common() feh_menu_add_entry(m, "By File Name", NULL, CB_SORT_FILENAME, 0, NULL); feh_menu_add_entry(m, "By Image Name", NULL, CB_SORT_IMAGENAME, 0, NULL); + feh_menu_add_entry(m, "By Directory Name", NULL, CB_SORT_DIRNAME, 0, NULL); feh_menu_add_entry(m, "By Modification Date", NULL, CB_SORT_MTIME, 0, NULL); if (opt.preload || (opt.sort > SORT_MTIME)) feh_menu_add_entry(m, "By File Size", NULL, CB_SORT_FILESIZE, 0, NULL); @@ -1277,6 +1279,12 @@ void feh_menu_cb(feh_menu * m, feh_menu_item * i, int action, unsigned short dat slideshow_change_image(m->fehwin, SLIDE_FIRST, 1); } break; + case CB_SORT_DIRNAME: + filelist = gib_list_sort(filelist, feh_cmp_dirname); + if (opt.jump_on_resort) { + slideshow_change_image(m->fehwin, SLIDE_FIRST, 1); + } + break; case CB_SORT_MTIME: filelist = gib_list_sort(filelist, feh_cmp_mtime); if (opt.jump_on_resort) { diff --git a/src/options.c b/src/options.c index b43db91..9e2ff5a 100644 --- a/src/options.c +++ b/src/options.c @@ -514,6 +514,8 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) opt.sort = SORT_NAME; else if (!strcasecmp(optarg, "filename")) opt.sort = SORT_FILENAME; + else if (!strcasecmp(optarg, "dirname")) + opt.sort = SORT_DIRNAME; else if (!strcasecmp(optarg, "mtime")) opt.sort = SORT_MTIME; else if (!strcasecmp(optarg, "width")) -- cgit v1.2.3 From 36b09fa038a8b7996a12e45419c28821c5596308 Mon Sep 17 00:00:00 2001 From: guns Date: Sat, 28 May 2016 00:45:33 -0500 Subject: Add prev_dir and next_dir navigation actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many image collections are organized by directory, so it is nice to have jump-to-adjacent-directory navigation. e.g. Given the following file hierarchy: . ├── A │   ├── 1.jpg │   ├── 2.jpg │   └── C │   ├── 1.jpg │   ├── 2.jpg │   └── 3.jpg └── B ├── 1.jpg ├── 2.jpg └── 3.jpg `feh --recursive` creates the following filelist: A/1.jpg <---- current_file A/2.jpg A/C/1.jpg A/C/2.jpg A/C/3.jpg B/1.jpg B/2.jpg B/3.jpg If we press [next_dir], we move the current_file pointer to: A/1.jpg A/2.jpg A/C/1.jpg <-- current_file A/C/2.jpg A/C/3.jpg B/1.jpg B/2.jpg B/3.jpg Pressing [next_dir] again moves the pointer to: A/1.jpg A/2.jpg A/C/1.jpg A/C/2.jpg A/C/3.jpg B/1.jpg <---- current_file B/2.jpg B/3.jpg [next_dir] now moves the pointer back to the top of the list: A/1.jpg <---- current_file A/2.jpg A/C/1.jpg A/C/2.jpg A/C/3.jpg B/1.jpg B/2.jpg B/3.jpg Pressing [prev_dir] from here moves backwards to the first image of the previous directory: A/1.jpg A/2.jpg A/C/1.jpg A/C/2.jpg A/C/3.jpg B/1.jpg <---- current_file B/2.jpg B/3.jpg When starting from an position that is not the first image of a directory, [prev_dir] moves the pointer to the first image of the current directory. These actions combine well with `--sort dirname` since all regular files in a directory will be sorted before any subdirectories, avoiding a filelist like the following: A/1.jpg A/SUBDIR/2.jpg A/SUBDIR/3.jpg A/4.jpg With `--sort dirname` that filelist becomes: A/1.jpg A/4.jpg A/SUBDIR/2.jpg A/SUBDIR/3.jpg --- man/feh.pre | 6 ++++++ src/feh.h | 4 +++- src/keyevents.c | 14 ++++++++++++++ src/options.h | 2 ++ src/slideshow.c | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/man/feh.pre b/man/feh.pre index 609ef57..dfa5cae 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -1284,6 +1284,12 @@ Close current window . Jump to a random position in the current filelist . +.It \&[, \&] Bq prev_dir, next_dir +. +Jump to the first image of the previous or next sequence of images sharing +a directory name in the current filelist. Use --sort dirname if you would +like to ensure that all images in a directory are grouped together. +. .It < , > Bq orient_3 , orient_1 . In place editing - rotate the images 90 degrees (counter)clockwise. diff --git a/src/feh.h b/src/feh.h index a2a586a..73ef1f6 100644 --- a/src/feh.h +++ b/src/feh.h @@ -102,7 +102,9 @@ enum text_bg { TEXT_BG_CLEAR = 0, TEXT_BG_TINTED }; enum slide_change { SLIDE_NEXT, SLIDE_PREV, SLIDE_RAND, SLIDE_FIRST, SLIDE_LAST, SLIDE_JUMP_FWD, - SLIDE_JUMP_BACK + SLIDE_JUMP_BACK, + SLIDE_JUMP_NEXT_DIR, + SLIDE_JUMP_PREV_DIR }; enum image_bg { IMAGE_BG_CHECKS = 1, IMAGE_BG_BLACK, IMAGE_BG_WHITE }; diff --git a/src/keyevents.c b/src/keyevents.c index 8977111..4837c0b 100644 --- a/src/keyevents.c +++ b/src/keyevents.c @@ -110,6 +110,8 @@ void init_keyevents(void) { feh_set_kb(&keys.next_img , 0, XK_Right , 0, XK_n , 0, XK_space); feh_set_kb(&keys.jump_back , 0, XK_Page_Up , 0, XK_KP_Page_Up, 0, 0); feh_set_kb(&keys.jump_fwd , 0, XK_Page_Down , 0, XK_KP_Page_Down,0,0); + feh_set_kb(&keys.prev_dir , 0, XK_bracketleft, 0, 0 , 0, 0); + feh_set_kb(&keys.next_dir , 0, XK_bracketright, 0, 0 , 0, 0); feh_set_kb(&keys.jump_random,0, XK_z , 0, 0 , 0, 0); feh_set_kb(&keys.quit , 0, XK_Escape , 0, XK_q , 0, 0); feh_set_kb(&keys.close , 0, XK_x , 0, 0 , 0, 0); @@ -222,6 +224,10 @@ void init_keyevents(void) { cur_kb = &keys.jump_back; else if (!strcmp(action, "jump_fwd")) cur_kb = &keys.jump_fwd; + else if (!strcmp(action, "prev_dir")) + cur_kb = &keys.prev_dir; + else if (!strcmp(action, "next_dir")) + cur_kb = &keys.next_dir; else if (!strcmp(action, "jump_random")) cur_kb = &keys.jump_random; else if (!strcmp(action, "quit")) @@ -532,6 +538,14 @@ void feh_event_handle_keypress(XEvent * ev) else if (winwid->type == WIN_TYPE_THUMBNAIL) feh_thumbnail_select_next(winwid, 10); } + else if (feh_is_kp(&keys.next_dir, keysym, state)) { + if (opt.slideshow) + slideshow_change_image(winwid, SLIDE_JUMP_NEXT_DIR, 1); + } + else if (feh_is_kp(&keys.prev_dir, keysym, state)) { + if (opt.slideshow) + slideshow_change_image(winwid, SLIDE_JUMP_PREV_DIR, 1); + } else if (feh_is_kp(&keys.quit, keysym, state)) { winwidget_destroy_all(); } diff --git a/src/options.h b/src/options.h index 0052d5d..bbf129f 100644 --- a/src/options.h +++ b/src/options.h @@ -153,6 +153,8 @@ struct __fehkb { struct __fehkey jump_back; struct __fehkey quit; struct __fehkey jump_fwd; + struct __fehkey prev_dir; + struct __fehkey next_dir; struct __fehkey remove; struct __fehkey delete; struct __fehkey jump_first; diff --git a/src/slideshow.c b/src/slideshow.c index 7636d31..2af78c9 100644 --- a/src/slideshow.c +++ b/src/slideshow.c @@ -322,6 +322,44 @@ void slideshow_change_image(winwidget winwid, int change, int render) try the previous file, not another jmp */ change = SLIDE_NEXT; break; + case SLIDE_JUMP_NEXT_DIR: + { + char old_dir[FEH_MAX_DIRNAME_LEN], new_dir[FEH_MAX_DIRNAME_LEN]; + int j; + + feh_file_dirname(old_dir, FEH_FILE(current_file->data), FEH_MAX_DIRNAME_LEN); + + for (j = 0; j < our_filelist_len; j++) { + current_file = feh_list_jump(filelist, current_file, FORWARD, 1); + feh_file_dirname(new_dir, FEH_FILE(current_file->data), FEH_MAX_DIRNAME_LEN); + if (strcmp(old_dir, new_dir) != 0) + break; + } + } + change = SLIDE_NEXT; + break; + case SLIDE_JUMP_PREV_DIR: + { + char old_dir[FEH_MAX_DIRNAME_LEN], new_dir[FEH_MAX_DIRNAME_LEN]; + int j; + + /* Start the search from the previous file in case we are on + the first file of a directory */ + current_file = feh_list_jump(filelist, current_file, BACK, 1); + feh_file_dirname(old_dir, FEH_FILE(current_file->data), FEH_MAX_DIRNAME_LEN); + + for (j = 0; j < our_filelist_len; j++) { + current_file = feh_list_jump(filelist, current_file, BACK, 1); + feh_file_dirname(new_dir, FEH_FILE(current_file->data), FEH_MAX_DIRNAME_LEN); + if (strcmp(old_dir, new_dir) != 0) + break; + } + + /* Next file is the first entry of prev_dir */ + current_file = feh_list_jump(filelist, current_file, FORWARD, 1); + } + change = SLIDE_NEXT; + break; default: eprintf("BUG!\n"); break; -- cgit v1.2.3