Krolyxon
Commit 4057453

Branches

Refs →

nsxivcommands.c

455 lines · 9.3 KB · C

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