Merge branch 'nsxiv-master'

This commit is contained in:
krolyxon 2023-06-11 21:37:49 +05:30
commit d566ca84e8
19 changed files with 281 additions and 261 deletions

View File

@ -1,7 +1,9 @@
# EditorConfig # EditorConfig
# See this if your editor doesn't have built-in editorconfig support:
# https://editorconfig.org/#download
# apply to all files # apply to all .c and .h files
[*] [*.{c,h}]
# top-most EditorConfig file # top-most EditorConfig file
root = true root = true

139
README.md
View File

@ -1,137 +1,2 @@
Dependencies ## Nsxiv
------------ This is my fork of Nsxiv
nsxiv requires the following software to be installed:
* Imlib2
* X11
The following dependencies are optional.
* `inotify`<sup>\*</sup>: Used for auto-reloading images on change.
Disabled via `HAVE_INOTIFY=0`.
* `libXft`, `freetype2`, `fontconfig`: Used for the status bar.
Disabled via `HAVE_LIBFONTS=0`.
* `giflib`: Used for animated gif playback.
Disabled via `HAVE_LIBGIF=0`.
* `libexif`: Used for auto-orientation and exif thumbnails.
Disable via `HAVE_LIBEXIF=0`.
* `libwebp`: Used for animated webp playback.
(***NOTE***: animated webp also requires Imlib2 v1.7.5 or above)
Disabled via `HAVE_LIBWEBP=0`.
Please make sure to install the corresponding development packages in case that
you want to build nsxiv on a distribution with separate runtime and development
packages (e.g. \*-dev on Debian).
\* [inotify][] is a Linux-specific API for monitoring filesystem changes.
It's not natively available on `*BSD` systems but can be enabed via installing
and linking against [libinotify-kqueue][].
[inotify]: https://www.man7.org/linux/man-pages/man7/inotify.7.html
[libinotify-kqueue]: https://github.com/libinotify-kqueue/libinotify-kqueue
Building
--------
nsxiv is built using the commands:
$ make
You can pass `HAVE_X=0` to `make` to disable an optional dependency.
For example:
$ make HAVE_LIBEXIF=0
will disable `libexif` support. Alternatively they can be disabled via editing
`config.mk`. `OPT_DEP_DEFAULT=0` can be used to disable all optional
dependencies.
Installing nsxiv:
# make install
Installing desktop entry:
# make install-desktop
Installing icons:
# make install-icon
Installing all of the above:
# make install-all
Please note, that these requires root privileges.
By default, nsxiv is installed using the prefix `/usr/local`, so the full path
of the executable will be `/usr/local/bin/nsxiv`, the `.desktop` entry will be
`/usr/local/share/applications/nsxiv.desktop` and the icon path will be
`/usr/local/share/icons/hicolor/{size}/apps/nsxiv.png`.
You can install nsxiv into a directory of your choice by changing this command to:
$ make PREFIX="/your/dir" install
Example scripts are installed using `EGPREFIX` which defaults to
`/usr/local/share/doc/nsxiv/examples`. You can change `EGPREFIX` the same way
you can change `PREFIX` shown above.
The build-time specific settings of nsxiv can be found in the file *config.h*.
Please check and change them, so that they fit your needs.
If the file *config.h* does not already exist, then you have to create it with
the following command:
$ make config.h
Usage
-----
Refer to the man-page for the documentation:
$ man nsxiv
You may also view the man-page [online](https://nsxiv.codeberg.page/man/).
However, note that the online man-page might not accurately represent your local
copy.
F.A.Q.
------
* Can I open remote urls with nsxiv? <br>
Yes, see [nsxiv-url](https://codeberg.org/nsxiv/nsxiv-extra/src/branch/master/scripts/nsxiv-url)
* Can I open all the images in a directory? <br>
Yes, see [nsxiv-rifle](https://codeberg.org/nsxiv/nsxiv-extra/src/branch/master/scripts/nsxiv-rifle)
* Can I set default arguments for nsxiv? <br>
Yes, see [nsxiv-env](https://codeberg.org/nsxiv/nsxiv-extra/src/branch/master/scripts/nsxiv-env)
* Can I pipe images into nsxiv? <br>
Yes, see [nsxiv-pipe](https://codeberg.org/nsxiv/nsxiv-extra/src/branch/master/scripts/nsxiv-pipe)
You may also wish to see the [known issues](https://codeberg.org/nsxiv/nsxiv/issues/242).
Customization
-------------
The main method of customizing nsxiv is by setting values for the variables in *config.h*,
or by using Xresources as explained in the manual. If these options are not sufficient,
you may implement your own features by following
[this guide](https://codeberg.org/nsxiv/nsxiv-extra/src/branch/master/CUSTOMIZATION.md).
Due to our limited [project scope](etc/CONTRIBUTING.md#project-scope), certain features or
customization cannot be merged into nsxiv mainline. Following the spirit of suckless
software, we host the [nsxiv-extra](https://codeberg.org/nsxiv/nsxiv-extra) repo where users
are free to submit whatever patches or scripts they wish.
If you think your custom features can be beneficial for the general user base and is within
our project scope, please submit it as a pull request on this repository, then we *may*
merge it to mainline.
Description on how to use or submit patches can be found on
nsxiv-extra's [README](https://codeberg.org/nsxiv/nsxiv-extra).

View File

@ -28,7 +28,10 @@
#include <sys/inotify.h> #include <sys/inotify.h>
#include <unistd.h> #include <unistd.h>
static struct { char *buf; size_t len; } scratch; static struct {
char *buf;
size_t len;
} scratch;
void arl_init(arl_t *arl) void arl_init(arl_t *arl)
{ {
@ -94,7 +97,10 @@ bool arl_handle(arl_t *arl)
char *ptr; char *ptr;
const struct inotify_event *e; const struct inotify_event *e;
/* inotify_event aligned buffer */ /* inotify_event aligned buffer */
static union { char d[4096]; struct inotify_event e; } buf; static union {
char d[4096];
struct inotify_event e;
} buf;
while (true) { while (true) {
ssize_t len = read(arl->fd, buf.d, sizeof(buf.d)); ssize_t len = read(arl->fd, buf.d, sizeof(buf.d));

View File

@ -59,6 +59,13 @@ bool cg_quit(arg_t status)
return None; /* silence tcc warning */ return None; /* silence tcc warning */
} }
bool cg_pick_quit(arg_t status)
{
if (options->to_stdout && markcnt == 0)
printf("%s%c", files[fileidx].name, options->using_null ? '\0' : '\n');
return cg_quit(status);
}
bool cg_switch_mode(arg_t _) bool cg_switch_mode(arg_t _)
{ {
if (mode == MODE_IMAGE) { if (mode == MODE_IMAGE) {
@ -326,10 +333,10 @@ bool ci_drag(arg_t drag_mode)
while (true) { while (true) {
if (drag_mode == DRAG_ABSOLUTE) { if (drag_mode == DRAG_ABSOLUTE) {
px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8) px = MIN(MAX(0.0, x - win.w * 0.1), win.w * 0.8) /
* (win.w - img.w * img.zoom); (win.w * 0.8) * (win.w - img.w * img.zoom);
py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8) py = MIN(MAX(0.0, y - win.h * 0.1), win.h * 0.8) /
* (win.h - img.h * img.zoom); (win.h * 0.8) * (win.h - img.h * img.zoom);
} else { } else {
px = img.x + x - ox; px = img.x + x - ox;
py = img.y + y - oy; py = img.y + y - oy;
@ -343,7 +350,8 @@ bool ci_drag(arg_t drag_mode)
ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
if (e.type == ButtonPress || e.type == ButtonRelease) if (e.type == ButtonPress || e.type == ButtonRelease)
break; break;
while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e)); while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e))
;
ox = x; ox = x;
oy = y; oy = y;
x = e.xmotion.x; x = e.xmotion.x;
@ -443,7 +451,8 @@ bool ct_drag_mark_image(arg_t _)
ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
if (e.type == ButtonPress || e.type == ButtonRelease) if (e.type == ButtonPress || e.type == ButtonRelease)
break; break;
while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e)); while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e))
;
sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y); sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y);
} }
} }

View File

@ -12,6 +12,7 @@ bool cg_n_or_last(arg_t);
bool cg_navigate_marked(arg_t); bool cg_navigate_marked(arg_t);
bool cg_prefix_external(arg_t); bool cg_prefix_external(arg_t);
bool cg_quit(arg_t); bool cg_quit(arg_t);
bool cg_pick_quit(arg_t);
bool cg_reload_image(arg_t); bool cg_reload_image(arg_t);
bool cg_remove_image(arg_t); bool cg_remove_image(arg_t);
bool cg_reverse_marks(arg_t); bool cg_reverse_marks(arg_t);
@ -57,6 +58,7 @@ bool ct_select(arg_t);
#define g_navigate_marked { cg_navigate_marked, MODE_ALL } #define g_navigate_marked { cg_navigate_marked, MODE_ALL }
#define g_prefix_external { cg_prefix_external, MODE_ALL } #define g_prefix_external { cg_prefix_external, MODE_ALL }
#define g_quit { cg_quit, MODE_ALL } #define g_quit { cg_quit, MODE_ALL }
#define g_pick_quit { cg_pick_quit, MODE_ALL }
#define g_reload_image { cg_reload_image, MODE_ALL } #define g_reload_image { cg_reload_image, MODE_ALL }
#define g_remove_image { cg_remove_image, MODE_ALL } #define g_remove_image { cg_remove_image, MODE_ALL }
#define g_reverse_marks { cg_reverse_marks, MODE_ALL } #define g_reverse_marks { cg_reverse_marks, MODE_ALL }

View File

@ -92,6 +92,7 @@ static const KeySym KEYHANDLER_ABORT = XK_Escape;
static const keymap_t keys[] = { static const keymap_t keys[] = {
/* modifiers key function argument */ /* modifiers key function argument */
{ 0, XK_q, g_quit, 0 }, { 0, XK_q, g_quit, 0 },
{ 0, XK_Q, g_pick_quit, 0 },
{ 0, XK_Return, g_switch_mode, None }, { 0, XK_Return, g_switch_mode, None },
{ 0, XK_f, g_toggle_fullscreen, None }, { 0, XK_f, g_toggle_fullscreen, None },
{ 0, XK_b, g_toggle_bar, None }, { 0, XK_b, g_toggle_bar, None },

View File

@ -23,8 +23,11 @@ HAVE_LIBWEBP = $(OPT_DEP_DEFAULT)
# Compiler and linker # Compiler and linker
CC = c99 CC = c99
# CFLAGS, any optimization flags goes here # CFLAGS, any additional compiler flags goes here
CFLAGS = -Wall -pedantic CFLAGS = -Wall -pedantic -O2 -DNDEBUG
# Uncomment for a debug build using gcc/clang
# CFLAGS = -Wall -pedantic -DDEBUG -g3 -fsanitize=address,undefined
# LDFLAGS = $(CFLAGS)
# icons that will be installed via `make icon` # icons that will be installed via `make icon`
ICONS = 16x16.png 32x32.png 48x48.png 64x64.png 128x128.png ICONS = 16x16.png 32x32.png 48x48.png 64x64.png 128x128.png

82
etc/.clang-format Normal file
View File

@ -0,0 +1,82 @@
# clang-format doesn't dictate the project's code style and can mess up a
# couple edge cases. However it comes quite close and can be used for fixing
# most style issues automatically on new changes via `git-clang-format`.
---
Standard: c++03
ColumnLimit: 0
AccessModifierOffset: -8
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentWrappedFunctionNames: false
NamespaceIndentation: None
TabWidth: 8
UseTab: AlignWithSpaces
AlignAfterOpenBracket: true
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: false
AlignOperands: true
AlignTrailingComments: false
DerivePointerAlignment: true
PointerAlignment: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterControlStatement: MultiLine
AfterEnum: false
AfterExternBlock: false
AfterFunction: true
AfterStruct: false
AfterUnion: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
BreakBeforeBinaryOperators: None
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializers: BeforeComma
BreakConstructorInitializersBeforeComma: false
BreakStringLiterals: true
Cpp11BracedListStyle: false
MaxEmptyLinesToKeep: 1
ReflowComments: false
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
...

View File

@ -116,7 +116,7 @@ references *above* can be found on the new main nsxiv repository on CodeBerg.
* Changes: * Changes:
* Window title is now customizeable via `win-title`, cli flag `-T` and related * Window title is now customizable via `win-title`, cli flag `-T` and related
config.h options are removed. See `WINDOW TITLE` section of the manpage for config.h options are removed. See `WINDOW TITLE` section of the manpage for
more info. [#213] more info. [#213]
* Imlib2 cache size is now set based on total memory percentage, by default * Imlib2 cache size is now set based on total memory percentage, by default

View File

@ -23,7 +23,7 @@ Contribution Guideline
When contributing, make sure: When contributing, make sure:
* Your contribution falls under nsxiv's scope and aim * Your contribution falls under nsxiv's scope and aim
* You follow the existing code style (see [.editorconfig](../.editorconfig)) * You follow the existing code style (see the "Code Style" section below)
* You open the pull request from a new branch, not from master * You open the pull request from a new branch, not from master
* To avoid using force pushes, especially for bigger patches. Only use them * To avoid using force pushes, especially for bigger patches. Only use them
when there's merge conflicts. when there's merge conflicts.
@ -44,6 +44,21 @@ to work on. You can also filter the issues via label:
(Intermediate/Experienced) Issues where we require some help. (Intermediate/Experienced) Issues where we require some help.
Code Style
----------
`nsxiv` mostly follows the [suckless code-style][sl], with a few exceptions.
If your editor supports [.editorconfig](../.editorconfig) then you'll already be
off to a good start without needing much manual intervention. Additionally we
provide a [clang-format](./.clang-format) configuration for reference, which you
may use via [`git-clang-format`][cf] to format the changes you've made (please
do not run it globally on the entire code-base since clang-format gets a decent
amount of edge cases wrong).
[sl]: https://suckless.org/coding_style/
[cf]: https://clang.llvm.org/docs/ClangFormat.html#git-integration
Development workflow for maintainers Development workflow for maintainers
------------------------------------ ------------------------------------

View File

@ -135,6 +135,10 @@ Prefix the next command with a number (denoted via
.B q .B q
Quit nsxiv. Quit nsxiv.
.TP .TP
.B Q
Quit nsxiv, but additionally print the current filename when \-o is active and
no files have been marked.
.TP
.B Return .B Return
Switch to thumbnail mode / open selected image in image mode. Switch to thumbnail mode / open selected image in image mode.
.TP .TP
@ -457,6 +461,9 @@ Color of the bar foreground. Defaults to window.foreground
Color of the mark foreground. Defaults to window.foreground Color of the mark foreground. Defaults to window.foreground
.TP .TP
Please see xrdb(1) on how to change them. Please see xrdb(1) on how to change them.
.LP
An X resources entry with an empty value means the default
(defined in config.h) will be used.
.SH WINDOW TITLE .SH WINDOW TITLE
The window title can be replaced with the output of a user-provided script, The window title can be replaced with the output of a user-provided script,
which is called by nsxiv whenever any of the relevant information changes. which is called by nsxiv whenever any of the relevant information changes.
@ -562,11 +569,6 @@ TAAPArthur <taaparthur at gmail.com>
eylles <ed.ylles1997 at gmail.com> eylles <ed.ylles1997 at gmail.com>
Stein Gunnar Bakkeby <bakkeby at gmail.com> Stein Gunnar Bakkeby <bakkeby at gmail.com>
explosion-mental <explosion0mental at gmail.com> explosion-mental <explosion0mental at gmail.com>
mamg22 <marcomonizg at gmail.com>
LuXu
Guilherme Freire
Sam Whitehead
Kian Kasad <kian at kasad.com>
.EE .EE
.SH CONTRIBUTORS .SH CONTRIBUTORS
.EX .EX

View File

@ -9,6 +9,7 @@ misc-*,android-cloexec-*,llvm-include-order
-bugprone-implicit-widening-of-multiplication-result,-bugprone-integer-division -bugprone-implicit-widening-of-multiplication-result,-bugprone-integer-division
-android-cloexec-fopen,-android-cloexec-pipe,-cert-err33-c -android-cloexec-fopen,-android-cloexec-pipe,-cert-err33-c
-bugprone-assignment-in-if-condition -bugprone-assignment-in-if-condition
-bugprone-suspicious-realloc-usage
# false positive warnings # false positive warnings
-clang-analyzer-valist.Uninitialized -clang-analyzer-valist.Uninitialized

30
image.c
View File

@ -54,6 +54,10 @@ enum { DEF_GIF_DELAY = 75 };
enum { DEF_WEBP_DELAY = 75 }; enum { DEF_WEBP_DELAY = 75 };
#endif #endif
#if HAVE_IMLIB2_MULTI_FRAME
enum { DEF_ANIM_DELAY = 75 };
#endif
#define ZOOM_MIN (zoom_levels[0] / 100) #define ZOOM_MIN (zoom_levels[0] / 100)
#define ZOOM_MAX (zoom_levels[ARRLEN(zoom_levels) - 1] / 100) #define ZOOM_MAX (zoom_levels[ARRLEN(zoom_levels) - 1] / 100)
@ -282,8 +286,9 @@ static bool img_load_gif(img_t *img, const fileinfo_t *file)
if (i < y || i >= y + h || j < x || j >= x + w || if (i < y || i >= y + h || j < x || j >= x + w ||
rows[i - y][j - x] == transp) rows[i - y][j - x] == transp)
{ {
if (prev_frame != NULL && (prev_disposal != 2 || if (prev_frame != NULL &&
i < py || i >= py + ph || j < px || j >= px + pw)) (prev_disposal != 2 || i < py || i >= py + ph ||
j < px || j >= px + pw))
{ {
*ptr = prev_frame[i * sw + j]; *ptr = prev_frame[i * sw + j];
} else { } else {
@ -412,8 +417,8 @@ static bool img_load_webp(img_t *img, const fileinfo_t *file)
/* Load and decode frames (also works on images with only 1 frame) */ /* Load and decode frames (also works on images with only 1 frame) */
m->length = m->cnt = m->sel = 0; m->length = m->cnt = m->sel = 0;
while (WebPAnimDecoderGetNext(dec, &buf, &ts)) { while (WebPAnimDecoderGetNext(dec, &buf, &ts)) {
im = imlib_create_image_using_copied_data( im = imlib_create_image_using_copied_data(info.canvas_width, info.canvas_height,
info.canvas_width, info.canvas_height, (uint32_t *)buf); (uint32_t *)buf);
imlib_context_set_image(im); imlib_context_set_image(im);
imlib_image_set_format("webp"); imlib_image_set_format("webp");
/* Get an iterator of this frame - used for frame info (duration, etc.) */ /* Get an iterator of this frame - used for frame info (duration, etc.) */
@ -469,11 +474,6 @@ static bool img_load_multiframe(img_t *img, const fileinfo_t *file)
m->frames = erealloc(m->frames, m->cap * sizeof(*m->frames)); m->frames = erealloc(m->frames, m->cap * sizeof(*m->frames));
} }
imlib_context_set_dither(0);
imlib_context_set_anti_alias(0);
imlib_context_set_color_modifier(NULL);
imlib_context_set_operation(IMLIB_OP_COPY);
if ((blank = imlib_create_image(img->w, img->h)) == NULL) { if ((blank = imlib_create_image(img->w, img->h)) == NULL) {
error(0, 0, "%s: couldn't create image", file->name); error(0, 0, "%s: couldn't create image", file->name);
return false; return false;
@ -481,6 +481,11 @@ static bool img_load_multiframe(img_t *img, const fileinfo_t *file)
imlib_context_set_image(blank); imlib_context_set_image(blank);
img_area_clear(0, 0, img->w, img->h); img_area_clear(0, 0, img->w, img->h);
imlib_context_set_dither(0);
imlib_context_set_anti_alias(0);
imlib_context_set_color_modifier(NULL);
imlib_context_set_operation(IMLIB_OP_COPY);
/* /*
* Imlib2 gives back a "raw frame", we need to blend it on top of the * Imlib2 gives back a "raw frame", we need to blend it on top of the
* previous frame ourselves if necessary to get the fully decoded frame. * previous frame ourselves if necessary to get the fully decoded frame.
@ -505,6 +510,7 @@ static bool img_load_multiframe(img_t *img, const fileinfo_t *file)
} }
imlib_context_set_image(frame); imlib_context_set_image(frame);
imlib_image_set_changes_on_disk(); /* see img_load() for rationale */
imlib_image_get_frame_info(&finfo); imlib_image_get_frame_info(&finfo);
assert(finfo.frame_count == (int)fcnt); assert(finfo.frame_count == (int)fcnt);
assert(finfo.canvas_w == img->w && finfo.canvas_h == img->h); assert(finfo.canvas_w == img->w && finfo.canvas_h == img->h);
@ -537,7 +543,7 @@ static bool img_load_multiframe(img_t *img, const fileinfo_t *file)
imlib_context_set_blend(!!(finfo.frame_flags & IMLIB_FRAME_BLEND)); imlib_context_set_blend(!!(finfo.frame_flags & IMLIB_FRAME_BLEND));
imlib_blend_image_onto_image(frame, has_alpha, 0, 0, sw, sh, sx, sy, sw, sh); imlib_blend_image_onto_image(frame, has_alpha, 0, 0, sw, sh, sx, sy, sw, sh);
m->frames[m->cnt].im = canvas; m->frames[m->cnt].im = canvas;
m->frames[m->cnt].delay = finfo.frame_delay; m->frames[m->cnt].delay = finfo.frame_delay ? finfo.frame_delay : DEF_ANIM_DELAY;
m->length += m->frames[m->cnt].delay; m->length += m->frames[m->cnt].delay;
m->cnt++; m->cnt++;
imlib_context_set_image(frame); imlib_context_set_image(frame);
@ -546,6 +552,7 @@ static bool img_load_multiframe(img_t *img, const fileinfo_t *file)
imlib_context_set_image(blank); imlib_context_set_image(blank);
imlib_free_image(); imlib_free_image();
img_multiframe_context_set(img); img_multiframe_context_set(img);
imlib_context_set_color_modifier(img->cmod); /* restore cmod */
return m->cnt > 0; return m->cnt > 0;
} }
#endif /* HAVE_IMLIB2_MULTI_FRAME */ #endif /* HAVE_IMLIB2_MULTI_FRAME */
@ -578,6 +585,9 @@ bool img_load(img_t *img, const fileinfo_t *file)
if ((img->im = img_open(file)) == NULL) if ((img->im = img_open(file)) == NULL)
return false; return false;
/* ensure that the image's timestamp is checked when loading from cache
* to avoid issues like: https://codeberg.org/nsxiv/nsxiv/issues/436
*/
imlib_image_set_changes_on_disk(); imlib_image_set_changes_on_disk();
/* since v1.7.5, Imlib2 can parse exif orientation from jpeg files. /* since v1.7.5, Imlib2 can parse exif orientation from jpeg files.

46
main.c
View File

@ -40,15 +40,16 @@
#include <X11/XF86keysym.h> #include <X11/XF86keysym.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#define MODMASK(mask) ((mask) & USED_MODMASK) #define MODMASK(mask) (USED_MODMASK & (mask))
#define BAR_SEP " " #define BAR_SEP " "
#define TV_DIFF(t1,t2) (((t1)->tv_sec - (t2)->tv_sec ) * 1000 + \ #define TV_DIFF(t1,t2) (((t1)->tv_sec - (t2)->tv_sec ) * 1000 + \
((t1)->tv_usec - (t2)->tv_usec) / 1000) ((t1)->tv_usec - (t2)->tv_usec) / 1000)
#define TV_ADD_MSEC(tv,t) { \ #define TV_ADD_MSEC(tv, t) \
do { \
(tv)->tv_sec += (t) / 1000; \ (tv)->tv_sec += (t) / 1000; \
(tv)->tv_usec += (t) % 1000 * 1000; \ (tv)->tv_usec += (t) % 1000 * 1000; \
} } while (0)
typedef struct { typedef struct {
int err; int err;
@ -200,8 +201,8 @@ void remove_file(int n, bool manual)
if (n + 1 < filecnt) { if (n + 1 < filecnt) {
if (tns.thumbs != NULL) { if (tns.thumbs != NULL) {
memmove(tns.thumbs + n, tns.thumbs + n + 1, (filecnt - n - 1) * memmove(tns.thumbs + n, tns.thumbs + n + 1,
sizeof(*tns.thumbs)); (filecnt - n - 1) * sizeof(*tns.thumbs));
memset(tns.thumbs + filecnt - 1, 0, sizeof(*tns.thumbs)); memset(tns.thumbs + filecnt - 1, 0, sizeof(*tns.thumbs));
} }
memmove(files + n, files + n + 1, (filecnt - n - 1) * sizeof(*files)); memmove(files + n, files + n + 1, (filecnt - n - 1) * sizeof(*files));
@ -377,7 +378,7 @@ void load_image(int new)
if (new >= filecnt) if (new >= filecnt)
new = filecnt - 1; new = filecnt - 1;
else if (new > 0 && prev) else if (new > 0 && prev)
new--; new -= 1;
} }
files[new].flags &= ~FF_WARN; files[new].flags &= ~FF_WARN;
fileidx = current = new; fileidx = current = new;
@ -426,18 +427,19 @@ static void update_info(void)
/* update bar contents */ /* update bar contents */
if (win.bar.h == 0 || extprefix) if (win.bar.h == 0 || extprefix)
return; return;
for (fw = 0, i = filecnt; i > 0; fw++, i /= 10); for (fw = 0, i = filecnt; i > 0; fw++, i /= 10)
;
mark = files[fileidx].flags & FF_MARK ? "* " : ""; mark = files[fileidx].flags & FF_MARK ? "* " : "";
l->p = l->buf; l->p = l->buf;
r->p = r->buf; r->p = r->buf;
if (mode == MODE_THUMB) { if (mode == MODE_THUMB) {
if (tns.loadnext < tns.end) if (tns.loadnext < tns.end)
bar_put(l, "Loading... %0*d", fw, tns.loadnext + 1); bar_put(r, "Loading... %0*d | ", fw, tns.loadnext + 1);
else if (tns.initnext < filecnt) else if (tns.initnext < filecnt)
bar_put(l, "Caching... %0*d", fw, tns.initnext + 1); bar_put(r, "Caching... %0*d | ", fw, tns.initnext + 1);
else if (info.ft.err)
strncpy(l->buf, files[fileidx].name, l->size);
bar_put(r, "%s%0*d/%d", mark, fw, fileidx + 1, filecnt); bar_put(r, "%s%0*d/%d", mark, fw, fileidx + 1, filecnt);
if (info.ft.err)
strncpy(l->buf, files[fileidx].name, l->size);
} else { } else {
bar_put(r, "%s", mark); bar_put(r, "%s", mark);
if (img.ss.on) { if (img.ss.on) {
@ -454,7 +456,8 @@ static void update_info(void)
bar_put(r, "C%+d" BAR_SEP, img.contrast); bar_put(r, "C%+d" BAR_SEP, img.contrast);
bar_put(r, "%3d%%" BAR_SEP, (int)(img.zoom * 100.0)); bar_put(r, "%3d%%" BAR_SEP, (int)(img.zoom * 100.0));
if (img.multi.cnt > 0) { if (img.multi.cnt > 0) {
for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10); for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10)
;
bar_put(r, "%0*d/%d" BAR_SEP, fn, img.multi.sel + 1, img.multi.cnt); bar_put(r, "%0*d/%d" BAR_SEP, fn, img.multi.sel + 1, img.multi.cnt);
} }
bar_put(r, "%0*d/%d", fw, fileidx + 1, filecnt); bar_put(r, "%0*d/%d", fw, fileidx + 1, filecnt);
@ -562,8 +565,9 @@ void handle_key_handler(bool init)
return; return;
if (init) { if (init) {
close_info(); close_info();
snprintf(win.bar.l.buf, win.bar.l.size, "Getting key handler input " snprintf(win.bar.l.buf, win.bar.l.size,
"(%s to abort)...", XKeysymToString(KEYHANDLER_ABORT)); "Getting key handler input (%s to abort)...",
XKeysymToString(KEYHANDLER_ABORT));
} else { /* abort */ } else { /* abort */
open_info(); open_info();
update_info(); update_info();
@ -622,7 +626,8 @@ static bool run_key_handler(const char *key, unsigned int mask)
} }
} }
fclose(pfs); fclose(pfs);
while (waitpid(pid, NULL, 0) == -1 && errno == EINTR); while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
;
for (f = i = 0; f < fcnt; i++) { for (f = i = 0; f < fcnt; i++) {
if ((marked && (files[i].flags & FF_MARK)) || (!marked && i == fileidx)) { if ((marked && (files[i].flags & FF_MARK)) || (!marked && i == fileidx)) {
@ -639,7 +644,8 @@ static bool run_key_handler(const char *key, unsigned int mask)
} }
} }
/* drop user input events that occurred while running the key handler */ /* drop user input events that occurred while running the key handler */
while (XCheckIfEvent(win.env.dpy, &dump, is_input_ev, NULL)); while (XCheckIfEvent(win.env.dpy, &dump, is_input_ev, NULL))
;
if (mode == MODE_IMAGE && changed) { if (mode == MODE_IMAGE && changed) {
img_close(&img, true); img_close(&img, true);
@ -739,8 +745,8 @@ static void run(void)
init_thumb = mode == MODE_THUMB && tns.initnext < filecnt; init_thumb = mode == MODE_THUMB && tns.initnext < filecnt;
load_thumb = mode == MODE_THUMB && tns.loadnext < tns.end; load_thumb = mode == MODE_THUMB && tns.loadnext < tns.end;
if ((init_thumb || load_thumb || to_set || info.fd != -1 || if ((init_thumb || load_thumb || to_set || info.fd != -1 || arl.fd != -1) &&
arl.fd != -1) && XPending(win.env.dpy) == 0) XPending(win.env.dpy) == 0)
{ {
if (load_thumb) { if (load_thumb) {
set_timeout(redraw, TO_REDRAW_THUMBS, false); set_timeout(redraw, TO_REDRAW_THUMBS, false);
@ -793,8 +799,8 @@ static void run(void)
discard = ev.type == nextev.type; discard = ev.type == nextev.type;
break; break;
case KeyPress: case KeyPress:
discard = (nextev.type == KeyPress || nextev.type == KeyRelease) discard = (nextev.type == KeyPress || nextev.type == KeyRelease) &&
&& ev.xkey.keycode == nextev.xkey.keycode; ev.xkey.keycode == nextev.xkey.keycode;
break; break;
} }
} }

View File

@ -20,6 +20,10 @@
#ifndef NSXIV_H #ifndef NSXIV_H
#define NSXIV_H #define NSXIV_H
#if !defined(DEBUG) && !defined(NDEBUG)
#define NDEBUG
#endif
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>

View File

@ -43,7 +43,8 @@ void print_usage(void)
{ {
printf("usage: %s [-abcfhiopqrtvZ0] [-A FRAMERATE] [-e WID] [-G GAMMA] " printf("usage: %s [-abcfhiopqrtvZ0] [-A FRAMERATE] [-e WID] [-G GAMMA] "
"[-g GEOMETRY] [-N NAME] [-n NUM] [-S DELAY] [-s MODE] " "[-g GEOMETRY] [-N NAME] [-n NUM] [-S DELAY] [-s MODE] "
"[-z ZOOM] FILES...\n", progname); "[-z ZOOM] FILES...\n",
progname);
} }
static void print_version(void) static void print_version(void)

View File

@ -343,10 +343,14 @@ bool tns_load(tns_t *tns, int n, bool force, bool cache_only)
} }
file->flags |= FF_TN_INIT; file->flags |= FF_TN_INIT;
if (n == tns->initnext) if (n == tns->initnext) {
while (++tns->initnext < *tns->cnt && ((++file)->flags & FF_TN_INIT)); while (++tns->initnext < *tns->cnt && ((++file)->flags & FF_TN_INIT))
if (n == tns->loadnext && !cache_only) ;
while (++tns->loadnext < tns->end && (++t)->im != NULL); }
if (n == tns->loadnext && !cache_only) {
while (++tns->loadnext < tns->end && (++t)->im != NULL)
;
}
return true; return true;
} }

3
util.c
View File

@ -203,7 +203,8 @@ int r_mkdir(char *path)
s++; s++;
continue; continue;
} }
for (; *s != '\0' && *s != '/'; s++); for (; *s != '\0' && *s != '/'; s++)
;
c = *s; c = *s;
*s = '\0'; *s = '\0';
if (mkdir(path, 0755) == -1) { if (mkdir(path, 0755) == -1) {

View File

@ -56,8 +56,12 @@ static struct {
int name; int name;
Cursor icon; Cursor icon;
} cursors[CURSOR_COUNT] = { } cursors[CURSOR_COUNT] = {
{ XC_left_ptr }, { XC_dotbox }, { XC_fleur }, { XC_watch }, { XC_left_ptr },
{ XC_sb_left_arrow }, { XC_sb_right_arrow } { XC_dotbox },
{ XC_fleur },
{ XC_watch },
{ XC_sb_left_arrow },
{ XC_sb_right_arrow }
}; };
#if HAVE_LIBFONTS #if HAVE_LIBFONTS
@ -226,8 +230,8 @@ void win_open(win_t *win)
if (gmask & YValue) { if (gmask & YValue) {
if (gmask & YNegative) { if (gmask & YNegative) {
win->y += e->scrh - win->h; win->y += e->scrh - win->h;
sizehints.win_gravity = sizehints.win_gravity == NorthEastGravity sizehints.win_gravity = sizehints.win_gravity == NorthEastGravity ?
? SouthEastGravity : SouthWestGravity; SouthEastGravity : SouthWestGravity;
} }
sizehints.flags |= USPosition; sizehints.flags |= USPosition;
} else { } else {
@ -466,8 +470,10 @@ static void win_draw_bar(win_t *win)
XSetBackground(e->dpy, gc, win->bar_bg.pixel); XSetBackground(e->dpy, gc, win->bar_bg.pixel);
if ((len = strlen(r->buf)) > 0) { if ((len = strlen(r->buf)) > 0) {
if ((tw = TEXTWIDTH(win, r->buf, len)) > w) if ((tw = TEXTWIDTH(win, r->buf, len)) > w) {
XftDrawDestroy(d);
return; return;
}
x = win->w - tw - H_TEXT_PAD; x = win->w - tw - H_TEXT_PAD;
w -= tw; w -= tw;
win_draw_text(win, d, &win->bar_fg, x, y, r->buf, len, tw); win_draw_text(win, d, &win->bar_fg, x, y, r->buf, len, tw);