diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile | 40 | ||||
| -rw-r--r-- | src/collage.c | 14 | ||||
| -rw-r--r-- | src/debug.h | 2 | ||||
| -rw-r--r-- | src/events.c | 102 | ||||
| -rw-r--r-- | src/feh.h | 19 | ||||
| -rw-r--r-- | src/feh_png.c | 18 | ||||
| -rw-r--r-- | src/feh_png.h | 4 | ||||
| -rw-r--r-- | src/filelist.c | 42 | ||||
| -rw-r--r-- | src/gib_hash.c | 1 | ||||
| -rw-r--r-- | src/gib_list.c | 1 | ||||
| -rw-r--r-- | src/help.raw | 9 | ||||
| -rw-r--r-- | src/imlib.c | 248 | ||||
| -rw-r--r-- | src/index.c | 27 | ||||
| -rw-r--r-- | src/index.h | 2 | ||||
| -rw-r--r-- | src/keyevents.c | 533 | ||||
| -rw-r--r-- | src/list.c | 4 | ||||
| -rw-r--r-- | src/main.c | 63 | ||||
| -rw-r--r-- | src/menu.c | 2 | ||||
| -rw-r--r-- | src/menu.h | 2 | ||||
| -rw-r--r-- | src/multiwindow.c | 20 | ||||
| -rw-r--r-- | src/options.c | 82 | ||||
| -rw-r--r-- | src/options.h | 166 | ||||
| -rw-r--r-- | src/signals.c | 16 | ||||
| -rw-r--r-- | src/signals.h | 2 | ||||
| -rw-r--r-- | src/slideshow.c | 182 | ||||
| -rw-r--r-- | src/structs.h | 2 | ||||
| -rw-r--r-- | src/thumbnail.c | 64 | ||||
| -rw-r--r-- | src/thumbnail.h | 2 | ||||
| -rw-r--r-- | src/timers.c | 2 | ||||
| -rw-r--r-- | src/utils.c | 25 | ||||
| -rw-r--r-- | src/utils.h | 1 | ||||
| -rw-r--r-- | src/wallpaper.c | 242 | ||||
| -rw-r--r-- | src/wallpaper.h | 2 | ||||
| -rw-r--r-- | src/winwidget.c | 268 | ||||
| -rw-r--r-- | src/winwidget.h | 7 | 
35 files changed, 1156 insertions, 1060 deletions
| diff --git a/src/Makefile b/src/Makefile index 0e2c543..8a9f97e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,40 @@  include ../config.mk -TARGETS = ${shell echo *.c} +TARGETS = \ +	collage.c \ +	events.c \ +	feh_png.c \ +	filelist.c \ +	getopt.c \ +	getopt1.c \ +	gib_hash.c \ +	gib_imlib.c \ +	gib_list.c \ +	gib_style.c \ +	imlib.c \ +	index.c \ +	keyevents.c \ +	list.c \ +	main.c \ +	md5.c \ +	menu.c \ +	multiwindow.c \ +	options.c \ +	signals.c \ +	slideshow.c \ +	thumbnail.c \ +	timers.c \ +	utils.c \ +	wallpaper.c \ +	winwidget.c + +ifeq (${exif},1) +	TARGETS += \ +		exif.c \ +		exif_canon.c \ +		exif_nikon.c +endif +  OBJECTS = ${TARGETS:.c=.o}  I_SRCS = ${shell echo *.raw} @@ -17,9 +51,9 @@ include deps.mk  fehrc.inc: fehrc.raw  help.inc: help.raw - +# CFLAGS might contain include paths needed to resolve includes in headers  deps.mk: ${TARGETS} ${I_DSTS} -	${CC} ${CPPFLAGS} -MM ${TARGETS} > $@ +	${CC} ${CFLAGS} -MM ${TARGETS} > $@  clean:  	rm -f feh *.o *.inc diff --git a/src/collage.c b/src/collage.c index b975136..2a4d9f9 100644 --- a/src/collage.c +++ b/src/collage.c @@ -1,7 +1,7 @@  /* collage.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -41,7 +41,6 @@ void init_collage_mode(void)  	feh_file *file = NULL;  	unsigned char trans_bg = 0;  	gib_list *l, *last = NULL; -	char *s;  	mode = "collage"; @@ -105,15 +104,9 @@ void init_collage_mode(void)  		gib_imlib_image_fill_rectangle(im_main, 0, 0, w, h, 0, 0, 0, 255);  	} -	/* Create the title string */ - -	if (!opt.title) -		s = estrdup(PACKAGE " [collage mode]"); -	else -		s = estrdup(feh_printf(opt.title, NULL, NULL)); -  	if (opt.display) { -		winwid = winwidget_create_from_image(im_main, s, WIN_TYPE_SINGLE); +		winwid = winwidget_create_from_image(im_main, WIN_TYPE_SINGLE); +		winwidget_rename(winwid, PACKAGE " [collage mode]");  		winwidget_show(winwid);  	} @@ -210,7 +203,6 @@ void init_collage_mode(void)  	if (!opt.display)  		gib_imlib_free_image_and_decache(im_main); -	free(s);  	return;  } diff --git a/src/debug.h b/src/debug.h index eb929e3..38cf83f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -1,7 +1,7 @@  /* debug.h  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to diff --git a/src/events.c b/src/events.c index b20fd4f..89eaab8 100644 --- a/src/events.c +++ b/src/events.c @@ -1,7 +1,7 @@  /* events.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -35,7 +35,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #define FEH_JITTER_OFFSET 2  #define FEH_JITTER_TIME 1 -extern fehkb keys; +extern struct __fehkey keys[EVENT_LIST_END]; +fehkey *feh_str_to_kb(char *action);  feh_event_handler *ev_handler[LASTEvent]; @@ -45,10 +46,10 @@ static void feh_event_handle_LeaveNotify(XEvent * ev);  static void feh_event_handle_MotionNotify(XEvent * ev);  static void feh_event_handle_ClientMessage(XEvent * ev); -static void feh_set_bb(fehkey *bb, int modifier, char button) +static void feh_set_bb(unsigned int bb_index, int modifier, char button)  { -	bb->state  = modifier; -	bb->button = button; +	keys[bb_index].state  = modifier; +	keys[bb_index].button = button;  }  static void feh_set_parse_bb_partial(fehkey *button, char *binding) @@ -101,13 +102,13 @@ void init_buttonbindings(void)  	FILE *conf = NULL;  	int read = 0; -	feh_set_bb(&keys.pan,         0, 1); -	feh_set_bb(&keys.zoom,        0, 2); -	feh_set_bb(&keys.toggle_menu, 0, 3); -	feh_set_bb(&keys.prev_img,    0, 4); -	feh_set_bb(&keys.next_img,    0, 5); -	feh_set_bb(&keys.blur,        4, 1); -	feh_set_bb(&keys.rotate,      4, 2); +	feh_set_bb(EVENT_pan,         0, 1); +	feh_set_bb(EVENT_zoom,        0, 2); +	feh_set_bb(EVENT_toggle_menu, 0, 3); +	feh_set_bb(EVENT_prev_img,    0, 4); +	feh_set_bb(EVENT_next_img,    0, 5); +	feh_set_bb(EVENT_blur,        4, 1); +	feh_set_bb(EVENT_rotate,      4, 2);  	home = getenv("HOME");  	confhome = getenv("XDG_CONFIG_HOME"); @@ -136,34 +137,17 @@ void init_buttonbindings(void)  		if ((read == EOF) || (read == 0) || (line[0] == '#'))  			continue; -		/* -		 * Note: This isn't really good code. But it works, and since it only -		 * runs once for each button config line the runtime penalty compared to -		 * e.g. a hash table is negligible in this case. -		 */ -		if (!strcmp(action, "reload")) -			cur_bb = &keys.reload; -		else if (!strcmp(action, "pan")) -			cur_bb = &keys.pan; -		else if (!strcmp(action, "zoom")) -			cur_bb = &keys.zoom; -		else if (!strcmp(action, "menu") || !strcmp(action, "toggle_menu")) -			cur_bb = &keys.toggle_menu; -		else if (!strcmp(action, "prev") || !strcmp(action, "prev_img")) -			cur_bb = &keys.prev_img; -		else if (!strcmp(action, "next") || !strcmp(action, "next_img")) -			cur_bb = &keys.next_img; -		else if (!strcmp(action, "blur")) -			cur_bb = &keys.blur; -		else if (!strcmp(action, "rotate")) -			cur_bb = &keys.rotate; -		else if (!strcmp(action, "zoom_in")) -			cur_bb = &keys.zoom_in; -		else if (!strcmp(action, "zoom_out")) -			cur_bb = &keys.zoom_out; -		else -			cur_bb = feh_str_to_kb(action); - +		cur_bb = feh_str_to_kb(action); +		if (cur_bb == NULL) { +			if (!strcmp(action, "reload")) +				cur_bb = &keys[EVENT_reload_image]; +			else if (!strcmp(action, "menu")) +				cur_bb = &keys[EVENT_toggle_menu]; +			else if (!strcmp(action, "prev")) +				cur_bb = &keys[EVENT_prev_img]; +			else if (!strcmp(action, "next")) +				cur_bb = &keys[EVENT_next_img]; +		}  		if (cur_bb)  			feh_set_parse_bb_partial(cur_bb, button);  		else @@ -172,9 +156,9 @@ void init_buttonbindings(void)  	fclose(conf);  } -static short feh_is_bb(fehkey *bb, unsigned int button, unsigned int mod) +static short feh_is_bb(unsigned int key_index, unsigned int button, unsigned int mod)  { -	if ((bb->state == mod) && (bb->button == button)) +	if ((keys[key_index].state == mod) && (keys[key_index].button == button))  		return 1;  	return 0;  } @@ -217,23 +201,23 @@ static void feh_event_handle_ButtonPress(XEvent * ev)  	state = ev->xbutton.state & (ControlMask | ShiftMask | Mod1Mask | Mod4Mask);  	button = ev->xbutton.button; -	if (!opt.no_menus && feh_is_bb(&keys.toggle_menu, button, state)) { +	if (!opt.no_menus && feh_is_bb(EVENT_toggle_menu, button, state)) {  		D(("Menu Button Press event\n"));  		winwidget_show_menu(winwid); -	} else if (feh_is_bb(&keys.rotate, button, state) +	} else if (feh_is_bb(EVENT_rotate, button, state)  		   && (winwid->type != WIN_TYPE_THUMBNAIL)) {  		opt.mode = MODE_ROTATE;  		winwid->mode = MODE_ROTATE;  		D(("rotate starting at %d, %d\n", ev->xbutton.x, ev->xbutton.y)); -	} else if (feh_is_bb(&keys.blur, button, state) +	} else if (feh_is_bb(EVENT_blur, button, state)  		   && (winwid->type != WIN_TYPE_THUMBNAIL)) {  		opt.mode = MODE_BLUR;  		winwid->mode = MODE_BLUR;  		D(("blur starting at %d, %d\n", ev->xbutton.x, ev->xbutton.y)); -	} else if (feh_is_bb(&keys.pan, button, state)) { +	} else if (feh_is_bb(EVENT_pan, button, state)) {  		D(("Next button, but could be pan mode\n"));  		opt.mode = MODE_NEXT;  		winwid->mode = MODE_NEXT; @@ -242,7 +226,7 @@ static void feh_event_handle_ButtonPress(XEvent * ev)  		winwid->click_offset_y = ev->xbutton.y - winwid->im_y;  		winwid->click_start_time = time(NULL); -	} else if (feh_is_bb(&keys.zoom, button, state)) { +	} else if (feh_is_bb(EVENT_zoom, button, state)) {  		D(("Zoom Button Press event\n"));  		opt.mode = MODE_ZOOM;  		winwid->mode = MODE_ZOOM; @@ -257,7 +241,7 @@ static void feh_event_handle_ButtonPress(XEvent * ev)  		winwid->im_click_offset_y = (winwid->click_offset_y  				- winwid->im_y) / winwid->old_zoom; -	} else if (feh_is_bb(&keys.zoom_in, button, state)) { +	} else if (feh_is_bb(EVENT_zoom_in, button, state)) {  		D(("Zoom_In Button Press event\n"));  		D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y));  		winwid->click_offset_x = ev->xbutton.x; @@ -285,7 +269,7 @@ static void feh_event_handle_ButtonPress(XEvent * ev)  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 0); -	} else if (feh_is_bb(&keys.zoom_out, button, state)) { +	} else if (feh_is_bb(EVENT_zoom_out, button, state)) {  		D(("Zoom_Out Button Press event\n"));  		D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y));  		winwid->click_offset_x = ev->xbutton.x; @@ -313,16 +297,16 @@ static void feh_event_handle_ButtonPress(XEvent * ev)  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 0); -	} else if (feh_is_bb(&keys.reload, button, state)) { +	} else if (feh_is_bb(EVENT_reload_image, button, state)) {  		D(("Reload Button Press event\n"));  			feh_reload_image(winwid, 0, 1); -	} else if (feh_is_bb(&keys.prev_img, button, state)) { +	} else if (feh_is_bb(EVENT_prev_img, button, state)) {  		D(("Prev Button Press event\n"));  		if (winwid->type == WIN_TYPE_SLIDESHOW)  			slideshow_change_image(winwid, SLIDE_PREV, 1); -	} else if (feh_is_bb(&keys.next_img, button, state)) { +	} else if (feh_is_bb(EVENT_next_img, button, state)) {  		D(("Next Button Press event\n"));  		if (winwid->type == WIN_TYPE_SLIDESHOW)  			slideshow_change_image(winwid, SLIDE_NEXT, 1); @@ -363,7 +347,7 @@ static void feh_event_handle_ButtonRelease(XEvent * ev)  		return;  	} -	if (feh_is_bb(&keys.pan, button, state)) { +	if (feh_is_bb(EVENT_pan, button, state)) {  		if (opt.mode == MODE_PAN) {  			D(("Disabling pan mode\n"));  			opt.mode = MODE_NORMAL; @@ -401,13 +385,13 @@ static void feh_event_handle_ButtonRelease(XEvent * ev)  			winwid->mode = MODE_NORMAL;  		} -	} else if (feh_is_bb(&keys.rotate, button, state) -			|| feh_is_bb(&keys.zoom, button, state)) { +	} else if (feh_is_bb(EVENT_rotate, button, state) +			|| feh_is_bb(EVENT_zoom, button, state)) {  		D(("Disabling mode\n"));  		opt.mode = MODE_NORMAL;  		winwid->mode = MODE_NORMAL; -		if ((feh_is_bb(&keys.zoom, button, state)) +		if ((feh_is_bb(EVENT_zoom, button, state))  				&& (ev->xbutton.x == winwid->click_offset_x)  				&& (ev->xbutton.y == winwid->click_offset_y)) {  			winwid->zoom = 1.0; @@ -417,7 +401,7 @@ static void feh_event_handle_ButtonRelease(XEvent * ev)  		winwidget_render_image(winwid, 0, 0); -	} else if (feh_is_bb(&keys.blur, button, state)) { +	} else if (feh_is_bb(EVENT_blur, button, state)) {  		D(("Disabling Blur mode\n"));  		opt.mode = MODE_NORMAL;  		winwid->mode = MODE_NORMAL; @@ -525,6 +509,8 @@ static void feh_event_handle_MotionNotify(XEvent * ev)  				dy = scr_height - (m->y + m->h);  				dx = dx < 0 ? dx : 0;  				dy = dy < 0 ? dy : 0; +				dx = m->x + dx < 0 ? -m->x : dx; +				dy = m->y + dy < 0 ? -m->y : dy;  				if (dx || dy)  					feh_menu_slide_all_menus_relative(dx, dy);  			} @@ -537,6 +523,8 @@ static void feh_event_handle_MotionNotify(XEvent * ev)  				dy = scr->height - (m->next->y + m->next->h);  				dx = dx < 0 ? dx : 0;  				dy = dy < 0 ? dy : 0; +				dx = m->x + dx < 0 ? -m->x : dx; +				dy = m->y + dy < 0 ? -m->y : dy;  				if (dx || dy)  					feh_menu_slide_all_menus_relative(dx, dy);  			} @@ -1,7 +1,7 @@  /* feh.h  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -27,6 +27,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #ifndef FEH_H  #define FEH_H +/* + * strverscmp(3) is a GNU extension. In most supporting C libraries it + * requires _GNU_SOURCE to be defined. + */ +#ifdef HAVE_VERSCMP +#define _GNU_SOURCE +#endif +  #include <X11/Xlib.h>  #include <X11/Xutil.h>  #include <X11/Xatom.h> @@ -107,8 +115,6 @@ enum slide_change { SLIDE_NEXT, SLIDE_PREV, SLIDE_RAND, SLIDE_FIRST, SLIDE_LAST,  	SLIDE_JUMP_PREV_DIR  }; -enum image_bg { IMAGE_BG_CHECKS = 1, IMAGE_BG_BLACK, IMAGE_BG_WHITE }; -  #define INPLACE_EDIT_FLIP   -1  #define INPLACE_EDIT_MIRROR -2 @@ -133,14 +139,15 @@ void init_list_mode(void);  void init_loadables_mode(void);  void init_unloadables_mode(void);  void feh_clean_exit(void); +int feh_should_ignore_image(Imlib_Image * im);  int feh_load_image(Imlib_Image * im, feh_file * file);  void show_mini_usage(void);  void slideshow_change_image(winwidget winwid, int change, int render);  void slideshow_pause_toggle(winwidget w); -char *slideshow_create_name(feh_file * file, winwidget winwid); -char *thumbnail_create_name(feh_file * file, winwidget winwid);  void init_keyevents(void);  void init_buttonbindings(void); +void setup_stdin(void); +void restore_stdin(void);  void feh_event_handle_keypress(XEvent * ev);  void feh_event_handle_stdin();  void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysym, unsigned int button); @@ -204,4 +211,6 @@ extern char *mode;		/* label for the current mode */  /* to terminate long-running children with SIGALRM */  extern int childpid; +extern unsigned char control_via_stdin; +  #endif diff --git a/src/feh_png.c b/src/feh_png.c index ff73f56..d0c1c8a 100644 --- a/src/feh_png.c +++ b/src/feh_png.c @@ -23,20 +23,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */ -#include "feh_png.h" -  #include <png.h>  #include <stdio.h>  #include <stdarg.h> +#include "feh_png.h" +  #define FEH_PNG_COMPRESSION 3  #define FEH_PNG_NUM_COMMENTS 4  gib_hash *feh_png_read_comments(char *file)  { -	gib_hash *hash = NULL; -  	FILE *fp;  	int i, sig_bytes, comments = 0; @@ -45,31 +43,31 @@ gib_hash *feh_png_read_comments(char *file)  	png_textp text_ptr;  	if (!(fp = fopen(file, "rb"))) -		return hash; +		return NULL;  	if (!(sig_bytes = feh_png_file_is_png(fp))) {  		fclose(fp); -		return hash; +		return NULL;  	}  	/* initialize data structures */  	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);  	if (!png_ptr) {  		fclose(fp); -		return hash; +		return NULL;  	}  	info_ptr = png_create_info_struct(png_ptr);  	if (!info_ptr) {  		png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);  		fclose(fp); -		return hash; +		return NULL;  	}  	if (setjmp(png_jmpbuf(png_ptr))) {  		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);  		fclose(fp); -		return hash; +		return NULL;  	}  	/* initialize reading */ @@ -78,6 +76,8 @@ gib_hash *feh_png_read_comments(char *file)  	png_read_info(png_ptr, info_ptr); +	gib_hash *hash = NULL; +  #ifdef PNG_TEXT_SUPPORTED  	png_get_text(png_ptr, info_ptr, &text_ptr, &comments);  	if (comments > 0) { diff --git a/src/feh_png.h b/src/feh_png.h index ac3375f..035d36a 100644 --- a/src/feh_png.h +++ b/src/feh_png.h @@ -26,11 +26,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #ifndef FEH_PNG_H  #define FEH_PNG_H -#include "feh.h" -  #include <stdio.h>  #include <stdarg.h> +#include "feh.h" +  gib_hash *feh_png_read_comments(char *file);  int feh_png_write_png_fd(Imlib_Image image, int fd, ...); diff --git a/src/filelist.c b/src/filelist.c index 162fd57..870e463 100644 --- a/src/filelist.c +++ b/src/filelist.c @@ -1,7 +1,7 @@  /* filelist.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -397,14 +397,26 @@ void feh_file_dirname(char *dst, feh_file * f, int maxlen)  	dst[n] = '\0';  } +#ifdef HAVE_VERSCMP +static inline int strcmp_or_strverscmp(const char *s1, const char *s2) +{ +	if (!opt.version_sort) +		return(strcmp(s1, s2)); +	else +		return(strverscmp(s1, s2)); +} +#else +#define strcmp_or_strverscmp strcmp +#endif +  int feh_cmp_filename(void *file1, void *file2)  { -	return(strcmp(FEH_FILE(file1)->filename, FEH_FILE(file2)->filename)); +	return(strcmp_or_strverscmp(FEH_FILE(file1)->filename, FEH_FILE(file2)->filename));  }  int feh_cmp_name(void *file1, void *file2)  { -	return(strcmp(FEH_FILE(file1)->name, FEH_FILE(file2)->name)); +	return(strcmp_or_strverscmp(FEH_FILE(file1)->name, FEH_FILE(file2)->name));  }  int feh_cmp_dirname(void *file1, void *file2) @@ -413,7 +425,7 @@ int feh_cmp_dirname(void *file1, void *file2)  	int cmp;  	feh_file_dirname(dir1, FEH_FILE(file1), PATH_MAX);  	feh_file_dirname(dir2, FEH_FILE(file2), PATH_MAX); -	if ((cmp = strcmp(dir1, dir2)) != 0) +	if ((cmp = strcmp_or_strverscmp(dir1, dir2)) != 0)  		return(cmp);  	return(feh_cmp_name(file1, file2));  } @@ -464,9 +476,17 @@ int feh_cmp_format(void *file1, void *file2)  void feh_prepare_filelist(void)  { -	if (opt.list || opt.customlist || (opt.sort > SORT_MTIME) -			|| opt.preload || opt.min_width || opt.min_height -			|| (opt.max_width != UINT_MAX) || (opt.max_height != UINT_MAX)) { +	/* +	 * list and customlist mode as well as the somewhat more fancy sort modes +	 * need access to file infos. Preloading them is also useful for +	 * list/customlist as --min-dimension/--max-dimension may filter images +	 * which should not be processed. +	 * Finally, if --min-dimension/--max-dimension (-> opt.filter_by_dimensions) +	 * is set and we're in thumbnail mode, we need to filter images first so +	 * we can create a properly sized thumbnail list. +	 */ +	if (opt.list || opt.preload || opt.customlist || (opt.sort > SORT_MTIME) +			|| (opt.filter_by_dimensions && (opt.index || opt.collage || opt.thumbs || opt.bgmode))) {  		/* For these sort options, we have to preload images */  		filelist = feh_file_info_preload(filelist);  		if (!gib_list_length(filelist)) @@ -554,7 +574,7 @@ gib_list *feh_read_filelist(char *filename)  	Imlib_Load_Error err = IMLIB_LOAD_ERROR_NONE;  	Imlib_Image tmp_im;  	struct stat st; -	signed short tmp_magick_timeout; +	signed short tmp_conversion_timeout;  	if (!filename)  		return(NULL); @@ -562,8 +582,8 @@ gib_list *feh_read_filelist(char *filename)  	/*  	 * feh_load_image will fail horribly if filename is not seekable  	 */ -	tmp_magick_timeout = opt.magick_timeout; -	opt.magick_timeout = -1; +	tmp_conversion_timeout = opt.conversion_timeout; +	opt.conversion_timeout = -1;  	if (!stat(filename, &st) && S_ISREG(st.st_mode)) {  		tmp_im = imlib_load_image_with_error_return(filename, &err);  		if (err == IMLIB_LOAD_ERROR_NONE) { @@ -574,7 +594,7 @@ gib_list *feh_read_filelist(char *filename)  			return NULL;  		}  	} -	opt.magick_timeout = tmp_magick_timeout; +	opt.conversion_timeout = tmp_conversion_timeout;  	errno = 0; diff --git a/src/gib_hash.c b/src/gib_hash.c index a378b9c..0d6a226 100644 --- a/src/gib_hash.c +++ b/src/gib_hash.c @@ -22,6 +22,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */ +#include <strings.h>  #include "gib_hash.h"  #include "utils.h" diff --git a/src/gib_list.c b/src/gib_list.c index 281f528..5384d98 100644 --- a/src/gib_list.c +++ b/src/gib_list.c @@ -360,7 +360,6 @@ gib_list_randomize(gib_list * list)     {        farray[i] = f;     } -   srand(getpid() * time(NULL) % ((unsigned int) -1));     for (i = 0; i < len - 1; i++)     {        r = i + rand() / (RAND_MAX / (len - i) + 1 ); diff --git a/src/help.raw b/src/help.raw index 997a259..2532325 100644 --- a/src/help.raw +++ b/src/help.raw @@ -20,7 +20,7 @@ OPTIONS   -g, --geometry WxH[+X+Y]  Limit the window size to DIMENSION[+OFFSET]   -f, --filelist FILE       Load/save images from/to the FILE filelist   -|, --start-at FILENAME   Start at FILENAME in the filelist - -p, --preload             Remove unlaodable files from the internal filelist + -p, --preload             Remove unloadable files from the internal filelist                             before attempting to display anything   -., --scale-down          Automatically scale down images to fit screen size   -F, --fullscreen          Make the window full screen @@ -38,7 +38,8 @@ OPTIONS       --auto-rotate         Rotate images according to Exif info (if compiled with exif=1)   -^, --title TITLE         Set window title (see FORMAT SPECIFIERS)   -D, --slideshow-delay NUM Set delay between automatically changing slides -     --cycle-once          Exit after one loop through the slideshow +     --on-last-slide quit  Exit after one loop through the slide show +     --on-last-slide hold  Stop at both ends of the filelist   -R, --reload NUM          Reload images after NUM seconds   -k, --keep-http           Keep local copies when viewing HTTP/FTP files       --insecure            Disable peer/host verification when using HTTPS. @@ -52,6 +53,7 @@ OPTIONS                             name, filename, mtime, width, height, pixels, size,                             or format   -n, --reverse             Reverse sort order +     --version-sort        Natural sort of (version) numbers within text   -A, --action [;]ACTION    Specify action to perform when pressing <return>.                             Executed by /bin/sh, may contain FORMAT SPECIFIERS                             reloads image with \";\", switches to next otherwise @@ -84,7 +86,7 @@ OPTIONS                             can be used multiple times to add multiple paths.   -M, --menu-font FONT      Use FONT for the font in menus.   -B, --image-bg STYLE      Set background for transparent images and the like. -                           Accepted values: white, black, default +                           Accepted values: default, checks, or a XColor (eg. #428bdd)   -N, --no-menus            Don't load or show any menus.       --no-xinerama         Disable Xinerama support       --no-screen-clip      Do not limit window size to screen size @@ -94,6 +96,7 @@ OPTIONS       --min-dimension WxH   Only show images with width >= W and height >= H       --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 diff --git a/src/imlib.c b/src/imlib.c index ecc44b5..f41cdcd 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -1,7 +1,7 @@  /* imlib.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -61,7 +61,9 @@ int num_xinerama_screens;  int childpid = 0; +static int feh_file_is_raw(char *filename);  static char *feh_http_load_image(char *url); +static char *feh_dcraw_load_image(char *filename);  static char *feh_magick_load_image(char *filename);  #ifdef HAVE_LIBXINERAMA @@ -131,12 +133,23 @@ void init_x_and_imlib(void)  	imlib_context_set_operation(IMLIB_OP_COPY);  	wmDeleteWindow = XInternAtom(disp, "WM_DELETE_WINDOW", False); -	/* Initialise random numbers */ -	srand(getpid() * time(NULL) % ((unsigned int) -1)); +	imlib_set_cache_size(opt.cache_size * 1024 * 1024);  	return;  } +int feh_should_ignore_image(Imlib_Image * im) +{ +	if (opt.filter_by_dimensions) { +		unsigned int w = gib_imlib_image_get_width(im); +		unsigned int h = gib_imlib_image_get_height(im); +		if (w < opt.min_width || w > opt.max_width || h < opt.min_height || h > opt.max_height) { +			return 1; +		} +	} +	return 0; +} +  int feh_load_image_char(Imlib_Image * im, char *filename)  {  	feh_file *file; @@ -202,15 +215,10 @@ void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err)  int feh_load_image(Imlib_Image * im, feh_file * file)  {  	Imlib_Load_Error err = IMLIB_LOAD_ERROR_NONE; -	enum { SRC_IMLIB, SRC_HTTP, SRC_MAGICK } image_source = -		SRC_IMLIB; +	enum { SRC_IMLIB, SRC_HTTP, SRC_MAGICK, SRC_DCRAW } image_source = SRC_IMLIB;  	char *tmpname = NULL;  	char *real_filename = NULL; -#ifdef HAVE_LIBEXIF -	ExifEntry *entry; -#endif -  	D(("filename is %s, image is %p\n", file->filename, im));  	if (!file || !file->filename) @@ -222,18 +230,25 @@ int feh_load_image(Imlib_Image * im, feh_file * file)  		if ((tmpname = feh_http_load_image(file->filename)) == NULL)  			err = IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST;  	} +	else if (opt.conversion_timeout >= 0 && feh_file_is_raw(file->filename)) { +		image_source = SRC_DCRAW; +		tmpname = feh_dcraw_load_image(file->filename); +		if (!tmpname) +			err = IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT; +	}  	else  		*im = imlib_load_image_with_error_return(file->filename, &err); -	if ((err == IMLIB_LOAD_ERROR_UNKNOWN) -			|| (err == IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT)) { +	if (opt.conversion_timeout >= 0 && ( +			(err == IMLIB_LOAD_ERROR_UNKNOWN) || +			(err == IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT))) {  		image_source = SRC_MAGICK;  		tmpname = feh_magick_load_image(file->filename);  	} -	if ((image_source != SRC_IMLIB) && tmpname) { +	if (tmpname) {  		*im = imlib_load_image_with_error_return(tmpname, &err); -		if (im) { +		if (!err && im) {  			real_filename = file->filename;  			file->filename = tmpname;  			feh_file_info_load(file, *im); @@ -242,7 +257,7 @@ int feh_load_image(Imlib_Image * im, feh_file * file)  			file->ed = exif_get_data(tmpname);  #endif  		} -		if ((image_source == SRC_MAGICK) || !opt.keep_http) +		if ((image_source != SRC_HTTP) || !opt.keep_http)  			unlink(tmpname);  		free(tmpname); @@ -258,6 +273,16 @@ int feh_load_image(Imlib_Image * im, feh_file * file)  		return(0);  	} +	/* +	 * By default, Imlib2 unconditionally loads a cached file without checking +	 * if it was modified on disk. However, feh (or rather its users) should +	 * expect image changes to appear at the next reload. So we tell Imlib2 to +	 * always check the file modification time and only use a cached image if +	 * the mtime was not changed. The performance penalty is usually negligible. +	 */ +	imlib_context_set_image(*im); +	imlib_image_set_changes_on_disk(); +  #ifdef HAVE_LIBEXIF  	int orientation = 0;  	ExifData *exifData = exif_data_new_from_file(file->filename); @@ -281,17 +306,105 @@ int feh_load_image(Imlib_Image * im, feh_file * file)  	return(1);  } +static int feh_file_is_raw(char *filename) +{ +	childpid = fork(); +	if (childpid == -1) { +		perror("fork"); +		return 0; +	} + +	if (childpid == 0) { +		if (opt.quiet) { +			int devnull = open("/dev/null", O_WRONLY); +			dup2(devnull, 1); +			dup2(devnull, 2); +		} +		execlp("dcraw", "dcraw", "-i", filename, NULL); +		_exit(1); +	} else { +		int status; +		do { +			waitpid(childpid, &status, WUNTRACED); +			if (WIFEXITED(status)) { +				return !WEXITSTATUS(status); +			} +		} while (!WIFEXITED(status) && !WIFSIGNALED(status)); +	} + +	return 0; +} + +static char *feh_dcraw_load_image(char *filename) +{ +	char *basename; +	char *tmpname; +	char *sfn; +	int fd = -1; + +	basename = strrchr(filename, '/'); + +	if (basename == NULL) +		basename = filename; +	else +		basename++; + +	tmpname = feh_unique_filename("/tmp/", basename); + +	if (strlen(tmpname) > (NAME_MAX-6)) +		tmpname[NAME_MAX-7] = '\0'; + +	sfn = estrjoin("_", tmpname, "XXXXXX", NULL); +	free(tmpname); + +	fd = mkstemp(sfn); + +	if (fd == -1) { +		free(sfn); +		return NULL; +	} + +	childpid = fork(); +	if (childpid == -1) { +		weprintf("%s: Can't load with dcraw. Fork failed:", filename); +		unlink(sfn); +		free(sfn); +		close(fd); +		return NULL; +	} else if (childpid == 0) { + +		close(1); +		dup(fd); +		close(fd); + +		alarm(opt.conversion_timeout); +		execlp("dcraw", "dcraw", "-c", "-e", filename, NULL); +		_exit(1); +	} + +	int status; +	waitpid(-1, &status, 0); +	if (WIFSIGNALED(status)) { +		unlink(sfn); +		free(sfn); +		sfn = NULL; +		if (!opt.quiet) +			weprintf("%s - Conversion took too long, skipping", filename); +	} + +	return sfn; +} +  static char *feh_magick_load_image(char *filename)  { -	char argv_fd[12]; +	char *argv_fn;  	char *basename;  	char *tmpname;  	char *sfn; +	char tempdir[] = "/tmp/.feh-magick-tmp-XXXXXX";  	int fd = -1, devnull = -1;  	int status; - -	if (opt.magick_timeout < 0) -		return NULL; +	char created_tempdir = 0;  	basename = strrchr(filename, '/'); @@ -310,10 +423,33 @@ static char *feh_magick_load_image(char *filename)  	fd = mkstemp(sfn); -	if (fd == -1) +	if (fd == -1) { +		free(sfn);  		return NULL; +	} -	snprintf(argv_fd, sizeof(argv_fd), "png:fd:%d", fd); +	/* +	 * We could use png:fd:(whatever mkstemp returned) as target filename +	 * for convert, but this seems to be broken in some ImageMagick versions. +	 * So we resort to png:(sfn) instead. +	 */ +	argv_fn = estrjoin(":", "png", sfn, NULL); + +	/* +	 * By default, ImageMagick saves (occasionally lots of) temporary files +	 * in /tmp. It doesn't remove them if it runs into a timeout and is killed +	 * by us, no matter whether we use SIGINT, SIGTERM or SIGKILL. So, unless +	 * MAGICK_TMPDIR has already been set by the user, we create our own +	 * temporary directory for ImageMagick and remove its contents at the end of +	 * this function. +	 */ +	if (getenv("MAGICK_TMPDIR") == NULL) { +		if (mkdtemp(tempdir) == NULL) { +			weprintf("%s: ImageMagick may leave temporary files in /tmp. mkdtemp failed:", filename); +		} else { +			created_tempdir = 1; +		} +	}  	if ((childpid = fork()) < 0) {  		weprintf("%s: Can't load with imagemagick. Fork failed:", filename); @@ -336,39 +472,58 @@ static char *feh_magick_load_image(char *filename)  		 */  		setpgid(0, 0); -		execlp("convert", "convert", filename, argv_fd, NULL); +		if (created_tempdir) { +			// no error checking - this is a best-effort code path +			setenv("MAGICK_TMPDIR", tempdir, 0); +		} + +		execlp("convert", "convert", filename, argv_fn, NULL);  		_exit(1);  	}  	else { -		alarm(opt.magick_timeout); +		alarm(opt.conversion_timeout);  		waitpid(childpid, &status, 0); -		alarm(0); -		if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { -			close(fd); +		kill(childpid, SIGKILL); +		if (opt.conversion_timeout > 0 && !alarm(0)) {  			unlink(sfn);  			free(sfn);  			sfn = NULL;  			if (!opt.quiet) { -				if (WIFSIGNALED(status)) -					weprintf("%s - Conversion took too long, skipping", -						filename); +				weprintf("%s: Conversion took too long, skipping", filename);  			} - -			/* -			 * Reap child.  The previous waitpid call was interrupted by -			 * alarm, but convert doesn't terminate immediately. -			 * XXX -			 * normally, if (WIFSIGNALED(status)) waitpid(childpid, &status, 0); -			 * would suffice. However, as soon as feh has its own window, -			 * this doesn't work anymore and the following workaround is -			 * required. Hm. -			 */ -			waitpid(-1, &status, 0);  		} +		close(fd);  		childpid = 0;  	} +	if (created_tempdir) { +		DIR *dir; +		struct dirent *de; +		if ((dir = opendir(tempdir)) == NULL) { +			weprintf("%s: Cannot remove temporary ImageMagick files from %s:", filename, tempdir); +		} else { +			while ((de = readdir(dir)) != NULL) { +				if (de->d_name[0] != '.') { +					char *temporary_file_name = estrjoin("/", tempdir, de->d_name, NULL); +					/* +					 * We assume that ImageMagick only creates temporary files and +					 * not directories. +					 */ +					if (unlink(temporary_file_name) == -1) { +						weprintf("unlink %s:", temporary_file_name); +					} +					free(temporary_file_name); +				} +			} +			if (rmdir(tempdir) == -1) { +				weprintf("rmdir %s:", tempdir); +			} +		} +		closedir(dir); +	} + +	free(argv_fn);  	return sfn;  } @@ -425,6 +580,10 @@ static char *feh_http_load_image(char *url)  			if (opt.insecure_ssl) {  				curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);  				curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); +			} else if (getenv("CURL_CA_BUNDLE") != NULL) { +				// Allow the user to specify custom CA certificates. +				curl_easy_setopt(curl, CURLOPT_CAINFO, +						getenv("CURL_CA_BUNDLE"));  			}  			res = curl_easy_perform(curl); @@ -459,7 +618,7 @@ static char *feh_http_load_image(char *url)  char *feh_http_load_image(char *url)  {  	weprintf( -		"Cannot load image %s\n Please recompile with libcurl support", +		"Cannot load image %s\nPlease recompile feh with libcurl support",  		url  	);  	return NULL; @@ -675,11 +834,12 @@ void feh_draw_exif(winwidget w)  	fn = feh_load_font(w); -	if (buffer == NULL) +	if (buffer[0] == '\0')  	{  		snprintf(buffer, EXIF_MAX_DATA, "%s", estrdup("Failed to run exif command")); -		gib_imlib_get_text_size(fn, &buffer[0], NULL, &width, &height, IMLIB_TEXT_TO_RIGHT); -		no_lines = 1; +		gib_imlib_get_text_size(fn, buffer, NULL, &width, &height, IMLIB_TEXT_TO_RIGHT); +		info_buf[no_lines] = estrdup(buffer); +		no_lines++;  	}  	else  	{ @@ -1262,7 +1422,7 @@ void feh_draw_actions(winwidget w)  	int i = 0;  	int num_actions = 0;  	int cur_action = 0; -	char index[2]; +	char index[3];  	char *line;  	/* Count number of defined actions. This method sucks a bit since it needs diff --git a/src/index.c b/src/index.c index fbc25b8..af3adea 100644 --- a/src/index.c +++ b/src/index.c @@ -1,7 +1,7 @@  /* index.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -59,7 +59,6 @@ void init_index_mode(void)  	int lineno;  	unsigned char trans_bg = 0;  	int index_image_width, index_image_height; -	char *s;  	gib_list *line, *lines;  	if (opt.montage) { @@ -148,9 +147,16 @@ void init_index_mode(void)  	index_image_height = h + title_area_h;  	im_main = imlib_create_image(index_image_width, index_image_height); -	if (!im_main) -		eprintf("Failed to create %dx%d pixels (%d MB) index image. Do you have enough RAM?", -				index_image_width, index_image_height, index_image_width * index_image_height * 4 / (1024*1024)); +	if (!im_main) { +		if (index_image_height >= 32768 || index_image_width >= 32768) { +			eprintf("Failed to create %dx%d pixels (%d MB) index image.\n" +					"This is probably due to Imlib2 issues when dealing with images larger than 32k x 32k pixels.", +					index_image_width, index_image_height, index_image_width * index_image_height * 4 / (1024*1024)); +		} else { +			eprintf("Failed to create %dx%d pixels (%d MB) index image. Do you have enough RAM?", +					index_image_width, index_image_height, index_image_width * index_image_height * 4 / (1024*1024)); +		} +	}  	if (bg_im)  		gib_imlib_blend_image_onto_image(im_main, bg_im, @@ -164,15 +170,9 @@ void init_index_mode(void)  		gib_imlib_image_fill_rectangle(im_main, 0, 0, w, h + title_area_h, 0, 0, 0, 255);  	} -	/* Create the window title at this point */ - -	if (!opt.title) -		s = estrdup(PACKAGE " [index mode]"); -	else -		s = estrdup(feh_printf(opt.title, NULL, NULL)); -  	if (opt.display) { -		winwid = winwidget_create_from_image(im_main, s, WIN_TYPE_SINGLE); +		winwid = winwidget_create_from_image(im_main, WIN_TYPE_SINGLE); +		winwidget_rename(winwid, PACKAGE " [index mode]");  		winwidget_show(winwid);  	} @@ -348,7 +348,6 @@ void init_index_mode(void)  	if (!opt.display)  		gib_imlib_free_image_and_decache(im_main); -	free(s);  	return;  } diff --git a/src/index.h b/src/index.h index 08ab337..b022f1a 100644 --- a/src/index.h +++ b/src/index.h @@ -1,6 +1,6 @@  /* index.h -Copyright (C) 2011 Daniel Friesel. +Copyright (C) 2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to diff --git a/src/keyevents.c b/src/keyevents.c index b5c1949..689aebd 100644 --- a/src/keyevents.c +++ b/src/keyevents.c @@ -1,7 +1,7 @@  /* keyevents.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -29,17 +29,51 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #include "filelist.h"  #include "winwidget.h"  #include "options.h" +#include <termios.h> -fehkb keys; +struct __fehkey keys[EVENT_LIST_END]; +struct termios old_term_settings; +unsigned char control_via_stdin = 0; -static void feh_set_kb(fehkey *key, unsigned int s0, unsigned int y0, unsigned -		int s1, unsigned int y1, unsigned int s2, unsigned int y2) { +void setup_stdin() { +	struct termios ctrl; + +	control_via_stdin = 1; + +	if (tcgetattr(STDIN_FILENO, &old_term_settings) == -1) +		eprintf("tcgetattr failed"); +	if (tcgetattr(STDIN_FILENO, &ctrl) == -1) +		eprintf("tcgetattr failed"); + +	ctrl.c_iflag &= ~(PARMRK | ISTRIP +			| INLCR | IGNCR | IXON); +	ctrl.c_lflag &= ~(ECHO | ICANON | IEXTEN); +	ctrl.c_cflag &= ~(CSIZE | PARENB); +	ctrl.c_cflag |= CS8; + +	if (tcsetattr(STDIN_FILENO, TCSANOW, &ctrl) == -1) +		eprintf("tcsetattr failed"); +} + +void restore_stdin() { +	if (tcsetattr(STDIN_FILENO, TCSANOW, &old_term_settings) == -1) +		eprintf("tcsetattr failed"); +} + +static void feh_set_kb(char *name, unsigned int s0, unsigned int y0, +		unsigned int s1, unsigned int y1, unsigned int s2, unsigned int y2) { +	static int key_index = 0; +	fehkey *key = &keys[key_index];  	key->keystates[0] = s0;  	key->keystates[1] = s1;  	key->keystates[2] = s2;  	key->keysyms[0] = y0;  	key->keysyms[1] = y1;  	key->keysyms[2] = y2; +	key->state = 0; +	key->button = 0; +	key->name = name; +	key_index++;  }  static inline int ignore_space(int keysym) { @@ -100,74 +134,83 @@ void init_keyevents(void) {  	FILE *conf = NULL;  	int read = 0; -	memset(&keys, 0, sizeof(keys)); - -	feh_set_kb(&keys.menu_close, 0, XK_Escape    , 0, 0            , 0, 0); -	feh_set_kb(&keys.menu_parent,0, XK_Left      , 0, 0            , 0, 0); -	feh_set_kb(&keys.menu_down , 0, XK_Down      , 0, 0            , 0, 0); -	feh_set_kb(&keys.menu_up   , 0, XK_Up        , 0, 0            , 0, 0); -	feh_set_kb(&keys.menu_child, 0, XK_Right     , 0, 0            , 0, 0); -	feh_set_kb(&keys.menu_select,0, XK_Return    , 0, XK_space     , 0, 0); -	feh_set_kb(&keys.scroll_left,0, XK_KP_Left   , 4, XK_Left      , 0, 0); -	feh_set_kb(&keys.scroll_right,0,XK_KP_Right  , 4, XK_Right     , 0, 0); -	feh_set_kb(&keys.scroll_down,0, XK_KP_Down   , 4, XK_Down      , 0, 0); -	feh_set_kb(&keys.scroll_up , 0, XK_KP_Up     , 4, XK_Up        , 0, 0); -	feh_set_kb(&keys.scroll_left_page , 8, XK_Left , 0, 0          , 0, 0); -	feh_set_kb(&keys.scroll_right_page, 8, XK_Right, 0, 0          , 0, 0); -	feh_set_kb(&keys.scroll_down_page , 8, XK_Down , 0, 0          , 0, 0); -	feh_set_kb(&keys.scroll_up_page   , 8, XK_Up   , 0, 0          , 0, 0); -	feh_set_kb(&keys.prev_img  , 0, XK_Left      , 0, XK_p         , 0, XK_BackSpace); -	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); -	feh_set_kb(&keys.remove    , 0, XK_Delete    , 0, 0            , 0, 0); -	feh_set_kb(&keys.delete    , 4, XK_Delete    , 0, 0            , 0, 0); -	feh_set_kb(&keys.jump_first, 0, XK_Home      , 0, XK_KP_Home   , 0, 0); -	feh_set_kb(&keys.jump_last , 0, XK_End       , 0, XK_KP_End    , 0, 0); -	feh_set_kb(&keys.action_0  , 0, XK_Return    , 0, XK_0         , 0, XK_KP_0); -	feh_set_kb(&keys.action_1  , 0, XK_1         , 0, XK_KP_1      , 0, 0); -	feh_set_kb(&keys.action_2  , 0, XK_2         , 0, XK_KP_2      , 0, 0); -	feh_set_kb(&keys.action_3  , 0, XK_3         , 0, XK_KP_3      , 0, 0); -	feh_set_kb(&keys.action_4  , 0, XK_4         , 0, XK_KP_4      , 0, 0); -	feh_set_kb(&keys.action_5  , 0, XK_5         , 0, XK_KP_5      , 0, 0); -	feh_set_kb(&keys.action_6  , 0, XK_6         , 0, XK_KP_6      , 0, 0); -	feh_set_kb(&keys.action_7  , 0, XK_7         , 0, XK_KP_7      , 0, 0); -	feh_set_kb(&keys.action_8  , 0, XK_8         , 0, XK_KP_8      , 0, 0); -	feh_set_kb(&keys.action_9  , 0, XK_9         , 0, XK_KP_9      , 0, 0); -	feh_set_kb(&keys.zoom_in   , 0, XK_Up        , 0, XK_KP_Add    , 0, 0); -	feh_set_kb(&keys.zoom_out  , 0, XK_Down      , 0, XK_KP_Subtract,0, 0); -	feh_set_kb(&keys.zoom_default, 0, XK_KP_Multiply, 0, XK_asterisk,0, 0); -	feh_set_kb(&keys.zoom_fit  , 0, XK_KP_Divide , 0, XK_slash     , 0, 0); -	feh_set_kb(&keys.zoom_fill , 0, XK_exclam    , 0, 0            , 0, 0); -	feh_set_kb(&keys.size_to_image, 0, XK_w      , 0, 0            , 0, 0); -	feh_set_kb(&keys.render    , 0, XK_KP_Begin  , 0, XK_R         , 0, 0); -	feh_set_kb(&keys.toggle_actions, 0, XK_a, 0, 0, 0, 0); -	feh_set_kb(&keys.toggle_aliasing, 0, XK_A, 0, 0, 0, 0); -	feh_set_kb(&keys.toggle_filenames, 0, XK_d, 0, 0, 0, 0); +	/* +	 * The feh_set_kb statements must have the same order as the key_action +	 * enum. +	 */ + +	feh_set_kb("menu_close" , 0, XK_Escape    , 0, 0            , 0, 0); +	feh_set_kb("menu_parent", 0, XK_Left      , 0, 0            , 0, 0); +	feh_set_kb("menu_down", 0, XK_Down      , 0, 0            , 0, 0); +	feh_set_kb("menu_up", 0, XK_Up        , 0, 0            , 0, 0); +	feh_set_kb("menu_child", 0, XK_Right     , 0, 0            , 0, 0); +	feh_set_kb("menu_select", 0, XK_Return    , 0, XK_space     , 0, 0); +	feh_set_kb("scroll_left",0, XK_KP_Left   , 4, XK_Left      , 0, 0); +	feh_set_kb("scroll_right", 0,XK_KP_Right  , 4, XK_Right     , 0, 0); +	feh_set_kb("scroll_down",0, XK_KP_Down   , 4, XK_Down      , 0, 0); +	feh_set_kb("scroll_up",  0, XK_KP_Up     , 4, XK_Up        , 0, 0); +	feh_set_kb("scroll_left_page" , 8, XK_Left , 0, 0          , 0, 0); +	feh_set_kb("scroll_right_page", 8, XK_Right, 0, 0          , 0, 0); +	feh_set_kb("scroll_down_page" , 8, XK_Down , 0, 0          , 0, 0); +	feh_set_kb("scroll_up_page" , 8, XK_Up   , 0, 0          , 0, 0); +	feh_set_kb("prev_img"  , 0, XK_Left      , 0, XK_p         , 0, XK_BackSpace); +	feh_set_kb("next_img"  , 0, XK_Right     , 0, XK_n         , 0, XK_space); +	feh_set_kb("jump_back" , 0, XK_Page_Up   , 0, XK_KP_Page_Up, 0, 0); +	feh_set_kb("jump_fwd"  , 0, XK_Page_Down , 0, XK_KP_Page_Down,0,0); +	feh_set_kb("prev_dir"  , 0, XK_bracketleft, 0, 0           , 0, 0); +	feh_set_kb("next_dir"  , 0, XK_bracketright, 0, 0          , 0, 0); +	feh_set_kb("jump_random" ,0, XK_z         , 0, 0            , 0, 0); +	feh_set_kb("quit"      , 0, XK_Escape    , 0, XK_q         , 0, 0); +	feh_set_kb("close"     , 0, XK_x         , 0, 0            , 0, 0); +	feh_set_kb("remove"    , 0, XK_Delete    , 0, 0            , 0, 0); +	feh_set_kb("delete"    , 4, XK_Delete    , 0, 0            , 0, 0); +	feh_set_kb("jump_first" , 0, XK_Home      , 0, XK_KP_Home   , 0, 0); +	feh_set_kb("jump_last" , 0, XK_End       , 0, XK_KP_End    , 0, 0); +	feh_set_kb("action_0"  , 0, XK_Return    , 0, XK_0         , 0, XK_KP_0); +	feh_set_kb("action_1"  , 0, XK_1         , 0, XK_KP_1      , 0, 0); +	feh_set_kb("action_2"  , 0, XK_2         , 0, XK_KP_2      , 0, 0); +	feh_set_kb("action_3"  , 0, XK_3         , 0, XK_KP_3      , 0, 0); +	feh_set_kb("action_4"  , 0, XK_4         , 0, XK_KP_4      , 0, 0); +	feh_set_kb("action_5"  , 0, XK_5         , 0, XK_KP_5      , 0, 0); +	feh_set_kb("action_6"  , 0, XK_6         , 0, XK_KP_6      , 0, 0); +	feh_set_kb("action_7"  , 0, XK_7         , 0, XK_KP_7      , 0, 0); +	feh_set_kb("action_8"  , 0, XK_8         , 0, XK_KP_8      , 0, 0); +	feh_set_kb("action_9"  , 0, XK_9         , 0, XK_KP_9      , 0, 0); +	feh_set_kb("zoom_in"   , 0, XK_Up        , 0, XK_KP_Add    , 0, 0); +	feh_set_kb("zoom_out"  , 0, XK_Down      , 0, XK_KP_Subtract,0, 0); +	feh_set_kb("zoom_default" , 0, XK_KP_Multiply, 0, XK_asterisk,0, 0); +	feh_set_kb("zoom_fit"  , 0, XK_KP_Divide , 0, XK_slash     , 0, 0); +	feh_set_kb("zoom_fill" , 0, XK_exclam    , 0, 0            , 0, 0); +	feh_set_kb("size_to_image" , 0, XK_w      , 0, 0            , 0, 0); +	feh_set_kb("render"    , 0, XK_KP_Begin  , 0, XK_R         , 0, 0); +	feh_set_kb("toggle_actions" , 0, XK_a, 0, 0, 0, 0); +	feh_set_kb("toggle_aliasing" , 0, XK_A, 0, 0, 0, 0); +	feh_set_kb("toggle_auto_zoom" , 0, XK_Z, 0, 0, 0, 0);  #ifdef HAVE_LIBEXIF -	feh_set_kb(&keys.toggle_exif, 0, XK_e, 0, 0, 0, 0); +	feh_set_kb("toggle_exif" , 0, XK_e, 0, 0, 0, 0);  #endif -	feh_set_kb(&keys.toggle_info, 0, XK_i, 0, 0, 0, 0); -	feh_set_kb(&keys.toggle_pointer, 0, XK_o, 0, 0, 0, 0); -	feh_set_kb(&keys.toggle_caption, 0, XK_c, 0, 0, 0, 0); -	feh_set_kb(&keys.toggle_pause, 0, XK_h, 0, 0, 0, 0); -	feh_set_kb(&keys.toggle_menu, 0, XK_m, 0, 0, 0, 0); -	feh_set_kb(&keys.toggle_fullscreen, 0, XK_v, 0, 0, 0, 0); -	feh_set_kb(&keys.reload_image, 0, XK_r, 0, 0, 0, 0); -	feh_set_kb(&keys.save_image, 0, XK_s, 0, 0, 0, 0); -	feh_set_kb(&keys.save_filelist, 0, XK_f, 0, 0, 0, 0); -	feh_set_kb(&keys.orient_1, 0, XK_greater, 0, 0, 0, 0); -	feh_set_kb(&keys.orient_3, 0, XK_less, 0, 0, 0, 0); -	feh_set_kb(&keys.flip, 0, XK_underscore, 0, 0, 0, 0); -	feh_set_kb(&keys.mirror, 0, XK_bar, 0, 0, 0, 0); -	feh_set_kb(&keys.reload_minus, 0, XK_minus, 0, 0, 0, 0); -	feh_set_kb(&keys.reload_plus, 0, XK_plus, 0, 0, 0, 0); -	feh_set_kb(&keys.toggle_keep_vp, 0, XK_k, 0, 0, 0, 0); +	feh_set_kb("toggle_filenames" , 0, XK_d, 0, 0, 0, 0); +	feh_set_kb("toggle_info" , 0, XK_i, 0, 0, 0, 0); +	feh_set_kb("toggle_pointer" , 0, XK_o, 0, 0, 0, 0); +	feh_set_kb("toggle_caption" , 0, XK_c, 0, 0, 0, 0); +	feh_set_kb("toggle_pause" , 0, XK_h, 0, 0, 0, 0); +	feh_set_kb("toggle_menu" , 0, XK_m, 0, 0, 0, 0); +	feh_set_kb("toggle_fullscreen" , 0, XK_v, 0, 0, 0, 0); +	feh_set_kb("reload_image" , 0, XK_r, 0, 0, 0, 0); +	feh_set_kb("save_image" , 0, XK_s, 0, 0, 0, 0); +	feh_set_kb("save_filelist" , 0, XK_f, 0, 0, 0, 0); +	feh_set_kb("orient_1" , 0, XK_greater, 0, 0, 0, 0); +	feh_set_kb("orient_3" , 0, XK_less, 0, 0, 0, 0); +	feh_set_kb("flip" , 0, XK_underscore, 0, 0, 0, 0); +	feh_set_kb("mirror" , 0, XK_bar, 0, 0, 0, 0); +	feh_set_kb("reload_minus" , 0, XK_minus, 0, 0, 0, 0); +	feh_set_kb("reload_plus" , 0, XK_plus, 0, 0, 0, 0); +	feh_set_kb("toggle_keep_vp" , 0, XK_k, 0, 0, 0, 0); +	feh_set_kb("toggle_fixed_geometry" , 0, XK_g, 0, 0, 0, 0); +	feh_set_kb("pan" , 0, 0, 0, 0, 0, 0); +	feh_set_kb("zoom" , 0, 0, 0, 0, 0, 0); +	feh_set_kb("blur" , 0, 0, 0, 0, 0, 0); +	feh_set_kb("rotate" , 0, 0, 0, 0, 0, 0);  	home = getenv("HOME");  	confhome = getenv("XDG_CONFIG_HOME"); @@ -212,21 +255,23 @@ void init_keyevents(void) {  	fclose(conf);  } -static short feh_is_kp(fehkey *key, unsigned int state, unsigned int sym, unsigned int button) { +static short feh_is_kp(unsigned int key_index, unsigned int state, +		unsigned int sym, unsigned int button) {  	int i;  	if (sym != NoSymbol) {  		for (i = 0; i < 3; i++) {  			if ( -					(key->keysyms[i] == sym) && -					(key->keystates[i] == state)) +					(keys[key_index].keysyms[i] == sym) && +					(keys[key_index].keystates[i] == state))  				return 1; -			else if (key->keysyms[i] == 0) +			else if (keys[key_index].keysyms[i] == 0)  				return 0;  		}  		return 0;  	} -	if ((key->state == state) && (key->button == button)) { +	if ((keys[key_index].state == state) +			&& (keys[key_index].button == button)) {  		return 1;  	}  	return 0; @@ -234,12 +279,15 @@ static short feh_is_kp(fehkey *key, unsigned int state, unsigned int sym, unsign  void feh_event_invoke_action(winwidget winwid, unsigned char action)  { +	struct stat st;  	if (opt.actions[action]) {  		if (opt.slideshow) {  			feh_action_run(FEH_FILE(winwid->file->data), opt.actions[action], winwid);  			if (opt.hold_actions[action])  				feh_reload_image(winwid, 1, 1); +			else if (stat(FEH_FILE(winwid->file->data)->filename, &st) == -1) +				feh_filelist_image_remove(winwid, 0);  			else  				slideshow_change_image(winwid, SLIDE_NEXT, 1); @@ -269,22 +317,52 @@ void feh_event_invoke_action(winwidget winwid, unsigned char action)  void feh_event_handle_stdin()  {  	char stdin_buf[2]; +	static char is_esc = 0;  	KeySym keysym = NoSymbol;  	if (read(STDIN_FILENO, &stdin_buf, 1) == -1) { -		weprintf("reading a command from stdin failed"); +		control_via_stdin = 0; +		if (isatty(STDIN_FILENO) && getpgrp() == (tcgetpgrp(STDIN_FILENO))) { +			weprintf("reading a command from stdin failed - disabling control via stdin"); +			restore_stdin(); +		}  		return;  	}  	stdin_buf[1] = '\0'; +	// escape? +	if (stdin_buf[0] == 0x1b) { +		is_esc = 1; +		return; +	} +	if ((is_esc == 1) && (stdin_buf[0] == '[')) { +		is_esc = 2; +		return; +	} +  	if (stdin_buf[0] == ' ')  		keysym = XK_space;  	else if (stdin_buf[0] == '\n')  		keysym = XK_Return; +	else if ((stdin_buf[0] == '\b') || (stdin_buf[0] == 127)) +		keysym = XK_BackSpace; +	else if (is_esc == 2) { +		if (stdin_buf[0] == 'A') +			keysym = XK_Up; +		else if (stdin_buf[0] == 'B') +			keysym = XK_Down; +		else if (stdin_buf[0] == 'C') +			keysym = XK_Right; +		else if (stdin_buf[0] == 'D') +			keysym = XK_Left; +		is_esc = 0; +	}  	else  		keysym = XStringToKeysym(stdin_buf);  	if (window_num) -		feh_event_handle_generic(windows[0], 0, keysym, 0); +		feh_event_handle_generic(windows[0], is_esc * Mod1Mask, keysym, 0); + +	is_esc = 0;  }  void feh_event_handle_keypress(XEvent * ev) @@ -314,17 +392,17 @@ void feh_event_handle_keypress(XEvent * ev)  	/* menus are showing, so this is a menu control keypress */  	if (ev->xbutton.window == menu_cover) {  		selected_item = feh_menu_find_selected_r(menu_root, &selected_menu); -		if (feh_is_kp(&keys.menu_close, state, keysym, 0)) +		if (feh_is_kp(EVENT_menu_close, state, keysym, 0))  			feh_menu_hide(menu_root, True); -		else if (feh_is_kp(&keys.menu_parent, state, keysym, 0)) +		else if (feh_is_kp(EVENT_menu_parent, state, keysym, 0))  			feh_menu_select_parent(selected_menu); -		else if (feh_is_kp(&keys.menu_down, state, keysym, 0)) +		else if (feh_is_kp(EVENT_menu_down, state, keysym, 0))  			feh_menu_select_next(selected_menu, selected_item); -		else if (feh_is_kp(&keys.menu_up, state, keysym, 0)) +		else if (feh_is_kp(EVENT_menu_up, state, keysym, 0))  			feh_menu_select_prev(selected_menu, selected_item); -		else if (feh_is_kp(&keys.menu_child, state, keysym, 0)) +		else if (feh_is_kp(EVENT_menu_child, state, keysym, 0))  			feh_menu_select_submenu(selected_menu); -		else if (feh_is_kp(&keys.menu_select, state, keysym, 0)) +		else if (feh_is_kp(EVENT_menu_select, state, keysym, 0))  			feh_menu_item_activate(selected_menu, selected_item);  		return;  	} @@ -332,7 +410,23 @@ void feh_event_handle_keypress(XEvent * ev)  	if (winwid == NULL)  		return; -	if (winwid->caption_entry) { +	feh_event_handle_generic(winwid, state, keysym, 0); +} + +fehkey *feh_str_to_kb(char *action) +{ +	for (unsigned int i = 0; i < EVENT_LIST_END; i++) { +		if (!strcmp(action, keys[i].name)) { +			return &keys[i]; +		} +	} +	return NULL; +} + +void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysym, unsigned int button) { +	int curr_screen = 0; + +	if (winwid->caption_entry && (keysym != NoSymbol)) {  		switch (keysym) {  		case XK_Return:  			if (state & ControlMask) { @@ -383,272 +477,131 @@ void feh_event_handle_keypress(XEvent * ev)  		}  		return;  	} -	feh_event_handle_generic(winwid, state, keysym, 0); -} -fehkey *feh_str_to_kb(char *action) -{ -	if (!strcmp(action, "menu_close")) -		return &keys.menu_close; -	else if (!strcmp(action, "menu_parent")) -		return &keys.menu_parent; -	else if (!strcmp(action, "menu_down")) -		return &keys.menu_down; -	else if (!strcmp(action, "menu_up")) -		return &keys.menu_up; -	else if (!strcmp(action, "menu_child")) -		return &keys.menu_child; -	else if (!strcmp(action, "menu_select")) -		return &keys.menu_select; -	else if (!strcmp(action, "scroll_right")) -		return &keys.scroll_right; -	else if (!strcmp(action, "scroll_left")) -		return &keys.scroll_left; -	else if (!strcmp(action, "scroll_up")) -		return &keys.scroll_up; -	else if (!strcmp(action, "scroll_down")) -		return &keys.scroll_down; -	else if (!strcmp(action, "scroll_right_page")) -		return &keys.scroll_right_page; -	else if (!strcmp(action, "scroll_left_page")) -		return &keys.scroll_left_page; -	else if (!strcmp(action, "scroll_up_page")) -		return &keys.scroll_up_page; -	else if (!strcmp(action, "scroll_down_page")) -		return &keys.scroll_down_page; -	else if (!strcmp(action, "prev_img")) -		return &keys.prev_img; -	else if (!strcmp(action, "next_img")) -		return &keys.next_img; -	else if (!strcmp(action, "jump_back")) -		return &keys.jump_back; -	else if (!strcmp(action, "jump_fwd")) -		return &keys.jump_fwd; -	else if (!strcmp(action, "prev_dir")) -		return &keys.prev_dir; -	else if (!strcmp(action, "next_dir")) -		return &keys.next_dir; -	else if (!strcmp(action, "jump_random")) -		return &keys.jump_random; -	else if (!strcmp(action, "quit")) -		return &keys.quit; -	else if (!strcmp(action, "close")) -		return &keys.close; -	else if (!strcmp(action, "remove")) -		return &keys.remove; -	else if (!strcmp(action, "delete")) -		return &keys.delete; -	else if (!strcmp(action, "jump_first")) -		return &keys.jump_first; -	else if (!strcmp(action, "jump_last")) -		return &keys.jump_last; -	else if (!strcmp(action, "action_0")) -		return &keys.action_0; -	else if (!strcmp(action, "action_1")) -		return &keys.action_1; -	else if (!strcmp(action, "action_2")) -		return &keys.action_2; -	else if (!strcmp(action, "action_3")) -		return &keys.action_3; -	else if (!strcmp(action, "action_4")) -		return &keys.action_4; -	else if (!strcmp(action, "action_5")) -		return &keys.action_5; -	else if (!strcmp(action, "action_6")) -		return &keys.action_6; -	else if (!strcmp(action, "action_7")) -		return &keys.action_7; -	else if (!strcmp(action, "action_8")) -		return &keys.action_8; -	else if (!strcmp(action, "action_9")) -		return &keys.action_9; -	else if (!strcmp(action, "zoom_in")) -		return &keys.zoom_in; -	else if (!strcmp(action, "zoom_out")) -		return &keys.zoom_out; -	else if (!strcmp(action, "zoom_default")) -		return &keys.zoom_default; -	else if (!strcmp(action, "zoom_fit")) -		return &keys.zoom_fit; -	else if (!strcmp(action, "zoom_fill")) -		return &keys.zoom_fill; -	else if (!strcmp(action, "size_to_image")) -		return &keys.size_to_image; -	else if (!strcmp(action, "render")) -		return &keys.render; -	else if (!strcmp(action, "toggle_actions")) -		return &keys.toggle_actions; -	else if (!strcmp(action, "toggle_aliasing")) -		return &keys.toggle_aliasing; -	else if (!strcmp(action, "toggle_filenames")) -		return &keys.toggle_filenames; -#ifdef HAVE_LIBEXIF -	else if (!strcmp(action, "toggle_exif")) -		return &keys.toggle_exif; -#endif -	else if (!strcmp(action, "toggle_info")) -		return &keys.toggle_info; -	else if (!strcmp(action, "toggle_pointer")) -		return &keys.toggle_pointer; -	else if (!strcmp(action, "toggle_caption")) -		return &keys.toggle_caption; -	else if (!strcmp(action, "toggle_pause")) -		return &keys.toggle_pause; -	else if (!strcmp(action, "toggle_menu")) -		return &keys.toggle_menu; -	else if (!strcmp(action, "toggle_fullscreen")) -		return &keys.toggle_fullscreen; -	else if (!strcmp(action, "reload_image")) -		return &keys.reload_image; -	else if (!strcmp(action, "save_image")) -		return &keys.save_image; -	else if (!strcmp(action, "save_filelist")) -		return &keys.save_filelist; -	else if (!strcmp(action, "orient_1")) -		return &keys.orient_1; -	else if (!strcmp(action, "orient_3")) -		return &keys.orient_3; -	else if (!strcmp(action, "flip")) -		return &keys.flip; -	else if (!strcmp(action, "mirror")) -		return &keys.mirror; -	else if (!strcmp(action, "reload_minus")) -		return &keys.reload_minus; -	else if (!strcmp(action, "reload_plus")) -		return &keys.reload_plus; -	else if (!strcmp(action, "toggle_keep_vp")) -		return &keys.toggle_keep_vp; - -	return NULL; -} - -void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysym, unsigned int button) { -	int curr_screen = 0; - -	if (feh_is_kp(&keys.next_img, state, keysym, button)) { +	if (feh_is_kp(EVENT_next_img, state, keysym, button)) {  		if (opt.slideshow)  			slideshow_change_image(winwid, SLIDE_NEXT, 1);  		else if (winwid->type == WIN_TYPE_THUMBNAIL)  			feh_thumbnail_select_next(winwid, 1);  	} -	else if (feh_is_kp(&keys.prev_img, state, keysym, button)) { +	else if (feh_is_kp(EVENT_prev_img, state, keysym, button)) {  		if (opt.slideshow)  			slideshow_change_image(winwid, SLIDE_PREV, 1);  		else if (winwid->type == WIN_TYPE_THUMBNAIL)  			feh_thumbnail_select_prev(winwid, 1);  	} -	else if (feh_is_kp(&keys.scroll_right, state, keysym, button)) { +	else if (feh_is_kp(EVENT_scroll_right, state, keysym, button)) {  		winwid->im_x -= opt.scroll_step;;  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 1);  	} -	else if (feh_is_kp(&keys.scroll_left, state, keysym, button)) { +	else if (feh_is_kp(EVENT_scroll_left, state, keysym, button)) {  		winwid->im_x += opt.scroll_step;  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 1);  	} -	else if (feh_is_kp(&keys.scroll_down, state, keysym, button)) { +	else if (feh_is_kp(EVENT_scroll_down, state, keysym, button)) {  		winwid->im_y -= opt.scroll_step;  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 1);  	} -	else if (feh_is_kp(&keys.scroll_up, state, keysym, button)) { +	else if (feh_is_kp(EVENT_scroll_up, state, keysym, button)) {  		winwid->im_y += opt.scroll_step;  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 1);  	} -	else if (feh_is_kp(&keys.scroll_right_page, state, keysym, button)) { +	else if (feh_is_kp(EVENT_scroll_right_page, state, keysym, button)) {  		winwid->im_x -= winwid->w;  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.scroll_left_page, state, keysym, button)) { +	else if (feh_is_kp(EVENT_scroll_left_page, state, keysym, button)) {  		winwid->im_x += winwid->w;  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.scroll_down_page, state, keysym, button)) { +	else if (feh_is_kp(EVENT_scroll_down_page, state, keysym, button)) {  		winwid->im_y -= winwid->h;  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.scroll_up_page, state, keysym, button)) { +	else if (feh_is_kp(EVENT_scroll_up_page, state, keysym, button)) {  		winwid->im_y += winwid->h;  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.jump_back, state, keysym, button)) { +	else if (feh_is_kp(EVENT_jump_back, state, keysym, button)) {  		if (opt.slideshow)  			slideshow_change_image(winwid, SLIDE_JUMP_BACK, 1);  		else if (winwid->type == WIN_TYPE_THUMBNAIL)  			feh_thumbnail_select_prev(winwid, 10);  	} -	else if (feh_is_kp(&keys.jump_fwd, state, keysym, button)) { +	else if (feh_is_kp(EVENT_jump_fwd, state, keysym, button)) {  		if (opt.slideshow)  			slideshow_change_image(winwid, SLIDE_JUMP_FWD, 1);  		else if (winwid->type == WIN_TYPE_THUMBNAIL)  			feh_thumbnail_select_next(winwid, 10);  	} -	else if (feh_is_kp(&keys.next_dir, state, keysym, button)) { +	else if (feh_is_kp(EVENT_next_dir, state, keysym, button)) {  		if (opt.slideshow)  			slideshow_change_image(winwid, SLIDE_JUMP_NEXT_DIR, 1);  	} -	else if (feh_is_kp(&keys.prev_dir, state, keysym, button)) { +	else if (feh_is_kp(EVENT_prev_dir, state, keysym, button)) {  		if (opt.slideshow)  			slideshow_change_image(winwid, SLIDE_JUMP_PREV_DIR, 1);  	} -	else if (feh_is_kp(&keys.quit, state, keysym, button)) { +	else if (feh_is_kp(EVENT_quit, state, keysym, button)) {  		winwidget_destroy_all();  	} -	else if (feh_is_kp(&keys.delete, state, keysym, button)) { +	else if (feh_is_kp(EVENT_delete, state, keysym, button)) {  		if (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)  			feh_thumbnail_mark_removed(FEH_FILE(winwid->file->data), 1);  		feh_filelist_image_remove(winwid, 1);  	} -	else if (feh_is_kp(&keys.remove, state, keysym, button)) { +	else if (feh_is_kp(EVENT_remove, state, keysym, button)) {  		if (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)  			feh_thumbnail_mark_removed(FEH_FILE(winwid->file->data), 0);  		feh_filelist_image_remove(winwid, 0);  	} -	else if (feh_is_kp(&keys.jump_first, state, keysym, button)) { +	else if (feh_is_kp(EVENT_jump_first, state, keysym, button)) {  		if (opt.slideshow)  			slideshow_change_image(winwid, SLIDE_FIRST, 1);  	} -	else if (feh_is_kp(&keys.jump_last, state, keysym, button)) { +	else if (feh_is_kp(EVENT_jump_last, state, keysym, button)) {  		if (opt.slideshow)  			slideshow_change_image(winwid, SLIDE_LAST, 1);  	} -	else if (feh_is_kp(&keys.action_0, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_0, state, keysym, button)) {  		feh_event_invoke_action(winwid, 0);  	} -	else if (feh_is_kp(&keys.action_1, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_1, state, keysym, button)) {  		feh_event_invoke_action(winwid, 1);  	} -	else if (feh_is_kp(&keys.action_2, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_2, state, keysym, button)) {  		feh_event_invoke_action(winwid, 2);  	} -	else if (feh_is_kp(&keys.action_3, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_3, state, keysym, button)) {  		feh_event_invoke_action(winwid, 3);  	} -	else if (feh_is_kp(&keys.action_4, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_4, state, keysym, button)) {  		feh_event_invoke_action(winwid, 4);  	} -	else if (feh_is_kp(&keys.action_5, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_5, state, keysym, button)) {  		feh_event_invoke_action(winwid, 5);  	} -	else if (feh_is_kp(&keys.action_6, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_6, state, keysym, button)) {  		feh_event_invoke_action(winwid, 6);  	} -	else if (feh_is_kp(&keys.action_7, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_7, state, keysym, button)) {  		feh_event_invoke_action(winwid, 7);  	} -	else if (feh_is_kp(&keys.action_8, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_8, state, keysym, button)) {  		feh_event_invoke_action(winwid, 8);  	} -	else if (feh_is_kp(&keys.action_9, state, keysym, button)) { +	else if (feh_is_kp(EVENT_action_9, state, keysym, button)) {  		feh_event_invoke_action(winwid, 9);  	} -	else if (feh_is_kp(&keys.zoom_in, state, keysym, button)) { +	else if (feh_is_kp(EVENT_zoom_in, state, keysym, button)) {  		winwid->old_zoom = winwid->zoom;  		winwid->zoom = winwid->zoom * 1.25; @@ -662,7 +615,7 @@ void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysy  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.zoom_out, state, keysym, button)) { +	else if (feh_is_kp(EVENT_zoom_out, state, keysym, button)) {  		winwid->old_zoom = winwid->zoom;  		winwid->zoom = winwid->zoom * 0.80; @@ -676,17 +629,17 @@ void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysy  		winwidget_sanitise_offsets(winwid);  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.zoom_default, state, keysym, button)) { +	else if (feh_is_kp(EVENT_zoom_default, state, keysym, button)) {  		winwid->zoom = 1.0;  		winwidget_center_image(winwid);  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.zoom_fit, state, keysym, button)) { +	else if (feh_is_kp(EVENT_zoom_fit, state, keysym, button)) {  		feh_calc_needed_zoom(&winwid->zoom, winwid->im_w, winwid->im_h, winwid->w, winwid->h);  		winwidget_center_image(winwid);  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.zoom_fill, state, keysym, button)) { +	else if (feh_is_kp(EVENT_zoom_fill, state, keysym, button)) {  		int save_zoom = opt.zoom_mode;  		opt.zoom_mode = ZOOM_MODE_FILL;  		feh_calc_needed_zoom(&winwid->zoom, winwid->im_w, winwid->im_h, winwid->w, winwid->h); @@ -694,46 +647,50 @@ void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysy  		winwidget_render_image(winwid, 0, 0);  		opt.zoom_mode = save_zoom;  	} -	else if (feh_is_kp(&keys.render, state, keysym, button)) { +	else if (feh_is_kp(EVENT_render, state, keysym, button)) {  		if (winwid->type == WIN_TYPE_THUMBNAIL)  			feh_thumbnail_show_selected();  		else  			winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.toggle_actions, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_actions, state, keysym, button)) {  		opt.draw_actions = !opt.draw_actions;  		winwidget_rerender_all(0);  	} -	else if (feh_is_kp(&keys.toggle_aliasing, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_aliasing, state, keysym, button)) {  		opt.force_aliasing = !opt.force_aliasing;  		winwid->force_aliasing = !winwid->force_aliasing;  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.toggle_filenames, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_auto_zoom, state, keysym, button)) { +		opt.zoom_mode = (opt.zoom_mode == 0 ? ZOOM_MODE_MAX : 0); +		winwidget_rerender_all(1); +	} +	else if (feh_is_kp(EVENT_toggle_filenames, state, keysym, button)) {  		opt.draw_filename = !opt.draw_filename;  		winwidget_rerender_all(0);  	}  #ifdef HAVE_LIBEXIF -	else if (feh_is_kp(&keys.toggle_exif, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_exif, state, keysym, button)) {  		opt.draw_exif = !opt.draw_exif;  		winwidget_rerender_all(0);  	}  #endif -	else if (feh_is_kp(&keys.toggle_info, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_info, state, keysym, button)) {  		opt.draw_info = !opt.draw_info;  		winwidget_rerender_all(0);  	} -	else if (feh_is_kp(&keys.toggle_pointer, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_pointer, state, keysym, button)) {  		winwidget_set_pointer(winwid, opt.hide_pointer);  		opt.hide_pointer = !opt.hide_pointer;  	} -	else if (feh_is_kp(&keys.jump_random, state, keysym, button)) { +	else if (feh_is_kp(EVENT_jump_random, state, keysym, button)) {  		if (winwid->type == WIN_TYPE_THUMBNAIL)  			feh_thumbnail_select_next(winwid, rand() % (filelist_len - 1));  		else  			slideshow_change_image(winwid, SLIDE_RAND, 1);  	} -	else if (feh_is_kp(&keys.toggle_caption, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_caption, state, keysym, button)) {  		if (opt.caption_path) {  			/*  			 * editing captions in slideshow mode does not make any sense @@ -745,44 +702,44 @@ void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysy  		}  		winwidget_render_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.reload_image, state, keysym, button)) { +	else if (feh_is_kp(EVENT_reload_image, state, keysym, button)) {  		feh_reload_image(winwid, 0, 0);  	} -	else if (feh_is_kp(&keys.toggle_pause, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_pause, state, keysym, button)) {  		slideshow_pause_toggle(winwid);  	} -	else if (feh_is_kp(&keys.save_image, state, keysym, button)) { +	else if (feh_is_kp(EVENT_save_image, state, keysym, button)) {  		slideshow_save_image(winwid);  	} -	else if (feh_is_kp(&keys.save_filelist, state, keysym, button)) { +	else if (feh_is_kp(EVENT_save_filelist, state, keysym, button)) {  		if ((winwid->type == WIN_TYPE_THUMBNAIL)  				|| (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER))  			weprintf("Filelist saving is not supported in thumbnail mode");  		else  			feh_save_filelist();  	} -	else if (feh_is_kp(&keys.size_to_image, state, keysym, button)) { +	else if (feh_is_kp(EVENT_size_to_image, state, keysym, button)) {  		winwidget_size_to_image(winwid);  	} -	else if (feh_is_kp(&keys.toggle_menu, state, keysym, button)) { +	else if (!opt.no_menus && feh_is_kp(EVENT_toggle_menu, state, keysym, button)) {  		winwidget_show_menu(winwid);  	} -	else if (feh_is_kp(&keys.close, state, keysym, button)) { +	else if (feh_is_kp(EVENT_close, state, keysym, button)) {  		winwidget_destroy(winwid);  	} -	else if (feh_is_kp(&keys.orient_1, state, keysym, button)) { +	else if (feh_is_kp(EVENT_orient_1, state, keysym, button)) {  		feh_edit_inplace(winwid, 1);  	} -	else if (feh_is_kp(&keys.orient_3, state, keysym, button)) { +	else if (feh_is_kp(EVENT_orient_3, state, keysym, button)) {  		feh_edit_inplace(winwid, 3);  	} -	else if (feh_is_kp(&keys.flip, state, keysym, button)) { +	else if (feh_is_kp(EVENT_flip, state, keysym, button)) {  		feh_edit_inplace(winwid, INPLACE_EDIT_FLIP);  	} -	else if (feh_is_kp(&keys.mirror, state, keysym, button)) { +	else if (feh_is_kp(EVENT_mirror, state, keysym, button)) {  		feh_edit_inplace(winwid, INPLACE_EDIT_MIRROR);  	} -	else if (feh_is_kp(&keys.toggle_fullscreen, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_fullscreen, state, keysym, button)) {  #ifdef HAVE_LIBXINERAMA  		if (opt.xinerama && xinerama_screens) {  			int i, rect[4]; @@ -818,20 +775,30 @@ void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysy  		}  #endif				/* HAVE_LIBXINERAMA */  	} -	else if (feh_is_kp(&keys.reload_plus, state, keysym, button)){ +	else if (feh_is_kp(EVENT_reload_plus, state, keysym, button)){  		if (opt.reload < SLIDESHOW_RELOAD_MAX)  			opt.reload++;  		else if (opt.verbose)  			weprintf("Cannot set RELOAD higher than %f seconds.", opt.reload);  	} -	else if (feh_is_kp(&keys.reload_minus, state, keysym, button)) { +	else if (feh_is_kp(EVENT_reload_minus, state, keysym, button)) {  		if (opt.reload > 1)  			opt.reload--;  		else if (opt.verbose)  			weprintf("Cannot set RELOAD lower than 1 second.");  	} -	else if (feh_is_kp(&keys.toggle_keep_vp, state, keysym, button)) { +	else if (feh_is_kp(EVENT_toggle_keep_vp, state, keysym, button)) {  		opt.keep_zoom_vp = !opt.keep_zoom_vp;  	} +	else if (feh_is_kp(EVENT_toggle_fixed_geometry, state, keysym, button)) { +		if (opt.geom_flags & ((WidthValue | HeightValue))) { +			opt.geom_flags &= ~(WidthValue | HeightValue); +		} else { +			opt.geom_flags |= (WidthValue | HeightValue); +			opt.geom_w = winwid->w; +			opt.geom_h = winwid->h; +		} +		winwidget_render_image(winwid, 1, 0); +	}  	return;  } @@ -1,7 +1,7 @@  /* list.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -92,6 +92,7 @@ void real_loadables_mode(int loadable)  				if (opt.verbose)  					feh_display_status('.');  				puts(file->filename); +				fflush(stdout);  				feh_action_run(file, opt.actions[0], NULL);  			}  			else { @@ -106,6 +107,7 @@ void real_loadables_mode(int loadable)  				if (opt.verbose)  					feh_display_status('.');  				puts(file->filename); +				fflush(stdout);  				feh_action_run(file, opt.actions[0], NULL);  			}  			else { @@ -1,7 +1,7 @@  /* main.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -42,13 +42,12 @@ char **cmdargv = NULL;  int cmdargc = 0;  char *mode = NULL; -struct termios old_term_settings; -int control_via_stdin = 0; -  int main(int argc, char **argv)  {  	atexit(feh_clean_exit); +	srand(getpid() * time(NULL) % ((unsigned int) -1)); +  	setup_signal_handlers();  	init_parse_options(argc, argv); @@ -89,16 +88,19 @@ int main(int argc, char **argv)  		feh_wm_set_bg_filelist(opt.bgmode);  		exit(0);  	} -	else { +	else if (opt.display){  		/* Slideshow mode is the default. Because it's spiffy */  		opt.slideshow = 1;  		init_slideshow_mode();  	} +	else { +		eprintf("Invalid option combination"); +	}  	/* main event loop */  	while (feh_main_iteration(1)); -	return(0); +	return(sig_exit);  }  /* Return 0 to stop iterating, 1 if ok to continue. */ @@ -115,7 +117,7 @@ int feh_main_iteration(int block)  	double t1 = 0.0, t2 = 0.0;  	fehtimer ft; -	if (window_num == 0) +	if (window_num == 0 || sig_exit != 0)  		return(0);  	if (first) { @@ -124,20 +126,18 @@ int feh_main_iteration(int block)  		fdsize = xfd + 1;  		pt = feh_get_time();  		first = 0; -		if (isatty(STDIN_FILENO)) { -			control_via_stdin = 1; -			struct termios ctrl; -			if (tcgetattr(STDIN_FILENO, &old_term_settings) == -1) -				eprintf("tcgetattr failed"); -			if (tcgetattr(STDIN_FILENO, &ctrl) == -1) -				eprintf("tcgetattr failed"); -			ctrl.c_iflag &= ~(PARMRK | ISTRIP -					| INLCR | IGNCR | IXON); -			ctrl.c_lflag &= ~(ECHO | ICANON | IEXTEN); -			ctrl.c_cflag &= ~(CSIZE | PARENB); -			ctrl.c_cflag |= CS8; -			if (tcsetattr(STDIN_FILENO, TCSANOW, &ctrl) == -1) -				eprintf("tcsetattr failed"); +		/* +		 * Only accept commands from stdin if +		 * - stdin is a terminal (otherwise it's probably used as an image / filelist) +		 * - we aren't running in multiwindow mode (cause it's not clear which +		 *   window commands should be applied to in that case) +		 * - we're in the same process group as stdin, AKA we're not running +		 *   in the background. Background processes are stopped with SIGTTOU +		 *   if they try to write to stdout or change terminal attributes. They +		 *   also don't get input from stdin anyway. +		 */ +		if (isatty(STDIN_FILENO) && !opt.multiwindow && getpgrp() == (tcgetpgrp(STDIN_FILENO))) { +			setup_stdin();  		}  	} @@ -150,7 +150,7 @@ int feh_main_iteration(int block)  		if (ev_handler[ev.type])  			(*(ev_handler[ev.type])) (&ev); -		if (window_num == 0) +		if (window_num == 0 || sig_exit != 0)  			return(0);  	}  	XFlush(disp); @@ -211,7 +211,7 @@ int feh_main_iteration(int block)  				   in that */  				feh_handle_timer();  			} -			else if (count && (FD_ISSET(0, &fdset))) +			else if ((count > 0) && (FD_ISSET(0, &fdset)))  				feh_event_handle_stdin();  #ifdef HAVE_INOTIFY  			else if (count && (FD_ISSET(opt.inotify_fd, &fdset))) @@ -228,7 +228,7 @@ int feh_main_iteration(int block)  					&& ((errno == ENOMEM) || (errno == EINVAL)  						|| (errno == EBADF)))  				eprintf("Connection to X display lost"); -			else if (count && (FD_ISSET(0, &fdset))) +			else if ((count > 0) && (FD_ISSET(0, &fdset)))  				feh_event_handle_stdin();  #ifdef HAVE_INOTIFY  			else if (count && (FD_ISSET(opt.inotify_fd, &fdset))) @@ -236,7 +236,7 @@ int feh_main_iteration(int block)  #endif  		}  	} -	if (window_num == 0) +	if (window_num == 0 || sig_exit != 0)  		return(0);  	return(1); @@ -258,9 +258,16 @@ void feh_clean_exit(void)  	if(disp)  		XCloseDisplay(disp); -	if (control_via_stdin) -		if (tcsetattr(STDIN_FILENO, TCSANOW, &old_term_settings) == -1) -			eprintf("tcsetattr failed"); +	/* +	 * Only restore the old terminal settings if +	 * - we changed them in the first place +	 * - stdin still is a terminal (it might have been closed) +	 * - stdin still belongs to us (we might have been detached from the +	 *   controlling terminal, in that case we probably shouldn't be messing +	 *   around with it) <https://github.com/derf/feh/issues/324> +	 */ +	if (control_via_stdin && isatty(STDIN_FILENO) && getpgrp() == (tcgetpgrp(STDIN_FILENO))) +		restore_stdin();  	if (opt.filelistfile)  		feh_write_filelist(filelist, opt.filelistfile); @@ -1,7 +1,7 @@  /* menu.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -1,7 +1,7 @@  /* menu.h  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to diff --git a/src/multiwindow.c b/src/multiwindow.c index 13cff90..abbf6c9 100644 --- a/src/multiwindow.c +++ b/src/multiwindow.c @@ -34,25 +34,14 @@ void init_multiwindow_mode(void)  {  	winwidget w = NULL;  	gib_list *l; -	feh_file *file = NULL; + +	if (!opt.title) +		opt.title = PACKAGE " - %f";  	mode = "multiwindow";  	for (l = filelist; l; l = l->next) { -		char *s = NULL; -		int len = 0; -		file = FEH_FILE(l->data); -		current_file = l; - -		if (!opt.title) { -			len = strlen(PACKAGE " - ") + strlen(file->filename) + 1; -			s = emalloc(len); -			snprintf(s, len, PACKAGE " - %s", file->filename); -		} else { -			s = estrdup(feh_printf(opt.title, file, w)); -		} - -		if ((w = winwidget_create_from_file(l, s, WIN_TYPE_SINGLE)) != NULL) { +		if ((w = winwidget_create_from_file(l, WIN_TYPE_SINGLE)) != NULL) {  			winwidget_show(w);  			if (opt.reload > 0)  				feh_add_unique_timer(cb_reload_timer, w, opt.reload); @@ -62,7 +51,6 @@ void init_multiwindow_mode(void)  			D(("EEEK. Couldn't load image in multiwindow mode. "  						"I 'm not sure if this is a problem\n"));  		} -		free(s);  	}  	return; diff --git a/src/options.c b/src/options.c index 20e6272..364fb42 100644 --- a/src/options.c +++ b/src/options.c @@ -1,7 +1,7 @@  /* options.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -24,6 +24,7 @@ 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" @@ -53,7 +54,7 @@ void init_parse_options(int argc, char **argv)  	opt.display = 1;  	opt.aspect = 1;  	opt.slideshow_delay = 0.0; -	opt.magick_timeout = -1; +	opt.conversion_timeout = -1;  	opt.thumb_w = 60;  	opt.thumb_h = 60;  	opt.thumb_redraw = 10; @@ -67,6 +68,7 @@ void init_parse_options(int argc, char **argv)  	opt.jump_on_resort = 1;  	opt.screen_clip = 1; +	opt.cache_size = 4;  #ifdef HAVE_LIBXINERAMA  	/* if we're using xinerama, then enable it by default */  	opt.xinerama = 1; @@ -211,7 +213,7 @@ static void feh_parse_options_from_string(char *opts)  	char *s;  	char *t;  	char last = 0; -	int inquote = 0; +	char inquote = 0;  	int i = 0;  	/* So we don't reinvent the wheel (not again, anyway), we use the @@ -226,7 +228,7 @@ static void feh_parse_options_from_string(char *opts)  			eprintf(PACKAGE " does not support more than 64 words per "  					"theme definition.\n Please shorten your lines."); -		if ((*t == ' ') && !(inquote)) { +		if ((*t == ' ') && !inquote) {  			*t = '\0';  			num++; @@ -237,8 +239,10 @@ static void feh_parse_options_from_string(char *opts)  			list[num - 1] = feh_string_normalize(s);  			break; -		} else if (((*t == '\"') || (*t == '\'')) && last != '\\') -			inquote = !(inquote); +		} else if ((*t == inquote) && (last != '\\')) { +			inquote = 0; +		} else if (((*t == '\"') || (*t == '\'')) && (last != '\\') && !inquote) +			inquote = *t;  		last = *t;  	} @@ -409,8 +413,13 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  		{"xinerama-index", 1, 0, 239},  		{"insecure"      , 0, 0, 240},  		{"no-recursive"  , 0, 0, 241}, +		{"cache-size"    , 1, 0, 243}, +		{"on-last-slide" , 1, 0, 244}, +		{"conversion-timeout" , 1, 0, 245}, +		{"version-sort"  , 0, 0, 246}, +		{"offset"        , 1, 0, 247},  #ifdef HAVE_INOTIFY -		{"auto-reload"   , 0, 0, 243}, +		{"auto-reload"   , 0, 0, 248},  #endif  		{0, 0, 0, 0}  	}; @@ -430,6 +439,7 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  			opt.debug = 1;  			break;  		case '<': +			opt.filter_by_dimensions = 1;  			XParseGeometry(optarg, &discard, &discard, &opt.max_width, &opt.max_height);  			if (opt.max_width == 0)  				opt.max_width = UINT_MAX; @@ -437,6 +447,7 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  				opt.max_height = UINT_MAX;  			break;  		case '>': +			opt.filter_by_dimensions = 1;  			XParseGeometry(optarg, &discard, &discard, &opt.min_width, &opt.min_height);  			break;  		case '.': @@ -449,14 +460,7 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  			opt.actions[0] = estrdup(optarg);  			break;  		case 'B': -			if (!strcmp(optarg, "checks")) -				opt.image_bg = IMAGE_BG_CHECKS; -			else if (!strcmp(optarg, "white")) -				opt.image_bg = IMAGE_BG_WHITE; -			else if (!strcmp(optarg, "black")) -				opt.image_bg = IMAGE_BG_BLACK; -			else -				weprintf("Unknown argument to --image-bg: %s", optarg); +			opt.image_bg = estrdup(optarg);  			break;  		case 'C':  			D(("adding fontpath %s\n", optarg)); @@ -592,6 +596,7 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  				opt.filelistfile = estrdup(optarg);  			break;  		case 'g': +			opt.geom_enabled = 1;  			opt.geom_flags = XParseGeometry(optarg, &opt.geom_x,  					&opt.geom_y, &opt.geom_w, &opt.geom_h);  			break; @@ -692,7 +697,8 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  			opt.index_info = estrdup(optarg);  			break;  		case 208: -			opt.magick_timeout = atoi(optarg); +			weprintf("--magick-timeout is deprecated, please use --conversion-timeout instead"); +			opt.conversion_timeout = atoi(optarg);  			break;  		case 209:  			opt.actions[1] = estrdup(optarg); @@ -738,13 +744,9 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  			opt.auto_rotate = 1;  			break;  #endif -#ifdef HAVE_INOTIFY -		case 243: -			opt.auto_reload = 1; -			break; -#endif  		case 224: -			opt.cycle_once = 1; +			weprintf("--cycle-once is deprecated, please use --on-last-slide=quit instead"); +			opt.on_last_slide = ON_LAST_SLIDE_QUIT;  			break;  		case 225:  			opt.xinerama = 0; @@ -776,8 +778,44 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)  			break;  		case 240:  			opt.insecure_ssl = 1; +			break;  		case 241:  			opt.recursive = 0; +			break; +		case 243: +			opt.cache_size = atoi(optarg); +			if (opt.cache_size < 0) +				opt.cache_size = 0; +			if (opt.cache_size > 2048) +				opt.cache_size = 2048; +			break; +		case 244: +			if (!strcmp(optarg, "quit")) { +				opt.on_last_slide = ON_LAST_SLIDE_QUIT; +			} else if (!strcmp(optarg, "hold")) { +				opt.on_last_slide = ON_LAST_SLIDE_HOLD; +			} else if (!strcmp(optarg, "resume")) { +				opt.on_last_slide = ON_LAST_SLIDE_RESUME; +			} else { +				weprintf("Unrecognized on-last-slide action \"%s\"." +						"Supported actions: hold, resume, quit\n", optarg); +			} +			break; +		case 245: +			opt.conversion_timeout = atoi(optarg); +			break; +		case 246: +			opt.version_sort = 1; +			break; +		case 247: +			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;  		} diff --git a/src/options.h b/src/options.h index 2cfef2f..cae04ec 100644 --- a/src/options.h +++ b/src/options.h @@ -1,7 +1,7 @@  /* options.h  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -27,6 +27,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #ifndef OPTIONS_H  #define OPTIONS_H +enum on_last_slide_action { +	ON_LAST_SLIDE_RESUME = 0, +	ON_LAST_SLIDE_QUIT, +	ON_LAST_SLIDE_HOLD +}; +  struct __fehoptions {  	unsigned char multiwindow;  	unsigned char montage; @@ -72,17 +78,18 @@ struct __fehoptions {  	unsigned char draw_actions;  	unsigned char draw_info;  	unsigned char cache_thumbnails; -	unsigned char cycle_once; +	unsigned char on_last_slide;  	unsigned char hold_actions[10];  	unsigned char text_bg; -	unsigned char image_bg;  	unsigned char no_fehbg;  	unsigned char keep_zoom_vp;  	unsigned char insecure_ssl; +	unsigned char filter_by_dimensions;  	char *output_file;  	char *output_dir;  	char *bg_file; +	char *image_bg;  	char *font;  	char *title_font;  	char *title; @@ -107,12 +114,17 @@ struct __fehoptions {  	unsigned int thumb_redraw;  	double reload;  	int sort; +	int version_sort;  	int debug; +	int geom_enabled;  	int geom_flags;  	int geom_x;  	int geom_y;  	unsigned int geom_w;  	unsigned int geom_h; +	int offset_flags; +	int offset_x; +	int offset_y;  	int default_zoom;  	int zoom_mode;  	unsigned char adjust_reload; @@ -121,6 +133,9 @@ struct __fehoptions {  	/* signed in case someone wants to invert scrolling real quick */  	int scroll_step; +	// imlib cache size in mebibytes +	int cache_size; +  	unsigned int min_width, min_height, max_width, max_height;  	unsigned char mode; @@ -128,7 +143,7 @@ struct __fehoptions {  	double slideshow_delay; -	signed short magick_timeout; +	signed int conversion_timeout;  	Imlib_Font menu_fn;  }; @@ -138,80 +153,83 @@ struct __fehkey {  	unsigned int keystates[3];  	unsigned int state;  	unsigned int button; +	char *name;  }; -struct __fehkb { -	struct __fehkey menu_close; -	struct __fehkey menu_parent; -	struct __fehkey menu_down; -	struct __fehkey menu_up; -	struct __fehkey menu_child; -	struct __fehkey menu_select; -	struct __fehkey scroll_right; -	struct __fehkey prev_img; -	struct __fehkey scroll_left; -	struct __fehkey next_img; -	struct __fehkey scroll_up; -	struct __fehkey scroll_down; -	struct __fehkey scroll_right_page; -	struct __fehkey scroll_left_page; -	struct __fehkey scroll_up_page; -	struct __fehkey scroll_down_page; -	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; -	struct __fehkey jump_last; -	struct __fehkey action_0; -	struct __fehkey action_1; -	struct __fehkey action_2; -	struct __fehkey action_3; -	struct __fehkey action_4; -	struct __fehkey action_5; -	struct __fehkey action_6; -	struct __fehkey action_7; -	struct __fehkey action_8; -	struct __fehkey action_9; -	struct __fehkey zoom_in; -	struct __fehkey zoom_out; -	struct __fehkey zoom_default; -	struct __fehkey zoom_fit; -	struct __fehkey zoom_fill; -	struct __fehkey render; -	struct __fehkey toggle_actions; -	struct __fehkey toggle_filenames; +enum key_action { +	EVENT_menu_close = 0, +	EVENT_menu_parent, +	EVENT_menu_down, +	EVENT_menu_up, +	EVENT_menu_child, +	EVENT_menu_select, +	EVENT_scroll_left, +	EVENT_scroll_right, +	EVENT_scroll_down, +	EVENT_scroll_up, +	EVENT_scroll_left_page, +	EVENT_scroll_right_page, +	EVENT_scroll_down_page, +	EVENT_scroll_up_page, +	EVENT_prev_img, +	EVENT_next_img, +	EVENT_jump_back, +	EVENT_jump_fwd, +	EVENT_prev_dir, +	EVENT_next_dir, +	EVENT_jump_random, +	EVENT_quit, +	EVENT_close, +	EVENT_remove, +	EVENT_delete, +	EVENT_jump_first, +	EVENT_jump_last, +	EVENT_action_0, +	EVENT_action_1, +	EVENT_action_2, +	EVENT_action_3, +	EVENT_action_4, +	EVENT_action_5, +	EVENT_action_6, +	EVENT_action_7, +	EVENT_action_8, +	EVENT_action_9, +	EVENT_zoom_in, +	EVENT_zoom_out, +	EVENT_zoom_default, +	EVENT_zoom_fit, +	EVENT_zoom_fill, +	EVENT_size_to_image, +	EVENT_render, +	EVENT_toggle_actions, +	EVENT_toggle_aliasing, +	EVENT_toggle_auto_zoom,  #ifdef HAVE_LIBEXIF -	struct __fehkey toggle_exif; +	EVENT_toggle_exif,  #endif -	struct __fehkey toggle_info; -	struct __fehkey toggle_pointer; -	struct __fehkey toggle_aliasing; -	struct __fehkey jump_random; -	struct __fehkey toggle_caption; -	struct __fehkey toggle_pause; -	struct __fehkey reload_image; -	struct __fehkey save_image; -	struct __fehkey save_filelist; -	struct __fehkey size_to_image; -	struct __fehkey toggle_menu; -	struct __fehkey close; -	struct __fehkey orient_1; -	struct __fehkey orient_3; -	struct __fehkey flip; -	struct __fehkey mirror; -	struct __fehkey toggle_fullscreen; -	struct __fehkey reload_minus; -	struct __fehkey reload_plus; -	struct __fehkey toggle_keep_vp; -	struct __fehkey pan; -	struct __fehkey zoom; -	struct __fehkey reload; -	struct __fehkey blur; -	struct __fehkey rotate; +	EVENT_toggle_filenames, +	EVENT_toggle_info, +	EVENT_toggle_pointer, +	EVENT_toggle_caption, +	EVENT_toggle_pause, +	EVENT_toggle_menu, +	EVENT_toggle_fullscreen, +	EVENT_reload_image, +	EVENT_save_image, +	EVENT_save_filelist, +	EVENT_orient_1, +	EVENT_orient_3, +	EVENT_flip, +	EVENT_mirror, +	EVENT_reload_minus, +	EVENT_reload_plus, +	EVENT_toggle_keep_vp, +	EVENT_toggle_fixed_geometry, +	EVENT_pan, +	EVENT_zoom, +	EVENT_blur, +	EVENT_rotate, +	EVENT_LIST_END  };  void init_parse_options(int argc, char **argv); diff --git a/src/signals.c b/src/signals.c index 0b18aac..aeaf889 100644 --- a/src/signals.c +++ b/src/signals.c @@ -1,6 +1,6 @@  /* signals.c -Copyright (C) 2010 by Daniel Friesel +Copyright (C) 2010-2018 by Daniel Friesel  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -28,6 +28,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #include "options.h"  void feh_handle_signal(int); +int sig_exit = 0;  void setup_signal_handlers()  { @@ -40,7 +41,8 @@ void setup_signal_handlers()  		(sigaddset(&feh_ss, SIGALRM) == -1) ||  		(sigaddset(&feh_ss, SIGTERM) == -1) ||  		(sigaddset(&feh_ss, SIGQUIT) == -1) || -		(sigaddset(&feh_ss, SIGINT) == -1)) +		(sigaddset(&feh_ss, SIGINT) == -1) || +		(sigaddset(&feh_ss, SIGTTIN) == -1))  	{  		weprintf("Failed to set up signal masks");  		return; @@ -56,7 +58,8 @@ void setup_signal_handlers()  		(sigaction(SIGALRM, &feh_sh, NULL) == -1) ||  		(sigaction(SIGTERM, &feh_sh, NULL) == -1) ||  		(sigaction(SIGQUIT, &feh_sh, NULL) == -1) || -		(sigaction(SIGINT, &feh_sh, NULL) == -1)) +		(sigaction(SIGINT, &feh_sh, NULL) == -1) || +		(sigaction(SIGTTIN, &feh_sh, NULL) == -1))  	{  		weprintf("Failed to set up signal handler");  		return; @@ -75,12 +78,17 @@ void feh_handle_signal(int signo)  			if (childpid)  				killpg(childpid, SIGINT);  			return; +		case SIGTTIN: +			// we were probably backgrounded while we were running +			control_via_stdin = 0; +			return;  		case SIGINT:  		case SIGTERM:  		case SIGQUIT:  			if (childpid)  				killpg(childpid, SIGINT); -			exit(128 + signo); +			sig_exit = 128 + signo; +			return;  	}  	winwid = winwidget_get_first_window_of_type(WIN_TYPE_SLIDESHOW); diff --git a/src/signals.h b/src/signals.h index 526285d..090ab0b 100644 --- a/src/signals.h +++ b/src/signals.h @@ -27,5 +27,5 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #define SIGNALS_H  void setup_signal_handlers(); - +extern int sig_exit;  #endif diff --git a/src/slideshow.c b/src/slideshow.c index 4a71dc3..3770677 100644 --- a/src/slideshow.c +++ b/src/slideshow.c @@ -1,7 +1,7 @@  /* slideshow.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -35,9 +35,7 @@ void init_slideshow_mode(void)  {  	winwidget w = NULL;  	int success = 0; -	char *s = NULL;  	gib_list *l = filelist, *last = NULL; -	feh_file *file = NULL;  	for (; l && opt.start_list_at; l = l->next) {  		if (!strcmp(opt.start_list_at, FEH_FILE(l->data)->filename)) { @@ -50,17 +48,17 @@ void init_slideshow_mode(void)  		eprintf("--start-at %s: File not found in filelist",  				opt.start_list_at); +	if (!opt.title) +		opt.title = PACKAGE " [%u of %l] - %f"; +  	mode = "slideshow";  	for (; l; l = l->next) { -		file = FEH_FILE(l->data);  		if (last) {  			filelist = feh_file_remove_from_list(filelist, last);  			last = NULL;  		}  		current_file = l; -		s = slideshow_create_name(file, NULL); -		if ((w = winwidget_create_from_file(l, s, WIN_TYPE_SLIDESHOW)) != NULL) { -			free(s); +		if ((w = winwidget_create_from_file(l, WIN_TYPE_SLIDESHOW)) != NULL) {  			success = 1;  			winwidget_show(w);  			if (opt.slideshow_delay > 0.0) @@ -69,7 +67,6 @@ void init_slideshow_mode(void)  				feh_add_unique_timer(cb_reload_timer, w, opt.reload);  			break;  		} else { -			free(s);  			last = l;  		}  	} @@ -110,6 +107,10 @@ void cb_reload_timer(void *data)  			add_file_to_filelist_recursively(l->data, FILELIST_FIRST);  	else if (!opt.filelistfile && !opt.bgmode)  		add_file_to_filelist_recursively(".", FILELIST_FIRST); + +	if (opt.filelistfile) { +		filelist = gib_list_cat(filelist, feh_read_filelist(opt.filelistfile)); +	}  	if (!(filelist_len = gib_list_length(filelist))) {  		eprintf("No files found to reload."); @@ -130,13 +131,6 @@ void cb_reload_timer(void *data)  		current_file = filelist;  	w->file = current_file; -	/* reset window name in case of current file order, -	 * filename, or filelist_length has changed. -	 */ -	current_filename = slideshow_create_name(FEH_FILE(current_file->data), w); -	winwidget_rename(w, current_filename); -	free(current_filename); -  	feh_reload_image(w, 1, 0);  	feh_add_unique_timer(cb_reload_timer, w, opt.reload);  	return; @@ -144,21 +138,11 @@ void cb_reload_timer(void *data)  void feh_reload_image(winwidget w, int resize, int force_new)  { -	char *title, *new_title; +	char *new_title;  	int len;  	Imlib_Image tmp;  	int old_w, old_h; -	unsigned char tmode =0; -	int tim_x =0; -	int tim_y =0; -	double tzoom =0; - -	tmode = w->mode; -	tim_x = w->im_x; -	tim_y = w->im_y; -	tzoom = w->zoom; -  	if (!w->file) {  		im_weprintf(w, "couldn't reload, this image has no file associated with it.");  		winwidget_render_image(w, 0, 0); @@ -173,8 +157,8 @@ void feh_reload_image(winwidget w, int resize, int force_new)  	len = strlen(w->name) + sizeof("Reloading: ") + 1;  	new_title = emalloc(len);  	snprintf(new_title, len, "Reloading: %s", w->name); -	title = estrdup(w->name);  	winwidget_rename(w, new_title); +	free(new_title);  	old_w = gib_imlib_image_get_width(w->im);  	old_h = gib_imlib_image_get_height(w->im); @@ -195,9 +179,6 @@ void feh_reload_image(winwidget w, int resize, int force_new)  			im_weprintf(w, "Couldn't reload image. Is it still there?");  			winwidget_render_image(w, 0, 0);  		} -		winwidget_rename(w, title); -		free(title); -		free(new_title);  		return;  	} @@ -226,20 +207,7 @@ void feh_reload_image(winwidget w, int resize, int force_new)  		w->im_w = gib_imlib_image_get_width(w->im);  		w->im_h = gib_imlib_image_get_height(w->im);  	} -	if (opt.keep_zoom_vp) { -		/* put back in: */ -		w->mode = tmode; -		w->im_x = tim_x; -		w->im_y = tim_y; -		w->zoom = tzoom; -		winwidget_render_image(w, 0, 0); -	} else { -		winwidget_render_image(w, resize, 0); -	} - -	winwidget_rename(w, title); -	free(title); -	free(new_title); +	winwidget_render_image(w, resize, 0);  	return;  } @@ -247,22 +215,20 @@ void feh_reload_image(winwidget w, int resize, int force_new)  void slideshow_change_image(winwidget winwid, int change, int render)  {  	gib_list *last = NULL; +	gib_list *previous_file = current_file;  	int i = 0;  	int jmp = 1;  	/* We can't use filelist_len in the for loop, since that changes when we  	 * encounter invalid images.  	 */  	int our_filelist_len = filelist_len; -	char *s; -	unsigned char tmode =0; -	int tim_x =0; -	int tim_y =0; -	double tzoom =0; +	if (opt.slideshow_delay > 0.0) +		feh_add_timer(cb_slide_timer, winwid, opt.slideshow_delay, "SLIDE_CHANGE");  	/* Without this, clicking a one-image slideshow reloads it. Not very *  	   intelligent behaviour :-) */ -	if (filelist_len < 2 && opt.cycle_once == 0) +	if (filelist_len < 2 && opt.on_last_slide != ON_LAST_SLIDE_QUIT)  		return;  	/* Ok. I do this in such an odd way to ensure that if the last or first * @@ -272,9 +238,11 @@ void slideshow_change_image(winwidget winwid, int change, int render)  	if (change == SLIDE_FIRST) {  		current_file = gib_list_last(filelist);  		change = SLIDE_NEXT; +		previous_file = NULL;  	} else if (change == SLIDE_LAST) {  		current_file = filelist;  		change = SLIDE_PREV; +		previous_file = NULL;  	}  	/* The for loop prevents us looping infinitely */ @@ -370,43 +338,29 @@ void slideshow_change_image(winwidget winwid, int change, int render)  			last = NULL;  		} -		if (opt.keep_zoom_vp) { -		/* pre loadimage - record settings */ -			tmode = winwid->mode; -			tim_x = winwid->im_x; -			tim_y = winwid->im_y; -			tzoom = winwid->zoom; +		if (opt.on_last_slide == ON_LAST_SLIDE_HOLD && previous_file && +			((current_file == filelist && change == SLIDE_NEXT) || +			(previous_file == filelist && change == SLIDE_PREV))) { +				current_file = previous_file;  		} -		if ((winwidget_loadimage(winwid, FEH_FILE(current_file->data))) -		    != 0) { +		if (winwidget_loadimage(winwid, FEH_FILE(current_file->data))) { +			int w = gib_imlib_image_get_width(winwid->im); +			int h = gib_imlib_image_get_height(winwid->im); +			if (feh_should_ignore_image(winwid->im)) { +				last = current_file; +				continue; +			}  			winwid->mode = MODE_NORMAL;  			winwid->file = current_file; -			if ((winwid->im_w != gib_imlib_image_get_width(winwid->im)) -			    || (winwid->im_h != gib_imlib_image_get_height(winwid->im))) +			if ((winwid->im_w != w) || (winwid->im_h != h))  				winwid->had_resize = 1;  			winwidget_reset_image(winwid); -			winwid->im_w = gib_imlib_image_get_width(winwid->im); -			winwid->im_h = gib_imlib_image_get_height(winwid->im); -			if (opt.keep_zoom_vp) { -				/* put back in: */ -				winwid->mode = tmode; -				winwid->im_x = tim_x; -				winwid->im_y = tim_y; -				winwid->zoom = tzoom; -			} +			winwid->im_w = w; +			winwid->im_h = h;  			if (render) { -				if (opt.keep_zoom_vp) { -					winwidget_render_image(winwid, 0, 0); -				} else { -					winwidget_render_image(winwid, 1, 0); -				} +				winwidget_render_image(winwid, 1, 0);  			} - -			s = slideshow_create_name(FEH_FILE(current_file->data), winwid); -			winwidget_rename(winwid, s); -			free(s); -  			break;  		} else  			last = current_file; @@ -417,8 +371,6 @@ void slideshow_change_image(winwidget winwid, int change, int render)  	if (filelist_len == 0)  		eprintf("No more slides in show"); -	if (opt.slideshow_delay > 0.0) -		feh_add_timer(cb_slide_timer, winwid, opt.slideshow_delay, "SLIDE_CHANGE");  	return;  } @@ -433,23 +385,6 @@ void slideshow_pause_toggle(winwidget w)  	winwidget_rename(w, NULL);  } -char *slideshow_create_name(feh_file * file, winwidget winwid) -{ -	char *s = NULL; -	int len = 0; - -	if (!opt.title) { -		len = strlen(PACKAGE " [slideshow mode] - ") + strlen(file->filename) + 1; -		s = emalloc(len); -		snprintf(s, len, PACKAGE " [%d of %d] - %s", -			gib_list_num(filelist, current_file) + 1, gib_list_length(filelist), file->filename); -	} else { -		s = estrdup(feh_printf(opt.title, file, winwid)); -	} - -	return(s); -} -  void feh_action_run(feh_file * file, char *action, winwidget winwid)  {  	if (action) { @@ -464,29 +399,6 @@ void feh_action_run(feh_file * file, char *action, winwidget winwid)  	return;  } -char *shell_escape(char *input) -{ -	static char ret[1024]; -	unsigned int out = 0, in = 0; - -	ret[out++] = '\''; -	for (in = 0; input[in] && (out < (sizeof(ret) - 7)); in++) { -		if (input[in] == '\'') { -			ret[out++] = '\''; -			ret[out++] = '"'; -			ret[out++] = '\''; -			ret[out++] = '"'; -			ret[out++] = '\''; -		} -		else -			ret[out++] = input[in]; -	} -	ret[out++] = '\''; -	ret[out++] = '\0'; - -	return ret; -} -  char *format_size(int size)  {  	static char ret[5]; @@ -509,6 +421,7 @@ char *feh_printf(char *str, feh_file * file, winwidget winwid)  	ret[0] = '\0';  	filelist_tmppath = NULL; +	gib_list *f;  	for (c = str; *c != '\0'; c++) {  		if ((*c == '%') && (*(c+1) != '\0')) { @@ -522,6 +435,12 @@ char *feh_printf(char *str, feh_file * file, winwidget winwid)  				if (file)  					strncat(ret, shell_escape(file->filename), sizeof(ret) - strlen(ret) - 1);  				break; +			case 'g': +				if (winwid) { +					snprintf(buf, sizeof(buf), "%d,%d", winwid->w, winwid->h); +					strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); +				} +				break;  			case 'h':  				if (file && (file->info || !feh_file_info_load(file, NULL))) {  					snprintf(buf, sizeof(buf), "%d", file->info->height); @@ -593,9 +512,8 @@ char *feh_printf(char *str, feh_file * file, winwidget winwid)  				}  				break;  			case 'u': -				snprintf(buf, sizeof(buf), "%d", -					 current_file != NULL ? gib_list_num(filelist, current_file) -					 + 1 : 0); +				f = current_file ? current_file : gib_list_find_by_data(filelist, file); +				snprintf(buf, sizeof(buf), "%d", f ? gib_list_num(filelist, f) + 1 : 0);  				strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);  				break;  			case 'v': @@ -619,6 +537,12 @@ char *feh_printf(char *str, feh_file * file, winwidget winwid)  					strncat(ret, "1.00", sizeof(ret) - strlen(ret) - 1);  				}  				break; +			case 'Z': +				if (winwid) { +					snprintf(buf, sizeof(buf), "%f", winwid->zoom); +					strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); +				} +				break;  			case '%':  				strncat(ret, "%", sizeof(ret) - strlen(ret) - 1);  				break; @@ -649,15 +573,14 @@ char *feh_printf(char *str, feh_file * file, winwidget winwid)  void feh_filelist_image_remove(winwidget winwid, char do_delete)  {  	if (winwid->type == WIN_TYPE_SLIDESHOW) { -		char *s;  		gib_list *doomed;  		doomed = current_file;  		/* -		 * work around feh_list_jump exiting if cycle_once is enabled +		 * work around feh_list_jump exiting if ON_LAST_SLIDE_QUIT is set  		 * and no further files are left (we need to delete first)  		 */ -		if (opt.cycle_once && ! doomed->next && do_delete) { +		if (opt.on_last_slide == ON_LAST_SLIDE_QUIT && ! doomed->next && do_delete) {  			feh_file_rm_and_free(filelist, doomed);  			exit(0);  		} @@ -676,9 +599,6 @@ void feh_filelist_image_remove(winwidget winwid, char do_delete)  			winwidget_destroy(winwid);  			return;  		} -		s = slideshow_create_name(FEH_FILE(winwid->file->data), winwid); -		winwidget_rename(winwid, s); -		free(s);  		winwidget_render_image(winwid, 1, 0);  	} else if ((winwid->type == WIN_TYPE_SINGLE)  		   || (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)) { @@ -736,7 +656,7 @@ gib_list *feh_list_jump(gib_list * root, gib_list * l, int direction, int num)  			if (ret->next) {  				ret = ret->next;  			} else { -				if (opt.cycle_once) { +				if (opt.on_last_slide == ON_LAST_SLIDE_QUIT) {  					exit(0);  				}  				if (opt.randomize) { diff --git a/src/structs.h b/src/structs.h index 3942bc0..ce30eb9 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1,7 +1,7 @@  /* structs.h  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to diff --git a/src/thumbnail.c b/src/thumbnail.c index 761162f..5197618 100644 --- a/src/thumbnail.c +++ b/src/thumbnail.c @@ -1,7 +1,7 @@  /* thumbnail.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -71,7 +71,6 @@ void init_thumbnail_mode(void)  	gib_list *l, *last = NULL;  	int lineno;  	int index_image_width, index_image_height; -	char *s;  	unsigned int thumb_counter = 0;  	gib_list *line, *lines; @@ -92,6 +91,8 @@ void init_thumbnail_mode(void)  	td.vertical = 0;  	td.max_column_w = 0; +	if (!opt.thumb_title) +		opt.thumb_title = "%n";  	mode = "thumbnail";  	if (opt.font) @@ -147,9 +148,16 @@ void init_thumbnail_mode(void)  	D(("imlib_create_image(%d, %d)\n", index_image_width, index_image_height));  	td.im_main = imlib_create_image(index_image_width, index_image_height); -	if (!td.im_main) -		eprintf("Failed to create %dx%d pixels (%d MB) index image. Do you have enough RAM?", -				index_image_width, index_image_height, index_image_width * index_image_height * 4 / (1024*1024)); +	if (!td.im_main) { +		if (index_image_height >= 32768 || index_image_width >= 32768) { +			eprintf("Failed to create %dx%d pixels (%d MB) index image.\n" +					"This is probably due to Imlib2 issues when dealing with images larger than 32k x 32k pixels.", +					index_image_width, index_image_height, index_image_width * index_image_height * 4 / (1024*1024)); +		} else { +			eprintf("Failed to create %dx%d pixels (%d MB) index image. Do you have enough RAM?", +					index_image_width, index_image_height, index_image_width * index_image_height * 4 / (1024*1024)); +		} +	}  	gib_imlib_image_set_has_alpha(td.im_main, 1); @@ -168,15 +176,10 @@ void init_thumbnail_mode(void)  				td.h + title_area_h, 0, 0, 0, 255);  	} -	/* Create title now */ - -	if (!opt.title) -		s = estrdup(PACKAGE " [thumbnail mode]"); -	else -		s = estrdup(feh_printf(opt.title, NULL, NULL));  	if (opt.display) { -		winwid = winwidget_create_from_image(td.im_main, s, WIN_TYPE_THUMBNAIL); +		winwid = winwidget_create_from_image(td.im_main, WIN_TYPE_THUMBNAIL); +		winwidget_rename(winwid, PACKAGE " [thumbnail mode]");  		winwidget_show(winwid);  	} @@ -416,7 +419,6 @@ void init_thumbnail_mode(void)  	} -	free(s);  	return;  } @@ -772,24 +774,25 @@ int feh_thumbnail_get_generated(Imlib_Image * image, feh_file * file,  void feh_thumbnail_show_fullsize(feh_file *thumbfile)  {  	winwidget thumbwin = NULL; -	char *s; +	gib_list *l; -	if (!opt.thumb_title) -		s = thumbfile->name; -	else -		s = feh_printf(opt.thumb_title, thumbfile, NULL); -	 +	for (l = filelist; l; l = l->next) { +		if (FEH_FILE(l->data) == thumbfile) { +			break; +		} +	} +	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( -				gib_list_add_front(NULL, thumbfile), -				s, WIN_TYPE_THUMBNAIL_VIEWER); +				l, +				WIN_TYPE_THUMBNAIL_VIEWER);  		if (thumbwin)  			winwidget_show(thumbwin);  	} else if (FEH_FILE(thumbwin->file->data) != thumbfile) { -		free(thumbwin->file); -		thumbwin->file = gib_list_add_front(NULL, thumbfile); -		winwidget_rename(thumbwin, s); +		thumbwin->file = l;  #ifdef HAVE_INOTIFY          winwidget_inotify_remove(thumbwin);  #endif @@ -931,16 +934,3 @@ int feh_thumbnail_setup_thumbnail_dir(void)  	return status;  } - -char *thumbnail_create_name(feh_file * file, winwidget winwid) -{ -	char *s = NULL; - -	if (!opt.thumb_title) { -		s = estrdup(file->filename); -	} else { -		s = estrdup(feh_printf(opt.thumb_title, file, winwid)); -	} - -	return(s); -} diff --git a/src/thumbnail.h b/src/thumbnail.h index f22ff77..09cd771 100644 --- a/src/thumbnail.h +++ b/src/thumbnail.h @@ -1,7 +1,7 @@  /* thumbnail.h  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to diff --git a/src/timers.c b/src/timers.c index 1cac94b..95fc9f8 100644 --- a/src/timers.c +++ b/src/timers.c @@ -1,7 +1,7 @@  /* timers.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to diff --git a/src/utils.c b/src/utils.c index 4c06a48..ec30d4a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -157,7 +157,7 @@ char *feh_unique_filename(char *path, char *basename)  {  	char *tmpname;  	char num[10]; -	char cppid[10]; +	char cppid[12];  	static long int i = 1;  	struct stat st;  	pid_t ppid; @@ -201,3 +201,26 @@ char *ereadfile(char *path)  	return estrdup(buffer);  } + +char *shell_escape(char *input) +{ +	static char ret[1024]; +	unsigned int out = 0, in = 0; + +	ret[out++] = '\''; +	for (in = 0; input[in] && (out < (sizeof(ret) - 7)); in++) { +		if (input[in] == '\'') { +			ret[out++] = '\''; +			ret[out++] = '"'; +			ret[out++] = '\''; +			ret[out++] = '"'; +			ret[out++] = '\''; +		} +		else +			ret[out++] = input[in]; +	} +	ret[out++] = '\''; +	ret[out++] = '\0'; + +	return ret; +} diff --git a/src/utils.h b/src/utils.h index c0d243b..22cbbf8 100644 --- a/src/utils.h +++ b/src/utils.h @@ -46,6 +46,7 @@ char *estrjoin(const char *separator, ...);  char path_is_url(char *path);  char *feh_unique_filename(char *path, char *basename);  char *ereadfile(char *path); +char *shell_escape(char *input);  #define ESTRAPPEND(a,b) \    {\ diff --git a/src/wallpaper.c b/src/wallpaper.c index 2f7810f..db14a8c 100644 --- a/src/wallpaper.c +++ b/src/wallpaper.c @@ -1,7 +1,7 @@  /* wallpaper.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -24,12 +24,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */ +#include <limits.h> +#include <sys/stat.h> +  #include "feh.h"  #include "filelist.h"  #include "options.h"  #include "wallpaper.h" -#include <limits.h> -#include <sys/stat.h> +  Window ipc_win = None;  Window my_ipc_win = None;  Atom ipc_atom = None; @@ -89,7 +91,7 @@ static void feh_wm_set_bg_scaled(Pixmap pmap, Imlib_Image im, int use_filelist,  		feh_wm_load_next(&im);  	gib_imlib_render_image_on_drawable_at_size(pmap, im, x, y, w, h, -			1, 0, !opt.force_aliasing); +			1, 1, !opt.force_aliasing);  	if (use_filelist)  		gib_imlib_free_image_and_decache(im); @@ -130,7 +132,7 @@ static void feh_wm_set_bg_centered(Pixmap pmap, Imlib_Image im, int use_filelist  		y + ((offset_y > 0) ? offset_y : 0),  		w,  		h, -		1, 0, 0); +		1, 1, 0);  	if (use_filelist)  		gib_imlib_free_image_and_decache(im); @@ -158,11 +160,36 @@ static void feh_wm_set_bg_filled(Pixmap pmap, Imlib_Image im, int use_filelist,  	render_x = (  cut_x ? ((img_w - render_w) >> 1) : 0);  	render_y = ( !cut_x ? ((img_h - render_h) >> 1) : 0); +	if ((opt.geom_flags & XValue) && cut_x) { +		if (opt.geom_flags & XNegative) { +			render_x = img_w - render_w + opt.geom_x; +		} else { +			render_x = opt.geom_x; +		} +		if (render_x < 0) { +			render_x = 0; +		} else if (render_x + render_w > img_w) { +			render_x = img_w - render_w; +		} +	} +	else if ((opt.geom_flags & YValue) && !cut_x) { +		if (opt.geom_flags & YNegative) { +			render_y = img_h - render_h + opt.geom_y; +		} else { +			render_y = opt.geom_y; +		} +		if (render_y < 0) { +			render_y = 0; +		} else if (render_y + render_h > img_h) { +			render_y = img_h - render_h; +		} +	} +  	gib_imlib_render_image_part_on_drawable_at_size(pmap, im,  		render_x, render_y,  		render_w, render_h,  		x, y, w, h, -		1, 0, !opt.force_aliasing); +		1, 1, !opt.force_aliasing);  	if (use_filelist)  		gib_imlib_free_image_and_decache(im); @@ -210,7 +237,7 @@ static void feh_wm_set_bg_maxed(Pixmap pmap, Imlib_Image im, int use_filelist,  	gib_imlib_render_image_on_drawable_at_size(pmap, im,  		render_x, render_y,  		render_w, render_h, -		1, 0, !opt.force_aliasing); +		1, 1, !opt.force_aliasing);  	if (use_filelist)  		gib_imlib_free_image_and_decache(im); @@ -294,97 +321,30 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled,  		unsigned long length, after;  		unsigned char *data_root = NULL, *data_esetroot = NULL;  		Pixmap pmap_d1, pmap_d2; -		gib_list *l; -		/* string for sticking in ~/.fehbg */ -		char *fehbg = NULL; -		char fehbg_args[512]; -		fehbg_args[0] = '\0'; -		char *argptr = fehbg_args;  		char *home; -		char filbuf[4096]; -		char *bgfill = NULL; -		bgfill = opt.image_bg == IMAGE_BG_WHITE ?  "--image-bg white" : "--image-bg black" ; - -#ifdef HAVE_LIBXINERAMA -		if (opt.xinerama) { -			if (opt.xinerama_index >= 0) { -				snprintf(argptr, sizeof(fehbg_args), -					"--xinerama-index %d", opt.xinerama_index); -			} -		} -		else -			snprintf(argptr, sizeof(fehbg_args), "--no-xinerama"); -		argptr += strlen(argptr); -#endif			/* HAVE_LIBXINERAMA */ -		if ((opt.geom_flags & XValue) && (sizeof(fehbg_args) - strlen(fehbg_args) > 60)) { -			snprintf(argptr, sizeof(fehbg_args) - strlen(fehbg_args), " --geometry %c%d", -					opt.geom_flags & XNegative ? '-' : '+', -					opt.geom_flags & XNegative ? abs(opt.geom_x) : opt.geom_x); -			argptr += strlen(argptr); -			if (opt.geom_flags & YValue) { -				snprintf(argptr, sizeof(fehbg_args) - strlen(fehbg_args), "%c%d", -						opt.geom_flags & YNegative ? '-' : '+', -						opt.geom_flags & YNegative ? abs(opt.geom_y) : opt.geom_y); -				argptr += strlen(argptr); -			} -		}  		/* local display to set closedownmode on */  		Display *disp2;  		Window root2;  		int depth2; -		int in, out, w, h; +		int w, h;  		D(("Falling back to XSetRootWindowPixmap\n")); -		/* Put the filename in filbuf between ' and escape ' in the filename */ -		out = 0; - -		if (fil && !use_filelist) { -			filbuf[out++] = '\''; - -			fil = feh_absolute_path(fil); - -			for (in = 0; fil[in] && out < 4092; in++) { - -				if (fil[in] == '\'') -					filbuf[out++] = '\\'; -				filbuf[out++] = fil[in]; -			} -			filbuf[out++] = '\''; -			free(fil); - -		} else { -			for (l = filelist; l && out < 4092; l = l->next) { -				filbuf[out++] = '\''; - -				fil = feh_absolute_path(FEH_FILE(l->data)->filename); - -				for (in = 0; fil[in] && out < 4092; in++) { - -					if (fil[in] == '\'') -						filbuf[out++] = '\\'; -					filbuf[out++] = fil[in]; -				} -				filbuf[out++] = '\''; -				filbuf[out++] = ' '; -				free(fil); -			} -		} - - -		filbuf[out++] = 0; +		XColor color; +		Colormap cmap = DefaultColormap(disp, DefaultScreen(disp)); +		if (opt.image_bg) +			XAllocNamedColor(disp, cmap, (char*) opt.image_bg, &color, &color); +		else +			XAllocNamedColor(disp, cmap, "black", &color, &color);  		if (scaled) {  			pmap_d1 = XCreatePixmap(disp, root, scr->width, scr->height, depth);  #ifdef HAVE_LIBXINERAMA  			if (opt.xinerama_index >= 0) { -				if (opt.image_bg == IMAGE_BG_WHITE) -					gcval.foreground = WhitePixel(disp, DefaultScreen(disp)); -				else -					gcval.foreground = BlackPixel(disp, DefaultScreen(disp)); +				gcval.foreground = color.pixel;  				gc = XCreateGC(disp, root, GCForeground, &gcval);  				XFillRectangle(disp, pmap_d1, gc, 0, 0, scr->width, scr->height);  				XFreeGC(disp, gc); @@ -403,16 +363,12 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled,  #endif			/* HAVE_LIBXINERAMA */  				feh_wm_set_bg_scaled(pmap_d1, im, use_filelist,  					0, 0, scr->width, scr->height); -			fehbg = estrjoin(" ", "feh", fehbg_args, "--bg-scale", filbuf, NULL);  		} else if (centered) {  			D(("centering\n"));  			pmap_d1 = XCreatePixmap(disp, root, scr->width, scr->height, depth); -			if (opt.image_bg == IMAGE_BG_WHITE) -				gcval.foreground = WhitePixel(disp, DefaultScreen(disp)); -			else -				gcval.foreground = BlackPixel(disp, DefaultScreen(disp)); +			gcval.foreground = color.pixel;  			gc = XCreateGC(disp, root, GCForeground, &gcval);  			XFillRectangle(disp, pmap_d1, gc, 0, 0, scr->width, scr->height); @@ -433,18 +389,13 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled,  			XFreeGC(disp, gc); -			fehbg = estrjoin(" ", "feh", fehbg_args, bgfill, "--bg-center", filbuf, NULL); -  		} else if (filled == 1) {  			pmap_d1 = XCreatePixmap(disp, root, scr->width, scr->height, depth);  #ifdef HAVE_LIBXINERAMA  			if (opt.xinerama_index >= 0) { -				if (opt.image_bg == IMAGE_BG_WHITE) -					gcval.foreground = WhitePixel(disp, DefaultScreen(disp)); -				else -					gcval.foreground = BlackPixel(disp, DefaultScreen(disp)); +				gcval.foreground = color.pixel;  				gc = XCreateGC(disp, root, GCForeground, &gcval);  				XFillRectangle(disp, pmap_d1, gc, 0, 0, scr->width, scr->height);  				XFreeGC(disp, gc); @@ -464,15 +415,10 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled,  				feh_wm_set_bg_filled(pmap_d1, im, use_filelist  					, 0, 0, scr->width, scr->height); -			fehbg = estrjoin(" ", "feh", fehbg_args, "--bg-fill", filbuf, NULL); -  		} else if (filled == 2) {  			pmap_d1 = XCreatePixmap(disp, root, scr->width, scr->height, depth); -			if (opt.image_bg == IMAGE_BG_WHITE) -				gcval.foreground = WhitePixel(disp, DefaultScreen(disp)); -			else -				gcval.foreground = BlackPixel(disp, DefaultScreen(disp)); +			gcval.foreground = color.pixel;  			gc = XCreateGC(disp, root, GCForeground, &gcval);  			XFillRectangle(disp, pmap_d1, gc, 0, 0, scr->width, scr->height); @@ -493,29 +439,85 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled,  			XFreeGC(disp, gc); -			fehbg = estrjoin(" ", "feh", fehbg_args, bgfill, "--bg-max", filbuf, NULL); -  		} else {  			if (use_filelist)  				feh_wm_load_next(&im);  			w = gib_imlib_image_get_width(im);  			h = gib_imlib_image_get_height(im);  			pmap_d1 = XCreatePixmap(disp, root, w, h, depth); -			gib_imlib_render_image_on_drawable(pmap_d1, im, 0, 0, 1, 0, 0); -			fehbg = estrjoin(" ", "feh --bg-tile", filbuf, NULL); +			gib_imlib_render_image_on_drawable(pmap_d1, im, 0, 0, 1, 1, 0);  		} -		if (fehbg && !opt.no_fehbg) { +		if (!opt.no_fehbg) {  			home = getenv("HOME");  			if (home) {  				FILE *fp;  				char *path; +				char *absolute_path;  				struct stat s; +				gib_list *filelist_pos = filelist;  				path = estrjoin("/", home, ".fehbg", NULL);  				if ((fp = fopen(path, "w")) == NULL) {  					weprintf("Can't write to %s", path);  				} else { -					fprintf(fp, "#!/bin/sh\n%s\n", fehbg); +					fputs("#!/bin/sh\n", fp); +					fputs(cmdargv[0], fp); +					fputs(" --bg-", fp); +					if (centered) +						fputs("center", fp); +					else if (scaled) +						fputs("scale", fp); +					else if (filled == 1) +						fputs("fill", fp); +					else if (filled == 2) +						fputs("max", fp); +					else +						fputs("tile", fp); +					if (opt.image_bg) { +						fputs(" --image-bg ", fp); +						fputs(shell_escape(opt.image_bg), fp); +					} +#ifdef HAVE_LIBXINERAMA +					if (opt.xinerama) { +						if (opt.xinerama_index >= 0) { +							fprintf(fp, " --xinerama-index %d", opt.xinerama_index); +						} +					} +					else { +						fputs(" --no-xinerama", fp); +					} +#endif			/* HAVE_LIBXINERAMA */ +					if (opt.geom_flags & XValue) { +						fprintf(fp, " --geometry %c%d", +								opt.geom_flags & XNegative ? '-' : '+', +								opt.geom_flags & XNegative ? abs(opt.geom_x) : opt.geom_x); +						if (opt.geom_flags & YValue) { +							fprintf(fp, "%c%d", +									opt.geom_flags & YNegative ? '-' : '+', +									opt.geom_flags & YNegative ? abs(opt.geom_y) : opt.geom_y); +						} +					} +					if (opt.force_aliasing) { +						fputs(" --force-aliasing", fp); +					} +					fputc(' ', fp); +					if (use_filelist) { +						for (int i = 0; i < cmdargc; i++) { +							if (filelist_pos && !strcmp(FEH_FILE(filelist_pos->data)->filename, cmdargv[i])) { +								/* argument is a file */ +								absolute_path = feh_absolute_path(cmdargv[i]); +								fputs(shell_escape(absolute_path), fp); +								filelist_pos = filelist_pos->next; +								free(absolute_path); +								fputc(' ', fp); +							} +						} +					} else if (fil) { +						absolute_path = feh_absolute_path(fil); +						fputs(shell_escape(absolute_path), fp); +						free(absolute_path); +					} +					fputc('\n', fp);  					fclose(fp);  					stat(path, &s);  					if (chmod(path, s.st_mode | S_IXUSR | S_IXGRP) != 0) { @@ -525,8 +527,6 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled,  				free(path);  			}  		} -		 -		free(fehbg);  		/* create new display, copy pixmap to new display */  		disp2 = XOpenDisplay(NULL); @@ -779,10 +779,11 @@ void enl_ipc_send(char *str)  	return;  } -static sighandler_t *enl_ipc_timeout(int sig) +void enl_ipc_timeout(int sig)  { -	timeout = 1; -	return((sighandler_t *) sig); +	if (sig == SIGALRM) +		timeout = 1; +	return;  }  char *enl_wait_for_reply(void) @@ -842,7 +843,8 @@ char *enl_ipc_get(const char *msg_data)  char *enl_send_and_wait(char *msg)  {  	char *reply = IPC_TIMEOUT; -	sighandler_t old_alrm; +	struct sigaction e17_sh, feh_sh; +	sigset_t e17_ss;  	/*  	 * Shortcut this func and return IPC_FAKE @@ -861,7 +863,19 @@ char *enl_send_and_wait(char *msg)  				sleep(1);  		}  	} -	old_alrm = (sighandler_t) signal(SIGALRM, (sighandler_t) enl_ipc_timeout); + +	if ((sigemptyset(&e17_ss) == -1) || sigaddset(&e17_ss, SIGALRM) == -1) { +		weprintf("Failed to set up temporary E17 signal masks"); +		return reply; +	} +	e17_sh.sa_handler = enl_ipc_timeout; +	e17_sh.sa_mask = e17_ss; +	e17_sh.sa_flags = 0; +	if (sigaction(SIGALRM, &e17_sh, &feh_sh) == -1) { +		weprintf("Failed to set up temporary E17 signal handler"); +		return reply; +	} +  	for (; reply == IPC_TIMEOUT;) {  		timeout = 0;  		enl_ipc_send(msg); @@ -873,6 +887,8 @@ char *enl_send_and_wait(char *msg)  			ipc_win = None;  		}  	} -	signal(SIGALRM, old_alrm); +	if (sigaction(SIGALRM, &feh_sh, NULL) == -1) { +		weprintf("Failed to restore signal handler"); +	}  	return(reply);  } diff --git a/src/wallpaper.h b/src/wallpaper.h index 0921129..02a6997 100644 --- a/src/wallpaper.h +++ b/src/wallpaper.h @@ -1,7 +1,7 @@  /* wallpaper.h  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to diff --git a/src/winwidget.c b/src/winwidget.c index c012fc0..4993fb6 100644 --- a/src/winwidget.c +++ b/src/winwidget.c @@ -1,7 +1,7 @@  /* winwidget.c  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -89,7 +89,7 @@ static winwidget winwidget_allocate(void)  	return(ret);  } -winwidget winwidget_create_from_image(Imlib_Image im, char *name, char type) +winwidget winwidget_create_from_image(Imlib_Image im, char type)  {  	winwidget ret = NULL; @@ -103,11 +103,6 @@ winwidget winwidget_create_from_image(Imlib_Image im, char *name, char type)  	ret->w = ret->im_w = gib_imlib_image_get_width(ret->im);  	ret->h = ret->im_h = gib_imlib_image_get_height(ret->im); -	if (name) -		ret->name = estrdup(name); -	else -		ret->name = estrdup(PACKAGE); -  	if (opt.full_screen && (type != WIN_TYPE_THUMBNAIL))  		ret->full_screen = True;  	winwidget_create_window(ret, ret->w, ret->h); @@ -116,7 +111,7 @@ winwidget winwidget_create_from_image(Imlib_Image im, char *name, char type)  	return(ret);  } -winwidget winwidget_create_from_file(gib_list * list, char *name, char type) +winwidget winwidget_create_from_file(gib_list * list, char type)  {  	winwidget ret = NULL;  	feh_file *file = FEH_FILE(list->data); @@ -127,12 +122,8 @@ winwidget winwidget_create_from_file(gib_list * list, char *name, char type)  	ret = winwidget_allocate();  	ret->file = list;  	ret->type = type; -	if (name) -		ret->name = estrdup(name); -	else -		ret->name = estrdup(file->filename); -	if (winwidget_loadimage(ret, file) == 0) { +	if ((winwidget_loadimage(ret, file) == 0) || feh_should_ignore_image(ret->im)) {  		winwidget_destroy(ret);  		return(NULL);  	} @@ -340,11 +331,12 @@ void winwidget_create_window(winwidget ret, int w, int h)  	winwidget_register(ret);  	/* do not scale down a thumbnail list window, only those created from it */ -	if (opt.scale_down && (ret->type != WIN_TYPE_THUMBNAIL)) { +	if (opt.geom_enabled && (ret->type != WIN_TYPE_THUMBNAIL)) {  		opt.geom_w = w;  		opt.geom_h = h;  		opt.geom_flags |= WidthValue | HeightValue;  	} +  	return;  } @@ -399,17 +391,18 @@ void winwidget_setup_pixmaps(winwidget winwid)  			if (winwid->gc == None) {  				XGCValues gcval; -				if (opt.image_bg == IMAGE_BG_WHITE) { -					gcval.foreground = WhitePixel(disp, DefaultScreen(disp)); +				if (!opt.image_bg || !strcmp(opt.image_bg, "default")) { +					gcval.foreground = BlackPixel(disp, DefaultScreen(disp));  					winwid->gc = XCreateGC(disp, winwid->win, GCForeground, &gcval); -				} -				else if (opt.image_bg == IMAGE_BG_CHECKS) { +				} else if (!strcmp(opt.image_bg, "checks")) {  					gcval.tile = feh_create_checks();  					gcval.fill_style = FillTiled;  					winwid->gc = XCreateGC(disp, winwid->win, GCTile | GCFillStyle, &gcval); -				} -				else { -					gcval.foreground = BlackPixel(disp, DefaultScreen(disp)); +				} else { +					XColor color; +					Colormap cmap = DefaultColormap(disp, DefaultScreen(disp)); +					XAllocNamedColor(disp, cmap, (char*) opt.image_bg, &color, &color); +					gcval.foreground = color.pixel;  					winwid->gc = XCreateGC(disp, winwid->win, GCForeground, &gcval);  				}  			} @@ -438,140 +431,65 @@ void winwidget_render_image(winwidget winwid, int resize, int force_alias)  	int sx, sy, sw, sh, dx, dy, dw, dh;  	int calc_w, calc_h;  	int antialias = 0; -	int need_center = winwid->had_resize;  	if (!winwid->full_screen && resize) {  		winwidget_resize(winwid, winwid->im_w, winwid->im_h, 0);  		winwidget_reset_image(winwid);  	} -	/* bounds checks for panning */ -	if (winwid->im_x > winwid->w) -		winwid->im_x = winwid->w; -	if (winwid->im_y > winwid->h) -		winwid->im_y = winwid->h; -  	D(("winwidget_render_image resize %d force_alias %d im %dx%d\n",  	      resize, force_alias, winwid->im_w, winwid->im_h)); -	winwidget_setup_pixmaps(winwid); +	/* winwidget_setup_pixmaps(winwid) resets the winwid->had_resize flag */ +	int had_resize = winwid->had_resize || resize; -	if (!winwid->full_screen && ((gib_imlib_image_has_alpha(winwid->im)) -				     || (opt.geom_flags & (WidthValue | HeightValue)) -				     || (winwid->im_x || winwid->im_y) || (winwid->zoom != 1.0) -				     || (winwid->w > winwid->im_w || winwid->h > winwid->im_h) -				     || (winwid->has_rotated))) -		feh_draw_checks(winwid); - -	if (!winwid->full_screen && opt.zoom_mode -				&& (winwid->zoom == 1.0) && ! (opt.geom_flags & (WidthValue | HeightValue)) -				&& (winwid->w > winwid->im_w) && (winwid->h > winwid->im_h)) -		feh_calc_needed_zoom(&(winwid->zoom), winwid->im_w, winwid->im_h, winwid->w, winwid->h); +	winwidget_setup_pixmaps(winwid); -	/* -	 * In case of a resize, the geomflags (and im_w, im_h) get updated by -	 * the ConfigureNotify handler. -	 */ -	if (need_center && !winwid->full_screen -				&& (opt.geom_flags & (WidthValue | HeightValue)) -				&& ((winwid->w < winwid->im_w) || (winwid->h < winwid->im_h))) -		feh_calc_needed_zoom(&(winwid->zoom), winwid->im_w, winwid->im_h, winwid->w, winwid->h); +	if (had_resize && !opt.keep_zoom_vp && (winwid->type != WIN_TYPE_THUMBNAIL)) { +		double required_zoom = 1.0; +		feh_calc_needed_zoom(&required_zoom, winwid->im_w, winwid->im_h, winwid->w, winwid->h); +		winwid->zoom = opt.default_zoom ? (0.01 * opt.default_zoom) : 1.0; -	if (resize && (winwid->full_screen -                     || (opt.geom_flags & (WidthValue | HeightValue)))) { -		int smaller;	/* Is the image smaller than screen? */ -		int max_w = 0, max_h = 0; +		if ((opt.scale_down || (winwid->full_screen && !opt.default_zoom)) +				&& winwid->zoom > required_zoom) +			winwid->zoom = required_zoom; +		else if ((opt.zoom_mode && required_zoom > 1) +				&& (!opt.default_zoom || required_zoom < winwid->zoom)) +			winwid->zoom = required_zoom; -		if (winwid->full_screen) { -			max_w = scr->width; -			max_h = scr->height; -#ifdef HAVE_LIBXINERAMA -			if (opt.xinerama && xinerama_screens) { -				max_w = xinerama_screens[xinerama_screen].width; -				max_h = xinerama_screens[xinerama_screen].height; +		if (opt.offset_flags & XValue) { +			if (opt.offset_flags & XNegative) { +				winwid->im_x = winwid->w - (winwid->im_w * winwid->zoom) - opt.offset_x; +			} else { +				winwid->im_x = - opt.offset_x * winwid->zoom;  			} -#endif				/* HAVE_LIBXINERAMA */  		} else { -			if (opt.geom_flags & WidthValue) { -				max_w = opt.geom_w; -			} -			if (opt.geom_flags & HeightValue) { -				max_h = opt.geom_h; -			} +			winwid->im_x = (int) (winwid->w - (winwid->im_w * winwid->zoom)) >> 1;  		} - -		D(("Calculating for fullscreen/fixed geom render\n")); -		smaller = ((winwid->im_w < max_w) -			   && (winwid->im_h < max_h)); - -		if (!smaller || opt.zoom_mode) { -			double ratio = 0.0; - -			/* Image is larger than the screen (so wants shrinking), or it's -			   smaller but wants expanding to fill it */ -			ratio = feh_calc_needed_zoom(&(winwid->zoom), winwid->im_w, winwid->im_h, max_w, max_h); - -			/* contributed by Jens Laas <jens.laas@data.slu.se> -			 * What it does: -			 * zooms images by a fixed amount but never larger than the screen. -			 * -			 * Why: -			 * This is nice if you got a collection of images where some -			 * are small and can stand a small zoom. Large images are unaffected. -			 * -			 * When does it work, and how? -			 * You have to be in fullscreen mode _and_ have auto-zoom turned on. -			 *   "feh -FZ --zoom 130 imagefile" will do the trick. -			 *        -zoom percent - the new switch. -			 *                        100 = orignal size, -			 *                        130 is 30% larger. -			 */ -			if (opt.default_zoom) { -				double old_zoom = winwid->zoom; - -				winwid->zoom = 0.01 * opt.default_zoom; -				if (opt.default_zoom != 100) { -					if ((winwid->im_h * winwid->zoom) > max_h) -						winwid->zoom = old_zoom; -					else if ((winwid->im_w * winwid->zoom) > max_w) -						winwid->zoom = old_zoom; -				} - -				winwid->im_x = ((int) -						(max_w - (winwid->im_w * winwid->zoom))) >> 1; -				winwid->im_y = ((int) -						(max_h - (winwid->im_h * winwid->zoom))) >> 1; +		if (opt.offset_flags & YValue) { +			if (opt.offset_flags & YNegative) { +				winwid->im_y = winwid->h - (winwid->im_h * winwid->zoom) - opt.offset_y;  			} else { -				if (ratio > 1.0) { -					/* height is the factor */ -					winwid->im_x = 0; -					winwid->im_y = ((int) -							(max_h - (winwid->im_h * winwid->zoom))) >> 1; -				} else { -					/* width is the factor */ -					winwid->im_x = ((int) -							(max_w - (winwid->im_w * winwid->zoom))) >> 1; -					winwid->im_y = 0; -				} +				winwid->im_y = - opt.offset_y * winwid->zoom;  			}  		} else { -			/* my modification to jens hack, allow --zoom without auto-zoom mode */ -			if (opt.default_zoom) { -				winwid->zoom = 0.01 * opt.default_zoom; -			} else { -				winwid->zoom = 1.0; -			} -			/* Just center the image in the window */ -			winwid->im_x = (int) (max_w - (winwid->im_w * winwid->zoom)) >> 1; -			winwid->im_y = (int) (max_h - (winwid->im_h * winwid->zoom)) >> 1; +			winwid->im_y = (int) (winwid->h - (winwid->im_h * winwid->zoom)) >> 1;  		}  	} -	else if (need_center && !winwid->full_screen -			&& (winwid->type != WIN_TYPE_THUMBNAIL) && !opt.keep_zoom_vp) { -		winwid->im_x = (int) (winwid->w - (winwid->im_w * winwid->zoom)) >> 1; -		winwid->im_y = (int) (winwid->h - (winwid->im_h * winwid->zoom)) >> 1; -	} + +	winwid->had_resize = 0; + +	if (opt.keep_zoom_vp) +		winwidget_sanitise_offsets(winwid); + +	if (!winwid->full_screen && ((gib_imlib_image_has_alpha(winwid->im)) +				     || (opt.geom_flags & (WidthValue | HeightValue)) +				     || (winwid->im_x || winwid->im_y) +				     || (winwid->w > winwid->im_w * winwid->zoom) +				     || (winwid->h > winwid->im_h * winwid->zoom) +				     || (winwid->has_rotated))) +		feh_draw_checks(winwid);  	/* Now we ensure only to render the area we're looking at */  	dx = winwid->im_x; @@ -610,7 +528,7 @@ void winwidget_render_image(winwidget winwid, int resize, int force_alias)  	D(("sx: %d sy: %d sw: %d sh: %d dx: %d dy: %d dw: %d dh: %d zoom: %f\n",  	   sx, sy, sw, sh, dx, dy, dw, dh, winwid->zoom)); -	if ((winwid->zoom != 1.0) && !force_alias && !winwid->force_aliasing) +	if ((winwid->zoom != 1.0 || winwid->has_rotated) && !force_alias && !winwid->force_aliasing)  		antialias = 1;  	D(("winwidget_render(): winwid->im_angle = %f\n", winwid->im_angle)); @@ -642,16 +560,12 @@ void winwidget_render_image(winwidget winwid, int resize, int force_alias)  			feh_draw_info(winwid);  		if (winwid->errstr)  			feh_draw_errstr(winwid); -		if (opt.title && (winwid->type != WIN_TYPE_THUMBNAIL_VIEWER) && -				(winwid->file != NULL)) { -			char *s = slideshow_create_name(FEH_FILE(winwid->file->data), winwid); -			winwidget_rename(winwid, s); -			free(s); -		} else if (opt.thumb_title && (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER) && -				(winwid->file != NULL)) { -			char *s = thumbnail_create_name(FEH_FILE(winwid->file->data), winwid); -			winwidget_rename(winwid, s); -			free(s); +		if (winwid->file != NULL) { +			if (opt.title && winwid->type != WIN_TYPE_THUMBNAIL_VIEWER) { +				winwidget_rename(winwid, feh_printf(opt.title, FEH_FILE(winwid->file->data), winwid)); +			} else if (opt.thumb_title && winwid->type == WIN_TYPE_THUMBNAIL_VIEWER) { +				winwidget_rename(winwid, feh_printf(opt.thumb_title, FEH_FILE(winwid->file->data), winwid)); +			}  		}  	} else if ((opt.mode == MODE_ZOOM) && !antialias)  		feh_draw_zoom(winwid); @@ -710,14 +624,15 @@ Pixmap feh_create_checks(void)  		if (!checks)  			eprintf("Unable to create a teeny weeny imlib image. I detect problems"); -		if (opt.image_bg == IMAGE_BG_WHITE) -			gib_imlib_image_fill_rectangle(checks, 0, 0, 16, 16, 255, 255, 255, 255); -		else if (opt.image_bg == IMAGE_BG_BLACK) -			gib_imlib_image_fill_rectangle(checks, 0, 0, 16, 16, 0, 0, 0, 255); -		else { +		if (!opt.image_bg || !strcmp(opt.image_bg, "default") || !strcmp(opt.image_bg, "checks")) {  			gib_imlib_image_fill_rectangle(checks, 0, 0, 16, 16, 144, 144, 144, 255);  			gib_imlib_image_fill_rectangle(checks, 0, 0,  8,  8, 100, 100, 100, 255);  			gib_imlib_image_fill_rectangle(checks, 8, 8,  8,  8, 100, 100, 100, 255); +		} else { +			XColor color; +			Colormap cmap = DefaultColormap(disp, DefaultScreen(disp)); +			XAllocNamedColor(disp, cmap, (char*) opt.image_bg, &color, &color); +			gib_imlib_image_fill_rectangle(checks, 0, 0, 16, 16, color.red, color.green, color.blue, 255);  		}  		checks_pmap = XCreatePixmap(disp, root, 16, 16, depth); @@ -727,13 +642,6 @@ Pixmap feh_create_checks(void)  	return(checks_pmap);  } -void winwidget_clear_background(winwidget w) -{ -	XSetWindowBackgroundPixmap(disp, w->win, feh_create_checks()); -	/* XClearWindow(disp, w->win); */ -	return; -} -  void feh_draw_checks(winwidget win)  {  	static GC gc = None; @@ -771,8 +679,6 @@ void winwidget_destroy(winwidget winwid)  		free(winwid->name);  	if (winwid->gc)  		XFreeGC(disp, winwid->gc); -	if ((winwid->type == WIN_TYPE_THUMBNAIL_VIEWER) && (winwid->file != NULL)) -		gib_list_free(winwid->file);  	if (winwid->im)  		gib_imlib_free_image_and_decache(winwid->im);  	free(winwid); @@ -968,24 +874,30 @@ void winwidget_resize(winwidget winwid, int w, int h, int force_resize)  	D(("   x %d y %d w %d h %d\n", attributes.x, attributes.y, winwid->w,  		winwid->h)); -    if ((opt.geom_flags & (WidthValue | HeightValue)) && !force_resize) { -        winwid->had_resize = 1; -        return; -    } +	if ((opt.geom_flags & (WidthValue | HeightValue)) && !force_resize) { +		winwid->had_resize = 1; +		return; +	}  	if (winwid && ((winwid->w != w) || (winwid->h != h))) { -		/* winwidget_clear_background(winwid); */  		if (opt.screen_clip) { -            winwid->w = (w > scr_width) ? scr_width : w; -            winwid->h = (h > scr_height) ? scr_height : h; +			double required_zoom = winwid->zoom; +			if (opt.scale_down && !opt.keep_zoom_vp) { +				int max_w = (w > scr_width) ? scr_width : w; +				int max_h = (h > scr_height) ? scr_height : h; +				feh_calc_needed_zoom(&required_zoom, winwid->im_w, winwid->im_h, max_w, max_h); +			} +			int desired_w = winwid->im_w * required_zoom; +			int desired_h = winwid->im_h * required_zoom; +			winwid->w = (desired_w > scr_width) ? scr_width : desired_w; +			winwid->h = (desired_h > scr_height) ? scr_height : desired_h;  		}  		if (winwid->full_screen) { -            XTranslateCoordinates(disp, winwid->win, attributes.root, -                        -attributes.border_width - -                        attributes.x, -                        -attributes.border_width - attributes.y, &tc_x, &tc_y, &dw); -            winwid->x = tc_x; -            winwid->y = tc_y; -            XMoveResizeWindow(disp, winwid->win, tc_x, tc_y, winwid->w, winwid->h); +			XTranslateCoordinates(disp, winwid->win, attributes.root, +						-attributes.border_width - attributes.x, +						-attributes.border_width - attributes.y, &tc_x, &tc_y, &dw); +			winwid->x = tc_x; +			winwid->y = tc_y; +			XMoveResizeWindow(disp, winwid->win, tc_x, tc_y, winwid->w, winwid->h);  		} else  			XResizeWindow(disp, winwid->win, winwid->w, winwid->h); @@ -1089,7 +1001,7 @@ void winwidget_rename(winwidget winwid, char *newname)  void winwidget_free_image(winwidget w)  {  	if (w->im) -		gib_imlib_free_image_and_decache(w->im); +		gib_imlib_free_image(w->im);  	w->im = NULL;  	w->im_w = 0;  	w->im_h = 0; @@ -1113,10 +1025,12 @@ void feh_debug_print_winwid(winwidget w)  void winwidget_reset_image(winwidget winwid)  { -	winwid->zoom = 1.0; -	winwid->old_zoom = 1.0; -	winwid->im_x = 0; -	winwid->im_y = 0; +	if (!opt.keep_zoom_vp) { +		winwid->zoom = 1.0; +		winwid->old_zoom = 1.0; +		winwid->im_x = 0; +		winwid->im_y = 0; +	}  	winwid->im_angle = 0.0;  	winwid->has_rotated = 0;  	return; diff --git a/src/winwidget.h b/src/winwidget.h index b8d777e..4d8fc4b 100644 --- a/src/winwidget.h +++ b/src/winwidget.h @@ -1,7 +1,7 @@  /* winwidget.h  Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2011 Daniel Friesel. +Copyright (C) 2010-2018 Daniel Friesel.  Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to @@ -150,12 +150,11 @@ void winwidget_get_geometry(winwidget winwid, int *rect);  int winwidget_get_width(winwidget winwid);  int winwidget_get_height(winwidget winwid);  winwidget winwidget_get_from_window(Window win); -winwidget winwidget_create_from_file(gib_list * filename, char *name, char type); -winwidget winwidget_create_from_image(Imlib_Image im, char *name, char type); +winwidget winwidget_create_from_file(gib_list * filename, char type); +winwidget winwidget_create_from_image(Imlib_Image im, char type);  void winwidget_rename(winwidget winwid, char *newname);  void winwidget_destroy(winwidget winwid);  void winwidget_create_window(winwidget ret, int w, int h); -void winwidget_clear_background(winwidget w);  Pixmap feh_create_checks(void);  double feh_calc_needed_zoom(double *zoom, int orig_w, int orig_h, int dest_w, int dest_h);  void feh_debug_print_winwid(winwidget winwid); | 
