Krolyxon
Commit fb6e4bd

Branches

Refs →

nsxivcommands.c

550 lines · 10.2 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 "options.h"
30#include "thumbs.h"
31#include "util.h"
32#include "config.h"
33
34void cleanup(void);
35void remove_file(int, bool);
36void load_image(int);
37void open_info(void);
38void redraw(void);
39void reset_cursor(void);
40void animate(void);
41void set_timeout(timeout_f, int, bool);
42void reset_timeout(timeout_f);
43
44extern appmode_t mode;
45extern img_t img;
46extern tns_t tns;
47extern win_t win;
48
49extern fileinfo_t *files;
50extern int filecnt, fileidx;
51extern int markcnt;
52extern int alternate;
53
54extern int prefix;
55
56const int ss_delays[] = {
57 1, 2, 3, 5, 10, 15, 20, 30, 60, 120, 180, 300, 600
58};
59
60bool it_quit(arg_t a)
61{
62 unsigned int i;
63
64 if (options->to_stdout && markcnt > 0) {
65 for (i = 0; i < filecnt; i++) {
66 if (files[i].marked)
67 printf("%s\n", files[i].name);
68 }
69 }
70 cleanup();
71 exit(EXIT_SUCCESS);
72}
73
74bool it_switch_mode(arg_t a)
75{
76 if (mode == MODE_IMAGE) {
77 if (tns.thumbs == NULL)
78 tns_init(&tns, filecnt, &win);
79 img_close(&img, false);
80 reset_timeout(reset_cursor);
81 tns.sel = fileidx;
82 tns.dirty = true;
83 mode = MODE_THUMB;
84 } else {
85 load_image(tns.sel);
86 mode = MODE_IMAGE;
87 }
88 return true;
89}
90
91bool it_toggle_fullscreen(arg_t a)
92{
93 win_toggle_fullscreen(&win);
94 /* redraw after next ConfigureNotify event */
95 set_timeout(redraw, TO_REDRAW_RESIZE, false);
96 if (mode == MODE_IMAGE)
97 img.checkpan = img.dirty = true;
98 else
99 tns.dirty = true;
100 return false;
101}
102
103bool it_toggle_bar(arg_t a)
104{
105 win_toggle_bar(&win);
106 if (mode == MODE_IMAGE) {
107 img.checkpan = img.dirty = true;
108 if (win.bar.h > 0)
109 open_info();
110 } else {
111 tns.dirty = true;
112 }
113 return true;
114}
115
116bool t_reload_all(arg_t a)
117{
118 if (mode == MODE_THUMB) {
119 tns_free(&tns);
120 tns_init(&tns, filecnt, &win);
121 return true;
122 } else {
123 return false;
124 }
125}
126
127bool it_reload_image(arg_t a)
128{
129 if (mode == MODE_IMAGE) {
130 load_image(fileidx);
131 } else {
132 win_set_cursor(&win, CURSOR_WATCH);
133 if (!tns_load(&tns, tns.sel, &files[tns.sel], true, false)) {
134 remove_file(tns.sel, false);
135 tns.dirty = true;
136 if (tns.sel >= tns.cnt)
137 tns.sel = tns.cnt - 1;
138 }
139 }
140 return true;
141}
142
143bool it_remove_image(arg_t a)
144{
145 if (mode == MODE_IMAGE) {
146 remove_file(fileidx, true);
147 load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
148 return true;
149 } else if (tns.sel < tns.cnt) {
150 remove_file(tns.sel, true);
151 tns.dirty = true;
152 if (tns.sel >= tns.cnt)
153 tns.sel = tns.cnt - 1;
154 return true;
155 } else {
156 return false;
157 }
158}
159
160bool i_navigate(arg_t a)
161{
162 long n = (long) a;
163
164 if (mode == MODE_IMAGE) {
165 if (prefix > 0)
166 n *= prefix;
167 n += fileidx;
168 if (n < 0)
169 n = 0;
170 if (n >= filecnt)
171 n = filecnt - 1;
172
173 if (n != fileidx) {
174 load_image(n);
175 return true;
176 }
177 }
178 return false;
179}
180
181bool i_alternate(arg_t a)
182{
183 if (mode == MODE_IMAGE) {
184 load_image(alternate);
185 return true;
186 } else {
187 return false;
188 }
189}
190
191bool it_first(arg_t a)
192{
193 if (mode == MODE_IMAGE && fileidx != 0) {
194 load_image(0);
195 return true;
196 } else if (mode == MODE_THUMB && tns.sel != 0) {
197 tns.sel = 0;
198 tns.dirty = true;
199 return true;
200 } else {
201 return false;
202 }
203}
204
205bool it_n_or_last(arg_t a)
206{
207 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
208
209 if (mode == MODE_IMAGE && fileidx != n) {
210 load_image(n);
211 return true;
212 } else if (mode == MODE_THUMB && tns.sel != n) {
213 tns.sel = n;
214 tns.dirty = true;
215 return true;
216 } else {
217 return false;
218 }
219}
220
221bool i_navigate_frame(arg_t a)
222{
223 if (mode == MODE_IMAGE && !img.multi.animate)
224 return img_frame_navigate(&img, (long) a);
225 else
226 return false;
227}
228
229bool i_toggle_animation(arg_t a)
230{
231 if (mode != MODE_IMAGE)
232 return false;
233
234 if (img.multi.animate) {
235 reset_timeout(animate);
236 img.multi.animate = false;
237 } else if (img_frame_animate(&img, true)) {
238 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
239 }
240 return true;
241}
242
243bool it_toggle_image_mark(arg_t a)
244{
245 int sel = mode == MODE_IMAGE ? fileidx : tns.sel;
246
247 files[sel].marked = !files[sel].marked;
248 markcnt += files[sel].marked ? 1 : -1;
249 return true;
250}
251
252bool it_navigate_marked(arg_t a)
253{
254 long n = (long) a;
255 int d, i, cnt, sel, new;
256
257 if (mode == MODE_IMAGE)
258 cnt = filecnt, sel = new = fileidx;
259 else
260 cnt = tns.cnt, sel = new = tns.sel;
261 if (prefix > 0)
262 n *= prefix;
263 d = n > 0 ? 1 : -1;
264 for (i = sel + d; n != 0 && i >= 0 && i < cnt; i += d) {
265 if (files[i].marked) {
266 n -= d;
267 new = i;
268 }
269 }
270 if (new != sel) {
271 if (mode == MODE_IMAGE) {
272 load_image(new);
273 } else {
274 tns.sel = new;
275 tns.dirty = true;
276 }
277 return true;
278 } else {
279 return false;
280 }
281}
282
283bool it_scroll_move(arg_t a)
284{
285 direction_t dir = (direction_t) a;
286
287 if (mode == MODE_IMAGE)
288 return img_pan(&img, dir, prefix);
289 else
290 return tns_move_selection(&tns, dir, prefix);
291}
292
293bool it_scroll_screen(arg_t a)
294{
295 direction_t dir = (direction_t) a;
296
297 if (mode == MODE_IMAGE)
298 return img_pan(&img, dir, -1);
299 else
300 return tns_scroll(&tns, dir, true);
301}
302
303bool i_scroll_to_edge(arg_t a)
304{
305 direction_t dir = (direction_t) a;
306
307 if (mode == MODE_IMAGE)
308 return img_pan_edge(&img, dir);
309 else
310 return false;
311}
312
313/* Xlib helper function for i_drag() */
314Bool is_motionnotify(Display *d, XEvent *e, XPointer a)
315{
316 return e != NULL && e->type == MotionNotify;
317}
318
319#define WARP(x,y) \
320 XWarpPointer(win.env.dpy, None, win.xwin, 0, 0, 0, 0, x, y); \
321 ox = x, oy = y; \
322 break
323
324bool i_drag(arg_t a)
325{
326 int dx = 0, dy = 0, i, ox, oy, x, y;
327 unsigned int ui;
328 bool dragging = true, next = false;
329 XEvent e;
330 Window w;
331
332 if (mode != MODE_IMAGE)
333 return false;
334 if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
335 return false;
336
337 win_set_cursor(&win, CURSOR_HAND);
338
339 while (dragging) {
340 if (!next)
341 XMaskEvent(win.env.dpy,
342 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
343 switch (e.type) {
344 case ButtonPress:
345 case ButtonRelease:
346 dragging = false;
347 break;
348 case MotionNotify:
349 x = e.xmotion.x;
350 y = e.xmotion.y;
351
352 /* wrap the mouse around */
353 if (x < 0) {
354 WARP(win.w, y);
355 } else if (x > win.w) {
356 WARP(0, y);
357 } else if (y < 0) {
358 WARP(x, win.h);
359 } else if (y > win.h) {
360 WARP(x, 0);
361 }
362 dx += x - ox;
363 dy += y - oy;
364 ox = x;
365 oy = y;
366 break;
367 }
368 if (dragging)
369 next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
370 if ((!dragging || !next) && (dx != 0 || dy != 0)) {
371 if (img_move(&img, dx, dy)) {
372 img_render(&img);
373 win_draw(&win);
374 }
375 dx = dy = 0;
376 }
377 }
378
379 win_set_cursor(&win, CURSOR_ARROW);
380 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
381 reset_timeout(redraw);
382
383 return false;
384}
385
386bool i_zoom(arg_t a)
387{
388 long scale = (long) a;
389
390 if (mode != MODE_IMAGE)
391 return false;
392
393 if (scale > 0)
394 return img_zoom_in(&img);
395 else if (scale < 0)
396 return img_zoom_out(&img);
397 else
398 return false;
399}
400
401bool i_set_zoom(arg_t a)
402{
403 if (mode == MODE_IMAGE)
404 return img_zoom(&img, (prefix ? prefix : (long) a) / 100.0);
405 else
406 return false;
407}
408
409bool i_fit_to_win(arg_t a)
410{
411 bool ret = false;
412 scalemode_t sm = (scalemode_t) a;
413
414 if (mode == MODE_IMAGE) {
415 if ((ret = img_fit_win(&img, sm)))
416 img_center(&img);
417 }
418 return ret;
419}
420
421bool i_fit_to_img(arg_t a)
422{
423 int x, y;
424 unsigned int w, h;
425 bool ret = false;
426
427 if (mode == MODE_IMAGE) {
428 x = MAX(0, win.x + img.x);
429 y = MAX(0, win.y + img.y);
430 w = img.w * img.zoom;
431 h = img.h * img.zoom;
432 if ((ret = win_moveresize(&win, x, y, w, h))) {
433 img.x = x - win.x;
434 img.y = y - win.y;
435 img.dirty = true;
436 }
437 }
438 return ret;
439}
440
441bool i_rotate(arg_t a)
442{
443 degree_t degree = (degree_t) a;
444
445 if (mode == MODE_IMAGE) {
446 img_rotate(&img, degree);
447 return true;
448 } else {
449 return false;
450 }
451}
452
453bool i_flip(arg_t a)
454{
455 flipdir_t dir = (flipdir_t) a;
456
457 if (mode == MODE_IMAGE) {
458 img_flip(&img, dir);
459 return true;
460 } else {
461 return false;
462 }
463}
464
465bool i_toggle_antialias(arg_t a)
466{
467 if (mode == MODE_IMAGE) {
468 img_toggle_antialias(&img);
469 return true;
470 } else {
471 return false;
472 }
473}
474
475bool it_toggle_alpha(arg_t a)
476{
477 img.alpha = tns.alpha = !img.alpha;
478 if (mode == MODE_IMAGE)
479 img.dirty = true;
480 else
481 tns.dirty = true;
482 return true;
483}
484
485bool it_open_with(arg_t a)
486{
487 const char *prog = (const char*) a;
488 pid_t pid;
489
490 if (prog == NULL || *prog == '\0')
491 return false;
492
493 if ((pid = fork()) == 0) {
494 execlp(prog, prog,
495 files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
496 warn("could not exec: %s", prog);
497 exit(EXIT_FAILURE);
498 } else if (pid < 0) {
499 warn("could not fork. program was: %s", prog);
500 }
501 return false;
502}
503
504bool it_shell_cmd(arg_t a)
505{
506 int n, status;
507 const char *cmdline = (const char*) a;
508 pid_t pid;
509
510 if (cmdline == NULL || *cmdline == '\0')
511 return false;
512
513 n = mode == MODE_IMAGE ? fileidx : tns.sel;
514
515 if (setenv("SXIV_IMG", files[n].path, 1) < 0) {
516 warn("could not set env.-variable: SXIV_IMG. command line was: %s",
517 cmdline);
518 return false;
519 }
520
521 if ((pid = fork()) == 0) {
522 execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
523 warn("could not exec: /bin/sh. command line was: %s", cmdline);
524 exit(EXIT_FAILURE);
525 } else if (pid < 0) {
526 warn("could not fork. command line was: %s", cmdline);
527 return false;
528 }
529
530 win_set_cursor(&win, CURSOR_WATCH);
531
532 waitpid(pid, &status, 0);
533 if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
534 warn("child exited with non-zero return value: %d. command line was: %s",
535 WEXITSTATUS(status), cmdline);
536
537 if (mode == MODE_IMAGE) {
538 img_close(&img, true);
539 load_image(fileidx);
540 }
541 if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) &&
542 mode == MODE_THUMB)
543 {
544 remove_file(tns.sel, false);
545 tns.dirty = true;
546 if (tns.sel >= tns.cnt)
547 tns.sel = tns.cnt - 1;
548 }
549 return true;
550}