Krolyxon
Commit c6bddfe

Branches

Refs →

nsxivcommands.c

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