Krolyxon
Commit f329840

Branches

Refs →

nsxivcommands.c

500 lines · 9.4 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
265#define WARP(x,y) \
266 XWarpPointer(win.env.dpy, None, win.xwin, 0, 0, 0, 0, x, y); \
267 ox = x, oy = y; \
268 break
269
270bool i_drag(arg_t a)
271{
272 int dx = 0, dy = 0, i, ox, oy, x, y;
273 unsigned int ui;
274 bool dragging = true, next = false;
275 XEvent e;
276 Window w;
277
278 if (mode != MODE_IMAGE)
279 return false;
280 if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
281 return false;
282
283 win_set_cursor(&win, CURSOR_HAND);
284
285 while (dragging) {
286 if (!next)
287 XMaskEvent(win.env.dpy,
288 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
289 switch (e.type) {
290 case ButtonPress:
291 case ButtonRelease:
292 dragging = false;
293 break;
294 case MotionNotify:
295 x = e.xmotion.x;
296 y = e.xmotion.y;
297
298 /* wrap the mouse around */
299 if (x < 0) {
300 WARP(win.w, y);
301 } else if (x > win.w) {
302 WARP(0, y);
303 } else if (y < 0) {
304 WARP(x, win.h);
305 } else if (y > win.h) {
306 WARP(x, 0);
307 }
308 dx += x - ox;
309 dy += y - oy;
310 ox = x;
311 oy = y;
312 break;
313 }
314 if (dragging)
315 next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
316 if ((!dragging || !next) && (dx != 0 || dy != 0)) {
317 if (img_move(&img, dx, dy)) {
318 img_render(&img);
319 win_draw(&win);
320 }
321 dx = dy = 0;
322 }
323 }
324
325 win_set_cursor(&win, CURSOR_ARROW);
326 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
327 reset_timeout(redraw);
328
329 return false;
330}
331
332bool i_zoom(arg_t a)
333{
334 long scale = (long) a;
335
336 if (mode != MODE_IMAGE)
337 return false;
338
339 if (scale > 0)
340 return img_zoom_in(&img);
341 else if (scale < 0)
342 return img_zoom_out(&img);
343 else
344 return false;
345}
346
347bool i_set_zoom(arg_t a)
348{
349 if (mode == MODE_IMAGE)
350 return img_zoom(&img, (prefix ? prefix : (long) a) / 100.0);
351 else
352 return false;
353}
354
355bool i_fit_to_win(arg_t a)
356{
357 bool ret = false;
358 scalemode_t sm = (scalemode_t) a;
359
360 if (mode == MODE_IMAGE) {
361 if ((ret = img_fit_win(&img, sm)))
362 img_center(&img);
363 }
364 return ret;
365}
366
367bool i_fit_to_img(arg_t a)
368{
369 int x, y;
370 unsigned int w, h;
371 bool ret = false;
372
373 if (mode == MODE_IMAGE) {
374 x = MAX(0, win.x + img.x);
375 y = MAX(0, win.y + img.y);
376 w = img.w * img.zoom;
377 h = img.h * img.zoom;
378 if ((ret = win_moveresize(&win, x, y, w, h))) {
379 img.x = x - win.x;
380 img.y = y - win.y;
381 img.dirty = true;
382 }
383 }
384 return ret;
385}
386
387bool i_rotate(arg_t a)
388{
389 direction_t dir = (direction_t) a;
390
391 if (mode == MODE_IMAGE) {
392 if (dir == DIR_LEFT) {
393 img_rotate_left(&img);
394 return true;
395 } else if (dir == DIR_RIGHT) {
396 img_rotate_right(&img);
397 return true;
398 }
399 }
400 return false;
401}
402
403bool i_flip(arg_t a)
404{
405 flipdir_t dir = (flipdir_t) a;
406
407 if (mode == MODE_IMAGE) {
408 img_flip(&img, dir);
409 return true;
410 } else {
411 return false;
412 }
413}
414
415bool i_toggle_antialias(arg_t a)
416{
417 if (mode == MODE_IMAGE) {
418 img_toggle_antialias(&img);
419 return true;
420 } else {
421 return false;
422 }
423}
424
425bool it_toggle_alpha(arg_t a)
426{
427 img.alpha = tns.alpha = !img.alpha;
428 if (mode == MODE_IMAGE)
429 img.dirty = true;
430 else
431 tns.dirty = true;
432 return true;
433}
434
435bool it_open_with(arg_t a)
436{
437 const char *prog = (const char*) a;
438 pid_t pid;
439
440 if (prog == NULL || *prog == '\0')
441 return false;
442
443 if ((pid = fork()) == 0) {
444 execlp(prog, prog,
445 files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
446 warn("could not exec: %s", prog);
447 exit(EXIT_FAILURE);
448 } else if (pid < 0) {
449 warn("could not fork. program was: %s", prog);
450 }
451 return false;
452}
453
454bool it_shell_cmd(arg_t a)
455{
456 int n, status;
457 const char *cmdline = (const char*) a;
458 pid_t pid;
459
460 if (cmdline == NULL || *cmdline == '\0')
461 return false;
462
463 n = mode == MODE_IMAGE ? fileidx : tns.sel;
464
465 if (setenv("SXIV_IMG", files[n].path, 1) < 0) {
466 warn("could not set env.-variable: SXIV_IMG. command line was: %s",
467 cmdline);
468 return false;
469 }
470
471 if ((pid = fork()) == 0) {
472 execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
473 warn("could not exec: /bin/sh. command line was: %s", cmdline);
474 exit(EXIT_FAILURE);
475 } else if (pid < 0) {
476 warn("could not fork. command line was: %s", cmdline);
477 return false;
478 }
479
480 win_set_cursor(&win, CURSOR_WATCH);
481
482 waitpid(pid, &status, 0);
483 if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
484 warn("child exited with non-zero return value: %d. command line was: %s",
485 WEXITSTATUS(status), cmdline);
486
487 if (mode == MODE_IMAGE) {
488 img_close(&img, true);
489 load_image(fileidx);
490 }
491 if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) &&
492 mode == MODE_THUMB)
493 {
494 remove_file(tns.sel, false);
495 tns.dirty = true;
496 if (tns.sel >= tns.cnt)
497 tns.sel = tns.cnt - 1;
498 }
499 return true;
500}