Krolyxon
Commit b8ff167

Branches

Refs →

nsxivb8ff167

Major code refactoring

- Configurable key and mouse mappings in config.h
- Put event handling code from main.c into events.[ch]
Author
Bert
Date
2011-07-26 18:01 +0200
Parent
a271e16
Commit
b8ff1677b1cbb4d3e769861d1e14234c6a38a80a

+807 −647

12 files changed

  1. M Makefile +2 −2
  2. M config.h +103 −19
  3. A events.c +562 −0
  4. A events.h +67 −0
  5. M image.c +4 −2
  6. M main.c +47 −603
  7. M options.c +1 −0
  8. M sxiv.1 +4 −4
  9. M thumbs.c +6 −4
  10. M types.h +4 −10
  11. M util.c +5 −3
  12. M window.c +2 −0
M Makefile View
@@ -1,6 +1,6 @@
11 all: sxiv
22
3−VERSION = git-20110722
3+VERSION = git-20110726
44
55 CC = gcc
66 DESTDIR =
@@ -9,7 +9,7 @@ CFLAGS = -Wall -pedantic -DVERSION=\"$(VERSION)\"
99 LDFLAGS =
1010 LIBS = -lX11 -lImlib2
1111
12−SRC = image.c main.c options.c thumbs.c util.c window.c
12+SRC = events.o image.c main.c options.c thumbs.c util.c window.c
1313 OBJ = $(SRC:.c=.o)
1414
1515 sxiv: $(OBJ)
M config.h View
@@ -1,36 +1,120 @@
1−/* default window dimensions (overwritten via -g option): */
1+#ifdef _GENERAL_CONFIG
2+
3+/* enable external commands (defined below)? 0 = off, 1 = on: */
4+enum { EXT_COMMANDS = 0 };
5+
6+#endif
7+#ifdef _WINDOW_CONFIG
8+
9+/* default window dimensions (overwritten via -g option): */
210 enum { WIN_WIDTH = 800, WIN_HEIGHT = 600 };
311
4−/* default color for window background: *
5− * (see X(7) "COLOR NAMES" section for valid values) */
12+/* default color for window background: *
13+ * (see X(7) "COLOR NAMES" section for valid values) */
614 static const char * const BG_COLOR = "#999999";
7−/* default color for thumbnail selection: */
15+/* default color for thumbnail selection: */
816 static const char * const SEL_COLOR = "#0066FF";
917
10−/* how should images be scaled when they are loaded?: *
11− * (also controllable via -d/-s/-Z/-z options) *
12− * SCALE_DOWN: 100%, but fit large images into window, *
13− * SCALE_FIT: fit all images into window, *
14− * SCALE_ZOOM: use current zoom level, 100% at startup */
18+#endif
19+#ifdef _IMAGE_CONFIG
20+
21+/* how should images be scaled when they are loaded?: *
22+ * (also controllable via -d/-s/-Z/-z options) *
23+ * SCALE_DOWN: 100%, but fit large images into window, *
24+ * SCALE_FIT: fit all images into window, *
25+ * SCALE_ZOOM: use current zoom level, 100% at startup */
1526 static const scalemode_t SCALE_MODE = SCALE_DOWN;
1627
17−/* levels (percent) to use when zooming via '-' and '+': */
28+/* levels (percent) to use when zooming via '-' and '+': */
1829 static const float zoom_levels[] = {
1930 12.5, 25.0, 50.0, 75.0,
2031 100.0, 150.0, 200.0, 400.0, 800.0
2132 };
2233
23−/* default dimension of thumbnails (width == height): */
34+#endif
35+#ifdef _THUMBS_CONFIG
36+
37+/* default dimension of thumbnails (width == height): */
2438 enum { THUMB_SIZE = 60 };
2539
26−/* enable external commands (defined below)? 0=off, 1=on: */
27−enum { EXT_COMMANDS = 0 };
40+#endif
41+#ifdef _MAPPINGS_CONFIG
42+
43+/* keyboard mappings for image and thumbnail mode: */
44+static const keymap_t keys[] = {
45+ /* key function argument */
46+ { XK_q, quit, None },
47+ { XK_r, reload, None },
48+ { XK_f, toggle_fullscreen, None },
49+ { XK_a, toggle_antialias, None },
50+ { XK_A, toggle_alpha, None },
51+ { XK_Return, switch_mode, None },
52+
53+ { XK_g, first, None },
54+ { XK_G, last, None },
55+ { XK_n, navigate, +1 },
56+ { XK_space, navigate, +1 },
57+ { XK_p, navigate, -1 },
58+ { XK_BackSpace, navigate, -1 },
59+ { XK_bracketright, navigate, +10 },
60+ { XK_bracketleft, navigate, -10 },
61+
62+ { XK_D, remove_image, None },
2863
29−/* external commands and corresponding key mappings: */
64+ { XK_h, move, DIR_LEFT },
65+ { XK_Left, move, DIR_LEFT },
66+ { XK_j, move, DIR_DOWN },
67+ { XK_Down, move, DIR_DOWN },
68+ { XK_k, move, DIR_UP },
69+ { XK_Up, move, DIR_UP },
70+ { XK_l, move, DIR_RIGHT },
71+ { XK_Right, move, DIR_RIGHT },
72+
73+ { XK_braceleft, scroll, DIR_LEFT },
74+ { XK_Next, scroll, DIR_DOWN },
75+ { XK_Prior, scroll, DIR_UP },
76+ { XK_braceright, scroll, DIR_RIGHT },
77+
78+ { XK_H, pan_edge, DIR_LEFT },
79+ { XK_J, pan_edge, DIR_DOWN },
80+ { XK_K, pan_edge, DIR_UP },
81+ { XK_L, pan_edge, DIR_RIGHT },
82+
83+ { XK_plus, zoom, +1 },
84+ { XK_equal, zoom, +1 },
85+ { XK_KP_Add, zoom, +1 },
86+ { XK_minus, zoom, -1 },
87+ { XK_KP_Subtract, zoom, -1 },
88+ { XK_0, zoom, 0 },
89+ { XK_KP_0, zoom, 0 },
90+ { XK_w, fit_to_win, None },
91+ { XK_W, fit_to_img, None },
92+
93+ { XK_less, rotate, DIR_LEFT },
94+ { XK_greater, rotate, DIR_RIGHT },
95+};
96+
97+/* external commands and corresponding key mappings: */
3098 static const command_t commands[] = {
31− /* ctrl-... reload? command, '#' is replaced by filename */
32− { ',', 1, "jpegtran -rotate 270 -copy all -outfile # #" },
33− { '.', 1, "jpegtran -rotate 90 -copy all -outfile # #" },
34− { '<', 1, "mogrify -rotate -90 #" },
35− { '>', 1, "mogrify -rotate +90 #" }
99+ /* ctrl-... reload? command, '#' is replaced by filename */
100+ { XK_comma, True, "jpegtran -rotate 270 -copy all -outfile # #" },
101+ { XK_period, True, "jpegtran -rotate 90 -copy all -outfile # #" },
102+ { XK_less, True, "mogrify -rotate -90 #" },
103+ { XK_greater, True, "mogrify -rotate +90 #" }
104+};
105+
106+/* mouse button mappings for image mode: */
107+static const button_t buttons[] = {
108+ /* modifier button function argument */
109+ { None, Button1, navigate, +1 },
110+ { None, Button3, navigate, -1 },
111+ { None, Button2, drag, None },
112+ { None, Button4, move, DIR_UP },
113+ { None, Button5, move, DIR_DOWN },
114+ { ShiftMask, Button4, move, DIR_LEFT },
115+ { ShiftMask, Button5, move, DIR_RIGHT },
116+ { ControlMask, Button4, zoom, +1 },
117+ { ControlMask, Button5, zoom, -1 },
36118 };
119+
120+#endif
A events.c View
@@ -0,0 +1,562 @@
1+/* sxiv: events.c
2+ * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; either version 2 of the License, or
7+ * (at your option) any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program; if not, write to the Free Software
16+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17+ */
18+
19+#define _GENERAL_CONFIG
20+#define _MAPPINGS_CONFIG
21+
22+#include <stdlib.h>
23+#include <string.h>
24+#include <unistd.h>
25+#include <sys/time.h>
26+#include <sys/wait.h>
27+#include <X11/keysym.h>
28+#include <X11/Xutil.h>
29+
30+#include "events.h"
31+#include "image.h"
32+#include "thumbs.h"
33+#include "types.h"
34+#include "util.h"
35+#include "window.h"
36+#include "config.h"
37+
38+/* timeouts in milliseconds: */
39+enum {
40+ TO_WIN_RESIZE = 75,
41+ TO_IMAGE_DRAG = 1,
42+ TO_CURSOR_HIDE = 1500,
43+ TO_THUMBS_LOAD = 200
44+};
45+
46+void cleanup();
47+void remove_file(int, unsigned char);
48+void load_image(int);
49+void update_title();
50+
51+extern appmode_t mode;
52+extern img_t img;
53+extern tns_t tns;
54+extern win_t win;
55+
56+extern char **filenames;
57+extern int filecnt, fileidx;
58+
59+int timo_cursor;
60+int timo_redraw;
61+unsigned char dragging;
62+int mox, moy;
63+
64+int run_command(const char *cline, Bool reload) {
65+ int fncnt, fnlen;
66+ char *cn, *cmdline;
67+ const char *co, *fname;
68+ pid_t pid;
69+ int ret, status;
70+
71+ if (!cline || !*cline)
72+ return 0;
73+
74+ fncnt = 0;
75+ co = cline - 1;
76+ while ((co = strchr(co + 1, '#')))
77+ fncnt++;
78+
79+ if (!fncnt)
80+ return 0;
81+
82+ ret = 0;
83+ fname = filenames[mode == MODE_NORMAL ? fileidx : tns.sel];
84+ fnlen = strlen(fname);
85+ cn = cmdline = (char*) s_malloc((strlen(cline) + fncnt * (fnlen + 2)) *
86+ sizeof(char));
87+
88+ /* replace all '#' with filename */
89+ for (co = cline; *co; co++) {
90+ if (*co == '#') {
91+ *cn++ = '"';
92+ strcpy(cn, fname);
93+ cn += fnlen;
94+ *cn++ = '"';
95+ } else {
96+ *cn++ = *co;
97+ }
98+ }
99+ *cn = '\0';
100+
101+ if ((pid = fork()) == 0) {
102+ execlp("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
103+ warn("could not exec: /bin/sh");
104+ exit(1);
105+ } else if (pid < 0) {
106+ warn("could not fork. command line was: %s", cmdline);
107+ } else if (reload) {
108+ waitpid(pid, &status, 0);
109+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
110+ ret = 1;
111+ else
112+ warn("child exited with non-zero return value: %d. command line was: %s",
113+ WEXITSTATUS(status), cmdline);
114+ }
115+
116+ free(cmdline);
117+ return ret;
118+}
119+
120+void redraw() {
121+ if (mode == MODE_NORMAL) {
122+ img_render(&img, &win);
123+ if (timo_cursor)
124+ win_set_cursor(&win, CURSOR_ARROW);
125+ else if (!dragging)
126+ win_set_cursor(&win, CURSOR_NONE);
127+ } else {
128+ tns_render(&tns, &win);
129+ }
130+ update_title();
131+ timo_redraw = 0;
132+}
133+
134+void on_keypress(XEvent *ev) {
135+ int i;
136+ XKeyEvent *kev;
137+ KeySym ksym;
138+ char key;
139+
140+ if (!ev || ev->type != KeyPress)
141+ return;
142+
143+ kev = &ev->xkey;
144+ XLookupString(kev, &key, 1, &ksym, NULL);
145+
146+ if (EXT_COMMANDS && (CLEANMASK(kev->state) & ControlMask)) {
147+ for (i = 0; i < LEN(commands); i++) {
148+ if (commands[i].ksym == ksym) {
149+ win_set_cursor(&win, CURSOR_WATCH);
150+ if (run_command(commands[i].cmdline, commands[i].reload)) {
151+ if (mode == MODE_NORMAL) {
152+ if (fileidx < tns.cnt)
153+ tns_load(&tns, fileidx, filenames[fileidx], 1);
154+ img_close(&img, 1);
155+ load_image(fileidx);
156+ } else {
157+ if (!tns_load(&tns, tns.sel, filenames[tns.sel], 0)) {
158+ remove_file(tns.sel, 0);
159+ tns.dirty = 1;
160+ if (tns.sel >= tns.cnt)
161+ tns.sel = tns.cnt - 1;
162+ }
163+ }
164+ redraw();
165+ }
166+ if (mode == MODE_THUMBS)
167+ win_set_cursor(&win, CURSOR_ARROW);
168+ else if (!timo_cursor)
169+ win_set_cursor(&win, CURSOR_NONE);
170+ return;
171+ }
172+ }
173+ }
174+
175+ for (i = 0; i < LEN(keys); i++) {
176+ if (ksym == keys[i].ksym && keys[i].handler) {
177+ if (keys[i].handler(ev, keys[i].arg))
178+ redraw();
179+ return;
180+ }
181+ }
182+}
183+
184+void on_buttonpress(XEvent *ev) {
185+ int i, sel;
186+ XButtonEvent *bev;
187+
188+ if (!ev || ev->type != ButtonPress)
189+ return;
190+
191+ bev = &ev->xbutton;
192+
193+ if (mode == MODE_NORMAL) {
194+ if (!dragging) {
195+ win_set_cursor(&win, CURSOR_ARROW);
196+ timo_cursor = TO_CURSOR_HIDE;
197+ }
198+
199+ for (i = 0; i < LEN(buttons); i++) {
200+ if (CLEANMASK(bev->state) == CLEANMASK(buttons[i].mod) &&
201+ bev->button == buttons[i].button && buttons[i].handler)
202+ {
203+ if (buttons[i].handler(ev, buttons[i].arg))
204+ redraw();
205+ return;
206+ }
207+ }
208+ } else {
209+ /* thumbnail mode */
210+ switch (bev->button) {
211+ case Button1:
212+ if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) {
213+ if (sel == tns.sel) {
214+ load_image(tns.sel);
215+ mode = MODE_NORMAL;
216+ timo_cursor = TO_CURSOR_HIDE;
217+ } else {
218+ tns_highlight(&tns, &win, tns.sel, False);
219+ tns_highlight(&tns, &win, sel, True);
220+ tns.sel = sel;
221+ }
222+ redraw();
223+ break;
224+ }
225+ break;
226+ case Button4:
227+ case Button5:
228+ if (tns_scroll(&tns, bev->button == Button4 ? DIR_UP : DIR_DOWN))
229+ redraw();
230+ break;
231+ }
232+ }
233+}
234+
235+void on_motionnotify(XEvent *ev) {
236+ XMotionEvent *mev;
237+
238+ if (!ev || ev->type != MotionNotify)
239+ return;
240+
241+ mev = &ev->xmotion;
242+
243+ if (mev->x >= 0 && mev->x <= win.w && mev->y >= 0 && mev->y <= win.h) {
244+ if (img_move(&img, &win, mev->x - mox, mev->y - moy))
245+ timo_redraw = TO_IMAGE_DRAG;
246+ mox = mev->x;
247+ moy = mev->y;
248+ }
249+}
250+
251+void run() {
252+ int xfd, timeout;
253+ fd_set fds;
254+ struct timeval tt, t0, t1;
255+ XEvent ev;
256+
257+ dragging = 0;
258+ timo_cursor = mode == MODE_NORMAL ? TO_CURSOR_HIDE : 0;
259+
260+ redraw();
261+
262+ while (1) {
263+ if (mode == MODE_THUMBS && tns.cnt < filecnt) {
264+ /* load thumbnails */
265+ win_set_cursor(&win, CURSOR_WATCH);
266+ gettimeofday(&t0, 0);
267+
268+ while (tns.cnt < filecnt && !XPending(win.env.dpy)) {
269+ if (tns_load(&tns, tns.cnt, filenames[tns.cnt], 0))
270+ tns.cnt++;
271+ else
272+ remove_file(tns.cnt, 0);
273+ gettimeofday(&t1, 0);
274+ if (TIMEDIFF(&t1, &t0) >= TO_THUMBS_LOAD)
275+ break;
276+ }
277+ if (tns.cnt == filecnt)
278+ win_set_cursor(&win, CURSOR_ARROW);
279+ if (!XPending(win.env.dpy)) {
280+ redraw();
281+ continue;
282+ } else {
283+ timo_redraw = TO_THUMBS_LOAD;
284+ }
285+ } else if (timo_cursor || timo_redraw) {
286+ /* check active timeouts */
287+ gettimeofday(&t0, 0);
288+ timeout = MIN(timo_cursor + 1, timo_redraw + 1);
289+ MSEC_TO_TIMEVAL(timeout, &tt);
290+ xfd = ConnectionNumber(win.env.dpy);
291+ FD_ZERO(&fds);
292+ FD_SET(xfd, &fds);
293+
294+ if (!XPending(win.env.dpy))
295+ select(xfd + 1, &fds, 0, 0, &tt);
296+ gettimeofday(&t1, 0);
297+ timeout = MIN(TIMEDIFF(&t1, &t0), timeout);
298+
299+ /* timeouts fired? */
300+ if (timo_cursor) {
301+ timo_cursor = MAX(0, timo_cursor - timeout);
302+ if (!timo_cursor)
303+ win_set_cursor(&win, CURSOR_NONE);
304+ }
305+ if (timo_redraw) {
306+ timo_redraw = MAX(0, timo_redraw - timeout);
307+ if (!timo_redraw)
308+ redraw();
309+ }
310+ if ((timo_cursor || timo_redraw) && !XPending(win.env.dpy))
311+ continue;
312+ }
313+
314+ if (!XNextEvent(win.env.dpy, &ev)) {
315+ switch (ev.type) {
316+ case ButtonPress:
317+ on_buttonpress(&ev);
318+ break;
319+ case ButtonRelease:
320+ if (dragging) {
321+ dragging = 0;
322+ if (mode == MODE_NORMAL) {
323+ win_set_cursor(&win, CURSOR_ARROW);
324+ timo_cursor = TO_CURSOR_HIDE;
325+ }
326+ }
327+ break;
328+ case ClientMessage:
329+ if ((Atom) ev.xclient.data.l[0] == wm_delete_win)
330+ return;
331+ break;
332+ case ConfigureNotify:
333+ if (win_configure(&win, &ev.xconfigure)) {
334+ timo_redraw = TO_WIN_RESIZE;
335+ if (mode == MODE_NORMAL)
336+ img.checkpan = 1;
337+ else
338+ tns.dirty = 1;
339+ }
340+ break;
341+ case KeyPress:
342+ on_keypress(&ev);
343+ break;
344+ case MotionNotify:
345+ if (dragging) {
346+ on_motionnotify(&ev);
347+ } else if (mode == MODE_NORMAL) {
348+ if (!timo_cursor)
349+ win_set_cursor(&win, CURSOR_ARROW);
350+ timo_cursor = TO_CURSOR_HIDE;
351+ }
352+ break;
353+ }
354+ }
355+ }
356+}
357+
358+
359+/* handler functions for key and button mappings: */
360+
361+int quit(XEvent *e, arg_t a) {
362+ cleanup();
363+ exit(0);
364+}
365+
366+int reload(XEvent *e, arg_t a) {
367+ if (mode == MODE_NORMAL) {
368+ load_image(fileidx);
369+ return 1;
370+ } else {
371+ return 0;
372+ }
373+}
374+
375+int toggle_fullscreen(XEvent *e, arg_t a) {
376+ win_toggle_fullscreen(&win);
377+ if (mode == MODE_NORMAL)
378+ img.checkpan = 1;
379+ else
380+ tns.dirty = 1;
381+ timo_redraw = TO_WIN_RESIZE;
382+ return 0;
383+}
384+
385+int toggle_antialias(XEvent *e, arg_t a) {
386+ if (mode == MODE_NORMAL) {
387+ img_toggle_antialias(&img);
388+ return 1;
389+ } else {
390+ return 0;
391+ }
392+}
393+
394+int toggle_alpha(XEvent *e, arg_t a) {
395+ if (mode == MODE_NORMAL) {
396+ img.alpha ^= 1;
397+ return 1;
398+ } else {
399+ return 0;
400+ }
401+}
402+
403+int switch_mode(XEvent *e, arg_t a) {
404+ if (mode == MODE_NORMAL) {
405+ if (!tns.thumbs)
406+ tns_init(&tns, filecnt);
407+ img_close(&img, 0);
408+ win_set_cursor(&win, CURSOR_ARROW);
409+ timo_cursor = 0;
410+ tns.sel = fileidx;
411+ tns.dirty = 1;
412+ mode = MODE_THUMBS;
413+ } else {
414+ timo_cursor = TO_CURSOR_HIDE;
415+ load_image(tns.sel);
416+ mode = MODE_NORMAL;
417+ }
418+ return 1;
419+}
420+
421+int navigate(XEvent *e, arg_t n) {
422+ if (mode == MODE_NORMAL) {
423+ n += fileidx;
424+ if (n < 0)
425+ n = 0;
426+ if (n >= filecnt)
427+ n = filecnt - 1;
428+
429+ if (n != fileidx) {
430+ load_image(n);
431+ return 1;
432+ }
433+ }
434+ return 0;
435+}
436+
437+int first(XEvent *e, arg_t a) {
438+ if (mode == MODE_NORMAL && fileidx != 0) {
439+ load_image(0);
440+ return 1;
441+ } else if (mode == MODE_THUMBS && tns.sel != 0) {
442+ tns.sel = 0;
443+ tns.dirty = 1;
444+ return 1;
445+ } else {
446+ return 0;
447+ }
448+}
449+
450+int last(XEvent *e, arg_t a) {
451+ if (mode == MODE_NORMAL && fileidx != filecnt - 1) {
452+ load_image(filecnt - 1);
453+ return 1;
454+ } else if (mode == MODE_THUMBS && tns.sel != tns.cnt - 1) {
455+ tns.sel = tns.cnt - 1;
456+ tns.dirty = 1;
457+ return 1;
458+ } else {
459+ return 0;
460+ }
461+}
462+
463+int remove_image(XEvent *e, arg_t a) {
464+ if (mode == MODE_NORMAL) {
465+ remove_file(fileidx, 1);
466+ load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
467+ return 1;
468+ } else if (tns.sel < tns.cnt) {
469+ remove_file(tns.sel, 1);
470+ tns.dirty = 1;
471+ if (tns.sel >= tns.cnt)
472+ tns.sel = tns.cnt - 1;
473+ return 1;
474+ } else {
475+ return 0;
476+ }
477+}
478+
479+int move(XEvent *e, arg_t dir) {
480+ if (mode == MODE_NORMAL)
481+ return img_pan(&img, &win, dir, 0);
482+ else
483+ return tns_move_selection(&tns, &win, dir);
484+}
485+
486+int scroll(XEvent *e, arg_t dir) {
487+ if (mode == MODE_NORMAL)
488+ return img_pan(&img, &win, dir, 1);
489+ else
490+ return 0;
491+}
492+
493+int pan_edge(XEvent *e, arg_t dir) {
494+ if (mode == MODE_NORMAL)
495+ return img_pan_edge(&img, &win, dir);
496+ else
497+ return 0;
498+}
499+
500+int drag(XEvent *e, arg_t a) {
501+ if (mode == MODE_NORMAL) {
502+ mox = e->xbutton.x;
503+ moy = e->xbutton.y;
504+ win_set_cursor(&win, CURSOR_HAND);
505+ timo_cursor = 0;
506+ dragging = 1;
507+ }
508+ return 0;
509+}
510+
511+int rotate(XEvent *e, arg_t dir) {
512+ if (mode == MODE_NORMAL) {
513+ if (dir == DIR_LEFT) {
514+ img_rotate_left(&img, &win);
515+ return 1;
516+ } else if (dir == DIR_RIGHT) {
517+ img_rotate_right(&img, &win);
518+ return 1;
519+ }
520+ }
521+ return 0;
522+}
523+
524+int zoom(XEvent *e, arg_t scale) {
525+ if (mode != MODE_NORMAL)
526+ return 0;
527+ if (scale > 0)
528+ return img_zoom_in(&img, &win);
529+ else if (scale < 0)
530+ return img_zoom_out(&img, &win);
531+ else
532+ return img_zoom(&img, &win, 1.0);
533+}
534+
535+int fit_to_win(XEvent *e, arg_t ret) {
536+ if (mode == MODE_NORMAL) {
537+ if ((ret = img_fit_win(&img, &win)))
538+ img_center(&img, &win);
539+ return ret;
540+ } else {
541+ return 0;
542+ }
543+}
544+
545+int fit_to_img(XEvent *e, arg_t ret) {
546+ int x, y;
547+ unsigned int w, h;
548+
549+ if (mode == MODE_NORMAL) {
550+ x = MAX(0, win.x + img.x);
551+ y = MAX(0, win.y + img.y);
552+ w = img.w * img.zoom;
553+ h = img.h * img.zoom;
554+ if ((ret = win_moveresize(&win, x, y, w, h))) {
555+ img.x = x - win.x;
556+ img.y = y - win.y;
557+ }
558+ return ret;
559+ } else {
560+ return 0;
561+ }
562+}
A events.h View
@@ -0,0 +1,67 @@
1+/* sxiv: events.h
2+ * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; either version 2 of the License, or
7+ * (at your option) any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program; if not, write to the Free Software
16+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17+ */
18+
19+#ifndef EVENTS_H
20+#define EVENTS_H
21+
22+#include <X11/Xlib.h>
23+
24+typedef struct {
25+ KeySym ksym;
26+ Bool reload;
27+ const char *cmdline;
28+} command_t;
29+
30+typedef int arg_t;
31+
32+typedef struct {
33+ KeySym ksym;
34+ int (*handler)(XEvent*, arg_t);
35+ arg_t arg;
36+} keymap_t;
37+
38+typedef struct {
39+ unsigned int mod;
40+ unsigned int button;
41+ int (*handler)(XEvent*, arg_t);
42+ arg_t arg;
43+} button_t;
44+
45+void run();
46+
47+/* handler functions for key and button mappings: */
48+int quit(XEvent*, arg_t);
49+int reload(XEvent*, arg_t);
50+int toggle_fullscreen(XEvent*, arg_t);
51+int toggle_antialias(XEvent*, arg_t);
52+int toggle_alpha(XEvent*, arg_t);
53+int switch_mode(XEvent*, arg_t);
54+int navigate(XEvent*, arg_t);
55+int first(XEvent*, arg_t);
56+int last(XEvent*, arg_t);
57+int remove_image(XEvent*, arg_t);
58+int move(XEvent*, arg_t);
59+int scroll(XEvent*, arg_t);
60+int pan_edge(XEvent*, arg_t);
61+int drag(XEvent*, arg_t);
62+int rotate(XEvent*, arg_t);
63+int zoom(XEvent*, arg_t);
64+int fit_to_win(XEvent*, arg_t);
65+int fit_to_img(XEvent*, arg_t);
66+
67+#endif /* EVENTS_H */
M image.c View
@@ -16,6 +16,8 @@
1616 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1717 */
1818
19+#define _IMAGE_CONFIG
20+
1921 #include <unistd.h>
2022
2123 #include "image.h"
@@ -238,7 +240,7 @@ int img_zoom_in(img_t *img, win_t *win) {
238240 if (!img || !img->im || !win)
239241 return 0;
240242
241− for (i = 1; i < zl_cnt; ++i) {
243+ for (i = 1; i < zl_cnt; i++) {
242244 if (zoom_levels[i] > img->zoom * 100.0)
243245 return img_zoom(img, win, zoom_levels[i] / 100.0);
244246 }
@@ -251,7 +253,7 @@ int img_zoom_out(img_t *img, win_t *win) {
251253 if (!img || !img->im || !win)
252254 return 0;
253255
254− for (i = zl_cnt - 2; i >= 0; --i) {
256+ for (i = zl_cnt - 2; i >= 0; i--) {
255257 if (zoom_levels[i] < img->zoom * 100.0)
256258 return img_zoom(img, win, zoom_levels[i] / 100.0);
257259 }
M main.c View
@@ -16,32 +16,22 @@
1616 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1717 */
1818
19−#define _XOPEN_SOURCE 700
20−
2119 #include <stdlib.h>
22−#include <stdio.h>
2320 #include <string.h>
24−#include <sys/select.h>
25−#include <sys/stat.h>
26−#include <sys/time.h>
27−#include <sys/wait.h>
2821 #include <unistd.h>
22+#include <sys/stat.h>
2923
30−#include <X11/Xlib.h>
31−#include <X11/Xutil.h>
32−#include <X11/keysym.h>
33−
24+#include "events.h"
3425 #include "image.h"
3526 #include "options.h"
3627 #include "thumbs.h"
37−#include "types.h"
3828 #include "util.h"
3929 #include "window.h"
40−#include "config.h"
4130
42−enum { TITLE_LEN = 256, FNAME_CNT = 1024 };
43−
44−void run();
31+enum {
32+ TITLE_LEN = 256,
33+ FNAME_CNT = 1024
34+};
4535
4636 appmode_t mode;
4737 img_t img;
@@ -64,6 +54,23 @@ void cleanup() {
6454 }
6555 }
6656
57+int check_add_file(char *filename) {
58+ if (!filename)
59+ return 0;
60+
61+ if (access(filename, R_OK)) {
62+ warn("could not open file: %s", filename);
63+ return 0;
64+ } else {
65+ if (fileidx == filecnt) {
66+ filecnt *= 2;
67+ filenames = (char**) s_realloc(filenames, filecnt * sizeof(char*));
68+ }
69+ filenames[fileidx++] = filename;
70+ return 1;
71+ }
72+}
73+
6774 void remove_file(int n, unsigned char silent) {
6875 if (n < 0 || n >= filecnt)
6976 return;
@@ -84,32 +91,32 @@ void remove_file(int n, unsigned char silent) {
8491 memset(tns.thumbs + tns.cnt - 1, 0, sizeof(thumb_t));
8592 }
8693
87− --filecnt;
94+ filecnt--;
8895 if (n < tns.cnt)
89− --tns.cnt;
96+ tns.cnt--;
9097 }
9198
92−int load_image(int new) {
99+void load_image(int new) {
93100 struct stat fstats;
94101
95− if (new >= 0 && new < filecnt) {
96− win_set_cursor(&win, CURSOR_WATCH);
97− img_close(&img, 0);
98−
99− while (!img_load(&img, filenames[new])) {
100− remove_file(new, 0);
101− if (new >= filecnt)
102− new = filecnt - 1;
103− }
104− fileidx = new;
105− if (!stat(filenames[new], &fstats))
106− filesize = fstats.st_size;
107− else
108− filesize = 0;
102+ if (new < 0 || new >= filecnt)
103+ return;
109104
110− /* cursor is reset in redraw() */
105+ /* cursor is reset in redraw() */
106+ win_set_cursor(&win, CURSOR_WATCH);
107+ img_close(&img, 0);
108+
109+ while (!img_load(&img, filenames[new])) {
110+ remove_file(new, 0);
111+ if (new >= filecnt)
112+ new = filecnt - 1;
111113 }
112− return 1;
114+
115+ fileidx = new;
116+ if (!stat(filenames[new], &fstats))
117+ filesize = fstats.st_size;
118+ else
119+ filesize = 0;
113120 }
114121
115122 void update_title() {
@@ -138,23 +145,6 @@ void update_title() {
138145 win_set_title(&win, win_title);
139146 }
140147
141−int check_append(char *filename) {
142− if (!filename)
143− return 0;
144−
145− if (access(filename, R_OK)) {
146− warn("could not open file: %s", filename);
147− return 0;
148− } else {
149− if (fileidx == filecnt) {
150− filecnt *= 2;
151− filenames = (char**) s_realloc(filenames, filecnt * sizeof(char*));
152− }
153− filenames[fileidx++] = filename;
154− return 1;
155− }
156−}
157−
158148 int fncmp(const void *a, const void *b) {
159149 return strcoll(*((char* const*) a), *((char* const*) b));
160150 }
@@ -187,20 +177,21 @@ int main(int argc, char **argv) {
187177 filenames = (char**) s_malloc(filecnt * sizeof(char*));
188178 fileidx = 0;
189179
180+ /* build file list: */
190181 if (options->from_stdin) {
191182 while ((len = getline(&filename, &n, stdin)) > 0) {
192183 if (filename[len-1] == '\n')
193184 filename[len-1] = '\0';
194− if (!*filename || !check_append(filename))
185+ if (!*filename || !check_add_file(filename))
195186 free(filename);
196187 filename = NULL;
197188 }
198189 } else {
199− for (i = 0; i < options->filecnt; ++i) {
190+ for (i = 0; i < options->filecnt; i++) {
200191 filename = options->filenames[i];
201192
202193 if (stat(filename, &fstats) || !S_ISDIR(fstats.st_mode)) {
203− check_append(filename);
194+ check_add_file(filename);
204195 } else {
205196 if (!options->recursive) {
206197 warn("ignoring directory: %s", filename);
@@ -212,7 +203,7 @@ int main(int argc, char **argv) {
212203 }
213204 start = fileidx;
214205 while ((filename = r_readdir(&dir))) {
215− if (!check_append(filename))
206+ if (!check_add_file(filename))
216207 free((void*) filename);
217208 }
218209 r_closedir(&dir);
@@ -252,550 +243,3 @@ int main(int argc, char **argv) {
252243
253244 return 0;
254245 }
255−
256−int run_command(const char *cline, Bool reload) {
257− int fncnt, fnlen;
258− char *cn, *cmdline;
259− const char *co, *fname;
260− pid_t pid;
261− int ret, status;
262−
263− if (!cline || !*cline)
264− return 0;
265−
266− fncnt = 0;
267− co = cline - 1;
268− while ((co = strchr(co + 1, '#')))
269− ++fncnt;
270−
271− if (!fncnt)
272− return 0;
273−
274− ret = 0;
275− fname = filenames[mode == MODE_NORMAL ? fileidx : tns.sel];
276− fnlen = strlen(fname);
277− cn = cmdline = (char*) s_malloc((strlen(cline) + fncnt * (fnlen + 2)) *
278− sizeof(char));
279−
280− /* replace all '#' with filename */
281− for (co = cline; *co; ++co) {
282− if (*co == '#') {
283− *cn++ = '"';
284− strcpy(cn, fname);
285− cn += fnlen;
286− *cn++ = '"';
287− } else {
288− *cn++ = *co;
289− }
290− }
291− *cn = '\0';
292−
293− if ((pid = fork()) == 0) {
294− execlp("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
295− warn("could not exec: /bin/sh");
296− exit(1);
297− } else if (pid < 0) {
298− warn("could not fork. command line was: %s", cmdline);
299− } else if (reload) {
300− waitpid(pid, &status, 0);
301− if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
302− ret = 1;
303− else
304− warn("child exited with non-zero return value: %d. command line was: %s",
305− WEXITSTATUS(status), cmdline);
306− }
307−
308− free(cmdline);
309− return ret;
310−}
311−
312−
313−/* event handling */
314−
315−/* timeouts in milliseconds: */
316−enum {
317− TO_WIN_RESIZE = 75,
318− TO_IMAGE_DRAG = 1,
319− TO_CURSOR_HIDE = 1500,
320− TO_THUMBS_LOAD = 200
321−};
322−
323−int timo_cursor;
324−int timo_redraw;
325−unsigned char drag;
326−int mox, moy;
327−
328−void redraw() {
329− if (mode == MODE_NORMAL) {
330− img_render(&img, &win);
331− if (timo_cursor)
332− win_set_cursor(&win, CURSOR_ARROW);
333− else if (!drag)
334− win_set_cursor(&win, CURSOR_NONE);
335− } else {
336− tns_render(&tns, &win);
337− }
338− update_title();
339− timo_redraw = 0;
340−}
341−
342−void on_keypress(XKeyEvent *kev) {
343− int x, y;
344− unsigned int w, h;
345− char key;
346− KeySym ksym;
347− int changed, ctrl;
348−
349− if (!kev)
350− return;
351−
352− XLookupString(kev, &key, 1, &ksym, NULL);
353− changed = 0;
354− ctrl = CLEANMASK(kev->state) & ControlMask;
355−
356− /* external commands from commands.h */
357− if (EXT_COMMANDS && ctrl) {
358− for (x = 0; x < LEN(commands); ++x) {
359− if (commands[x].key == key) {
360− win_set_cursor(&win, CURSOR_WATCH);
361− if (run_command(commands[x].cmdline, commands[x].reload)) {
362− if (mode == MODE_NORMAL) {
363− if (fileidx < tns.cnt)
364− tns_load(&tns, fileidx, filenames[fileidx], 1);
365− img_close(&img, 1);
366− load_image(fileidx);
367− } else {
368− if (!tns_load(&tns, tns.sel, filenames[tns.sel], 0)) {
369− remove_file(tns.sel, 0);
370− tns.dirty = 1;
371− if (tns.sel >= tns.cnt)
372− tns.sel = tns.cnt - 1;
373− }
374− }
375− redraw();
376− }
377− if (mode == MODE_THUMBS)
378− win_set_cursor(&win, CURSOR_ARROW);
379− else if (!timo_cursor)
380− win_set_cursor(&win, CURSOR_NONE);
381− return;
382− }
383− }
384− }
385−
386− if (mode == MODE_NORMAL) {
387− switch (ksym) {
388− /* navigate image list */
389− case XK_n:
390− case XK_space:
391− if (fileidx + 1 < filecnt)
392− changed = load_image(fileidx + 1);
393− break;
394− case XK_p:
395− case XK_BackSpace:
396− if (fileidx > 0)
397− changed = load_image(fileidx - 1);
398− break;
399− case XK_bracketleft:
400− if (fileidx != 0)
401− changed = load_image(MAX(0, fileidx - 10));
402− break;
403− case XK_bracketright:
404− if (fileidx != filecnt - 1)
405− changed = load_image(MIN(fileidx + 10, filecnt - 1));
406− break;
407− case XK_g:
408− if (fileidx != 0)
409− changed = load_image(0);
410− break;
411− case XK_G:
412− if (fileidx != filecnt - 1)
413− changed = load_image(filecnt - 1);
414− break;
415−
416− /* zooming */
417− case XK_plus:
418− case XK_equal:
419− case XK_KP_Add:
420− changed = img_zoom_in(&img, &win);
421− break;
422− case XK_minus:
423− case XK_KP_Subtract:
424− changed = img_zoom_out(&img, &win);
425− break;
426− case XK_0:
427− case XK_KP_0:
428− changed = img_zoom(&img, &win, 1.0);
429− break;
430− case XK_w:
431− if ((changed = img_fit_win(&img, &win)))
432− img_center(&img, &win);
433− break;
434−
435− /* panning */
436− case XK_h:
437− case XK_Left:
438− changed = img_pan(&img, &win, DIR_LEFT, ctrl);
439− break;
440− case XK_j:
441− case XK_Down:
442− changed = img_pan(&img, &win, DIR_DOWN, ctrl);
443− break;
444− case XK_k:
445− case XK_Up:
446− changed = img_pan(&img, &win, DIR_UP, ctrl);
447− break;
448− case XK_l:
449− case XK_Right:
450− changed = img_pan(&img, &win, DIR_RIGHT, ctrl);
451− break;
452− case XK_Prior:
453− changed = img_pan(&img, &win, DIR_UP, 1);
454− break;
455− case XK_Next:
456− changed = img_pan(&img, &win, DIR_DOWN, 1);
457− break;
458−
459− case XK_H:
460− changed = img_pan_edge(&img, &win, DIR_LEFT);
461− break;
462− case XK_J:
463− changed = img_pan_edge(&img, &win, DIR_DOWN);
464− break;
465− case XK_K:
466− changed = img_pan_edge(&img, &win, DIR_UP);
467− break;
468− case XK_L:
469− changed = img_pan_edge(&img, &win, DIR_RIGHT);
470− break;
471−
472− /* rotation */
473− case XK_less:
474− img_rotate_left(&img, &win);
475− changed = 1;
476− break;
477− case XK_greater:
478− img_rotate_right(&img, &win);
479− changed = 1;
480− break;
481−
482− /* control window */
483− case XK_W:
484− x = MAX(0, win.x + img.x);
485− y = MAX(0, win.y + img.y);
486− w = img.w * img.zoom;
487− h = img.h * img.zoom;
488− if ((changed = win_moveresize(&win, x, y, w, h))) {
489− img.x = x - win.x;
490− img.y = y - win.y;
491− }
492− break;
493−
494− /* switch to thumbnail mode */
495− case XK_Return:
496− if (!tns.thumbs)
497− tns_init(&tns, filecnt);
498− img_close(&img, 0);
499− mode = MODE_THUMBS;
500− win_set_cursor(&win, CURSOR_ARROW);
501− timo_cursor = 0;
502− tns.sel = fileidx;
503− changed = tns.dirty = 1;
504− break;
505−
506− /* miscellaneous */
507− case XK_a:
508− img_toggle_antialias(&img);
509− changed = 1;
510− break;
511− case XK_A:
512− img.alpha ^= 1;
513− changed = 1;
514− break;
515− case XK_D:
516− remove_file(fileidx, 1);
517− changed = load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
518− break;
519− case XK_r:
520− changed = load_image(fileidx);
521− break;
522− }
523− } else {
524− /* thumbnail mode */
525− switch (ksym) {
526− /* open selected image */
527− case XK_Return:
528− load_image(tns.sel);
529− mode = MODE_NORMAL;
530− changed = 1;
531− break;
532−
533− /* move selection */
534− case XK_h:
535− case XK_Left:
536− changed = tns_move_selection(&tns, &win, DIR_LEFT);
537− break;
538− case XK_j:
539− case XK_Down:
540− changed = tns_move_selection(&tns, &win, DIR_DOWN);
541− break;
542− case XK_k:
543− case XK_Up:
544− changed = tns_move_selection(&tns, &win, DIR_UP);
545− break;
546− case XK_l:
547− case XK_Right:
548− changed = tns_move_selection(&tns, &win, DIR_RIGHT);
549− break;
550− case XK_g:
551− if (tns.sel != 0) {
552− tns.sel = 0;
553− changed = tns.dirty = 1;
554− }
555− break;
556− case XK_G:
557− if (tns.sel != tns.cnt - 1) {
558− tns.sel = tns.cnt - 1;
559− changed = tns.dirty = 1;
560− }
561− break;
562−
563− /* miscellaneous */
564− case XK_D:
565− if (tns.sel < tns.cnt) {
566− remove_file(tns.sel, 1);
567− changed = tns.dirty = 1;
568− if (tns.sel >= tns.cnt)
569− tns.sel = tns.cnt - 1;
570− }
571− break;
572− }
573− }
574−
575− /* common key mappings */
576− switch (ksym) {
577− case XK_q:
578− cleanup();
579− exit(0);
580− case XK_f:
581− win_toggle_fullscreen(&win);
582− if (mode == MODE_NORMAL)
583− img.checkpan = 1;
584− else
585− tns.dirty = 1;
586− timo_redraw = TO_WIN_RESIZE;
587− break;
588− }
589−
590− if (changed)
591− redraw();
592−}
593−
594−void on_buttonpress(XButtonEvent *bev) {
595− int changed, sel;
596− unsigned int mask;
597−
598− if (!bev)
599− return;
600−
601− mask = CLEANMASK(bev->state);
602− changed = 0;
603−
604− if (mode == MODE_NORMAL) {
605− if (!drag) {
606− win_set_cursor(&win, CURSOR_ARROW);
607− timo_cursor = TO_CURSOR_HIDE;
608− }
609−
610− switch (bev->button) {
611− case Button1:
612− if (fileidx + 1 < filecnt)
613− changed = load_image(fileidx + 1);
614− break;
615− case Button2:
616− mox = bev->x;
617− moy = bev->y;
618− win_set_cursor(&win, CURSOR_HAND);
619− timo_cursor = 0;
620− drag = 1;
621− break;
622− case Button3:
623− if (fileidx > 0)
624− changed = load_image(fileidx - 1);
625− break;
626− case Button4:
627− if (mask == ControlMask)
628− changed = img_zoom_in(&img, &win);
629− else if (mask == ShiftMask)
630− changed = img_pan(&img, &win, DIR_LEFT, 0);
631− else
632− changed = img_pan(&img, &win, DIR_UP, 0);
633− break;
634− case Button5:
635− if (mask == ControlMask)
636− changed = img_zoom_out(&img, &win);
637− else if (mask == ShiftMask)
638− changed = img_pan(&img, &win, DIR_RIGHT, 0);
639− else
640− changed = img_pan(&img, &win, DIR_DOWN, 0);
641− break;
642− case 6:
643− changed = img_pan(&img, &win, DIR_LEFT, 0);
644− break;
645− case 7:
646− changed = img_pan(&img, &win, DIR_RIGHT, 0);
647− break;
648− }
649− } else {
650− /* thumbnail mode */
651− switch (bev->button) {
652− case Button1:
653− if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) {
654− if (sel == tns.sel) {
655− load_image(tns.sel);
656− mode = MODE_NORMAL;
657− timo_cursor = TO_CURSOR_HIDE;
658− } else {
659− tns_highlight(&tns, &win, tns.sel, False);
660− tns_highlight(&tns, &win, sel, True);
661− tns.sel = sel;
662− }
663− changed = 1;
664− break;
665− }
666− break;
667− case Button4:
668− changed = tns_scroll(&tns, DIR_UP);
669− break;
670− case Button5:
671− changed = tns_scroll(&tns, DIR_DOWN);
672− break;
673− }
674− }
675−
676− if (changed)
677− redraw();
678−}
679−
680−void on_motionnotify(XMotionEvent *mev) {
681− if (!mev)
682− return;
683−
684− if (mev->x >= 0 && mev->x <= win.w && mev->y >= 0 && mev->y <= win.h) {
685− if (img_move(&img, &win, mev->x - mox, mev->y - moy))
686− timo_redraw = TO_IMAGE_DRAG;
687−
688− mox = mev->x;
689− moy = mev->y;
690− }
691−}
692−
693−void run() {
694− int xfd, timeout;
695− fd_set fds;
696− struct timeval tt, t0, t1;
697− XEvent ev;
698−
699− drag = 0;
700− timo_cursor = mode == MODE_NORMAL ? TO_CURSOR_HIDE : 0;
701−
702− redraw();
703−
704− while (1) {
705− if (mode == MODE_THUMBS && tns.cnt < filecnt) {
706− win_set_cursor(&win, CURSOR_WATCH);
707− gettimeofday(&t0, 0);
708−
709− while (tns.cnt < filecnt && !XPending(win.env.dpy)) {
710− if (tns_load(&tns, tns.cnt, filenames[tns.cnt], 0))
711− ++tns.cnt;
712− else
713− remove_file(tns.cnt, 0);
714− gettimeofday(&t1, 0);
715− if (TIMEDIFF(&t1, &t0) >= TO_THUMBS_LOAD)
716− break;
717− }
718− if (tns.cnt == filecnt)
719− win_set_cursor(&win, CURSOR_ARROW);
720− if (!XPending(win.env.dpy)) {
721− redraw();
722− continue;
723− } else {
724− timo_redraw = TO_THUMBS_LOAD;
725− }
726− } else if (timo_cursor || timo_redraw) {
727− gettimeofday(&t0, 0);
728− if (timo_cursor && timo_redraw)
729− timeout = MIN(timo_cursor, timo_redraw);
730− else if (timo_cursor)
731− timeout = timo_cursor;
732− else
733− timeout = timo_redraw;
734− MSEC_TO_TIMEVAL(timeout, &tt);
735− xfd = ConnectionNumber(win.env.dpy);
736− FD_ZERO(&fds);
737− FD_SET(xfd, &fds);
738−
739− if (!XPending(win.env.dpy))
740− select(xfd + 1, &fds, 0, 0, &tt);
741− gettimeofday(&t1, 0);
742− timeout = MIN(TIMEDIFF(&t1, &t0), timeout);
743−
744− /* timeouts fired? */
745− if (timo_cursor) {
746− timo_cursor = MAX(0, timo_cursor - timeout);
747− if (!timo_cursor)
748− win_set_cursor(&win, CURSOR_NONE);
749− }
750− if (timo_redraw) {
751− timo_redraw = MAX(0, timo_redraw - timeout);
752− if (!timo_redraw)
753− redraw();
754− }
755− if (!XPending(win.env.dpy) && (timo_cursor || timo_redraw))
756− continue;
757− }
758−
759− if (!XNextEvent(win.env.dpy, &ev)) {
760− switch (ev.type) {
761− case KeyPress:
762− on_keypress(&ev.xkey);
763− break;
764− case ButtonPress:
765− on_buttonpress(&ev.xbutton);
766− break;
767− case ButtonRelease:
768− if (ev.xbutton.button == Button2) {
769− drag = 0;
770− if (mode == MODE_NORMAL) {
771− win_set_cursor(&win, CURSOR_ARROW);
772− timo_cursor = TO_CURSOR_HIDE;
773− }
774− }
775− break;
776− case MotionNotify:
777− if (drag) {
778− on_motionnotify(&ev.xmotion);
779− } else if (mode == MODE_NORMAL) {
780− if (!timo_cursor)
781− win_set_cursor(&win, CURSOR_ARROW);
782− timo_cursor = TO_CURSOR_HIDE;
783− }
784− break;
785− case ConfigureNotify:
786− if (win_configure(&win, &ev.xconfigure)) {
787− timo_redraw = TO_WIN_RESIZE;
788− if (mode == MODE_NORMAL)
789− img.checkpan = 1;
790− else
791− tns.dirty = 1;
792− }
793− break;
794− case ClientMessage:
795− if ((Atom) ev.xclient.data.l[0] == wm_delete_win)
796− return;
797− break;
798− }
799− }
800− }
801−}
M options.c View
@@ -17,6 +17,7 @@
1717 */
1818
1919 #define _XOPEN_SOURCE
20+#define _IMAGE_CONFIG
2021
2122 #include <stdlib.h>
2223 #include <string.h>
M sxiv.1 View
@@ -150,16 +150,16 @@ Pan to top image edge.
150150 .B L
151151 Pan to right image edge.
152152 .TP
153−.BR Ctrl-h ", " Ctrl-Left
153+.BR {
154154 Pan image one window width left.
155155 .TP
156−.BR Ctrl-j ", " Ctrl-Down ", " PageDn
156+.BR PageDn
157157 Pan image one window height down.
158158 .TP
159−.BR Ctrl-k ", " Ctrl-Up ", " PageUp
159+.BR PageUp
160160 Pan image one window height up.
161161 .TP
162−.BR Ctrl-l ", " Ctrl-Right
162+.BR }
163163 Pan image one window width right.
164164 .SS Rotation
165165 .TP
M thumbs.c View
@@ -16,6 +16,8 @@
1616 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1717 */
1818
19+#define _THUMBS_CONFIG
20+
1921 #include <stdlib.h>
2022 #include <string.h>
2123 #include <sys/time.h>
@@ -205,7 +207,7 @@ void tns_free(tns_t *tns) {
205207 return;
206208
207209 if (tns->thumbs) {
208− for (i = 0; i < tns->cnt; ++i) {
210+ for (i = 0; i < tns->cnt; i++) {
209211 if (tns->thumbs[i].im) {
210212 imlib_context_set_image(tns->thumbs[i].im);
211213 imlib_free_image();
@@ -337,7 +339,7 @@ void tns_render(tns_t *tns, win_t *win) {
337339 tns->x = x = (win->w - MIN(cnt, tns->cols) * thumb_dim) / 2 + 5;
338340 tns->y = y = (win->h - (cnt / tns->cols + r) * thumb_dim) / 2 + 5;
339341
340− for (i = 0; i < cnt; ++i) {
342+ for (i = 0; i < cnt; i++) {
341343 t = &tns->thumbs[tns->first + i];
342344 t->x = x + (THUMB_SIZE - t->w) / 2;
343345 t->y = y + (THUMB_SIZE - t->h) / 2;
@@ -391,11 +393,11 @@ int tns_move_selection(tns_t *tns, win_t *win, direction_t dir) {
391393 switch (dir) {
392394 case DIR_LEFT:
393395 if (tns->sel > 0)
394− --tns->sel;
396+ tns->sel--;
395397 break;
396398 case DIR_RIGHT:
397399 if (tns->sel < tns->cnt - 1)
398− ++tns->sel;
400+ tns->sel++;
399401 break;
400402 case DIR_UP:
401403 if (tns->sel >= tns->cols)
M types.h View
@@ -2,31 +2,25 @@
22 #define TYPES_H
33
44 typedef enum {
5− MODE_NORMAL = 0,
5+ MODE_NORMAL,
66 MODE_THUMBS
77 } appmode_t;
88
9−typedef struct {
10− char key;
11− int reload;
12− const char *cmdline;
13−} command_t;
14−
159 typedef enum {
16− DIR_LEFT = 0,
10+ DIR_LEFT,
1711 DIR_RIGHT,
1812 DIR_UP,
1913 DIR_DOWN
2014 } direction_t;
2115
2216 typedef enum {
23− SCALE_DOWN = 0,
17+ SCALE_DOWN,
2418 SCALE_FIT,
2519 SCALE_ZOOM
2620 } scalemode_t;
2721
2822 typedef enum {
29− CURSOR_ARROW = 0,
23+ CURSOR_ARROW,
3024 CURSOR_NONE,
3125 CURSOR_HAND,
3226 CURSOR_WATCH
M util.c View
@@ -26,8 +26,10 @@
2626 #include "options.h"
2727 #include "util.h"
2828
29−#define DNAME_CNT 512
30−#define FNAME_LEN 1024
29+enum {
30+ DNAME_CNT = 512,
31+ FNAME_LEN = 1024
32+};
3133
3234 void cleanup();
3335
@@ -78,7 +80,7 @@ void size_readable(float *size, const char **unit) {
7880 const char *units[] = { "", "K", "M", "G" };
7981 int i;
8082
81− for (i = 0; i < LEN(units) && *size > 1024; ++i)
83+ for (i = 0; i < LEN(units) && *size > 1024; i++)
8284 *size /= 1024;
8385 *unit = units[MIN(i, LEN(units) - 1)];
8486 }
M window.c View
@@ -16,6 +16,8 @@
1616 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1717 */
1818
19+#define _WINDOW_CONFIG
20+
1921 #include <string.h>
2022
2123 #include <X11/Xutil.h>