summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Willner <sven.willner@gmail.com>2018-09-13 15:47:18 +0200
committerSven Willner <sven.willner@gmail.com>2018-09-13 15:47:18 +0200
commit4ca5b177bbaf656611dd253d7c8e37317b5b186f (patch)
tree5f66934df56dfcbe11364bda57899d078511c3c8
parent3671b53046afbeced26162fc413fcfb7971116b9 (diff)
parent9241e8faa78cc02c08537ed0bd7b236d172c3ed7 (diff)
Merge branch 'master' of github.com:derf/feh
-rw-r--r--.travis.yml29
-rw-r--r--COPYING2
-rw-r--r--ChangeLog159
-rw-r--r--Makefile5
-rw-r--r--README.md3
-rw-r--r--config.mk16
-rw-r--r--man/Makefile1
-rw-r--r--man/feh.pre755
-rw-r--r--src/Makefile40
-rw-r--r--src/collage.c14
-rw-r--r--src/debug.h2
-rw-r--r--src/events.c102
-rw-r--r--src/feh.h19
-rw-r--r--src/feh_png.c18
-rw-r--r--src/feh_png.h4
-rw-r--r--src/filelist.c42
-rw-r--r--src/gib_hash.c1
-rw-r--r--src/gib_list.c1
-rw-r--r--src/help.raw9
-rw-r--r--src/imlib.c248
-rw-r--r--src/index.c27
-rw-r--r--src/index.h2
-rw-r--r--src/keyevents.c533
-rw-r--r--src/list.c4
-rw-r--r--src/main.c63
-rw-r--r--src/menu.c2
-rw-r--r--src/menu.h2
-rw-r--r--src/multiwindow.c20
-rw-r--r--src/options.c82
-rw-r--r--src/options.h166
-rw-r--r--src/signals.c16
-rw-r--r--src/signals.h2
-rw-r--r--src/slideshow.c182
-rw-r--r--src/structs.h2
-rw-r--r--src/thumbnail.c64
-rw-r--r--src/thumbnail.h2
-rw-r--r--src/timers.c2
-rw-r--r--src/utils.c25
-rw-r--r--src/utils.h1
-rw-r--r--src/wallpaper.c242
-rw-r--r--src/wallpaper.h2
-rw-r--r--src/winwidget.c268
-rw-r--r--src/winwidget.h7
-rw-r--r--test/list/custom8
-rwxr-xr-xtest/mandoc.t13
-rw-r--r--test/nx_action/loadable_action8
-rw-r--r--test/nx_action/loadable_naction8
-rw-r--r--test/nx_action/unloadable_action8
-rw-r--r--test/nx_action/unloadable_naction8
49 files changed, 1864 insertions, 1375 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..f59e68c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,29 @@
+language: c
+addons:
+ apt:
+ packages:
+ - libcurl4-openssl-dev
+ - libx11-dev
+ - libxt-dev
+ - libimlib2-dev
+ - libxinerama-dev
+ - libjpeg-progs
+ - libtest-command-perl
+ - libtest-simple-perl
+ - libexif-dev
+ - libexif12
+script:
+ - make
+ - make test
+compiler:
+ - clang
+ - gcc
+env:
+ - default=1
+ - app=1
+ - curl=0
+ - exif=1
+ - help=1
+ - stat64=1
+ - verscmp=0
+ - xinerama=0
diff --git a/COPYING b/COPYING
index a71c9bd..5d6b707 100644
--- a/COPYING
+++ b/COPYING
@@ -1,5 +1,5 @@
Copyright (C) 1999,2000 Tom Gilbert.
-Copyright (C) 2010-2016 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/ChangeLog b/ChangeLog
index 243c73e..901afc0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,158 @@
+Tue, 17 Jul 2018 17:33:10 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.27.1
+ * Fix feh occasionally becoming unresponsive when asked to terminate
+ via SIGINT/SIGQUIT/SIGTERM (based on a patch by
+ <https://github.com/giladogit>)
+ * Fix --keep-zoom-vp issues introduced in 2.27
+ (patch by <https://github.com/ulteq>)
+
+Thu, 28 Jun 2018 17:26:54 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.27
+ * Fix size_to_image ("w") command when both --scale-down and --keep-zoom-vp
+ are enabled
+ * Fix --auto-zoom not being triggered on window resize events when
+ --scale-down is enabled
+ * Fix --auto-zoom conflicting with manual zoom
+ * Fix feh_draw_checks not taking the zoom level into account properly
+ * Prevent --zoom <percent> from blocking --scale-down in fullscreen / fixed
+ geometry mode
+ * Prevent --keep-zoom-vp from blocking the dynamic window resizing
+ mechanism
+ * Prevent automatic recalculation of the zoom ratio when --keep_zoom_vp
+ is enabled
+ * All patches provided by <https://github.com/ulteq>. Thanks a lot!
+
+Tue, 26 Jun 2018 10:33:04 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.26.4
+ * Correctly save --bg-max in ~/.fehbg (patch by Sebastian Bickerle)
+
+Fri, 18 May 2018 22:58:02 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.26.3
+ * Properly escape --image-bg argument in ~/.fehbg (broken in 2.26.1)
+
+Sat, 12 May 2018 16:33:56 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.26.2
+ * Show correct filelist position in windows opened from thumbnail mode.
+ Note that navigation is still not supported in those windows
+ * Improve support for key input from stdin
+ * Do not push menus off the screen when hitting screen limits
+
+Fri, 11 May 2018 15:11:17 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.26.1
+ * Restore pre-2.21 ~/.fehbg behaviour. This fixes nondeterministic
+ wallpaper setting when using --bg-* --randomize, issues when specifying
+ --theme both in ~/.fehbg and on the commandline, and possibly other
+ edge cases
+ * Fix /tmp being cluttered with temporary ImageMagick files when using
+ --magick-timeout and a conversion takes longer than allowed
+
+Thu, 19 Apr 2018 21:43:12 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.26
+ * Save absolute file paths in ~/.fehbg, similar to the behaviour prior to
+ feh 2.21
+ * Add %g (window dimensions) and %Z (precise zoom level) format specifiers
+ * Improve -z/--randomize randomness
+
+Wed, 07 Mar 2018 17:49:52 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.25.1
+ * Fix compilation issues when using CFLAGS=-m64 on some gcc versions
+ * Re-render current image when toggle_fixed_geometry is input
+
+Sun, 04 Mar 2018 08:53:50 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.25
+ * Add --version-sort option to enable natural sorting of file and directory
+ names. This requires a libc with strverscmp support, which is a
+ non-POSIX GNU extension. Use the new build flag `verscmp=0` to disable
+ this feature on systems which do not ship strverscmp
+ (patch by ulteq)
+ * Allow arbitrary X11 colors as -B/--image-bg argument (patch by ulteq)
+ * Improve --image-bg support and transparency handling in --bg-* mode
+ * Respect --geometry settings in --bg-fill mode
+ * Add keybinding toggle_auto_zoom (default "Z") to toggle --auto-zoom
+ * Fix filelists specified by -f/--filelist not being reloaded when using
+ --reload
+
+Mon, 26 Feb 2018 21:41:38 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.24
+ * Improve performance when using --{max,min}-dimension in slideshow mode
+ (patch by ulteq)
+ * Fix crash when using %m format specifier in slideshow mode
+ (introduced in feh 2.23.1)
+
+
+Mon, 12 Feb 2018 22:11:55 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.23.2
+ * Fix support for nested quotes in .confeg/feh/themes
+
+Wed, 31 Jan 2018 17:38:25 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.23.1
+ * The Makefile no longer honors CPPFLAGS and instead consistently uses
+ CFLAGS for user-provided include paths
+ * Fix %u format specifier in multiwindow and list modes (patch by ulteq)
+ * Minor performance improvements (patches by ulteq)
+ * Stability improvements when using --magick-timeout (patch by ulteq)
+
+Thu, 28 Dec 2017 19:26:29 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.23
+ * Fix broken thumbnail/index windows when using --scale-down
+ * Use Imlib2 in-memory image cache (default cache size: 4MiB). This allows
+ for significant performance improvements especially in small slideshows
+ * Add --cache-size option to set Imlib2 image cache size
+
+Tue, 07 Nov 2017 17:36:26 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.22.2
+ * Fix HTTPS certificate errors on some systems (broken in 2.22)
+
+Tue, 07 Nov 2017 07:51:48 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.22.1
+ * Allow ~/.fehbg to be sourced (instead of executed) from other shell
+ scripts again (broken in 2.22)
+
+Sat, 04 Nov 2017 14:55:38 +0100 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.22
+ * Add support for CURL_CA_BUNDLE environment variable when loading images
+ via HTTPS
+ * Fix ~/.fehbg not being updated when setting a wallpaper via menu
+ (broken in 2.21)
+
+Sat, 07 Oct 2017 12:14:17 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.21
+ * Add toggle_fixed_geometry ('g') key binding to toggle window auto-resize
+ * Improve control via terminal input
+ * Fix crash (segmentation fault) when using feh -O in non-index mode
+ * Fix --force-aliasing (and possibly other options) missing from ~/.fehbg
+ when using them for background setting
+
+Thu, 07 Sep 2017 20:20:11 +0200 Daniel Friesel <derf+feh@finalrewind.org>
+
+* Release v2.20
+ * Fix clang/gcc warnings (Patches by orbea)
+ * Add support for control via terminal input. feh will read key presses
+ from the controlling terminal and handle them like X11 key presses
+ inside the feh window. Note that at the moment, only lower / upper case
+ ASCII letters and a very small set of additional keys are supported.
+ * Fix broken ImageMagick support (see --magick-timeout) when using some
+ ImageMagick versions <https://github.com/derf/feh/issues/323>
+ * Remove images from the filelist if they were removed by executing a
+ user-defined action <https://github.com/derf/feh/issues/322>
+
Mon, 21 Aug 2017 19:04:00 +0200 Daniel Friesel <derf+feh@finalrewind.org>
* Release v2.19.3
@@ -129,7 +284,7 @@ Thu, 28 Apr 2016 11:41:04 +0200 Daniel Friesel <derf+feh@finalrewind.org>
size which will not be updated when changing images (as was the case in
feh < 2.15). This may or may not be fixed in the future.
-Sat, 16 Apr 2016 18:32:38 +0200 Daniel Frisel <derf+feh@finalrewind.org>
+Sat, 16 Apr 2016 18:32:38 +0200 Daniel Friesel <derf+feh@finalrewind.org>
* Release v2.15.2
* Fix --keep-zoom-vp not keeping the viewport x/y offsets (broken by 2.15)
@@ -701,7 +856,7 @@ Fri, 25 Jun 2010 16:07:20 +0200 Daniel Friesel <derf@chaosdorf.de>
malicious URLs containing shell metacharacters (but only if those URLs
led to a valid file)
* Don't add ?randomnumber to URLs when downloading them, it confuses some
- servers and is not really neccessary in general
+ servers and is not really necessary in general
Thu Jun 10 12:12:04 CEST 2010 Daniel Friesel <derf@chaosdorf.de>
diff --git a/Makefile b/Makefile
index 5d369bc..925e3fb 100644
--- a/Makefile
+++ b/Makefile
@@ -58,18 +58,21 @@ install-doc:
install-bin:
@echo installing executables to ${bin_dir}
@mkdir -p ${bin_dir}
- @cp src/feh ${bin_dir}
+ @cp src/feh ${bin_dir}/feh.tmp
+ @mv ${bin_dir}/feh.tmp ${bin_dir}/feh
@chmod 755 ${bin_dir}/feh
install-font:
@echo installing fonts to ${font_dir}
@mkdir -p ${font_dir}
+ @chmod 755 ${font_dir}
@cp share/fonts/* ${font_dir}
@chmod 644 ${font_dir}/*
install-img:
@echo installing images to ${image_dir}
@mkdir -p ${image_dir}
+ @chmod 755 ${image_dir}
@cp share/images/* ${image_dir}
@chmod 644 ${image_dir}/*
diff --git a/README.md b/README.md
index 63659c0..a90513e 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+[![build status](https://travis-ci.org/derf/feh.svg?branch=master)](https://travis-ci.org/derf/feh)
+
# feh
Imlib2 based image viewer
---
@@ -84,6 +86,7 @@ Available flags are:
| help | 0 | include help text (refers to the manpage otherwise) |
| inotify | 0 | enable inotify, needed for `--auto-reload` |
| stat64 | 0 | Support CIFS shares from 64bit hosts on 32bit machines |
+| verscmp | 1 | Support naturing sorting (`--version-sort`). Requires a GNU-compatible libc exposing `strverscmp` |
| xinerama | 1 | Support Xinerama/XRandR multiscreen setups |
So, by default **libcurl** and **Xinerama** are enabled, the rest is disabled.
diff --git a/config.mk b/config.mk
index c133e46..2fd36f0 100644
--- a/config.mk
+++ b/config.mk
@@ -5,14 +5,18 @@ app ?= 0
cam ?= 0
curl ?= 1
debug ?= 0
+exif ?= 0
help ?= 0
+verscmp ?= 1
xinerama ?= 1
-exif ?= 0
# Prefix for all installed files
PREFIX ?= /usr/local
ICON_PREFIX ?= ${DESTDIR}${PREFIX}/share/icons
+# icons in /usr/share/local/icons (and other prefixes != /usr) are not
+# generally supported. So ignore PREFIX and always install icons into
+# /usr/share/icons if the user wants to install feh on their local machine.
ifeq (${app},1)
ICON_PREFIX = /usr/share/icons
endif
@@ -34,6 +38,9 @@ scalable_icon_dir = ${icon_dir}/scalable/apps
CFLAGS ?= -g -O2
CFLAGS += -Wall -Wextra -pedantic
+# Settings for glibc >= 2.19 - may need to be adjusted for other systems
+CFLAGS += -std=c11 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700
+
ifeq (${curl},1)
CFLAGS += -DHAVE_LIBCURL
LDLIBS += -lcurl
@@ -57,6 +64,13 @@ ifeq (${stat64},1)
CFLAGS += -D_FILE_OFFSET_BITS=64
endif
+ifeq (${verscmp},1)
+ CFLAGS += -DHAVE_VERSCMP
+ MAN_VERSCMP = enabled
+else
+ MAN_VERSCMP = disabled
+endif
+
ifeq (${xinerama},1)
CFLAGS += -DHAVE_LIBXINERAMA
LDLIBS += -lXinerama
diff --git a/man/Makefile b/man/Makefile
index 3be07e3..acf8629 100644
--- a/man/Makefile
+++ b/man/Makefile
@@ -13,6 +13,7 @@ all: ${TARGETS}
-e 's/\$$MAN_DEBUG\$$/${MAN_DEBUG}/' \
-e 's/\$$MAN_EXIF\$$/${MAN_EXIF}/' \
-e 's/\$$MAN_INOTIFY\$$/${MAN_INOTIFY}/' \
+ -e 's/\$$MAN_VERSCMP\$$/${MAN_VERSCMP}/' \
-e 's/\$$MAN_XINERAMA\$$/${MAN_XINERAMA}/' \
< ${@:.1=.pre} > $@
diff --git a/man/feh.pre b/man/feh.pre
index b258b2b..e1ade10 100644
--- a/man/feh.pre
+++ b/man/feh.pre
@@ -13,7 +13,7 @@
.
.Nm
.Op Ar options
-.Op Ar files No | Ar directories No | Ar URLs ...
+.Op Ar files | Ar directories | Ar URLs ...
.
.
.Sh VERSION
@@ -24,7 +24,8 @@ $VERSION$
.
.Pp
.
-Compile-time switches: libcurl support $MAN_CURL$, Xinerama support
+Compile-time switches: libcurl support $MAN_CURL$, natural sorting support
+$MAN_VERSCMP$, Xinerama support
$MAN_XINERAMA$, builtin EXIF support $MAN_EXIF$, inotify support
$MAN_INOTIFY$$MAN_DEBUG$
.
@@ -32,9 +33,9 @@ $MAN_INOTIFY$$MAN_DEBUG$
.Sh DESCRIPTION
.
.Nm
-is a mode-based image viewer. It is especially aimed at command line users who
-need a fast image viewer without huge GUI dependencies, though it can also be
-started by
+is a mode-based image viewer.
+It is especially aimed at command line users who need a fast image viewer
+without huge GUI dependencies, though it can also be started by
.Pq graphical
file managers to view an image.
By default
@@ -46,7 +47,8 @@ displays all files in the current directory.
.
.Nm
supports filelists, various image sorting modes, image captions, HTTP and more.
-Configurable keyboard and mouse shortcuts are used to control it.
+It can be controlled by configurable keyboard and mouse shortcuts, terminal
+input and signals.
.
.Pp
.
@@ -74,8 +76,9 @@ options.
.
.Pp
.
-Slideshow mode is the default. It opens a window and displays the first
-image in it; the slideshow position can be advanced
+Slideshow mode is the default.
+It opens a window and displays the first image in it;
+the slideshow position can be advanced
.Pq or otherwise changed
using keyboard and mouse shortcuts.
In slideshow mode, images can be deleted either from the filelist or from the
@@ -86,14 +89,17 @@ An image can also be read from stdin via
.
.Pp
.
-Montage mode forms a montage from the filelist. The resulting image can be
-viewed or saved, and its size can be limited by height, width or both.
+Montage mode forms a montage from the filelist.
+The resulting image can be viewed or saved,
+and its size can be limited by height, width or both.
.
.Pp
.
-Index mode forms an index print from the filelist. Image thumbnails are shown
-along with the filename, filesize and pixel size, printed using a truetype
-font of your choice. The resulting image can be viewed or saved, and its size
+Index mode forms an index print from the filelist.
+Image thumbnails are shown along with the filename,
+filesize and pixel size, printed using a truetype
+font of your choice.
+The resulting image can be viewed or saved, and its size
can be limited by height, width or both.
.
.Pp
@@ -104,35 +110,45 @@ the selected image in a new window.
.Pp
.
Multiwindow mode shows images in multiple windows, instead of as a slideshow
-in one window. Don't use with a large filelist ;)
+in one window.
+Don't use with a large filelist ;)
.
.Pp
.
-List mode doesn't display images. Instead, it outputs an
+List mode doesn't display images.
+Instead, it outputs an
.Cm ls Ns No - Ns style
listing of the files in the filelist, including image info such as size, number
-of pixels, type, etc. There is also a Customlist mode which prints image info
+of pixels, type, etc.
+There is also a Customlist mode which prints image info
in a custom format specified by a printf-like format string.
.
.Pp
.
.Nm
can also list either all the loadable files in a filelist or all the
-unloadable files. This is useful for preening a directory.
+unloadable files.
+This is useful for preening a directory.
.
.
.Sh SUPPORTED FORMATS
.
.Nm
can open any format supported by Imlib2, most notably jpeg, png,
-pnm, tiff, and bmp. The gif format is also supported, but only for static
-images. In case of animations, only the first frame will be shown.
+pnm, tiff, and bmp.
+The gif format is also supported, but only for static images.
+In case of animations, only the first frame will be shown.
.
If the convert binary
.Pq supplied by ImageMagick
is available, it also has limited support for many other filetypes, such as
-svg, xcf and otf. Use
-.Cm --magick-timeout Ar num
+svg, xcf and otf.
+If dcraw is available,
+.Nm
+also supports RAW files provided by cameras and will display the embedded
+thumbnails.
+Use
+.Cm --conversion-timeout Ar num
with a non-negative value to enable it.
.
.
@@ -142,11 +158,13 @@ with a non-negative value to enable it.
.
.It Cm -A , --action Oo Ar flag Oc Ns Oo [ Ar title ] Oc Ns Ar action
.
-Specify a shell command as an action to perform on the image. In slideshow or
-multiwindow mode, the action will be run when the action_0 key is pressed, in
-list mode, it will be run for each file. In loadable/unloadable mode, it will
-be run for each loadable/unloadable file, respectively. In thumbnail mode,
-clicking on an image will cause the action to run instead of opening the image.
+Specify a shell command as an action to perform on the image.
+In slideshow or multiwindow mode, the action will be run when
+the action_0 key is pressed, in list mode, it will be run for each file.
+In loadable/unloadable mode, it will be run for each loadable/unloadable
+file, respectively.
+In thumbnail mode, clicking on an image will cause the action to run instead
+of opening the image.
.
.Pp
.
@@ -163,7 +181,7 @@ after
executing the action.
.
If
-.No [ Ar title ]
+.Ar [ title ]
is specified
.Pq note the literal Qo \&[ Qc and Qo ] Qc ,
.Cm --draw-actions
@@ -171,10 +189,12 @@ will display
.Ar title
instead of
.Ar action
-in the action list. Note that
+in the action list.
+Note that
.Ar title
-must not start with a space. If it does, the action is handled as if it did
-not have a title. This special case exists for backwards compatibility reasons
+must not start with a space.
+If it does, the action is handled as if it did not have a title.
+This special case exists for backwards compatibility reasons
and makes sure that actions like
.Qq \&[ -L %F \&] && foo
still work.
@@ -182,25 +202,22 @@ still work.
.
.Pp
.
-The action will be executed by /bin/sh. Use format specifiers to refer to
-image info, see
+The action will be executed by /bin/sh.
+Use format specifiers to refer to image info, see
.Sx FORMAT SPECIFIERS
-for details. Example usage:
+for details.
+Example usage:
.Qq feh -A Qo mv ~/images/%N Qc * .
.
.It Cm --action1 No .. Cm --action9 Oo Ar flag Oc Ns Oo [ Ar title ] Oc Ns Ar action
.
Extra actions which can be set and triggered using the appropriate number key.
.
-.It Cm --auto-reload
-.
-.Pq only if compiled with inotify=1
-automatically reload shown image if file was changed
-.
.It Cm --auto-rotate
.
-.Pq only if compiled with exif=1
-Automatically rotate images based on EXIF data. Does not alter the image files.
+.Pq optional feature, $MAN_EXIF$ in this build
+Automatically rotate images based on EXIF data.
+Does not alter the image files.
.
.It Cm -Z , --auto-zoom
.
@@ -210,19 +227,34 @@ Zoom pictures to screen size in fullscreen / fixed geometry mode.
.
Create borderless windows.
.
+.It Cm --cache-size Ar size
+.
+Set Imlib2 in-memory cache to
+.Ar size
+MiB.
+A higher cache size can significantly improve performance especially for small
+slide shows, however at the cost of increased memory consumption.
+.Ar size
+must be between 0 and 2048 MiB and defaults to 4.
+.
.It Cm -P , --cache-thumbnails
.
-Enable thumbnail caching in
-.Pa ~/.thumbnails .
-Only works with thumbnails <= 256x256 pixels.
+Enable thumbnail caching.
+Thumbnails are saved in
+.Pa $XDG_CACHE_HOME/thumbnails ,
+which defaults to
+.Pa ~/.cache/thumbnails .
+Note that thumbnails are only cached if the configured thumbnail size does
+not exceed 256x256 pixels.
.
.It Cm -K , --caption-path Ar path
.
-Path to directory containing image captions. This turns on caption viewing,
-and if captions are found in
+Path to directory containing image captions.
+This turns on caption viewing, and if captions are found in
.Ar path ,
which is relative to the directory of each image, they are overlayed on the
-displayed image. E.g. with caption path
+displayed image.
+E.g. with caption path
.Qq captions/ ,
and viewing image
.Qq images/foo.jpg ,
@@ -233,22 +265,17 @@ the caption will be looked for in
.
Don't display images, print image info according to
.Ar format
-instead. See
+instead.
+See
.Sx FORMAT SPECIFIERS .
.
-.It Cm --cycle-once
-.
-Exit
-.Nm
-after one loop through the slideshow.
-.
.It Cm -G , --draw-actions
.
Draw the defined actions and what they do at the top-left of the image.
.
.It Cm --draw-exif
.
-.Pq only if compiled with exif=1
+.Pq optional feature, $MAN_EXIF$ in this build
display some EXIF information in the bottom left corner, similar to using
.Cm --info
with exiv2 / exifgrep .
@@ -265,7 +292,8 @@ on a semi-transparent background to improve their readability
.
.It Cm -f , --filelist Ar file
.
-This option is similar to the playlists used by music software. If
+This option is similar to the playlists used by music software.
+If
.Ar file
exists, it will be read for a list of files to load, in the order they appear.
The format is a list of image filenames, absolute or relative to the current
@@ -276,7 +304,8 @@ directory, one filename per line.
If
.Ar file
doesn't exist, it will be created from the internal filelist at the end of a
-viewing session. This is best used to store the results of complex sorts
+viewing session.
+This is best used to store the results of complex sorts
.Pq Cm -Spixels No for example
for later viewing.
.
@@ -288,7 +317,8 @@ will be saved to
.Ar file
when
.Nm
-exits. You can add files to filelists by specifying them on the command line
+exits.
+You can add files to filelists by specifying them on the command line
when also specifying the list.
.
.Pp
@@ -302,8 +332,9 @@ will read the filelist from its standard input.
.
.It Cm -e , --font Ar font
.
-Set global font. Should be a truetype font, resident in the current directory
-or the font directory, and should be defined in the form fontname/points, like
+Set global font.
+Should be a truetype font, resident in the current directory or the font
+directory, and should be defined in the form fontname/points, like
.Qq myfont/12 .
.
.It Cm -C , --fontpath Ar path
@@ -331,7 +362,8 @@ Note: This option needs to load all images to calculate the dimensions of the
.Nm
window, so when using it with many files it will take a while before a
.Nm
-window is visible. Use
+window is visible.
+Use
.Cm --preload
to get a progress bar.
.
@@ -342,7 +374,8 @@ Note that in this mode, large images will always be scaled down to fit the
screen,
.Cm --zoom Ar zoom
only affects smaller images and never scales larger than necessary to fit the
-screen size. The only exception is a
+screen size.
+The only exception is a
.Ar zoom
of 100, in which case images will always be shown at 100% zoom, no matter
their dimensions.
@@ -351,20 +384,22 @@ their dimensions.
.
When combined with
.Cm --thumbnails ,
-this option only affects images opened from the thumbnail overview. The
-thumbnail list itself will still be windowed.
+this option only affects images opened from the thumbnail overview.
+The thumbnail list itself will still be windowed.
.
-.It Cm -g , --geometry Oo Ar width No x Ar height Oc Op + Ar x No + Ar y
+.It Cm -g , --geometry Ar width Cm x Ar height | Cm + Ar x Cm + Ar y | Ar width Cm x Ar height Cm + Ar x Cm + Ar y
.
-Limit (and don't change) the window size. Takes an X-style geometry
+Limit (and don't change) the window size.
+Takes an X-style geometry
.Ar string
like 640x480 with optional +x+y window offset.
-Note that larger images will be zoomed out to fit, but you can see them at 1:1
-by clicking the zoom button.
+Use
+.Cm --scale-down
+to scale down larger images like in fullscreen mode.
.
Also note that this option does not enforce the geometry, changing it by a tiling
-WM or manually is still possible. After each resize, the resulting window size
-is used as the new size limit.
+WM or manually is still possible.
+After each resize, the resulting window size is used as the new size limit.
.
.It Cm -Y , --hide-pointer
.
@@ -373,16 +408,24 @@ Hide the pointer
.
.It Cm -B , --image-bg Ar style
.
-Use style as background for transparent image parts and the like.
-Accepted values: checks, white, black.
+Use
+.Ar style
+as background for transparent image parts and the like.
+Accepted values: default, checks, or an XColor
+.Pq eg. Qo black Qc or Qo #428bdd Qc .
.
-The default for windowed mode is checks, while fullscreen defaults to black.
+In windowed mode, the default is checks
+.Pq a checkered background so transparent image parts are easy to see .
+In fullscreen and background setting mode, checks is not accepted and the
+default is black.
.
.It Cm -i , --index
.
-Enable Index mode. Index mode is similar to montage mode, and accepts the
-same options. It creates an index print of thumbnails, printing the image
-name beneath each thumbnail. Index mode enables certain other options, see
+Enable Index mode.
+Index mode is similar to montage mode, and accepts the same options.
+It creates an index print of thumbnails, printing the image name beneath
+each thumbnail.
+Index mode enables certain other options, see
.Sx INDEX AND THUMBNAIL MODE OPTIONS
and
.Sx MONTAGE MODE OPTIONS .
@@ -391,8 +434,9 @@ and
.
Execute
.Ar commandline
-and display its output in the bottom left corner of the image. Can be used to
-display e.g. image dimensions or EXIF information. Supports
+and display its output in the bottom left corner of the image.
+Can be used to display e.g. image dimensions or EXIF information.
+Supports
.Sx FORMAT SPECIFIERS .
.
If
@@ -415,8 +459,9 @@ or in the current working directory.
.It Cm --insecure
.
When viewing files with HTTPS, this option disables strict hostname and peer
-checking. This allows images on sites with self-signed certificates to be
-opened, but is no more secure than plain HTTP.
+checking.
+This allows images on sites with self-signed certificates to be opened, but is
+no more secure than plain HTTP.
.
.It Cm --keep-zoom-vp
.
@@ -425,25 +470,27 @@ When switching images, keep zoom and viewport settings
.
.It Cm -l , --list
.
-Don't display images. Analyze them and display an
+Don't display images.
+Analyze them and display an
.Xr ls 1 - No style
-listing. Useful in scripts to hunt out images of a certain
-size/resolution/type etc.
+listing.
+Useful in scripts to hunt out images of a certain size/resolution/type etc.
.
.It Cm -U , --loadable
.
-Don't display images. Just print out their names if imlib2 can successfully
-load them.
+Don't display images.
+Just print out their names if imlib2 can successfully load them.
Returns false if at least one image failed to load.
.
-.It Cm --magick-timeout Ar timeout
+.It Cm --conversion-timeout Ar timeout
.
Stop trying to convert unloadable files after
.Ar timeout
-seconds. A negative value disables covert / magick support altogether, a value
-of zero causes
+seconds.
+Negative values disable conversion altogether, zero causes
.Nm
-to try indefinitely. By default, magick support is disabled.
+to try indefinitely.
+By default, conversion is disabled.
.
.It Cm --max-dimension Ar width No x Ar height
.
@@ -471,15 +518,18 @@ If you only care about one parameter, set the other to 0.
.
.It Cm -m , --montage
.
-Enable montage mode. Montage mode creates a new image consisting of a grid of
-thumbnails of the images in the filelist. When montage mode is selected,
-certain other options become available. See
+Enable montage mode.
+Montage mode creates a new image consisting of a grid of thumbnails of the
+images in the filelist.
+When montage mode is selected, certain other options become available.
+See
.Sx MONTAGE MODE OPTIONS .
.
.It Cm -w , --multiwindow
.
-Disable slideshow mode. With this setting, instead of opening multiple files
-in slideshow mode, multiple windows will be opened; one per file.
+Disable slideshow mode.
+With this setting, instead of opening multiple files in slideshow mode,
+multiple windows will be opened; one per file.
.
.It Cm --no-jump-on-resort
.
@@ -491,15 +541,50 @@ Don't load or show any menus.
.
.It Cm --no-screen-clip
.
-By default, window sizes are limited to the screen size. With this option,
-windows will have the size of the image inside them. Note that they may
-become very large this way, making them unmanageable in certain window
-managers.
+By default, window sizes are limited to the screen size.
+With this option, windows will have the size of the image inside them.
+Note that they may become very large this way, making them unmanageable
+in certain window managers.
.
.It Cm --no-xinerama
.
-Disable Xinerama support. Only makes sense when you have Xinerama support
-compiled in.
+.Pq optional feature, $MAN_XINERAMA$ in this build
+Disable Xinerama support.
+.
+.It Cm --on-last-slide Cm hold | Cm quit | Cm resume
+.
+Select behaviour when trying to select the next image on the last slide
+.Pq or the previous image on the first slide
+in a slide show.
+.
+.Pp
+.
+With
+.Cm hold ,
+.Nm
+will stop advancing images in this case and continue displaying the first/last
+image, respectively.
+This is intended for linear slide shows.
+Behaviour is unspecified when using other navigation commands than previous
+and next image.
+.
+.Pp
+.
+.Cm quit
+will cause
+.Nm
+to quit when trying to advance past the last image in the slide show.
+.
+.Pp
+.
+.Cm resume
+is the default behaviour: On the last
+.Pq first
+image,
+.Nm
+will wrap around to the first
+.Pq last
+image.
.
.It Cm -j , --output-dir Ar directory
.
@@ -510,23 +595,27 @@ By default, files are saved in the current working directory.
.
.It Cm -p , --preload
.
-Preload images. This doesn't mean hold them in RAM, it means run through
-them and eliminate unloadable images first. Otherwise they will be removed
-as you flick through. This also analyses the images to get data for use in
-sorting, such as pixel size, type etc. A preload run will be automatically
-performed if you specify one of these sort modes.
+Preload images.
+This doesn't mean hold them in RAM, it means run through them and eliminate
+unloadable images first.
+Otherwise they will be removed as you flick through.
+This also analyses the images to get data for use in sorting, such as pixel
+size, type etc.
+A preload run will be automatically performed if you specify one of these
+sort modes.
.
.It Cm -q , --quiet
.
-Don't report non-fatal errors for failed loads. Verbose and quiet modes are
-not mutually exclusive, the first controls informational messages, the second
-only errors.
+Don't report non-fatal errors for failed loads.
+Verbose and quiet modes are not mutually exclusive, the first controls
+informational messages, the second only errors.
.
.It Cm -z , --randomize
.
When viewing multiple files in a slideshow, randomize the file list before
-displaying. The list is re-randomized whenever the slideshow cycles (that is,
-transitions from last to first image).
+displaying.
+The list is re-randomized whenever the slideshow cycles (that is, transitions
+from last to first image).
.
.It Cm -r , --recursive
.
@@ -542,29 +631,32 @@ Useful to override theme options.
.
Reload filelist and current image after
.Ar int
-seconds. Useful for viewing HTTP webcams or frequently changing directories.
+seconds.
+Useful for viewing HTTP webcams or frequently changing directories.
.Pq Note that the filelist reloading is still experimental.
.
.Pp
.
If an image is removed,
.Nm
-will either show the next one or quit. However, if an image still exists, but
-can no longer be loaded,
+will either show the next one or quit.
+However, if an image still exists, but can no longer be loaded,
.Nm
will continue to try loading it.
.
.It Cm -n , --reverse
.
-Reverse the sort order. Use this to invert the order of the filelist.
+Reverse the sort order.
+Use this to invert the order of the filelist.
E.g. to sort in reverse width order, use
.Cm -nSwidth .
.
.It Cm -. , --scale-down
.
Scale images to fit window geometry (defaults to screen size when no geometry
-was specified). Note that the window geometry is not updated when changing
-images at the moment. This option is recommended for tiling window managers.
+was specified).
+Note that the window geometry is not updated when changing images at the moment.
+This option is recommended for tiling window managers.
.
This option is ignored when in fullscreen and thumbnail list mode.
.
@@ -587,7 +679,8 @@ Default: 20
.
For slideshow mode, wait
.Ar float
-seconds between automatically changing slides. Useful for presentations.
+seconds between automatically changing slides.
+Useful for presentations.
Specify a negative number to set the delay
.Pq which will then be Ar float No * (-1) ,
but start
@@ -596,15 +689,16 @@ in paused mode.
.
.It Cm -S , --sort Ar sort_type
.
-The file list may be sorted according to image parameters. Allowed sort types
-are: name, filename, dirname, mtime, width, height, pixels, size, format. For
-sort modes other than name, filename, dirname, or mtime, a preload run will be
-necessary, causing a delay proportional to the number of images in the list.
+The file list may be sorted according to image parameters.
+Allowed sort types are: name, filename, dirname, mtime, width, height, pixels,
+size, format.
+For sort modes other than name, filename, dirname, or mtime, a preload run will
+be necessary, causing a delay proportional to the number of images in the list.
.
.Pp
.
-The mtime sort mode sorts images by most recently modified. To sort by oldest
-first, reverse the filelist with --reverse.
+The mtime sort mode sorts images by most recently modified.
+To sort by oldest first, reverse the filelist with --reverse.
.
.It Cm -| , --start-at Ar filename
.
@@ -615,12 +709,14 @@ Note that at the moment,
.Ar filename
must match an
.Pq expanded
-path in the filelist. So, if the file to be matched is passed via an absolute
-path in the filelist,
+path in the filelist.
+So, if the file to be matched is passed via an absolute path in the filelist,
.Ar filename
-must be an absolute path. If the file is passed via a relative path,
+must be an absolute path.
+If the file is passed via a relative path,
.Ar filename
-must be an identical relative path. This is a known issue.
+must be an identical relative path.
+This is a known issue.
See also
.Sx USAGE EXAMPLES .
.
@@ -630,7 +726,8 @@ Load options from config file with name
.Ar theme
- see
.Sx THEMES CONFIG SYNTAX
-for more info. Note that commandline options always override theme options.
+for more info.
+Note that commandline options always override theme options.
The theme can also be set via the program name
.Pq e.g. with symlinks ,
so by default
@@ -646,8 +743,8 @@ Note that
.Cm --fullscreen
and
.Cm --scale-down
-do not affect the thumbnail window. They do, however, work for image windows
-launched from thumbnail mode.
+do not affect the thumbnail window.
+They do, however, work for image windows launched from thumbnail mode.
Also supports
.Sx INDEX AND THUMBNAIL MODE OPTIONS
as well as
@@ -657,19 +754,21 @@ as well as
.
Set
.Ar title
-for windows opened from thumbnail mode. See also
+for windows opened from thumbnail mode.
+See also
.Sx FORMAT SPECIFIERS .
.
.It Cm -^ , --title Ar title
.
-Set window title. Applies to all windows except those opened from thumbnail
-mode. See
+Set window title.
+Applies to all windows except those opened from thumbnail mode.
+See
.Sx FORMAT SPECIFIERS .
.
.It Cm -u , --unloadable
.
-Don't display images. Just print out their names if imlib2 can NOT
-successfully load them.
+Don't display images.
+Just print out their names if imlib2 can NOT successfully load them.
Returns false if at least one image was loadable.
.
.It Cm -V , --verbose
@@ -680,12 +779,23 @@ output useful information, progress bars, etc.
.
output version information and exit.
.
+.It Cm --version-sort
+.
+.Pq optional feature, $MAN_VERSCMP$ in this build
+Use natural sorting for file and directory names.
+In this mode, filenames are sorted as an ordinary human would expect, e.g.
+.Qq 2.jpg
+comes before
+.Qq 10.jpg .
+.
.It Cm --xinerama-index Ar screen
.
+.Pq optional feature, $MAN_XINERAMA$ in this build
Override
.Nm Ns No 's
-idea of the active Xinerama screen. May be useful in certain circumstances
-where the window manager places the feh window on Xinerama screen A while
+idea of the active Xinerama screen.
+May be useful in certain circumstances where the window manager places the feh
+window on Xinerama screen A while
.Nm
assumes that it will be placed on screen B.
.
@@ -697,18 +807,20 @@ Only set wallpaper on
.Ar screen .
All other screens will be filled black/white.
.
-This is most useful in a Xinerama configuration with
-overlapping screens. For instance, assume you have two overlapping displays
-(index 0 and 1), where index 0 is smaller. To center a background on the
-display with index 0 and fill the extra space on index 1 black/white, use
+This is most useful in a Xinerama configuration with overlapping screens.
+For instance, assume you have two overlapping displays (index 0 and 1),
+where index 0 is smaller.
+To center a background on the display with index 0 and fill the extra space
+on index 1 black/white, use
.Qq --xinerama-index 0
when setting the wallpaper.
.
-.It Cm --zoom Ar percent No | Cm max No | Cm fill
+.It Cm --zoom Ar percent | Cm max | Cm fill
.
Zoom images by
.Ar percent
-when in full screen mode or when window geometry is fixed. When combined with
+when in full screen mode or when window geometry is fixed.
+When combined with
.Cm --auto-zoom ,
zooming will be limited to the specified
.Ar percent .
@@ -741,14 +853,15 @@ When drawing thumbnails onto the background, set their transparency level to
.Ar int
.Pq 0 - 255 .
.
-.It Cm -b , --bg Ar file No | Cm trans
+.It Cm -b , --bg Ar file | Cm trans
.
Use
.Ar file
-as background for your montage. With this option specified, the montage size
-will default to the size of
+as background for your montage.
+With this option specified, the montage size will default to the size of
.Ar file
-if no size restrictions were specified. Alternatively, if
+if no size restrictions were specified.
+Alternatively, if
.Ar file
is
.Qq trans ,
@@ -757,8 +870,8 @@ the background will be made transparent.
.It Cm -X , --ignore-aspect
.
By default, the montage thumbnails will retain their aspect ratios, while
-fitting into thumb-width/-height. This options forces them to be the size set
-by
+fitting into thumb-width/-height.
+This options forces them to be the size set by
.Cm --thumb-width No and Cm --thumb-height .
This will prevent any empty space in the final montage.
.
@@ -792,8 +905,9 @@ without displaying it.
.It Cm -s , --stretch
.
Normally, if an image is smaller than the specified thumbnail size, it will
-not be enlarged. If this option is set, the image will be scaled up to fit
-the thumbnail size. Aspect ratio will be maintained unless
+not be enlarged.
+If this option is set, the image will be scaled up to fit the thumbnail size.
+Aspect ratio will be maintained unless
.Cm --ignore-aspect
is specified.
.
@@ -805,38 +919,25 @@ Set thumbnail height.
.
Set thumbnail width.
.
-.It Cm -J , --thumb-redraw Ar n
-.
-Only relevant for
-.Cm --thumbnails :
-Redraw thumbnail window every
-.Ar n
-images. In
-.Nm
-<= 1.5, the thumbnail image used to be redrawn after every computed thumbnail
-.Pq so, it updated immediately .
-However, since the redrawing takes quite long
-.Pq especially for thumbnail mode on a large filelist ,
-this turned out to be a major performance penalty.
-As a workaround, the thumbnail image is redrawn every 10th image now by
-default. Set
-.Ar n No = 1
-to get the old behaviour,
-.Ar n No = 0
-will only redraw once all thumbnails are loaded.
-.
.El
.
.
.Sh INDEX AND THUMBNAIL MODE OPTIONS
.
+In addition to
+.Sx MONTAGE MODE OPTIONS
+.Cm --alpha , --bg , --limit-height , --limit-width , --output , --output-only ,
+.Cm --thumb-height , --thumb-width ,
+the following options can be used.
+.
.Bl -tag -width indent
.
.It Cm --index-info Ar format
.
Show image information based on
.Ar format
-below thumbnails in index / thumbnail mode. See
+below thumbnails in index / thumbnail mode.
+See
.Sx FORMAT SPECIFIERS .
May contain newlines.
.
@@ -852,7 +953,8 @@ Note: If you specify image-related formats
needs to load all images to calculate the dimensions of its own window.
So when using them with many files, it will take a while before a
.Nm
-window becomes visible. Use
+window becomes visible.
+Use
.Cm --preload
to get a progress bar.
.
@@ -860,6 +962,26 @@ to get a progress bar.
.
Set font to print a title on the index, if no font is specified, no title will
be printed.
+.
+.It Cm -J , --thumb-redraw Ar n
+.
+Redraw thumbnail window every
+.Ar n
+images.
+In
+.Nm
+<= 1.5, the thumbnail image used to be redrawn after every computed thumbnail
+.Pq so, it updated immediately .
+However, since the redrawing takes quite long
+.Pq especially for thumbnail mode on a large filelist ,
+this turned out to be a major performance penalty.
+As a workaround, the thumbnail image is redrawn every 10th image now by default.
+Set
+.Ar n No = 1
+to get the old behaviour,
+.Ar n No = 0
+will only redraw once all thumbnails are loaded.
+.
.El
.
.
@@ -867,41 +989,37 @@ be printed.
.
In many desktop environments,
.Nm
-can also be used as a background setter. Unless you pass the
+can also be used as a background setter.
+Unless you pass the
.Cm --no-fehbg
option, it will write a script to set the current background to
.Pa ~/.fehbg .
So to have your background restored every time you start X, you can add
-.Qq sh ~/.fehbg &
+.Qq ~/.fehbg &
to your X startup script
.Pq such as Pa ~/.xinitrc .
-As of
-.Nm
-2.13, this script is executable, so
-.Qq ~/.fehbg &
-will work as well.
.
.Pp
.
Note that
.Nm
-does not support setting the wallpaper of GNOME shell desktops. In this
-environment, you can use
+does not support setting the wallpaper of GNOME shell desktops.
+In this environment, you can use
.Qq gsettings set org.gnome.desktop.background picture-uri file:/// Ns Ar path
instead.
.
.Pp
.
-For the
-.Cm --bg-center
+For
+.Cm --bg-center , --bg-fill ,
and
-.Cm --bg-max
-options, you can use the
+.Cm --bg-max ,
+you can use
.Cm --geometry
-option to specify an offset from one side of the screen instead of
-centering the image. Positive values will offset from the left/top
-side, negative values from the bottom/right. +0 and -0 are both
-valid and distinct values.
+to specify an offset from one side of the screen instead of centering the image.
+Positive values will offset from the left/top side, negative values from the
+bottom/right.
++0 and -0 are both valid and distinct values.
.
.Pp
.
@@ -919,8 +1037,8 @@ on screen 0, the second on screen 1, and so on.
.
Use
.Cm --no-xinerama
-to treat the whole X display as one screen when setting wallpapers. You
-may also use
+to treat the whole X display as one screen when setting wallpapers.
+You may also use
.Cm --xinerama-index
to use
.Nm
@@ -930,26 +1048,30 @@ as a background setter for a specific screen.
.
.It Cm --bg-center
.
-Center the file on the background. If it is too small, it will be surrounded
-by a black border
+Center the file on the background.
+If it is too small, it will be surrounded by a border as specified by
+.Cm --image-bg .
.
.It Cm --bg-fill
.
Like
.Cm --bg-scale ,
-but preserves aspect ratio by zooming the image until it fits. Either a
-horizontal or a vertical part of the image will be cut off
+but preserves aspect ratio by zooming the image until it fits.
+Either a horizontal or a vertical part of the image will be cut off
.
.It Cm --bg-max
.
Like
.Cm --bg-fill ,
-but scale the image to the maximum size that fits the screen with black borders on one side.
+but scale the image to the maximum size that fits the screen with borders on one side.
+The border color can be set using
+.Cm --image-bg .
.
.It Cm --bg-scale
.
Fit the file into the background without repeating it, cutting off stuff or
-using borders. But the aspect ratio is not preserved either
+using borders.
+But the aspect ratio is not preserved either
.
.It Cm --bg-tile
.
@@ -979,6 +1101,10 @@ Image path/filename
Escaped image path/filename
.Pq for use in shell commands
.
+.It %g
+.
+w,h window dimensions in pixels (mnemonic: geometry)
+.
.It %h
.
Image height
@@ -989,7 +1115,8 @@ Total number of files in filelist
.
.It %L
.
-Temporary copy of filelist. Multiple uses of %L within the same format string will return the same copy.
+Temporary copy of filelist.
+Multiple uses of %L within the same format string will return the same copy.
.
.It %m
.
@@ -1013,12 +1140,14 @@ Number of image pixels
.
.It \&%P
.
-Number of image pixels
+Number of image pixels in human-readable format with k/M
.Pq kilopixels / megapixels
+suffix
.
.It %r
.
-Image rotation. A half right turn equals pi.
+Image rotation.
+A half right turn equals pi.
.
.It %s
.
@@ -1052,7 +1181,11 @@ Process ID
.
.It %z
.
-current image zoom
+Current image zoom, rounded to two decimal places
+.
+.It %Z
+.
+Current image zoom, higher precision
.
.It %%
.
@@ -1101,29 +1234,42 @@ is the name of the entry and
.Ar options
are the options which will be applied when the theme is used.
.
-Note that the options are not parsed by any shell. Therefore, filename expansion
-.Po
-.Qq *.jpg
-and similar
-.Pc
-is not supported. Quoting with both single and double quotes works, though.
+.Pp
+.
+Note that the option parser does not behave like a normal shell: filename
+expansion and backslash escape sequences are not supported and passed to
+feh's option parser as-is.
+However, quoting of arguments is respected and can be used for arguments
+with whitespace.
+.
+So, the sequence
+.Qq --info Qq foo bar
+works as intended
+.Pq that is, it display the string Qq foo bar ,
+whereas the option string
+.Qq --info foo\e bar
+will only display
+.Qq foo\e
+and complain about the file bar not existing.
+Please keep this in mind when writing theme files.
.
.Pp
.
-An example entry would be
+An example entry is
.Qq imagemap -rVq --thumb-width 40 --thumb-height 30 --index-info \&'%n\en\&%wx\&%h\&' .
.
.Pp
.
-You can use this theme in two ways. Either call
+You can use this theme in two ways.
+Either call
.Qo
.Nm
-Timagemap *.jpg
.Qc ,
or create a symbolic link to
.Nm
-with the name of the theme you want it to use. For the example above,
-this would be
+with the name of the theme you want it to use.
+For the example above, this would be
.Qo
ln -s `which
.Nm
@@ -1190,9 +1336,9 @@ without any keys unbinds it (i.e. the default bindings are removed).
.
.Pp
.
-.Em Note :
-Do not use the same keybinding for multiple actions. When binding an action
-to a new key
+.Em Note:\&
+Do not use the same keybinding for multiple actions.
+When binding an action to a new key
.Pq or mouse button ,
make sure to unbind it from its previous action, if present.
.Nm
@@ -1216,8 +1362,20 @@ do not.
.
.Sh KEYS
.
-In an image window, the following keys may be used
-.Pq The strings in Bo square brackets Bc are the config action names :
+The following actions and default key bindings can be used in an image window.
+.Pq The strings in Bo square brackets Bc are the config action names .
+.
+If
+.Nm
+is running inside a terminal and its standard input is not used for images or
+filelists, key input from the terminal is also accepted.
+However, terminal input support is currently limited to most alphanumeric
+characters
+.Pq 0-9 a-z A-Z and some more ,
+arrow keys, return and backspace.
+The Alt
+.Pq Mod1
+modifier is also supported.
.
.Bl -tag -width indent
.
@@ -1232,12 +1390,13 @@ Enable/Disable anti-aliasing
.
.It c Bq toggle_caption
.
-Caption entry mode. If
+Caption entry mode.
+If
.Cm --caption-path
-has been specified, then this enables caption editing. The caption at the
-bottom of the screen will turn yellow and can be edited. Hit return to confirm
-and save the caption, or escape to cancel editing. Note that you can insert
-an actual newline into the caption using
+has been specified, then this enables caption editing.
+The caption at the bottom of the screen will turn yellow and can be edited.
+Hit return to confirm and save the caption, or escape to cancel editing.
+Note that you can insert an actual newline into the caption using
.Aq Ctrl+return .
.
.It d Bq toggle_filenames
@@ -1247,7 +1406,7 @@ Toggle filename display
.
.It e Bq toggle_exif
.
-.Pq only if compiled with exif=1
+.Pq optional feature, $MAN_EXIF$ in this build
Toggle EXIF tag display
.
.It f Bq save_filelist
@@ -1255,10 +1414,14 @@ Toggle EXIF tag display
Save the current filelist as
.Qq feh_PID_ID_filelist
.
+.It g Bq toggle_fixed_geometry
+.
+Enable/Disable automatic window resize when changing images.
+.
.It h Bq toggle_pause
.
-Pause/Continue the slideshow. When it is paused, it will not automatically
-change slides based on
+Pause/Continue the slideshow.
+When it is paused, it will not automatically change slides based on
.Cm --slideshow-delay .
.
.It i Bq toggle_info
@@ -1268,19 +1431,22 @@ Toggle info display
.
.It k Bq toggle_keep_vp
.
-Toggle zoom and viewport keeping. When enabled,
+Toggle zoom and viewport keeping.
+When enabled,
.Nm
will keep zoom and X, Y offset when switching images.
.
.It m Bq toggle_menu
.
-Show menu. Use the arrow keys and return to select items,
+Show menu.
+Use the arrow keys and return to select items,
.Aq escape
to close the menu.
.
.It n , Ao space Ac , Ao Right Ac Bq next_img
.
-Show next image. Selects the next image in thumbnail mode.
+Show next image.
+Selects the next image in thumbnail mode.
.
.It o Bq toggle_pointer
.
@@ -1288,7 +1454,8 @@ Toggle pointer visibility
.
.It p , Ao BackSpace Ac , Ao Left Ac Bq prev_img
.
-Show previous image. Selects the previous image in thumbnail mode.
+Show previous image.
+Selects the previous image in thumbnail mode.
.
.It q , Ao Escape Ac Bq quit
.
@@ -1297,7 +1464,8 @@ Quit
.
.It r Bq reload_image
.
-Reload current image. Useful for webcams
+Reload current image.
+Useful for webcams
.
.It s Bq save_image
.
@@ -1312,8 +1480,7 @@ Toggle fullscreen
.
Change window size to fit current image size
.Pq plus/minus zoom, if set .
-In scale-down and fixed-geometry mode, this also updates the window size
-limits.
+In scale-down and fixed-geometry mode, this also updates the window size limits.
.
.It x Bq close
.
@@ -1323,27 +1490,35 @@ Close current window
.
Jump to a random position in the current filelist
.
+.It Z Bq toggle_auto_zoom
+.
+Toggle auto-zoom.
+.
.It \&[, \&] Bq prev_dir, next_dir
.
Jump to the first image of the previous or next sequence of images sharing
-a directory name in the current filelist. Use --sort dirname if you would
-like to ensure that all images in a directory are grouped together.
+a directory name in the current filelist.
+Use --sort dirname if you would like to ensure that all images in a directory
+are grouped together.
.
.It < , > Bq orient_3 , orient_1
.
In place editing - rotate the image 90 degrees (counter)clockwise.
The rotation is lossless, but may create artifacts in some image corners when
-used with JPEG images. Rotating in the reverse direction will make them go
-away. See
+used with JPEG images.
+Rotating in the reverse direction will make them go away.
+See
.Xr jpegtran 1
for more about lossless JPEG rotation.
.
-.Em Note:
+.Em Note:\&
.Nm
-assumes that this feature is used to normalize image orientation. For JPEG
-images, it will unconditionally set the EXIF orientation tag to 1
+assumes that this feature is used to normalize image orientation.
+For JPEG images, it will unconditionally set the EXIF orientation
+tag to 1
.Pq Qq 0,0 is top left
-after every rotation. See
+after every rotation.
+See
.Xr jpegexiforient 1
for details on how to change this flag.
.
@@ -1504,8 +1679,8 @@ This works like the keys config file: the entries are of the form
.
Each
.Ar binding
-is a button number. It may optionally start with modifiers for things like
-Control, in which case
+is a button number.
+It may optionally start with modifiers for things like Control, in which case
.Ar binding
looks like
.Ar mod Ns No - Ns Ar button
@@ -1513,7 +1688,7 @@ looks like
.
.Pp
.
-.Em Note :
+.Em Note:\&
Do not use the same button for multiple actions.
.Nm
does not check for conflicting bindings, so their behaviour is undefined.
@@ -1615,11 +1790,12 @@ will warp your cursor to the opposite border so you can continue panning.
.Pp
.
When clicking the zoom button and immediately releasing it, the image will be
-back at 100% zoom. When clicking it and moving the mouse while holding the
-button down, the zoom will be continued at the previous zoom level. The zoom
-will always happen so that the pixel on which you entered the zoom mode
-remains stationary. So, to enlarge a specific part of an image, click the
-zoom button on that part.
+back at 100% zoom.
+When clicking it and moving the mouse while holding the button down, the zoom
+will be continued at the previous zoom level.
+The zoom will always happen so that the pixel on which you entered the zoom mode
+remains stationary.
+So, to enlarge a specific part of an image, click the zoom button on that part.
.
.
.Sh SIGNALS
@@ -1643,67 +1819,71 @@ Switch to previous image
.
.Sh USAGE EXAMPLES
.
-Here are some examples of useful option combinations. See also:
+Here are some examples of useful option combinations.
+See also:
.Aq http://feh.finalrewind.org/examples/
.
.Bl -tag -width indent
.
-.It feh /opt/images
+.It feh ~/Pictures
.
-Show all images in /opt/images
+Show all images in ~/Pictures
.
-.It feh -r /opt/images
+.It feh -r ~/Pictures
.
-Recursively show all images found in /opt/images and subdirectories
+Recursively show all images found in ~/Pictures and subdirectories
.
-.It feh -rSfilename /opt/images
+.It feh -rSfilename --version-sort ~/Pictures
.
-Same as above, but sort by filename. By default, feh will show files in the
-order it finds them on the hard disk, which is usually somewhat random.
+Same as above, but sort naturally.
+By default, feh will show files in the string order of their names, meaning e.g.
+.Qq foo 10.jpg
+will come before
+.Qq foo 2.jpg .
+In this case, they are instead ordered as a human would expect.
.
-.It feh -t -Sfilename -E 128 -y 128 -W 1024 /opt/images
+.It feh -t -Sfilename -E 128 -y 128 -W 1024 ~/Pictures
.
Show 128x128 pixel thumbnails, limit window width to 1024 pixels.
.
-.It feh -t -Sfilename -E 128 -y 128 -W 1024 -P -C /usr/share/fonts/truetype/ttf-dejavu/ -e DejaVuSans/8 /opt/images
+.It feh -t -Sfilename -E 128 -y 128 -W 1024 -P -C /usr/share/fonts/truetype/ttf-dejavu/ -e DejaVuSans/8 ~/Pictures
.
-Same as above, but enable thumbnail caching in ~/.thumbnails and use a smaller
-font.
+Same as above, but enable thumbnail caching and use a smaller font.
.
-.It feh -irFarial/14 -O index.jpg /opt/images
+.It feh -irFarial/14 -O index.jpg ~/Pictures
.
-Make an index print of /opt/images and all directories below it, using 14 point
-Arial to write the image info under each thumbnail. Save the image as
-index.jpg and don't display it, just exit. Note that this even works without
-a running X server
+Make an index print of ~/Pictures and all directories below it, using 14 point
+Arial to write the image info under each thumbnail.
+Save the image as index.jpg and don't display it, just exit.
+Note that this even works without a running X server
.
-.It feh --unloadable -r /opt/images
+.It feh --unloadable -r ~/Pictures
.
-Print all unloadable images in /opt/images, recursively
+Print all unloadable images in ~/Pictures, recursively
.
.It feh -f by_width -S width --reverse --list \&.
.
Write a list of all images in the directory to by_width, sorted by width
.Pq widest images first
.
-.It feh -w /opt/images/holidays
+.It feh -w ~/Pictures/holidays
.
-Open each image in /opt/images/holidays in its own window
+Open each image in ~/Pictures/holidays in its own window
.
-.It feh -FD5 -Sname /opt/images/presentation
+.It feh -FD5 -Sname ~/Pictures/presentation
.
Show the images in .../presentation, sorted by name, in fullscreen,
automatically change to the next image after 5 seconds
.
-.It feh -rSwidth -A Qo mv %F ~/images/\&%N Qc /opt/images
+.It feh -rSwidth -A Qo mv %F ~/images/\&%N Qc ~/Pictures
.
-View all images in /opt/images and below, sorted by width, move an image to
+View all images in ~/Pictures and below, sorted by width, move an image to
~/image/image_name when enter is pressed
.
.It feh --start-at ./foo.jpg \&.
.
-View all images in the current directory, starting with foo.jpg. All other
-images are still in the slideshow and can be viewed normally
+View all images in the current directory, starting with foo.jpg.
+All other images are still in the slideshow and can be viewed normally
.
.It feh --start-at foo.jpg *
.
@@ -1736,25 +1916,26 @@ for lossless rotation.
.
To view images from URLs such as http://, you need
.Nm
-compiled with libcurl support (enabled by default). See the
+compiled with libcurl support (enabled by default).
+See the
.Sx VERSION
section.
.
.
.Sh BUGS
.
-.Pp
-.
On systems with giflib 5.1.2,
.Nm
-may be unable to load gif images. For affected mips, mipsel and arm devices,
-gif support is completely broken, while on x86 / x86_64 gifs can usually
-only be loaded if they are the first image in the filelist.
+may be unable to load gif images.
+For affected mips, mipsel and arm devices, gif support is completely
+broken, while on x86 / x86_64 gifs can usually only be loaded if they are
+the first image in the filelist.
This appears to be a bug in giflib,
see
.Aq https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=813729
-for details. Workaround: Use
-.Cm --magick-timeout 5
+for details.
+Workaround: Use
+.Cm --conversion-timeout 5
.Pq or some other positive value
to load gifs with imagemagick instead, or downgrade to giflib 5.1.1, or
upgrade to giflib 5.1.4.
@@ -1770,7 +1951,6 @@ as it could be.
does not take window decorations into account and may therefore make the
window slightly too large.
.
-.
.Ss REPORTING BUGS
.
If you find a bug, please report it to
@@ -1803,7 +1983,7 @@ Make zoom options more intuitive
.
Copyright (C) 1999, 2000 by Paul Duncan.
Copyright (C) 1999, 2000 by Tom Gilbert (and various contributors).
-Copyright (C) 2010-2016 by Daniel Friesel (and even more contributors).
+Copyright (C) 2010-2018 by Daniel Friesel (and even more contributors).
.
.Pp
.
@@ -1825,10 +2005,11 @@ used.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-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.
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER 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.
.
.Pp
.
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);
}
diff --git a/src/feh.h b/src/feh.h
index 9778efb..614ccef 100644
--- a/src/feh.h
+++ b/src/feh.h
@@ -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;
}
diff --git a/src/list.c b/src/list.c
index 6f317c4..2f6cf76 100644
--- a/src/list.c
+++ b/src/list.c
@@ -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 {
diff --git a/src/main.c b/src/main.c
index b935e53..d839a93 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);
diff --git a/src/menu.c b/src/menu.c
index ddb2db1..2f8875d 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -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
diff --git a/src/menu.h b/src/menu.h
index 403728f..b53b32f 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -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);
diff --git a/test/list/custom b/test/list/custom
index b5ddb32..dbe2074 100644
--- a/test/list/custom
+++ b/test/list/custom
@@ -1,4 +1,4 @@
-test/ok/gif; 16; 4; list; gif; 256; 953; gif; 0; 16
-test/ok/jpg; 16; 4; list; jpg; 256; 354; jpeg; 0; 16
-test/ok/png; 16; 4; list; png; 256; 403; png; 0; 16
-test/ok/pnm; 16; 4; list; pnm; 256; 269; pnm; 0; 16
+test/ok/gif; 16; 4; list; gif; 256; 953; gif; 1; 16
+test/ok/jpg; 16; 4; list; jpg; 256; 354; jpeg; 2; 16
+test/ok/png; 16; 4; list; png; 256; 403; png; 3; 16
+test/ok/pnm; 16; 4; list; pnm; 256; 269; pnm; 4; 16
diff --git a/test/mandoc.t b/test/mandoc.t
index 3740809..638c5e9 100755
--- a/test/mandoc.t
+++ b/test/mandoc.t
@@ -6,15 +6,22 @@ use 5.010;
use Test::More tests => 3;
SKIP: {
- qx{mandoc -V};
+ my $mandoc_present = 0;
- if ( $? != 0 ) {
+ for my $path (split(qr{:}, $ENV{PATH})) {
+ if (-x "${path}/mandoc") {
+ $mandoc_present = 1;
+ last;
+ }
+ }
+
+ if ( not $mandoc_present ) {
diag('mandoc not installed, test skipped. This is NOT fatal.');
skip( 'mandoc not installed', 3 );
}
for my $file ( 'feh', 'feh-cam', 'gen-cam-menu' ) {
- qx{mandoc -Tlint man/${file}.1};
+ qx{mandoc -Tlint -Werror man/${file}.1};
is( $?, 0, "${file}.1: Valid mdoc syntax" );
}
}
diff --git a/test/nx_action/loadable_action b/test/nx_action/loadable_action
index d173261..fbf517b 100644
--- a/test/nx_action/loadable_action
+++ b/test/nx_action/loadable_action
@@ -1,8 +1,8 @@
-touch test/ok/gif
-touch test/ok/jpg
-touch test/ok/png
-touch test/ok/pnm
test/ok/gif
+touch test/ok/gif
test/ok/jpg
+touch test/ok/jpg
test/ok/png
+touch test/ok/png
test/ok/pnm
+touch test/ok/pnm
diff --git a/test/nx_action/loadable_naction b/test/nx_action/loadable_naction
index d173261..fbf517b 100644
--- a/test/nx_action/loadable_naction
+++ b/test/nx_action/loadable_naction
@@ -1,8 +1,8 @@
-touch test/ok/gif
-touch test/ok/jpg
-touch test/ok/png
-touch test/ok/pnm
test/ok/gif
+touch test/ok/gif
test/ok/jpg
+touch test/ok/jpg
test/ok/png
+touch test/ok/png
test/ok/pnm
+touch test/ok/pnm
diff --git a/test/nx_action/unloadable_action b/test/nx_action/unloadable_action
index c16572e..cdf3ed8 100644
--- a/test/nx_action/unloadable_action
+++ b/test/nx_action/unloadable_action
@@ -1,8 +1,8 @@
-rm test/fail/gif
-rm test/fail/jpg
-rm test/fail/png
-rm test/fail/pnm
test/fail/gif
+rm test/fail/gif
test/fail/jpg
+rm test/fail/jpg
test/fail/png
+rm test/fail/png
test/fail/pnm
+rm test/fail/pnm
diff --git a/test/nx_action/unloadable_naction b/test/nx_action/unloadable_naction
index c16572e..cdf3ed8 100644
--- a/test/nx_action/unloadable_naction
+++ b/test/nx_action/unloadable_naction
@@ -1,8 +1,8 @@
-rm test/fail/gif
-rm test/fail/jpg
-rm test/fail/png
-rm test/fail/pnm
test/fail/gif
+rm test/fail/gif
test/fail/jpg
+rm test/fail/jpg
test/fail/png
+rm test/fail/png
test/fail/pnm
+rm test/fail/pnm