Krolyxon
Commit ce84601

Branches

Refs →

nsxivcommands.c

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