Krolyxon
Commit 304fd38

Branches

Refs →

nsxivcommands.c

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