Krolyxon
Commit bf41012

Branches

Refs →

nsxivcommands.c

486 lines · 9.1 KB · C

1/* Copyright 2011, 2012 Bert Muennich
2 *
3 * This file is part of sxiv.
4 *
5 * sxiv is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License,
8 * or (at your option) any later version.
9 *
10 * sxiv is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
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{
59 cleanup();
60 exit(EXIT_SUCCESS);
61}
62
63bool it_switch_mode(arg_t a)
64{
65 if (mode == MODE_IMAGE) {
66 if (tns.thumbs == NULL)
67 tns_init(&tns, filecnt, &win);
68 img_close(&img, false);
69 reset_timeout(reset_cursor);
70 tns.sel = fileidx;
71 tns.dirty = true;
72 mode = MODE_THUMB;
73 } else {
74 load_image(tns.sel);
75 mode = MODE_IMAGE;
76 }
77 return true;
78}
79
80bool it_toggle_fullscreen(arg_t a)
81{
82 win_toggle_fullscreen(&win);
83 /* redraw after next ConfigureNotify event */
84 set_timeout(redraw, TO_REDRAW_RESIZE, false);
85 if (mode == MODE_IMAGE)
86 img.checkpan = img.dirty = true;
87 else
88 tns.dirty = true;
89 return false;
90}
91
92bool it_toggle_bar(arg_t a)
93{
94 win_toggle_bar(&win);
95 if (mode == MODE_IMAGE)
96 img.checkpan = img.dirty = true;
97 else
98 tns.dirty = true;
99 return true;
100}
101
102bool t_reload_all(arg_t a)
103{
104 if (mode == MODE_THUMB) {
105 tns_free(&tns);
106 tns_init(&tns, filecnt, &win);
107 return true;
108 } else {
109 return false;
110 }
111}
112
113bool it_reload_image(arg_t a)
114{
115 if (mode == MODE_IMAGE) {
116 load_image(fileidx);
117 } else {
118 win_set_cursor(&win, CURSOR_WATCH);
119 if (!tns_load(&tns, tns.sel, &files[tns.sel], true, false)) {
120 remove_file(tns.sel, false);
121 tns.dirty = true;
122 if (tns.sel >= tns.cnt)
123 tns.sel = tns.cnt - 1;
124 }
125 }
126 return true;
127}
128
129bool it_remove_image(arg_t a)
130{
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{
148 long n = (long) a;
149
150 if (mode == MODE_IMAGE) {
151 if (prefix > 0)
152 n *= prefix;
153 n += fileidx;
154 if (n < 0)
155 n = 0;
156 if (n >= filecnt)
157 n = filecnt - 1;
158
159 if (n != fileidx) {
160 load_image(n);
161 return true;
162 }
163 }
164 return false;
165}
166
167bool i_alternate(arg_t a)
168{
169 if (mode == MODE_IMAGE) {
170 load_image(alternate);
171 return true;
172 } else {
173 return false;
174 }
175}
176
177bool it_first(arg_t a)
178{
179 if (mode == MODE_IMAGE && fileidx != 0) {
180 load_image(0);
181 return true;
182 } else if (mode == MODE_THUMB && tns.sel != 0) {
183 tns.sel = 0;
184 tns.dirty = true;
185 return true;
186 } else {
187 return false;
188 }
189}
190
191bool it_n_or_last(arg_t a)
192{
193 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
194
195 if (mode == MODE_IMAGE && fileidx != n) {
196 load_image(n);
197 return true;
198 } else if (mode == MODE_THUMB && tns.sel != n) {
199 tns.sel = n;
200 tns.dirty = true;
201 return true;
202 } else {
203 return false;
204 }
205}
206
207bool i_navigate_frame(arg_t a)
208{
209 if (mode == MODE_IMAGE && !img.multi.animate)
210 return img_frame_navigate(&img, (long) a);
211 else
212 return false;
213}
214
215bool i_toggle_animation(arg_t a)
216{
217 if (mode != MODE_IMAGE)
218 return false;
219
220 if (img.multi.animate) {
221 reset_timeout(animate);
222 img.multi.animate = false;
223 } else if (img_frame_animate(&img, true)) {
224 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
225 }
226 return true;
227}
228
229bool it_scroll_move(arg_t a)
230{
231 direction_t dir = (direction_t) a;
232
233 if (mode == MODE_IMAGE)
234 return img_pan(&img, dir, prefix);
235 else
236 return tns_move_selection(&tns, dir, prefix);
237}
238
239bool it_scroll_screen(arg_t a)
240{
241 direction_t dir = (direction_t) a;
242
243 if (mode == MODE_IMAGE)
244 return img_pan(&img, dir, -1);
245 else
246 return tns_scroll(&tns, dir, true);
247}
248
249bool i_scroll_to_edge(arg_t a)
250{
251 direction_t dir = (direction_t) a;
252
253 if (mode == MODE_IMAGE)
254 return img_pan_edge(&img, dir);
255 else
256 return false;
257}
258
259/* Xlib helper function for i_drag() */
260Bool is_motionnotify(Display *d, XEvent *e, XPointer a)
261{
262 return e != NULL && e->type == MotionNotify;
263}
264
265bool i_drag(arg_t a)
266{
267 int dx = 0, dy = 0, i, ox, oy, x, y;
268 unsigned int ui;
269 bool dragging = true, next = false;
270 XEvent e;
271 Window w;
272
273 if (mode != MODE_IMAGE)
274 return false;
275 if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
276 return false;
277
278 win_set_cursor(&win, CURSOR_HAND);
279
280 while (dragging) {
281 if (!next)
282 XMaskEvent(win.env.dpy,
283 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
284 switch (e.type) {
285 case ButtonPress:
286 case ButtonRelease:
287 dragging = false;
288 break;
289 case MotionNotify:
290 x = e.xmotion.x;
291 y = e.xmotion.y;
292 if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) {
293 dx += x - ox;
294 dy += y - oy;
295 }
296 ox = x;
297 oy = y;
298 break;
299 }
300 if (dragging)
301 next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
302 if ((!dragging || !next) && (dx != 0 || dy != 0)) {
303 if (img_move(&img, dx, dy)) {
304 img_render(&img);
305 win_draw(&win);
306 }
307 dx = dy = 0;
308 }
309 }
310
311 win_set_cursor(&win, CURSOR_ARROW);
312 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
313 reset_timeout(redraw);
314
315 return false;
316}
317
318bool i_zoom(arg_t a)
319{
320 long scale = (long) a;
321
322 if (mode != MODE_IMAGE)
323 return false;
324
325 if (scale > 0)
326 return img_zoom_in(&img);
327 else if (scale < 0)
328 return img_zoom_out(&img);
329 else
330 return false;
331}
332
333bool i_set_zoom(arg_t a)
334{
335 if (mode == MODE_IMAGE)
336 return img_zoom(&img, (prefix ? prefix : (long) a) / 100.0);
337 else
338 return false;
339}
340
341bool i_fit_to_win(arg_t a)
342{
343 bool ret = false;
344 scalemode_t sm = (scalemode_t) a;
345
346 if (mode == MODE_IMAGE) {
347 if ((ret = img_fit_win(&img, sm)))
348 img_center(&img);
349 }
350 return ret;
351}
352
353bool i_fit_to_img(arg_t a)
354{
355 int x, y;
356 unsigned int w, h;
357 bool ret = false;
358
359 if (mode == MODE_IMAGE) {
360 x = MAX(0, win.x + img.x);
361 y = MAX(0, win.y + img.y);
362 w = img.w * img.zoom;
363 h = img.h * img.zoom;
364 if ((ret = win_moveresize(&win, x, y, w, h))) {
365 img.x = x - win.x;
366 img.y = y - win.y;
367 img.dirty = true;
368 }
369 }
370 return ret;
371}
372
373bool i_rotate(arg_t a)
374{
375 direction_t dir = (direction_t) a;
376
377 if (mode == MODE_IMAGE) {
378 if (dir == DIR_LEFT) {
379 img_rotate_left(&img);
380 return true;
381 } else if (dir == DIR_RIGHT) {
382 img_rotate_right(&img);
383 return true;
384 }
385 }
386 return false;
387}
388
389bool i_flip(arg_t a)
390{
391 flipdir_t dir = (flipdir_t) a;
392
393 if (mode == MODE_IMAGE) {
394 img_flip(&img, dir);
395 return true;
396 } else {
397 return false;
398 }
399}
400
401bool i_toggle_antialias(arg_t a)
402{
403 if (mode == MODE_IMAGE) {
404 img_toggle_antialias(&img);
405 return true;
406 } else {
407 return false;
408 }
409}
410
411bool it_toggle_alpha(arg_t a)
412{
413 img.alpha = tns.alpha = !img.alpha;
414 if (mode == MODE_IMAGE)
415 img.dirty = true;
416 else
417 tns.dirty = true;
418 return true;
419}
420
421bool it_open_with(arg_t a)
422{
423 const char *prog = (const char*) a;
424 pid_t pid;
425
426 if (prog == NULL || *prog == '\0')
427 return false;
428
429 if ((pid = fork()) == 0) {
430 execlp(prog, prog,
431 files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
432 warn("could not exec: %s", prog);
433 exit(EXIT_FAILURE);
434 } else if (pid < 0) {
435 warn("could not fork. program was: %s", prog);
436 }
437 return false;
438}
439
440bool it_shell_cmd(arg_t a)
441{
442 int n, status;
443 const char *cmdline = (const char*) a;
444 pid_t pid;
445
446 if (cmdline == NULL || *cmdline == '\0')
447 return false;
448
449 n = mode == MODE_IMAGE ? fileidx : tns.sel;
450
451 if (setenv("SXIV_IMG", files[n].path, 1) < 0) {
452 warn("could not set env.-variable: SXIV_IMG. command line was: %s",
453 cmdline);
454 return false;
455 }
456
457 if ((pid = fork()) == 0) {
458 execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
459 warn("could not exec: /bin/sh. command line was: %s", cmdline);
460 exit(EXIT_FAILURE);
461 } else if (pid < 0) {
462 warn("could not fork. command line was: %s", cmdline);
463 return false;
464 }
465
466 win_set_cursor(&win, CURSOR_WATCH);
467
468 waitpid(pid, &status, 0);
469 if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
470 warn("child exited with non-zero return value: %d. command line was: %s",
471 WEXITSTATUS(status), cmdline);
472
473 if (mode == MODE_IMAGE) {
474 img_close(&img, true);
475 load_image(fileidx);
476 }
477 if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) &&
478 mode == MODE_THUMB)
479 {
480 remove_file(tns.sel, false);
481 tns.dirty = true;
482 if (tns.sel >= tns.cnt)
483 tns.sel = tns.cnt - 1;
484 }
485 return true;
486}