Krolyxon
Commit 8a652a7

Branches

Refs →

nsxivcommands.c

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