diff options
| -rw-r--r-- | .travis.yml | 1 | ||||
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | config.mk | 19 | ||||
| -rwxr-xr-x | examples/find-lowres | 17 | ||||
| -rw-r--r-- | man/Makefile | 1 | ||||
| -rw-r--r-- | man/feh.pre | 64 | ||||
| -rw-r--r-- | src/feh.h | 5 | ||||
| -rw-r--r-- | src/filelist.c | 2 | ||||
| -rw-r--r-- | src/help.raw | 1 | ||||
| -rw-r--r-- | src/main.c | 35 | ||||
| -rw-r--r-- | src/options.c | 19 | ||||
| -rw-r--r-- | src/options.h | 4 | ||||
| -rw-r--r-- | src/signals.c | 13 | ||||
| -rw-r--r-- | src/slideshow.c | 4 | ||||
| -rw-r--r-- | src/thumbnail.c | 12 | ||||
| -rw-r--r-- | src/winwidget.c | 92 | ||||
| -rw-r--r-- | src/winwidget.h | 9 | 
17 files changed, 262 insertions, 37 deletions
| diff --git a/.travis.yml b/.travis.yml index f59e68c..a12b97d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,3 +27,4 @@ env:    - stat64=1    - verscmp=0    - xinerama=0 +  - inotify=1 @@ -89,6 +89,7 @@ indicates that the corresponding feature is enabled by default.  | debug | 0 | debug build, enables `--debug` |  | exif | 0 | Builtin EXIF tag display support |  | help | 0 | include help text (refers to the manpage otherwise) | +| inotify | 0 | enable inotify, needed for `--auto-reload` |  | stat64 | 0 | Support CIFS shares from 64bit hosts on 32bit machines |  | verscmp | 1 | Support naturing sorting (`--version-sort`). Requires a GNU-compatible libc exposing `strverscmp` |  | xinerama | 1 | Support Xinerama/XRandR multiscreen setups | @@ -50,9 +50,9 @@ endif  ifeq (${debug},1)  	CFLAGS += -DDEBUG -O0 -	MAN_DEBUG = . This is a debug build. +	MAN_DEBUG = This is a debug build.  else -	MAN_DEBUG = +	MAN_DEBUG = .  endif  ifeq (${help},1) @@ -65,9 +65,9 @@ endif  ifeq (${verscmp},1)  	CFLAGS += -DHAVE_VERSCMP -	MAN_VERSCMP = enabled +	MAN_VERSCMP = available  else -	MAN_VERSCMP = disabled +	MAN_VERSCMP = not available  endif  ifeq (${xinerama},1) @@ -81,9 +81,16 @@ endif  ifeq (${exif},1)  	CFLAGS += -DHAVE_LIBEXIF  	LDLIBS += -lexif -	MAN_EXIF = enabled +	MAN_EXIF = available  else -	MAN_EXIF = disabled +	MAN_EXIF = not available +endif + +ifeq (${inotify},1) +	CFLAGS += -DHAVE_INOTIFY +	MAN_INOTIFY = enabled +else +	MAN_INOTIFY = disabled  endif  MAN_DATE ?= ${shell date '+%B %d, %Y'} diff --git a/examples/find-lowres b/examples/find-lowres index 4a7d9a9..ac77e7b 100755 --- a/examples/find-lowres +++ b/examples/find-lowres @@ -1,4 +1,4 @@ -#!/usr/bin/env zsh +#!/bin/sh  # Recursively find images below a certain resolution  #  # Usage: find-lowres [-r] [directory [dimension]] @@ -10,20 +10,23 @@  remove=0 -while [[ $1 == -* ]]; do +while true +do  	case $1 in  		-r) remove=1 ;; +		-*) echo "option \"$1\" ignored" ;;  		-|--) shift; break ;; +		*) break ;;  	esac  	shift  done -base=${1-.} -dimension=${2-1000x800} +dir=${1:-.} +dimension=${2:-1000x800} -if (( remove )) +if [ "$remove" = "1" ]  then -	feh --action 'rm %F' -rlV --max-dim ${dimension} ${base} +	feh --action 'rm %F' -rlV --max-dim "${dimension}" "${dir}"  else -	feh -rlV --max-dim ${dimension} ${base} +	feh -rlV --max-dim "${dimension}" "${dir}"  fi diff --git a/man/Makefile b/man/Makefile index 9209de1..acf8629 100644 --- a/man/Makefile +++ b/man/Makefile @@ -12,6 +12,7 @@ all: ${TARGETS}  	-e 's/\$$MAN_CURL\$$/${MAN_CURL}/' \  	-e 's/\$$MAN_DEBUG\$$/${MAN_DEBUG}/' \  	-e 's/\$$MAN_EXIF\$$/${MAN_EXIF}/' \ +	-e 's/\$$MAN_INOTIFY\$$/${MAN_INOTIFY}/' \  	-e 's/\$$MAN_VERSCMP\$$/${MAN_VERSCMP}/' \  	-e 's/\$$MAN_XINERAMA\$$/${MAN_XINERAMA}/' \  	< ${@:.1=.pre} > $@ diff --git a/man/feh.pre b/man/feh.pre index 913b9b3..a313fd4 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -24,9 +24,28 @@ $VERSION$  .  .Pp  . -Compile-time switches: libcurl support $MAN_CURL$, natural sorting support -$MAN_VERSCMP$, Xinerama support -$MAN_XINERAMA$, builtin EXIF support $MAN_EXIF$$MAN_DEBUG$ +Compile-time switches in this build: +. +.Bl -bullet -compact +. +.It +remote file support: libcurl $MAN_CURL$ +. +.It +natural sorting option $MAN_VERSCMP$ +. +.It +Xinerama multi-monitor support $MAN_XINERAMA$ +. +.It +builtin EXIF reader $MAN_EXIF$ +. +.It +inotify-based auto-reload of changed files $MAN_INOTIFY$ +. +.El +. +$MAN_DEBUG$  .  .  .Sh DESCRIPTION @@ -208,6 +227,18 @@ Example usage:  .  Extra actions which can be set and triggered using the appropriate number key.  . +.It Cm --auto-reload +. +.Pq optional feature, $MAN_INOTIFY$ in this build +automatically reload image when the underlying file changes. +Note that auto-reload +.Pq if enabled in the build +is on by default. +This option is only useful to re-enable auto-reload after it has been +disabled by a preceding +.Cm --reload=0 +option. +.  .It Cm --auto-rotate  .  .Pq optional feature, $MAN_EXIF$ in this build @@ -303,7 +334,8 @@ on a semi-transparent background to improve their readability  .  .It Cm --edit  . -Enable basic editing of files. This makes rotation and mirroring +Enable basic editing of files. +This makes rotation and mirroring  .Pq bound to Qo < Qc , Qo > Qc , Qo | Qc , and Qo _ Qc by default  change the underlying file and not just its displayed content.  . @@ -465,9 +497,9 @@ toggle_info key.  .  .It Cm --insecure  . -When viewing files with HTTPS, this option disables all certificate checks.  It -allows images on sites with self-signed or expired certificates to be opened, -but is no more secure than plain HTTP. +When viewing files with HTTPS, this option disables all certificate checks. +It allows images on sites with self-signed or expired certificates to be +opened, but is no more secure than plain HTTP.  .  .It Cm -k , --keep-http  . @@ -643,6 +675,7 @@ Reload filelist and current image after  seconds.  Useful for viewing HTTP webcams or frequently changing directories.  .Pq Note that filelist reloading is still experimental. +Set to zero to disable any kind of automatic reloading.  .  .Pp  . @@ -653,6 +686,10 @@ However, if an image still exists, but can no longer be loaded,  .Nm  will continue to try loading it.  . +.Pp +. +Setting this option causes inotify-based auto-reload to be disabled. +.  .It Cm -n , --reverse  .  Reverse the sort order. @@ -679,7 +716,8 @@ Scroll  .Ar count  pixels whenever scroll_up, scroll_down, scroll_left or scroll_right is pressed.  Note that this option accepts negative numbers in case you need to reverse the -scroll direction. See +scroll direction. +See  .Sx KEYS CONFIG SYNTAX  for how to reverse it permanently.  Default: 20 @@ -1856,7 +1894,7 @@ So, to enlarge a specific part of an image, click the zoom button on that part.  .  .Sh SIGNALS  . -In slideshow mode, +In slideshow and multiwindow mode,  .Nm  handles the following signals:  . @@ -1864,11 +1902,15 @@ handles the following signals:  .  .It Dv SIGUSR1  . -Switch to next image +Slideshow mode: switch to next image; +reload current image if the slideshow consists of a single file. +Multiwindow mode: reload all images.  .  .It Dv SIGUSR2  . -Switch to previous image +Slideshow mode: switch to previous image; +reload current image if the slideshow consists of a single file. +Multiwindow mode: reload all images.  .  .El  . @@ -152,7 +152,7 @@ void feh_event_handle_stdin();  void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysym, unsigned int button);  fehkey *feh_str_to_kb(char * action);  void feh_action_run(feh_file * file, char *action, winwidget winwid); -char *format_size(int size); +char *format_size(double size);  char *feh_printf(char *str, feh_file * file, winwidget winwid);  void im_weprintf(winwidget w, char *fmt, ...);  void feh_draw_zoom(winwidget w); @@ -179,6 +179,9 @@ void feh_edit_inplace_lossless(winwidget w, int orientation);  gib_list *feh_wrap_string(char *text, int wrap_width, Imlib_Font fn, gib_style * style);  char *build_caption_filename(feh_file * file, short create_dir);  gib_list *feh_list_jump(gib_list * root, gib_list * l, int direction, int num); +#ifdef HAVE_INOTIFY +void feh_event_handle_inotify(void); +#endif  /* Imlib stuff */  extern Display *disp; diff --git a/src/filelist.c b/src/filelist.c index 6f4f6df..e3ae020 100644 --- a/src/filelist.c +++ b/src/filelist.c @@ -76,7 +76,7 @@ void feh_file_free(feh_file * file)  #ifdef HAVE_LIBEXIF  	if (file->ed)  		exif_data_unref(file->ed); -#endif		 +#endif  	free(file);  	return;  } diff --git a/src/help.raw b/src/help.raw index ca7c85c..7a9a658 100644 --- a/src/help.raw +++ b/src/help.raw @@ -99,6 +99,7 @@ OPTIONS       --max-dimension WxH   Only show images with width <= W and height <= H       --scroll-step COUNT   scroll COUNT pixels when movement key is pressed       --cache-size NUM      imlib cache size in mebibytes (0 .. 2048) +     --auto-reload         automatically reload shown image if file was changed  MONTAGE MODE OPTIONS   -X, --ignore-aspect       Set thumbnail to specified width/height without @@ -34,6 +34,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #include "wallpaper.h"  #include <termios.h> +#ifdef HAVE_INOTIFY +#include <sys/inotify.h> +#endif +  char **cmdargv = NULL;  int cmdargc = 0;  char *mode = NULL; @@ -53,6 +57,16 @@ int main(int argc, char **argv)  		init_x_and_imlib();  		init_keyevents();  		init_buttonbindings(); +#ifdef HAVE_INOTIFY +        if (opt.auto_reload) { +            opt.inotify_fd = inotify_init(); +            if (opt.inotify_fd < 0) { +                opt.auto_reload = 0; +                weprintf("inotify_init failed:"); +                weprintf("Disabling inotify-based auto-reload"); +            } +        } +#endif  	}  	feh_event_init(); @@ -146,6 +160,13 @@ int feh_main_iteration(int block)  	FD_SET(xfd, &fdset);  	if (control_via_stdin)  		FD_SET(STDIN_FILENO, &fdset); +#ifdef HAVE_INOTIFY +    if (opt.auto_reload) { +        FD_SET(opt.inotify_fd, &fdset); +        if (opt.inotify_fd >= fdsize) +            fdsize = opt.inotify_fd + 1; +    } +#endif  	/* Timers */  	ft = first_timer; @@ -191,6 +212,10 @@ int feh_main_iteration(int block)  			}  			else if ((count > 0) && (FD_ISSET(0, &fdset)))  				feh_event_handle_stdin(); +#ifdef HAVE_INOTIFY +			else if ((count > 0) && (FD_ISSET(opt.inotify_fd, &fdset))) +                feh_event_handle_inotify(); +#endif  		}  	} else {  		/* Don't block if there are events in the queue. That's a bit rude ;-) */ @@ -204,6 +229,10 @@ int feh_main_iteration(int block)  				eprintf("Connection to X display lost");  			else if ((count > 0) && (FD_ISSET(0, &fdset)))  				feh_event_handle_stdin(); +#ifdef HAVE_INOTIFY +			else if ((count > 0) && (FD_ISSET(opt.inotify_fd, &fdset))) +                feh_event_handle_inotify(); +#endif  		}  	}  	if (window_num == 0 || sig_exit != 0) @@ -218,6 +247,12 @@ void feh_clean_exit(void)  	free(opt.menu_font); +#ifdef HAVE_INOTIFY +    if (opt.auto_reload) +        if (close(opt.inotify_fd)) +            eprintf("inotify close failed"); +#endif +  	if(disp)  		XCloseDisplay(disp); diff --git a/src/options.c b/src/options.c index 37fad88..4c34b66 100644 --- a/src/options.c +++ b/src/options.c @@ -25,7 +25,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */  #include <strings.h> -  #include "feh.h"  #include "filelist.h"  #include "options.h" @@ -74,6 +73,9 @@ void init_parse_options(int argc, char **argv)  	opt.xinerama = 1;  	opt.xinerama_index = -1;  #endif				/* HAVE_LIBXINERAMA */ +#ifdef HAVE_INOTIFY +	opt.auto_reload = 1; +#endif				/* HAVE_INOTIFY */  	feh_getopt_theme(argc, argv); @@ -425,6 +427,9 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  		{"conversion-timeout" , 1, 0, 245},  		{"version-sort"  , 0, 0, 246},  		{"offset"        , 1, 0, 247}, +#ifdef HAVE_INOTIFY +		{"auto-reload"   , 0, 0, 248}, +#endif  		{0, 0, 0, 0}  	};  	int optch = 0, cmdx = 0; @@ -517,6 +522,9 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  			break;  		case 'R':  			opt.reload = atof(optarg); +#ifdef HAVE_INOTIFY +			opt.auto_reload = 0; +#endif  			break;  		case 'S':  			if (!strcasecmp(optarg, "name")) @@ -810,6 +818,11 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  			opt.offset_flags = XParseGeometry(optarg, &opt.offset_x,  					&opt.offset_y, (unsigned int *)&discard, (unsigned int *)&discard);  			break; +#ifdef HAVE_INOTIFY +		case 248: +			opt.auto_reload = 1; +			break; +#endif  		default:  			break;  		} @@ -897,6 +910,10 @@ static void show_version(void)  		"exif "  #endif +#ifdef HAVE_INOTIFY +		"inotify " +#endif +  #ifdef INCLUDE_HELP  		"help "  #endif diff --git a/src/options.h b/src/options.h index 7f8fe9c..883c8e2 100644 --- a/src/options.h +++ b/src/options.h @@ -58,6 +58,10 @@ struct __fehoptions {  	unsigned char draw_exif;  	unsigned char auto_rotate;  #endif +#ifdef HAVE_INOTIFY +	unsigned char auto_reload; +    int inotify_fd; +#endif  	unsigned char list;  	unsigned char quiet;  	unsigned char preload; diff --git a/src/signals.c b/src/signals.c index d65f49b..85d81bc 100644 --- a/src/signals.c +++ b/src/signals.c @@ -24,6 +24,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */  #include "feh.h" +#include "filelist.h"  #include "winwidget.h"  #include "options.h" @@ -94,10 +95,14 @@ void feh_handle_signal(int signo)  	winwid = winwidget_get_first_window_of_type(WIN_TYPE_SLIDESHOW);  	if (winwid) { -		if (signo == SIGUSR1) -			slideshow_change_image(winwid, SLIDE_NEXT, 1); -		else if (signo == SIGUSR2) -			slideshow_change_image(winwid, SLIDE_PREV, 1); +		if (filelist_len > 1) { +			if (signo == SIGUSR1) +				slideshow_change_image(winwid, SLIDE_NEXT, 1); +			else if (signo == SIGUSR2) +				slideshow_change_image(winwid, SLIDE_PREV, 1); +		} else { +			feh_reload_image(winwid, 0, 0); +		}  	} else if (opt.multiwindow) {  		for (i = window_num - 1; i >= 0; i--)  			feh_reload_image(windows[i], 0, 0); diff --git a/src/slideshow.c b/src/slideshow.c index 145ced1..ac8c545 100644 --- a/src/slideshow.c +++ b/src/slideshow.c @@ -445,7 +445,7 @@ void feh_action_run(feh_file * file, char *action, winwidget winwid)  	return;  } -char *format_size(int size) +char *format_size(double size)  {  	static char ret[5];  	char units[] = {' ', 'k', 'M', 'G', 'T'}; @@ -454,7 +454,7 @@ char *format_size(int size)  		size /= 1000;  		postfix++;  	} -	snprintf(ret, 5, "%3d%c", size, units[postfix]); +	snprintf(ret, 5, "%3.0f%c", size, units[postfix]);  	return ret;  } diff --git a/src/thumbnail.c b/src/thumbnail.c index 45fbabe..79109f4 100644 --- a/src/thumbnail.c +++ b/src/thumbnail.c @@ -93,7 +93,6 @@ void init_thumbnail_mode(void)  	if (!opt.thumb_title)  		opt.thumb_title = "%n"; -  	mode = "thumbnail";  	if (opt.font) @@ -177,6 +176,7 @@ void init_thumbnail_mode(void)  				td.h + title_area_h, 0, 0, 0, 255);  	} +  	if (opt.display) {  		winwid = winwidget_create_from_image(td.im_main, WIN_TYPE_THUMBNAIL);  		winwidget_rename(winwid, PACKAGE " [thumbnail mode]"); @@ -418,6 +418,7 @@ void init_thumbnail_mode(void)  		}  	} +  	return;  } @@ -783,7 +784,6 @@ void feh_thumbnail_show_fullsize(feh_file *thumbfile)  	if (!l) {  		eprintf("Cannot find %s in filelist, wtf", thumbfile->filename);  	} -  	thumbwin = winwidget_get_first_window_of_type(WIN_TYPE_THUMBNAIL_VIEWER);  	if (!thumbwin) {  		thumbwin = winwidget_create_from_file( @@ -793,7 +793,13 @@ void feh_thumbnail_show_fullsize(feh_file *thumbfile)  			winwidget_show(thumbwin);  	} else if (FEH_FILE(thumbwin->file->data) != thumbfile) {  		thumbwin->file = l; -		feh_reload_image(thumbwin, 1, 1); +#ifdef HAVE_INOTIFY +        winwidget_inotify_remove(thumbwin); +#endif +		feh_reload_image(thumbwin, 1, 0); +#ifdef HAVE_INOTIFY +        winwidget_inotify_add(thumbwin, thumbfile); +#endif  	}  } diff --git a/src/winwidget.c b/src/winwidget.c index f3ecc84..70a65e0 100644 --- a/src/winwidget.c +++ b/src/winwidget.c @@ -30,6 +30,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #include "options.h"  #include "events.h" +#ifdef HAVE_INOTIFY +#include <sys/inotify.h> +#endif +  static void winwidget_unregister(winwidget win);  static void winwidget_register(winwidget win);  static winwidget winwidget_allocate(void); @@ -78,6 +82,10 @@ static winwidget winwidget_allocate(void)  	ret->click_offset_y = 0;  	ret->has_rotated = 0; +#ifdef HAVE_INOTIFY +    ret->inotify_wd = -1; +#endif +  	return(ret);  } @@ -662,6 +670,9 @@ void winwidget_destroy_xwin(winwidget winwid)  void winwidget_destroy(winwidget winwid)  { +#ifdef HAVE_INOTIFY +    winwidget_inotify_remove(winwid); +#endif  	winwidget_destroy_xwin(winwid);  	if (winwid->name)  		free(winwid->name); @@ -673,6 +684,76 @@ void winwidget_destroy(winwidget winwid)  	return;  } +#ifdef HAVE_INOTIFY +void winwidget_inotify_remove(winwidget winwid) +{ +    if (winwid->inotify_wd >= 0) { +        D(("Removing inotify watch\n")); +        if (inotify_rm_watch(opt.inotify_fd, winwid->inotify_wd)) +            weprintf("inotify_rm_watch failed:"); +        winwid->inotify_wd = -1; +    } +} +#endif + +#ifdef HAVE_INOTIFY +void winwidget_inotify_add(winwidget winwid, feh_file * file) +{ +    if (opt.auto_reload) { +        D(("Adding inotify watch for %s\n", file->filename)); +        char dir[PATH_MAX]; +        feh_file_dirname(dir, file, PATH_MAX); + +        /* +         * Handle files without directory part, e.g. "feh somefile.jpg". +         * These always reside in the current directory. +         */ +        if (dir[0] == '\0') { +            dir[0] = '.'; +            dir[1] = '\0'; +        } +        winwid->inotify_wd = inotify_add_watch(opt.inotify_fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO); +        if (winwid->inotify_wd < 0) +            weprintf("inotify_add_watch failed:"); +    } +} +#endif + +#ifdef HAVE_INOTIFY +#define INOTIFY_BUFFER_LEN (1024 * (sizeof (struct inotify_event)) + 16) +void feh_event_handle_inotify(void) +{ +    D(("Received inotify events\n")); +    char buf[INOTIFY_BUFFER_LEN]; +    int i = 0; +    int len = read (opt.inotify_fd, buf, INOTIFY_BUFFER_LEN); +    if (len < 0) { +        if (errno != EINTR) +            eprintf("inotify event read failed"); +    } else if (!len) +        eprintf("inotify event read failed"); +    while (i < len) { +        struct inotify_event *event; +        event = (struct inotify_event *) &buf[i]; +        for (int j = 0; j < window_num; j++) { +            if(windows[j]->inotify_wd == event->wd) { +                if (event->mask & IN_IGNORED) { +                    D(("inotify watch was implicitely removed\n")); +                    windows[j]->inotify_wd = -1; +                } else if (event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) { +                    if (strcmp(event->name, FEH_FILE(windows[j]->file->data)->name) == 0) { +                        D(("inotify says file changed\n")); +                        feh_reload_image(windows[j], 0, 0); +                    } +                } +                break; +            } +        } +        i += sizeof(struct inotify_event) + event->len; +    } +} +#endif +  void winwidget_destroy_all(void)  {  	int i; @@ -706,7 +787,16 @@ winwidget winwidget_get_first_window_of_type(unsigned int type)  int winwidget_loadimage(winwidget winwid, feh_file * file)  {  	D(("filename %s\n", file->filename)); -	return(feh_load_image(&(winwid->im), file)); +#ifdef HAVE_INOTIFY +    winwidget_inotify_remove(winwid); +#endif +    int res = feh_load_image(&(winwid->im), file); +#ifdef HAVE_INOTIFY +    if (res) { +        winwidget_inotify_add(winwid, file); +    } +#endif +	return(res);  }  void winwidget_show(winwidget winwid) diff --git a/src/winwidget.h b/src/winwidget.h index 0a707ac..4d8fc4b 100644 --- a/src/winwidget.h +++ b/src/winwidget.h @@ -116,8 +116,17 @@ struct __winwidget {  	time_t click_start_time;  	unsigned char has_rotated; + +#ifdef HAVE_INOTIFY +	int inotify_wd; +#endif  }; +#ifdef HAVE_INOTIFY +void winwidget_inotify_remove(winwidget winwid); +void winwidget_inotify_add(winwidget winwid, feh_file * file); +#endif +  int winwidget_loadimage(winwidget winwid, feh_file * filename);  void winwidget_show(winwidget winwid);  void winwidget_show_menu(winwidget winwid); | 
