Krolyxon
Commit e2ea759

Branches

Refs →

nsxivcommands.c

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