Krolyxon
Commit ac1300a

Branches

Refs →

nsxivcommands.c

474 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 if (fileidx < tns.cnt)
73 tns.sel = fileidx;
74 else
75 tns.sel = tns.cnt > 0 ? tns.cnt - 1 : 0;
76 tns.dirty = true;
77 mode = MODE_THUMB;
78 } else {
79 load_image(tns.sel);
80 mode = MODE_IMAGE;
81 }
82 return true;
83}
84
85bool it_toggle_fullscreen(arg_t a) {
86 win_toggle_fullscreen(&win);
87 set_timeout(redraw, TO_REDRAW_RESIZE, false);
88 if (mode == MODE_IMAGE)
89 img.checkpan = true;
90 else
91 tns.dirty = true;
92 return false;
93}
94
95bool it_reload_image(arg_t a) {
96 if (mode == MODE_IMAGE) {
97 load_image(fileidx);
98 } else {
99 win_set_cursor(&win, CURSOR_WATCH);
100 if (!tns_load(&tns, tns.sel, &files[tns.sel], true, false)) {
101 remove_file(tns.sel, false);
102 tns.dirty = true;
103 if (tns.sel >= tns.cnt)
104 tns.sel = tns.cnt - 1;
105 }
106 }
107 return true;
108}
109
110bool it_remove_image(arg_t a) {
111 if (mode == MODE_IMAGE) {
112 remove_file(fileidx, true);
113 load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
114 return true;
115 } else if (tns.sel < tns.cnt) {
116 remove_file(tns.sel, true);
117 tns.dirty = true;
118 if (tns.sel >= tns.cnt)
119 tns.sel = tns.cnt - 1;
120 return true;
121 } else {
122 return false;
123 }
124}
125
126bool i_navigate(arg_t a) {
127 long n = (long) a;
128
129 if (mode == MODE_IMAGE) {
130 if (prefix > 0)
131 n *= prefix;
132 n += fileidx;
133 if (n < 0)
134 n = 0;
135 if (n >= filecnt)
136 n = filecnt - 1;
137
138 if (n != fileidx) {
139 load_image(n);
140 return true;
141 }
142 }
143 return false;
144}
145
146bool it_first(arg_t a) {
147 if (mode == MODE_IMAGE && fileidx != 0) {
148 load_image(0);
149 return true;
150 } else if (mode == MODE_THUMB && tns.sel != 0) {
151 tns.sel = 0;
152 tns.dirty = true;
153 return true;
154 } else {
155 return false;
156 }
157}
158
159bool it_n_or_last(arg_t a) {
160 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
161
162 if (mode == MODE_IMAGE && fileidx != n) {
163 load_image(n);
164 return true;
165 } else if (mode == MODE_THUMB && tns.sel != n) {
166 tns.sel = n;
167 tns.dirty = true;
168 return true;
169 } else {
170 return false;
171 }
172}
173
174bool i_navigate_frame(arg_t a) {
175 if (mode == MODE_IMAGE && !img.multi.animate)
176 return img_frame_navigate(&img, (long) a);
177 else
178 return false;
179}
180
181bool i_toggle_animation(arg_t a) {
182 if (mode != MODE_IMAGE)
183 return false;
184
185 if (img.multi.animate) {
186 reset_timeout(animate);
187 img.multi.animate = false;
188 } else if (img_frame_animate(&img, true)) {
189 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
190 }
191 return true;
192}
193
194bool it_scroll_move(arg_t a) {
195 direction_t dir = (direction_t) a;
196
197 if (mode == MODE_IMAGE)
198 return img_pan(&img, dir, prefix);
199 else
200 return tns_move_selection(&tns, dir);
201}
202
203bool it_scroll_screen(arg_t a) {
204 direction_t dir = (direction_t) a;
205
206 if (mode == MODE_IMAGE)
207 return img_pan(&img, dir, -1);
208 else
209 return tns_scroll(&tns, dir, true);
210}
211
212bool i_scroll_to_edge(arg_t a) {
213 direction_t dir = (direction_t) a;
214
215 if (mode == MODE_IMAGE)
216 return img_pan_edge(&img, dir);
217 else
218 return false;
219}
220
221/* Xlib helper function for i_drag() */
222Bool is_motionnotify(Display *d, XEvent *e, XPointer a) {
223 return e != NULL && e->type == MotionNotify;
224}
225
226bool i_drag(arg_t a) {
227 int dx = 0, dy = 0, i, ox, oy, x, y;
228 unsigned int ui;
229 bool dragging = true, next = false;
230 XEvent e;
231 Window w;
232
233 if (mode != MODE_IMAGE)
234 return false;
235 if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
236 return false;
237
238 win_set_cursor(&win, CURSOR_HAND);
239
240 while (dragging) {
241 if (!next)
242 XMaskEvent(win.env.dpy,
243 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
244 switch (e.type) {
245 case ButtonPress:
246 case ButtonRelease:
247 dragging = false;
248 break;
249 case MotionNotify:
250 x = e.xmotion.x;
251 y = e.xmotion.y;
252 if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) {
253 dx += x - ox;
254 dy += y - oy;
255 }
256 ox = x;
257 oy = y;
258 break;
259 }
260 if (dragging)
261 next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
262 if ((!dragging || !next) && (dx != 0 || dy != 0)) {
263 if (img_move(&img, dx, dy))
264 img_render(&img);
265 dx = dy = 0;
266 }
267 }
268
269 win_set_cursor(&win, CURSOR_ARROW);
270 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
271 reset_timeout(redraw);
272
273 return false;
274}
275
276bool i_zoom(arg_t a) {
277 long scale = (long) a;
278
279 if (mode != MODE_IMAGE)
280 return false;
281
282 if (scale > 0)
283 return img_zoom_in(&img);
284 else if (scale < 0)
285 return img_zoom_out(&img);
286 else
287 return false;
288}
289
290bool i_set_zoom(arg_t a) {
291 if (mode == MODE_IMAGE)
292 return img_zoom(&img, (prefix ? prefix : (long) a) / 100.0);
293 else
294 return false;
295}
296
297bool i_fit_to_win(arg_t a) {
298 bool ret = false;
299
300 if (mode == MODE_IMAGE) {
301 if ((ret = img_fit_win(&img)))
302 img_center(&img);
303 }
304 return ret;
305}
306
307bool i_fit_to_img(arg_t a) {
308 int x, y;
309 unsigned int w, h;
310 bool ret = false;
311
312 if (mode == MODE_IMAGE) {
313 x = MAX(0, win.x + img.x);
314 y = MAX(0, win.y + img.y);
315 w = img.w * img.zoom;
316 h = img.h * img.zoom;
317 if ((ret = win_moveresize(&win, x, y, w, h))) {
318 img.x = x - win.x;
319 img.y = y - win.y;
320 }
321 }
322 return ret;
323}
324
325bool i_rotate(arg_t a) {
326 direction_t dir = (direction_t) a;
327
328 if (mode == MODE_IMAGE) {
329 if (dir == DIR_LEFT) {
330 img_rotate_left(&img);
331 return true;
332 } else if (dir == DIR_RIGHT) {
333 img_rotate_right(&img);
334 return true;
335 }
336 }
337 return false;
338}
339
340bool i_toggle_slideshow(arg_t a) {
341 if (mode == MODE_IMAGE) {
342 if (img.slideshow) {
343 img.slideshow = false;
344 reset_timeout(slideshow);
345 return true;
346 } else if (fileidx + 1 < filecnt) {
347 img.slideshow = true;
348 set_timeout(slideshow, img.ss_delay, true);
349 return true;
350 }
351 }
352 return false;
353}
354
355bool i_adjust_slideshow(arg_t a) {
356 long d = (long) a;
357 int i;
358
359 if (mode != MODE_IMAGE || !img.slideshow)
360 return false;
361
362 if (d < 0) {
363 for (i = ARRLEN(ss_delays) - 2; i >= 0; i--) {
364 if (img.ss_delay > ss_delays[i] * 1000) {
365 img.ss_delay = ss_delays[i] * 1000;
366 return true;
367 }
368 }
369 } else {
370 for (i = 1; i < ARRLEN(ss_delays); i++) {
371 if (img.ss_delay < ss_delays[i] * 1000) {
372 img.ss_delay = ss_delays[i] * 1000;
373 return true;
374 }
375 }
376 }
377 return false;
378}
379
380bool i_reset_slideshow(arg_t a) {
381 if (mode != MODE_IMAGE || !img.slideshow)
382 return false;
383
384 if (prefix > 0) {
385 img.ss_delay = MIN(prefix, ss_delays[ARRLEN(ss_delays) - 1]);
386 img.ss_delay = MAX(img.ss_delay, ss_delays[0]) * 1000;
387 } else {
388 img.ss_delay = SLIDESHOW_DELAY * 1000;
389 }
390 return true;
391}
392
393bool i_toggle_antialias(arg_t a) {
394 if (mode == MODE_IMAGE) {
395 img_toggle_antialias(&img);
396 return true;
397 } else {
398 return false;
399 }
400}
401
402bool it_toggle_alpha(arg_t a) {
403 img.alpha = tns.alpha = !img.alpha;
404 if (mode == MODE_IMAGE)
405 img.dirty = true;
406 else
407 tns.dirty = true;
408 return true;
409}
410
411bool it_open_with(arg_t a) {
412 const char *prog = (const char*) a;
413 pid_t pid;
414
415 if (prog == NULL || *prog == '\0')
416 return false;
417
418 if ((pid = fork()) == 0) {
419 execlp(prog, prog,
420 files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
421 warn("could not exec: %s", prog);
422 exit(EXIT_FAILURE);
423 } else if (pid < 0) {
424 warn("could not fork. program was: %s", prog);
425 }
426 return false;
427}
428
429bool it_shell_cmd(arg_t a) {
430 int n, status;
431 const char *cmdline = (const char*) a;
432 pid_t pid;
433
434 if (cmdline == NULL || *cmdline == '\0')
435 return false;
436
437 n = mode == MODE_IMAGE ? fileidx : tns.sel;
438
439 if (setenv("SXIV_IMG", files[n].path, 1) < 0) {
440 warn("could not set env.-variable: SXIV_IMG. command line was: %s",
441 cmdline);
442 return false;
443 }
444
445 if ((pid = fork()) == 0) {
446 execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
447 warn("could not exec: /bin/sh. command line was: %s", cmdline);
448 exit(EXIT_FAILURE);
449 } else if (pid < 0) {
450 warn("could not fork. command line was: %s", cmdline);
451 return false;
452 }
453
454 win_set_cursor(&win, CURSOR_WATCH);
455
456 waitpid(pid, &status, 0);
457 if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
458 warn("child exited with non-zero return value: %d. command line was: %s",
459 WEXITSTATUS(status), cmdline);
460
461 if (mode == MODE_IMAGE) {
462 img_close(&img, true);
463 load_image(fileidx);
464 }
465 if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) &&
466 mode == MODE_THUMB)
467 {
468 remove_file(tns.sel, false);
469 tns.dirty = true;
470 if (tns.sel >= tns.cnt)
471 tns.sel = tns.cnt - 1;
472 }
473 return true;
474}