Krolyxon
Commit b1a24cb

Branches

Refs →

nsxivcommands.c

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