Krolyxon
Commit a329615

Branches

Refs →

nsxivcommands.c

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