Krolyxon
Commit 4383a65

Branches

Refs →

nsxivcommands.c

439 lines · 9.0 KB · C

1/* sxiv: commands.c
2 * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#define _POSIX_C_SOURCE 200112L
20
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24#include <sys/wait.h>
25
26#include "commands.h"
27#include "image.h"
28#include "thumbs.h"
29#include "util.h"
30
31void cleanup(void);
32void remove_file(int, bool);
33void load_image(int);
34void redraw(void);
35void reset_cursor(void);
36void animate(void);
37void slideshow(void);
38void set_timeout(timeout_f, int, bool);
39void reset_timeout(timeout_f);
40
41extern appmode_t mode;
42extern img_t img;
43extern tns_t tns;
44extern win_t win;
45
46extern fileinfo_t *files;
47extern int filecnt, fileidx;
48
49bool it_quit(arg_t a) {
50 cleanup();
51 exit(EXIT_SUCCESS);
52}
53
54bool it_switch_mode(arg_t a) {
55 if (mode == MODE_IMAGE) {
56 if (tns.thumbs == NULL)
57 tns_init(&tns, filecnt, &win);
58 img_close(&img, false);
59 reset_timeout(reset_cursor);
60 if (img.slideshow) {
61 img.slideshow = false;
62 reset_timeout(slideshow);
63 }
64 tns.sel = fileidx;
65 tns.dirty = true;
66 mode = MODE_THUMB;
67 } else {
68 load_image(tns.sel);
69 mode = MODE_IMAGE;
70 }
71 return true;
72}
73
74bool it_toggle_fullscreen(arg_t a) {
75 win_toggle_fullscreen(&win);
76 set_timeout(redraw, TO_REDRAW_RESIZE, false);
77 if (mode == MODE_IMAGE)
78 img.checkpan = true;
79 else
80 tns.dirty = true;
81 return false;
82}
83
84bool it_reload_image(arg_t a) {
85 if (mode == MODE_IMAGE) {
86 load_image(fileidx);
87 } else {
88 win_set_cursor(&win, CURSOR_WATCH);
89 if (!tns_load(&tns, tns.sel, &files[tns.sel], true, false)) {
90 remove_file(tns.sel, false);
91 tns.dirty = true;
92 if (tns.sel >= tns.cnt)
93 tns.sel = tns.cnt - 1;
94 }
95 }
96 return true;
97}
98
99bool it_remove_image(arg_t a) {
100 if (mode == MODE_IMAGE) {
101 remove_file(fileidx, true);
102 load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
103 return true;
104 } else if (tns.sel < tns.cnt) {
105 remove_file(tns.sel, true);
106 tns.dirty = true;
107 if (tns.sel >= tns.cnt)
108 tns.sel = tns.cnt - 1;
109 return true;
110 } else {
111 return false;
112 }
113}
114
115bool i_navigate(arg_t a) {
116 long n = (long) a;
117
118 if (mode == MODE_IMAGE) {
119 n += fileidx;
120 if (n < 0)
121 n = 0;
122 if (n >= filecnt)
123 n = filecnt - 1;
124
125 if (n != fileidx) {
126 load_image(n);
127 return true;
128 }
129 }
130 return false;
131}
132
133bool it_first(arg_t a) {
134 if (mode == MODE_IMAGE && fileidx != 0) {
135 load_image(0);
136 return true;
137 } else if (mode == MODE_THUMB && tns.sel != 0) {
138 tns.sel = 0;
139 tns.dirty = true;
140 return true;
141 } else {
142 return false;
143 }
144}
145
146bool it_last(arg_t a) {
147 if (mode == MODE_IMAGE && fileidx != filecnt - 1) {
148 load_image(filecnt - 1);
149 return true;
150 } else if (mode == MODE_THUMB && tns.sel != tns.cnt - 1) {
151 tns.sel = tns.cnt - 1;
152 tns.dirty = true;
153 return true;
154 } else {
155 return false;
156 }
157}
158
159bool i_navigate_frame(arg_t a) {
160 if (mode == MODE_IMAGE && !img.multi.animate)
161 return img_frame_navigate(&img, (long) a);
162 else
163 return false;
164}
165
166bool i_toggle_animation(arg_t a) {
167 if (mode != MODE_IMAGE)
168 return false;
169
170 if (img.multi.animate) {
171 reset_timeout(animate);
172 img.multi.animate = false;
173 } else if (img_frame_animate(&img, true)) {
174 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
175 }
176 return true;
177}
178
179bool it_move(arg_t a) {
180 direction_t dir = (direction_t) a;
181
182 if (mode == MODE_IMAGE)
183 return img_pan(&img, dir, false);
184 else
185 return tns_move_selection(&tns, dir);
186}
187
188bool i_pan_screen(arg_t a) {
189 direction_t dir = (direction_t) a;
190
191 if (mode == MODE_IMAGE)
192 return img_pan(&img, dir, true);
193 else
194 return false;
195}
196
197bool i_pan_edge(arg_t a) {
198 direction_t dir = (direction_t) a;
199
200 if (mode == MODE_IMAGE)
201 return img_pan_edge(&img, dir);
202 else
203 return false;
204}
205
206/* Xlib helper function for i_drag() */
207Bool is_motionnotify(Display *d, XEvent *e, XPointer a) {
208 return e != NULL && e->type == MotionNotify;
209}
210
211bool i_drag(arg_t a) {
212 int dx = 0, dy = 0, i, ox, oy, x, y;
213 unsigned int ui;
214 bool dragging = true, next = false;
215 XEvent e;
216 Window w;
217
218 if (mode != MODE_IMAGE)
219 return false;
220 if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
221 return false;
222
223 win_set_cursor(&win, CURSOR_HAND);
224
225 while (dragging) {
226 if (!next)
227 XMaskEvent(win.env.dpy,
228 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
229 switch (e.type) {
230 case ButtonPress:
231 case ButtonRelease:
232 dragging = false;
233 break;
234 case MotionNotify:
235 x = e.xmotion.x;
236 y = e.xmotion.y;
237 if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) {
238 dx += x - ox;
239 dy += y - oy;
240 }
241 ox = x;
242 oy = y;
243 break;
244 }
245 if (dragging)
246 next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
247 if ((!dragging || !next) && (dx != 0 || dy != 0)) {
248 if (img_move(&img, dx, dy))
249 img_render(&img);
250 dx = dy = 0;
251 }
252 }
253
254 win_set_cursor(&win, CURSOR_ARROW);
255 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
256 reset_timeout(redraw);
257
258 return false;
259}
260
261bool i_zoom(arg_t a) {
262 long scale = (long) a;
263
264 if (mode != MODE_IMAGE)
265 return false;
266
267 if (scale > 0)
268 return img_zoom_in(&img);
269 else if (scale < 0)
270 return img_zoom_out(&img);
271 else
272 return img_zoom(&img, 1.0);
273}
274
275bool i_fit_to_win(arg_t a) {
276 bool ret = false;
277
278 if (mode == MODE_IMAGE) {
279 if ((ret = img_fit_win(&img)))
280 img_center(&img);
281 }
282 return ret;
283}
284
285bool i_fit_to_img(arg_t a) {
286 int x, y;
287 unsigned int w, h;
288 bool ret = false;
289
290 if (mode == MODE_IMAGE) {
291 x = MAX(0, win.x + img.x);
292 y = MAX(0, win.y + img.y);
293 w = img.w * img.zoom;
294 h = img.h * img.zoom;
295 if ((ret = win_moveresize(&win, x, y, w, h))) {
296 img.x = x - win.x;
297 img.y = y - win.y;
298 }
299 }
300 return ret;
301}
302
303bool i_rotate(arg_t a) {
304 direction_t dir = (direction_t) a;
305
306 if (mode == MODE_IMAGE) {
307 if (dir == DIR_LEFT) {
308 img_rotate_left(&img);
309 return true;
310 } else if (dir == DIR_RIGHT) {
311 img_rotate_right(&img);
312 return true;
313 }
314 }
315 return false;
316}
317
318bool i_toggle_slideshow(arg_t a) {
319 if (mode == MODE_IMAGE) {
320 if (img.slideshow) {
321 img.slideshow = false;
322 reset_timeout(slideshow);
323 return true;
324 } else if (fileidx + 1 < filecnt) {
325 img.slideshow = true;
326 set_timeout(slideshow, img.ss_delay, true);
327 return true;
328 }
329 }
330 return false;
331}
332
333bool i_adjust_slideshow(arg_t a) {
334 long d = (long) a;
335 int i, delays[] = { 1, 2, 3, 5, 10, 15, 20, 30, 60, 120, 180, 300, 600 };
336
337 if (mode != MODE_IMAGE || !img.slideshow)
338 return false;
339
340 if (d < 0) {
341 for (i = ARRLEN(delays) - 2; i >= 0; i--) {
342 if (img.ss_delay > delays[i] * 1000) {
343 img.ss_delay = delays[i] * 1000;
344 return true;
345 }
346 }
347 } else {
348 for (i = 1; i < ARRLEN(delays); i++) {
349 if (img.ss_delay < delays[i] * 1000) {
350 img.ss_delay = delays[i] * 1000;
351 return true;
352 }
353 }
354 }
355 return false;
356}
357
358bool i_toggle_antialias(arg_t a) {
359 if (mode == MODE_IMAGE) {
360 img_toggle_antialias(&img);
361 return true;
362 } else {
363 return false;
364 }
365}
366
367bool it_toggle_alpha(arg_t a) {
368 img.alpha = tns.alpha = !img.alpha;
369 if (mode == MODE_IMAGE)
370 img.dirty = true;
371 else
372 tns.dirty = true;
373 return true;
374}
375
376bool it_open_with(arg_t a) {
377 const char *prog = (const char*) a;
378 pid_t pid;
379
380 if (prog == NULL || *prog == '\0')
381 return false;
382
383 if ((pid = fork()) == 0) {
384 execlp(prog, prog,
385 files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
386 warn("could not exec: %s", prog);
387 exit(EXIT_FAILURE);
388 } else if (pid < 0) {
389 warn("could not fork. program was: %s", prog);
390 }
391 return false;
392}
393
394bool it_shell_cmd(arg_t a) {
395 int n, status;
396 const char *cmdline = (const char*) a;
397 pid_t pid;
398
399 if (cmdline == NULL || *cmdline == '\0')
400 return false;
401
402 n = mode == MODE_IMAGE ? fileidx : tns.sel;
403
404 if (setenv("SXIV_IMG", files[n].path, 1) < 0) {
405 warn("could not set env.-variable: SXIV_IMG. command line was: %s",
406 cmdline);
407 return false;
408 }
409
410 if ((pid = fork()) == 0) {
411 execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
412 warn("could not exec: /bin/sh. command line was: %s", cmdline);
413 exit(EXIT_FAILURE);
414 } else if (pid < 0) {
415 warn("could not fork. command line was: %s", cmdline);
416 return false;
417 }
418
419 win_set_cursor(&win, CURSOR_WATCH);
420
421 waitpid(pid, &status, 0);
422 if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
423 warn("child exited with non-zero return value: %d. command line was: %s",
424 WEXITSTATUS(status), cmdline);
425
426 if (mode == MODE_IMAGE) {
427 img_close(&img, true);
428 load_image(fileidx);
429 }
430 if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) &&
431 mode == MODE_THUMB)
432 {
433 remove_file(tns.sel, false);
434 tns.dirty = true;
435 if (tns.sel >= tns.cnt)
436 tns.sel = tns.cnt - 1;
437 }
438 return true;
439}