nsxivb8ff167
Major code refactoring
- Configurable key and mouse mappings in config.h - Put event handling code from main.c into events.[ch]
+807 −647
12 files changed
- M Makefile +2 −2
- M config.h +103 −19
- A events.c +562 −0
- A events.h +67 −0
- M image.c +4 −2
- M main.c +47 −603
- M options.c +1 −0
- M sxiv.1 +4 −4
- M thumbs.c +6 −4
- M types.h +4 −10
- M util.c +5 −3
- M window.c +2 −0
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | all: sxiv | |
| 2 | 2 | ||
| 3 | − | VERSION = git-20110722 | |
| 3 | + | VERSION = git-20110726 | |
| 4 | 4 | ||
| 5 | 5 | CC = gcc | |
| 6 | 6 | DESTDIR = | |
| @@ -9,7 +9,7 @@ CFLAGS = -Wall -pedantic -DVERSION=\"$(VERSION)\" | |||
| 9 | 9 | LDFLAGS = | |
| 10 | 10 | LIBS = -lX11 -lImlib2 | |
| 11 | 11 | ||
| 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 | |
| 13 | 13 | OBJ = $(SRC:.c=.o) | |
| 14 | 14 | ||
| 15 | 15 | sxiv: $(OBJ) | |
| @@ -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): */ | |
| 2 | 10 | enum { WIN_WIDTH = 800, WIN_HEIGHT = 600 }; | |
| 3 | 11 | ||
| 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) */ | |
| 6 | 14 | static const char * const BG_COLOR = "#999999"; | |
| 7 | − | /* default color for thumbnail selection: */ | |
| 15 | + | /* default color for thumbnail selection: */ | |
| 8 | 16 | static const char * const SEL_COLOR = "#0066FF"; | |
| 9 | 17 | ||
| 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 */ | |
| 15 | 26 | static const scalemode_t SCALE_MODE = SCALE_DOWN; | |
| 16 | 27 | ||
| 17 | − | /* levels (percent) to use when zooming via '-' and '+': */ | |
| 28 | + | /* levels (percent) to use when zooming via '-' and '+': */ | |
| 18 | 29 | static const float zoom_levels[] = { | |
| 19 | 30 | 12.5, 25.0, 50.0, 75.0, | |
| 20 | 31 | 100.0, 150.0, 200.0, 400.0, 800.0 | |
| 21 | 32 | }; | |
| 22 | 33 | ||
| 23 | − | /* default dimension of thumbnails (width == height): */ | |
| 34 | + | #endif | |
| 35 | + | #ifdef _THUMBS_CONFIG | |
| 36 | + | ||
| 37 | + | /* default dimension of thumbnails (width == height): */ | |
| 24 | 38 | enum { THUMB_SIZE = 60 }; | |
| 25 | 39 | ||
| 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 }, | |
| 28 | 63 | ||
| 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: */ | |
| 30 | 98 | 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 }, | |
| 36 | 118 | }; | |
| 119 | + | ||
| 120 | + | #endif | |
| @@ -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 | + | } | |
| @@ -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 */ | |
| @@ -16,6 +16,8 @@ | |||
| 16 | 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 17 | 17 | */ | |
| 18 | 18 | ||
| 19 | + | #define _IMAGE_CONFIG | |
| 20 | + | ||
| 19 | 21 | #include <unistd.h> | |
| 20 | 22 | ||
| 21 | 23 | #include "image.h" | |
| @@ -238,7 +240,7 @@ int img_zoom_in(img_t *img, win_t *win) { | |||
| 238 | 240 | if (!img || !img->im || !win) | |
| 239 | 241 | return 0; | |
| 240 | 242 | ||
| 241 | − | for (i = 1; i < zl_cnt; ++i) { | |
| 243 | + | for (i = 1; i < zl_cnt; i++) { | |
| 242 | 244 | if (zoom_levels[i] > img->zoom * 100.0) | |
| 243 | 245 | return img_zoom(img, win, zoom_levels[i] / 100.0); | |
| 244 | 246 | } | |
| @@ -251,7 +253,7 @@ int img_zoom_out(img_t *img, win_t *win) { | |||
| 251 | 253 | if (!img || !img->im || !win) | |
| 252 | 254 | return 0; | |
| 253 | 255 | ||
| 254 | − | for (i = zl_cnt - 2; i >= 0; --i) { | |
| 256 | + | for (i = zl_cnt - 2; i >= 0; i--) { | |
| 255 | 257 | if (zoom_levels[i] < img->zoom * 100.0) | |
| 256 | 258 | return img_zoom(img, win, zoom_levels[i] / 100.0); | |
| 257 | 259 | } | |
| @@ -16,32 +16,22 @@ | |||
| 16 | 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 17 | 17 | */ | |
| 18 | 18 | ||
| 19 | − | #define _XOPEN_SOURCE 700 | |
| 20 | − | ||
| 21 | 19 | #include <stdlib.h> | |
| 22 | − | #include <stdio.h> | |
| 23 | 20 | #include <string.h> | |
| 24 | − | #include <sys/select.h> | |
| 25 | − | #include <sys/stat.h> | |
| 26 | − | #include <sys/time.h> | |
| 27 | − | #include <sys/wait.h> | |
| 28 | 21 | #include <unistd.h> | |
| 22 | + | #include <sys/stat.h> | |
| 29 | 23 | ||
| 30 | − | #include <X11/Xlib.h> | |
| 31 | − | #include <X11/Xutil.h> | |
| 32 | − | #include <X11/keysym.h> | |
| 33 | − | ||
| 24 | + | #include "events.h" | |
| 34 | 25 | #include "image.h" | |
| 35 | 26 | #include "options.h" | |
| 36 | 27 | #include "thumbs.h" | |
| 37 | − | #include "types.h" | |
| 38 | 28 | #include "util.h" | |
| 39 | 29 | #include "window.h" | |
| 40 | − | #include "config.h" | |
| 41 | 30 | ||
| 42 | − | enum { TITLE_LEN = 256, FNAME_CNT = 1024 }; | |
| 43 | − | ||
| 44 | − | void run(); | |
| 31 | + | enum { | |
| 32 | + | TITLE_LEN = 256, | |
| 33 | + | FNAME_CNT = 1024 | |
| 34 | + | }; | |
| 45 | 35 | ||
| 46 | 36 | appmode_t mode; | |
| 47 | 37 | img_t img; | |
| @@ -64,6 +54,23 @@ void cleanup() { | |||
| 64 | 54 | } | |
| 65 | 55 | } | |
| 66 | 56 | ||
| 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 | + | ||
| 67 | 74 | void remove_file(int n, unsigned char silent) { | |
| 68 | 75 | if (n < 0 || n >= filecnt) | |
| 69 | 76 | return; | |
| @@ -84,32 +91,32 @@ void remove_file(int n, unsigned char silent) { | |||
| 84 | 91 | memset(tns.thumbs + tns.cnt - 1, 0, sizeof(thumb_t)); | |
| 85 | 92 | } | |
| 86 | 93 | ||
| 87 | − | --filecnt; | |
| 94 | + | filecnt--; | |
| 88 | 95 | if (n < tns.cnt) | |
| 89 | − | --tns.cnt; | |
| 96 | + | tns.cnt--; | |
| 90 | 97 | } | |
| 91 | 98 | ||
| 92 | − | int load_image(int new) { | |
| 99 | + | void load_image(int new) { | |
| 93 | 100 | struct stat fstats; | |
| 94 | 101 | ||
| 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; | |
| 109 | 104 | ||
| 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; | |
| 111 | 113 | } | |
| 112 | − | return 1; | |
| 114 | + | ||
| 115 | + | fileidx = new; | |
| 116 | + | if (!stat(filenames[new], &fstats)) | |
| 117 | + | filesize = fstats.st_size; | |
| 118 | + | else | |
| 119 | + | filesize = 0; | |
| 113 | 120 | } | |
| 114 | 121 | ||
| 115 | 122 | void update_title() { | |
| @@ -138,23 +145,6 @@ void update_title() { | |||
| 138 | 145 | win_set_title(&win, win_title); | |
| 139 | 146 | } | |
| 140 | 147 | ||
| 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 | − | ||
| 158 | 148 | int fncmp(const void *a, const void *b) { | |
| 159 | 149 | return strcoll(*((char* const*) a), *((char* const*) b)); | |
| 160 | 150 | } | |
| @@ -187,20 +177,21 @@ int main(int argc, char **argv) { | |||
| 187 | 177 | filenames = (char**) s_malloc(filecnt * sizeof(char*)); | |
| 188 | 178 | fileidx = 0; | |
| 189 | 179 | ||
| 180 | + | /* build file list: */ | |
| 190 | 181 | if (options->from_stdin) { | |
| 191 | 182 | while ((len = getline(&filename, &n, stdin)) > 0) { | |
| 192 | 183 | if (filename[len-1] == '\n') | |
| 193 | 184 | filename[len-1] = '\0'; | |
| 194 | − | if (!*filename || !check_append(filename)) | |
| 185 | + | if (!*filename || !check_add_file(filename)) | |
| 195 | 186 | free(filename); | |
| 196 | 187 | filename = NULL; | |
| 197 | 188 | } | |
| 198 | 189 | } else { | |
| 199 | − | for (i = 0; i < options->filecnt; ++i) { | |
| 190 | + | for (i = 0; i < options->filecnt; i++) { | |
| 200 | 191 | filename = options->filenames[i]; | |
| 201 | 192 | ||
| 202 | 193 | if (stat(filename, &fstats) || !S_ISDIR(fstats.st_mode)) { | |
| 203 | − | check_append(filename); | |
| 194 | + | check_add_file(filename); | |
| 204 | 195 | } else { | |
| 205 | 196 | if (!options->recursive) { | |
| 206 | 197 | warn("ignoring directory: %s", filename); | |
| @@ -212,7 +203,7 @@ int main(int argc, char **argv) { | |||
| 212 | 203 | } | |
| 213 | 204 | start = fileidx; | |
| 214 | 205 | while ((filename = r_readdir(&dir))) { | |
| 215 | − | if (!check_append(filename)) | |
| 206 | + | if (!check_add_file(filename)) | |
| 216 | 207 | free((void*) filename); | |
| 217 | 208 | } | |
| 218 | 209 | r_closedir(&dir); | |
| @@ -252,550 +243,3 @@ int main(int argc, char **argv) { | |||
| 252 | 243 | ||
| 253 | 244 | return 0; | |
| 254 | 245 | } | |
| 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 | − | } | |
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | */ | |
| 18 | 18 | ||
| 19 | 19 | #define _XOPEN_SOURCE | |
| 20 | + | #define _IMAGE_CONFIG | |
| 20 | 21 | ||
| 21 | 22 | #include <stdlib.h> | |
| 22 | 23 | #include <string.h> | |
| @@ -150,16 +150,16 @@ Pan to top image edge. | |||
| 150 | 150 | .B L | |
| 151 | 151 | Pan to right image edge. | |
| 152 | 152 | .TP | |
| 153 | − | .BR Ctrl-h ", " Ctrl-Left | |
| 153 | + | .BR { | |
| 154 | 154 | Pan image one window width left. | |
| 155 | 155 | .TP | |
| 156 | − | .BR Ctrl-j ", " Ctrl-Down ", " PageDn | |
| 156 | + | .BR PageDn | |
| 157 | 157 | Pan image one window height down. | |
| 158 | 158 | .TP | |
| 159 | − | .BR Ctrl-k ", " Ctrl-Up ", " PageUp | |
| 159 | + | .BR PageUp | |
| 160 | 160 | Pan image one window height up. | |
| 161 | 161 | .TP | |
| 162 | − | .BR Ctrl-l ", " Ctrl-Right | |
| 162 | + | .BR } | |
| 163 | 163 | Pan image one window width right. | |
| 164 | 164 | .SS Rotation | |
| 165 | 165 | .TP | |
| @@ -16,6 +16,8 @@ | |||
| 16 | 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 17 | 17 | */ | |
| 18 | 18 | ||
| 19 | + | #define _THUMBS_CONFIG | |
| 20 | + | ||
| 19 | 21 | #include <stdlib.h> | |
| 20 | 22 | #include <string.h> | |
| 21 | 23 | #include <sys/time.h> | |
| @@ -205,7 +207,7 @@ void tns_free(tns_t *tns) { | |||
| 205 | 207 | return; | |
| 206 | 208 | ||
| 207 | 209 | if (tns->thumbs) { | |
| 208 | − | for (i = 0; i < tns->cnt; ++i) { | |
| 210 | + | for (i = 0; i < tns->cnt; i++) { | |
| 209 | 211 | if (tns->thumbs[i].im) { | |
| 210 | 212 | imlib_context_set_image(tns->thumbs[i].im); | |
| 211 | 213 | imlib_free_image(); | |
| @@ -337,7 +339,7 @@ void tns_render(tns_t *tns, win_t *win) { | |||
| 337 | 339 | tns->x = x = (win->w - MIN(cnt, tns->cols) * thumb_dim) / 2 + 5; | |
| 338 | 340 | tns->y = y = (win->h - (cnt / tns->cols + r) * thumb_dim) / 2 + 5; | |
| 339 | 341 | ||
| 340 | − | for (i = 0; i < cnt; ++i) { | |
| 342 | + | for (i = 0; i < cnt; i++) { | |
| 341 | 343 | t = &tns->thumbs[tns->first + i]; | |
| 342 | 344 | t->x = x + (THUMB_SIZE - t->w) / 2; | |
| 343 | 345 | 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) { | |||
| 391 | 393 | switch (dir) { | |
| 392 | 394 | case DIR_LEFT: | |
| 393 | 395 | if (tns->sel > 0) | |
| 394 | − | --tns->sel; | |
| 396 | + | tns->sel--; | |
| 395 | 397 | break; | |
| 396 | 398 | case DIR_RIGHT: | |
| 397 | 399 | if (tns->sel < tns->cnt - 1) | |
| 398 | − | ++tns->sel; | |
| 400 | + | tns->sel++; | |
| 399 | 401 | break; | |
| 400 | 402 | case DIR_UP: | |
| 401 | 403 | if (tns->sel >= tns->cols) | |
| @@ -2,31 +2,25 @@ | |||
| 2 | 2 | #define TYPES_H | |
| 3 | 3 | ||
| 4 | 4 | typedef enum { | |
| 5 | − | MODE_NORMAL = 0, | |
| 5 | + | MODE_NORMAL, | |
| 6 | 6 | MODE_THUMBS | |
| 7 | 7 | } appmode_t; | |
| 8 | 8 | ||
| 9 | − | typedef struct { | |
| 10 | − | char key; | |
| 11 | − | int reload; | |
| 12 | − | const char *cmdline; | |
| 13 | − | } command_t; | |
| 14 | − | ||
| 15 | 9 | typedef enum { | |
| 16 | − | DIR_LEFT = 0, | |
| 10 | + | DIR_LEFT, | |
| 17 | 11 | DIR_RIGHT, | |
| 18 | 12 | DIR_UP, | |
| 19 | 13 | DIR_DOWN | |
| 20 | 14 | } direction_t; | |
| 21 | 15 | ||
| 22 | 16 | typedef enum { | |
| 23 | − | SCALE_DOWN = 0, | |
| 17 | + | SCALE_DOWN, | |
| 24 | 18 | SCALE_FIT, | |
| 25 | 19 | SCALE_ZOOM | |
| 26 | 20 | } scalemode_t; | |
| 27 | 21 | ||
| 28 | 22 | typedef enum { | |
| 29 | − | CURSOR_ARROW = 0, | |
| 23 | + | CURSOR_ARROW, | |
| 30 | 24 | CURSOR_NONE, | |
| 31 | 25 | CURSOR_HAND, | |
| 32 | 26 | CURSOR_WATCH | |
| @@ -26,8 +26,10 @@ | |||
| 26 | 26 | #include "options.h" | |
| 27 | 27 | #include "util.h" | |
| 28 | 28 | ||
| 29 | − | #define DNAME_CNT 512 | |
| 30 | − | #define FNAME_LEN 1024 | |
| 29 | + | enum { | |
| 30 | + | DNAME_CNT = 512, | |
| 31 | + | FNAME_LEN = 1024 | |
| 32 | + | }; | |
| 31 | 33 | ||
| 32 | 34 | void cleanup(); | |
| 33 | 35 | ||
| @@ -78,7 +80,7 @@ void size_readable(float *size, const char **unit) { | |||
| 78 | 80 | const char *units[] = { "", "K", "M", "G" }; | |
| 79 | 81 | int i; | |
| 80 | 82 | ||
| 81 | − | for (i = 0; i < LEN(units) && *size > 1024; ++i) | |
| 83 | + | for (i = 0; i < LEN(units) && *size > 1024; i++) | |
| 82 | 84 | *size /= 1024; | |
| 83 | 85 | *unit = units[MIN(i, LEN(units) - 1)]; | |
| 84 | 86 | } | |
| @@ -16,6 +16,8 @@ | |||
| 16 | 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 17 | 17 | */ | |
| 18 | 18 | ||
| 19 | + | #define _WINDOW_CONFIG | |
| 20 | + | ||
| 19 | 21 | #include <string.h> | |
| 20 | 22 | ||
| 21 | 23 | #include <X11/Xutil.h> | |