Krolyxon
Commit 385ba28

Branches

Refs →

nsxivcommands.c

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