Krolyxon
Commit caec32d

Branches

Refs →

nsxivcaec32d

Merge branch 'autoreload'

Pull request #278.

Fixes issue #29 and issue #199.
Author
Bert Münnich
Date
2017-05-17 20:22 +0200
Parents
1fb3ec5 a20173a
Commit
caec32d2578db9973e0ed3d87fbb9974e0b03f04

+219 −3

5 files changed

  1. M Makefile +5 −1
  2. A autoreload.h +36 −0
  3. A autoreload_inotify.c +113 −0
  4. A autoreload_nop.c +43 −0
  5. M main.c +22 −2
M Makefile View
@@ -21,9 +21,13 @@ ifndef NO_LIBEXIF
2121 LIBS += -lexif
2222 endif
2323
24+# select autoreload backend
25+# overwritten with `make AUTORELOAD=nop`
26+AUTORELOAD := inotify
27+
2428 .PHONY: clean install uninstall
2529
26−SRC := commands.c image.c main.c options.c thumbs.c util.c window.c
30+SRC := autoreload_$(AUTORELOAD).c commands.c image.c main.c options.c thumbs.c util.c window.c
2731 DEP := $(SRC:.c=.d)
2832 OBJ := $(SRC:.c=.o)
2933
A autoreload.h View
@@ -0,0 +1,36 @@
1+/* Copyright 2017 Max Voit
2+ *
3+ * This file is part of sxiv.
4+ *
5+ * sxiv is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published
7+ * by the Free Software Foundation; either version 2 of the License,
8+ * or (at your option) any later version.
9+ *
10+ * sxiv is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#ifndef AUTORELOAD_H
20+#define AUTORELOAD_H
21+
22+#include "types.h"
23+
24+typedef struct {
25+ int fd;
26+ int wd_dir;
27+ int wd_file;
28+ char *filename;
29+} arl_t;
30+
31+void arl_init(arl_t*);
32+void arl_cleanup(arl_t*);
33+void arl_setup(arl_t*, const char* /* result of realpath(3) */);
34+bool arl_handle(arl_t*);
35+
36+#endif /* AUTORELOAD_H */
A autoreload_inotify.c View
@@ -0,0 +1,113 @@
1+/* Copyright 2017 Max Voit
2+ *
3+ * This file is part of sxiv.
4+ *
5+ * sxiv is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published
7+ * by the Free Software Foundation; either version 2 of the License,
8+ * or (at your option) any later version.
9+ *
10+ * sxiv is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#include <errno.h>
20+#include <stdlib.h>
21+#include <string.h>
22+#include <unistd.h>
23+#include <sys/inotify.h>
24+
25+#include "util.h"
26+#include "autoreload.h"
27+
28+void arl_init(arl_t *arl)
29+{
30+ arl->fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
31+ arl->wd_dir = arl->wd_file = -1;
32+ if (arl->fd == -1)
33+ error(0, 0, "Could not initialize inotify, no automatic image reloading");
34+}
35+
36+CLEANUP void arl_cleanup(arl_t *arl)
37+{
38+ if (arl->fd != -1)
39+ close(arl->fd);
40+ free(arl->filename);
41+}
42+
43+static void rm_watch(int fd, int *wd)
44+{
45+ if (*wd != -1) {
46+ inotify_rm_watch(fd, *wd);
47+ *wd = -1;
48+ }
49+}
50+
51+static void add_watch(int fd, int *wd, const char *path, uint32_t mask)
52+{
53+ *wd = inotify_add_watch(fd, path, mask);
54+ if (*wd == -1)
55+ error(0, errno, "inotify: %s", path);
56+}
57+
58+void arl_setup(arl_t *arl, const char *filepath)
59+{
60+ char *base = strrchr(filepath, '/');
61+
62+ if (arl->fd == -1)
63+ return;
64+
65+ rm_watch(arl->fd, &arl->wd_dir);
66+ rm_watch(arl->fd, &arl->wd_file);
67+
68+ add_watch(arl->fd, &arl->wd_file, filepath, IN_CLOSE_WRITE | IN_DELETE_SELF);
69+
70+ free(arl->filename);
71+ arl->filename = estrdup(filepath);
72+
73+ if (base != NULL) {
74+ arl->filename[++base - filepath] = '\0';
75+ add_watch(arl->fd, &arl->wd_dir, arl->filename, IN_CREATE | IN_MOVED_TO);
76+ strcpy(arl->filename, base);
77+ }
78+}
79+
80+union {
81+ char d[4096]; /* aligned buffer */
82+ struct inotify_event e;
83+} buf;
84+
85+bool arl_handle(arl_t *arl)
86+{
87+ bool reload = false;
88+ char *ptr;
89+ const struct inotify_event *event;
90+
91+ for (;;) {
92+ ssize_t len = read(arl->fd, buf.d, sizeof(buf.d));
93+
94+ if (len == -1) {
95+ if (errno == EINTR)
96+ continue;
97+ break;
98+ }
99+ for (ptr = buf.d; ptr < buf.d + len; ptr += sizeof(*event) + event->len) {
100+ event = (const struct inotify_event*) ptr;
101+ if (event->mask & IN_CLOSE_WRITE) {
102+ reload = true;
103+ } else if (event->mask & IN_DELETE_SELF) {
104+ rm_watch(arl->fd, &arl->wd_file);
105+ } else if (event->mask & (IN_CREATE | IN_MOVED_TO)) {
106+ if (STREQ(event->name, arl->filename))
107+ reload = true;
108+ }
109+ }
110+ }
111+ return reload;
112+}
113+
A autoreload_nop.c View
@@ -0,0 +1,43 @@
1+/* Copyright 2017 Max Voit
2+ *
3+ * This file is part of sxiv.
4+ *
5+ * sxiv is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published
7+ * by the Free Software Foundation; either version 2 of the License,
8+ * or (at your option) any later version.
9+ *
10+ * sxiv is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#include "autoreload.h"
20+
21+void arl_cleanup(arl_t *arl)
22+{
23+ (void) arl;
24+}
25+
26+bool arl_handle(arl_t *arl, const char *filepath)
27+{
28+ (void) arl;
29+ (void) filepath;
30+ return false;
31+}
32+
33+void arl_init(arl_t *arl)
34+{
35+ (void) arl;
36+}
37+
38+void arl_setup(arl_t *arl, const char *filepath)
39+{
40+ (void) arl;
41+ (void) filepath;
42+}
43+
M main.c View
@@ -28,6 +28,7 @@
2828 #include <sys/stat.h>
2929 #include <sys/time.h>
3030 #include <sys/wait.h>
31+#include <time.h>
3132 #include <X11/keysym.h>
3233 #include <X11/XF86keysym.h>
3334
@@ -38,6 +39,7 @@
3839 #include "thumbs.h"
3940 #include "util.h"
4041 #include "window.h"
42+#include "autoreload.h"
4143
4244 #define _MAPPINGS_CONFIG
4345 #include "config.h"
@@ -56,6 +58,7 @@ void slideshow(void);
5658 void clear_resize(void);
5759
5860 appmode_t mode;
61+arl_t arl;
5962 img_t img;
6063 tns_t tns;
6164 win_t win;
@@ -98,6 +101,7 @@ timeout_t timeouts[] = {
98101 void cleanup(void)
99102 {
100103 img_close(&img, false);
104+ arl_cleanup(&arl);
101105 tns_free(&tns);
102106 win_close(&win);
103107 }
@@ -317,6 +321,7 @@ void load_image(int new)
317321
318322 info.open = false;
319323 open_info();
324+ arl_setup(&arl, files[fileidx].path);
320325
321326 if (img.multi.cnt > 0 && img.multi.animate)
322327 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
@@ -672,6 +677,8 @@ void on_buttonpress(XButtonEvent *bev)
672677 prefix = 0;
673678 }
674679
680+const struct timespec ten_ms = {0, 10000000};
681+
675682 void run(void)
676683 {
677684 int xfd;
@@ -685,8 +692,8 @@ void run(void)
685692 init_thumb = mode == MODE_THUMB && tns.initnext < filecnt;
686693 load_thumb = mode == MODE_THUMB && tns.loadnext < tns.end;
687694
688− if ((init_thumb || load_thumb || to_set || info.fd != -1) &&
689− XPending(win.env.dpy) == 0)
695+ if ((init_thumb || load_thumb || to_set || info.fd != -1 ||
696+ arl.fd != -1) && XPending(win.env.dpy) == 0)
690697 {
691698 if (load_thumb) {
692699 set_timeout(redraw, TO_REDRAW_THUMBS, false);
@@ -708,9 +715,21 @@ void run(void)
708715 FD_SET(info.fd, &fds);
709716 xfd = MAX(xfd, info.fd);
710717 }
718+ if (arl.fd != -1) {
719+ FD_SET(arl.fd, &fds);
720+ xfd = MAX(xfd, arl.fd);
721+ }
711722 select(xfd + 1, &fds, 0, 0, to_set ? &timeout : NULL);
712723 if (info.fd != -1 && FD_ISSET(info.fd, &fds))
713724 read_info();
725+ if (arl.fd != -1 && FD_ISSET(arl.fd, &fds)) {
726+ if (arl_handle(&arl)) {
727+ /* when too fast, imlib2 can't load the image */
728+ nanosleep(&ten_ms, NULL);
729+ load_image(fileidx);
730+ redraw();
731+ }
732+ }
714733 }
715734 continue;
716735 }
@@ -854,6 +873,7 @@ int main(int argc, char **argv)
854873
855874 win_init(&win);
856875 img_init(&img, &win);
876+ arl_init(&arl);
857877
858878 if ((homedir = getenv("XDG_CONFIG_HOME")) == NULL || homedir[0] == '\0') {
859879 homedir = getenv("HOME");