Krolyxon
Commit 5ca20ad

Branches

Refs →

nsxivcommands.c

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