Krolyxon
Commit 38ecea3

Branches

Refs →

nsxivcommands.c

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