Krolyxon
Commit c4007be

Branches

Refs →

nsxivcommands.c

472 lines · 9.7 KB · C

1/* sxiv: commands.c
2 * Copyright (c) 2011 Bert Muennich <be.muennich at googlemail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#define _POSIX_C_SOURCE 200112L
20#define _IMAGE_CONFIG
21
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include <sys/wait.h>
26
27#include "commands.h"
28#include "image.h"
29#include "thumbs.h"
30#include "util.h"
31#include "config.h"
32
33void cleanup(void);
34void remove_file(int, bool);
35void load_image(int);
36void redraw(void);
37void reset_cursor(void);
38void animate(void);
39void slideshow(void);
40void set_timeout(timeout_f, int, bool);
41void reset_timeout(timeout_f);
42
43extern appmode_t mode;
44extern img_t img;
45extern tns_t tns;
46extern win_t win;
47
48extern fileinfo_t *files;
49extern int filecnt, fileidx;
50
51extern int prefix;
52
53const int ss_delays[] = {
54 1, 2, 3, 5, 10, 15, 20, 30, 60, 120, 180, 300, 600
55};
56
57bool it_quit(arg_t a) {
58 cleanup();
59 exit(EXIT_SUCCESS);
60}
61
62bool it_switch_mode(arg_t a) {
63 if (mode == MODE_IMAGE) {
64 if (tns.thumbs == NULL)
65 tns_init(&tns, filecnt, &win);
66 img_close(&img, false);
67 reset_timeout(reset_cursor);
68 if (img.slideshow) {
69 img.slideshow = false;
70 reset_timeout(slideshow);
71 }
72 tns.sel = fileidx;
73 tns.dirty = true;
74 mode = MODE_THUMB;
75 } else {
76 load_image(tns.sel);
77 mode = MODE_IMAGE;
78 }
79 return true;
80}
81
82bool it_toggle_fullscreen(arg_t a) {
83 win_toggle_fullscreen(&win);
84 set_timeout(redraw, TO_REDRAW_RESIZE, false);
85 if (mode == MODE_IMAGE)
86 img.checkpan = true;
87 else
88 tns.dirty = true;
89 return false;
90}
91
92bool it_reload_image(arg_t a) {
93 if (mode == MODE_IMAGE) {
94 load_image(fileidx);
95 } else {
96 win_set_cursor(&win, CURSOR_WATCH);
97 if (!tns_load(&tns, tns.sel, &files[tns.sel], true, false)) {
98 remove_file(tns.sel, false);
99 tns.dirty = true;
100 if (tns.sel >= tns.cnt)
101 tns.sel = tns.cnt - 1;
102 }
103 }
104 return true;
105}
106
107bool it_remove_image(arg_t a) {
108 if (mode == MODE_IMAGE) {
109 remove_file(fileidx, true);
110 load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
111 return true;
112 } else if (tns.sel < tns.cnt) {
113 remove_file(tns.sel, true);
114 tns.dirty = true;
115 if (tns.sel >= tns.cnt)
116 tns.sel = tns.cnt - 1;
117 return true;
118 } else {
119 return false;
120 }
121}
122
123bool i_navigate(arg_t a) {
124 long n = (long) a;
125
126 if (mode == MODE_IMAGE) {
127 if (prefix > 0)
128 n *= prefix;
129 n += fileidx;
130 if (n < 0)
131 n = 0;
132 if (n >= filecnt)
133 n = filecnt - 1;
134
135 if (n != fileidx) {
136 load_image(n);
137 return true;
138 }
139 }
140 return false;
141}
142
143bool it_first(arg_t a) {
144 if (mode == MODE_IMAGE && fileidx != 0) {
145 load_image(0);
146 return true;
147 } else if (mode == MODE_THUMB && tns.sel != 0) {
148 tns.sel = 0;
149 tns.dirty = true;
150 return true;
151 } else {
152 return false;
153 }
154}
155
156bool it_n_or_last(arg_t a) {
157 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
158
159 if (mode == MODE_IMAGE && fileidx != n) {
160 load_image(n);
161 return true;
162 } else if (mode == MODE_THUMB && tns.sel != n) {
163 tns.sel = n;
164 tns.dirty = true;
165 return true;
166 } else {
167 return false;
168 }
169}
170
171bool i_navigate_frame(arg_t a) {
172 if (mode == MODE_IMAGE && !img.multi.animate)
173 return img_frame_navigate(&img, (long) a);
174 else
175 return false;
176}
177
178bool i_toggle_animation(arg_t a) {
179 if (mode != MODE_IMAGE)
180 return false;
181
182 if (img.multi.animate) {
183 reset_timeout(animate);
184 img.multi.animate = false;
185 } else if (img_frame_animate(&img, true)) {
186 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
187 }
188 return true;
189}
190
191bool it_scroll_move(arg_t a) {
192 direction_t dir = (direction_t) a;
193
194 if (mode == MODE_IMAGE)
195 return img_pan(&img, dir, prefix);
196 else
197 return tns_move_selection(&tns, dir);
198}
199
200bool it_scroll_screen(arg_t a) {
201 direction_t dir = (direction_t) a;
202
203 if (mode == MODE_IMAGE)
204 return img_pan(&img, dir, -1);
205 else
206 return tns_scroll(&tns, dir, true);
207}
208
209bool i_scroll_to_edge(arg_t a) {
210 direction_t dir = (direction_t) a;
211
212 if (mode == MODE_IMAGE)
213 return img_pan_edge(&img, dir);
214 else
215 return false;
216}
217
218/* Xlib helper function for i_drag() */
219Bool is_motionnotify(Display *d, XEvent *e, XPointer a) {
220 return e != NULL && e->type == MotionNotify;
221}
222
223bool i_drag(arg_t a) {
224 int dx = 0, dy = 0, i, ox, oy, x, y;
225 unsigned int ui;
226 bool dragging = true, next = false;
227 XEvent e;
228 Window w;
229
230 if (mode != MODE_IMAGE)
231 return false;
232 if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
233 return false;
234
235 win_set_cursor(&win, CURSOR_HAND);
236
237 while (dragging) {
238 if (!next)
239 XMaskEvent(win.env.dpy,
240 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
241 switch (e.type) {
242 case ButtonPress:
243 case ButtonRelease:
244 dragging = false;
245 break;
246 case MotionNotify:
247 x = e.xmotion.x;
248 y = e.xmotion.y;
249 if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) {
250 dx += x - ox;
251 dy += y - oy;
252 }
253 ox = x;
254 oy = y;
255 break;
256 }
257 if (dragging)
258 next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
259 if ((!dragging || !next) && (dx != 0 || dy != 0)) {
260 if (img_move(&img, dx, dy))
261 img_render(&img);
262 dx = dy = 0;
263 }
264 }
265
266 win_set_cursor(&win, CURSOR_ARROW);
267 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
268 reset_timeout(redraw);
269
270 return false;
271}
272
273bool i_zoom(arg_t a) {
274 long scale = (long) a;
275
276 if (mode != MODE_IMAGE)
277 return false;
278
279 if (scale > 0)
280 return img_zoom_in(&img);
281 else if (scale < 0)
282 return img_zoom_out(&img);
283 else
284 return false;
285}
286
287bool i_set_zoom(arg_t a) {
288 if (mode == MODE_IMAGE)
289 return img_zoom(&img, (prefix ? prefix : (long) a) / 100.0);
290 else
291 return false;
292}
293
294bool i_fit_to_win(arg_t a) {
295 bool ret = false;
296
297 if (mode == MODE_IMAGE) {
298 if ((ret = img_fit_win(&img)))
299 img_center(&img);
300 }
301 return ret;
302}
303
304bool i_fit_to_img(arg_t a) {
305 int x, y;
306 unsigned int w, h;
307 bool ret = false;
308
309 if (mode == MODE_IMAGE) {
310 x = MAX(0, win.x + img.x);
311 y = MAX(0, win.y + img.y);
312 w = img.w * img.zoom;
313 h = img.h * img.zoom;
314 if ((ret = win_moveresize(&win, x, y, w, h))) {
315 img.x = x - win.x;
316 img.y = y - win.y;
317 img.dirty = true;
318 }
319 }
320 return ret;
321}
322
323bool i_rotate(arg_t a) {
324 direction_t dir = (direction_t) a;
325
326 if (mode == MODE_IMAGE) {
327 if (dir == DIR_LEFT) {
328 img_rotate_left(&img);
329 return true;
330 } else if (dir == DIR_RIGHT) {
331 img_rotate_right(&img);
332 return true;
333 }
334 }
335 return false;
336}
337
338bool i_toggle_slideshow(arg_t a) {
339 if (mode == MODE_IMAGE) {
340 if (img.slideshow) {
341 img.slideshow = false;
342 reset_timeout(slideshow);
343 return true;
344 } else if (fileidx + 1 < filecnt) {
345 img.slideshow = true;
346 set_timeout(slideshow, img.ss_delay, true);
347 return true;
348 }
349 }
350 return false;
351}
352
353bool i_adjust_slideshow(arg_t a) {
354 long d = (long) a;
355 int i;
356
357 if (mode != MODE_IMAGE || !img.slideshow)
358 return false;
359
360 if (d < 0) {
361 for (i = ARRLEN(ss_delays) - 2; i >= 0; i--) {
362 if (img.ss_delay > ss_delays[i] * 1000) {
363 img.ss_delay = ss_delays[i] * 1000;
364 return true;
365 }
366 }
367 } else {
368 for (i = 1; i < ARRLEN(ss_delays); i++) {
369 if (img.ss_delay < ss_delays[i] * 1000) {
370 img.ss_delay = ss_delays[i] * 1000;
371 return true;
372 }
373 }
374 }
375 return false;
376}
377
378bool i_reset_slideshow(arg_t a) {
379 if (mode != MODE_IMAGE || !img.slideshow)
380 return false;
381
382 if (prefix > 0) {
383 img.ss_delay = MIN(prefix, ss_delays[ARRLEN(ss_delays) - 1]);
384 img.ss_delay = MAX(img.ss_delay, ss_delays[0]) * 1000;
385 } else {
386 img.ss_delay = SLIDESHOW_DELAY * 1000;
387 }
388 return true;
389}
390
391bool i_toggle_antialias(arg_t a) {
392 if (mode == MODE_IMAGE) {
393 img_toggle_antialias(&img);
394 return true;
395 } else {
396 return false;
397 }
398}
399
400bool it_toggle_alpha(arg_t a) {
401 img.alpha = tns.alpha = !img.alpha;
402 if (mode == MODE_IMAGE)
403 img.dirty = true;
404 else
405 tns.dirty = true;
406 return true;
407}
408
409bool it_open_with(arg_t a) {
410 const char *prog = (const char*) a;
411 pid_t pid;
412
413 if (prog == NULL || *prog == '\0')
414 return false;
415
416 if ((pid = fork()) == 0) {
417 execlp(prog, prog,
418 files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
419 warn("could not exec: %s", prog);
420 exit(EXIT_FAILURE);
421 } else if (pid < 0) {
422 warn("could not fork. program was: %s", prog);
423 }
424 return false;
425}
426
427bool it_shell_cmd(arg_t a) {
428 int n, status;
429 const char *cmdline = (const char*) a;
430 pid_t pid;
431
432 if (cmdline == NULL || *cmdline == '\0')
433 return false;
434
435 n = mode == MODE_IMAGE ? fileidx : tns.sel;
436
437 if (setenv("SXIV_IMG", files[n].path, 1) < 0) {
438 warn("could not set env.-variable: SXIV_IMG. command line was: %s",
439 cmdline);
440 return false;
441 }
442
443 if ((pid = fork()) == 0) {
444 execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
445 warn("could not exec: /bin/sh. command line was: %s", cmdline);
446 exit(EXIT_FAILURE);
447 } else if (pid < 0) {
448 warn("could not fork. command line was: %s", cmdline);
449 return false;
450 }
451
452 win_set_cursor(&win, CURSOR_WATCH);
453
454 waitpid(pid, &status, 0);
455 if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
456 warn("child exited with non-zero return value: %d. command line was: %s",
457 WEXITSTATUS(status), cmdline);
458
459 if (mode == MODE_IMAGE) {
460 img_close(&img, true);
461 load_image(fileidx);
462 }
463 if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) &&
464 mode == MODE_THUMB)
465 {
466 remove_file(tns.sel, false);
467 tns.dirty = true;
468 if (tns.sel >= tns.cnt)
469 tns.sel = tns.cnt - 1;
470 }
471 return true;
472}