Krolyxon
Commit 591be8c

Branches

Refs →

nsxivcommands.c

502 lines · 9.4 KB · C

1/* Copyright 2011-2020 Bert Muennich
2 * Copyright 2021-2022 nsxiv contributors
3 *
4 * This file is a part of nsxiv.
5 *
6 * nsxiv is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License,
9 * or (at your option) any later version.
10 *
11 * nsxiv is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with nsxiv. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "nsxiv.h"
21
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include <sys/wait.h>
26
27void remove_file(int, bool);
28void load_image(int);
29bool mark_image(int, bool);
30void close_info(void);
31void open_info(void);
32int nav_button(void);
33void redraw(void);
34void reset_cursor(void);
35void animate(void);
36void slideshow(void);
37void set_timeout(timeout_f, int, bool);
38void reset_timeout(timeout_f);
39void handle_key_handler(bool);
40
41extern appmode_t mode;
42extern img_t img;
43extern tns_t tns;
44extern win_t win;
45extern const XButtonEvent *xbutton_ev;
46
47extern fileinfo_t *files;
48extern int filecnt, fileidx;
49extern int alternate;
50extern int markcnt;
51extern int markidx;
52
53extern int prefix;
54extern bool extprefix;
55
56bool cg_quit(arg_t status)
57{
58 unsigned int i;
59
60 if (options->to_stdout && markcnt > 0) {
61 for (i = 0; i < filecnt; i++) {
62 if (files[i].flags & FF_MARK)
63 printf("%s%c", files[i].name, options->using_null ? '\0' : '\n');
64 }
65 }
66 exit(status);
67 return None; /* silence tcc warning */
68}
69
70bool cg_switch_mode(arg_t _)
71{
72 if (mode == MODE_IMAGE) {
73 if (tns.thumbs == NULL)
74 tns_init(&tns, files, &filecnt, &fileidx, &win);
75 img_close(&img, false);
76 reset_timeout(reset_cursor);
77 if (img.ss.on) {
78 img.ss.on = false;
79 reset_timeout(slideshow);
80 }
81 tns.dirty = true;
82 mode = MODE_THUMB;
83 } else {
84 load_image(fileidx);
85 mode = MODE_IMAGE;
86 }
87 close_info();
88 open_info();
89 return true;
90}
91
92bool cg_toggle_fullscreen(arg_t _)
93{
94 win_toggle_fullscreen(&win);
95 /* redraw after next ConfigureNotify event */
96 set_timeout(redraw, TO_REDRAW_RESIZE, false);
97 if (mode == MODE_IMAGE)
98 img.checkpan = img.dirty = true;
99 else
100 tns.dirty = true;
101 return false;
102}
103
104bool cg_toggle_bar(arg_t _)
105{
106 win_toggle_bar(&win);
107 if (mode == MODE_IMAGE) {
108 if (win.bar.h > 0)
109 open_info();
110 else
111 close_info();
112 img.checkpan = img.dirty = true;
113 } else {
114 tns.dirty = true;
115 }
116 return true;
117}
118
119bool cg_prefix_external(arg_t _)
120{
121 handle_key_handler(true);
122 return false;
123}
124
125bool cg_reload_image(arg_t _)
126{
127 if (mode == MODE_IMAGE) {
128 load_image(fileidx);
129 } else {
130 win_set_cursor(&win, CURSOR_WATCH);
131 if (!tns_load(&tns, fileidx, true, false)) {
132 remove_file(fileidx, false);
133 tns.dirty = true;
134 }
135 }
136 return true;
137}
138
139bool cg_remove_image(arg_t _)
140{
141 remove_file(fileidx, true);
142 if (mode == MODE_IMAGE)
143 load_image(fileidx);
144 else
145 tns.dirty = true;
146 return true;
147}
148
149bool cg_first(arg_t _)
150{
151 if (mode == MODE_IMAGE && fileidx != 0) {
152 load_image(0);
153 return true;
154 } else if (mode == MODE_THUMB && fileidx != 0) {
155 fileidx = 0;
156 tns.dirty = true;
157 return true;
158 } else {
159 return false;
160 }
161}
162
163bool cg_n_or_last(arg_t _)
164{
165 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
166
167 if (mode == MODE_IMAGE && fileidx != n) {
168 load_image(n);
169 return true;
170 } else if (mode == MODE_THUMB && fileidx != n) {
171 fileidx = n;
172 tns.dirty = true;
173 return true;
174 } else {
175 return false;
176 }
177}
178
179bool cg_scroll_screen(arg_t dir)
180{
181 if (mode == MODE_IMAGE)
182 return img_pan(&img, dir, -1);
183 else
184 return tns_scroll(&tns, dir, true);
185}
186
187bool cg_zoom(arg_t d)
188{
189 if (mode == MODE_THUMB)
190 return tns_zoom(&tns, d);
191 else
192 return img_zoom(&img, d);
193}
194
195bool cg_toggle_image_mark(arg_t _)
196{
197 return mark_image(fileidx, !(files[fileidx].flags & FF_MARK));
198}
199
200bool cg_reverse_marks(arg_t _)
201{
202 int i;
203
204 for (i = 0; i < filecnt; i++) {
205 files[i].flags ^= FF_MARK;
206 markcnt += files[i].flags & FF_MARK ? 1 : -1;
207 }
208 if (mode == MODE_THUMB)
209 tns.dirty = true;
210 return true;
211}
212
213bool cg_mark_range(arg_t _)
214{
215 int d = markidx < fileidx ? 1 : -1, end, i;
216 bool dirty = false, on = !!(files[markidx].flags & FF_MARK);
217
218 for (i = markidx + d, end = fileidx + d; i != end; i += d)
219 dirty |= mark_image(i, on);
220 return dirty;
221}
222
223bool cg_unmark_all(arg_t _)
224{
225 int i;
226
227 for (i = 0; i < filecnt; i++)
228 files[i].flags &= ~FF_MARK;
229 markcnt = 0;
230 if (mode == MODE_THUMB)
231 tns.dirty = true;
232 return true;
233}
234
235bool cg_navigate_marked(arg_t n)
236{
237 int d, i;
238 int new = fileidx;
239
240 if (prefix > 0)
241 n *= prefix;
242 d = n > 0 ? 1 : -1;
243 for (i = fileidx + d; n != 0 && i >= 0 && i < filecnt; i += d) {
244 if (files[i].flags & FF_MARK) {
245 n -= d;
246 new = i;
247 }
248 }
249 if (new != fileidx) {
250 if (mode == MODE_IMAGE) {
251 load_image(new);
252 } else {
253 fileidx = new;
254 tns.dirty = true;
255 }
256 return true;
257 } else {
258 return false;
259 }
260}
261
262bool cg_change_gamma(arg_t d)
263{
264 if (img_change_gamma(&img, d * (prefix > 0 ? prefix : 1))) {
265 if (mode == MODE_THUMB)
266 tns.dirty = true;
267 return true;
268 } else {
269 return false;
270 }
271}
272
273bool ci_navigate(arg_t n)
274{
275 if (prefix > 0)
276 n *= prefix;
277 n += fileidx;
278 n = MAX(0, MIN(n, filecnt - 1));
279
280 if (n != fileidx) {
281 load_image(n);
282 return true;
283 } else {
284 return false;
285 }
286}
287
288bool ci_cursor_navigate(arg_t _)
289{
290 return ci_navigate(nav_button() - 1);
291}
292
293bool ci_alternate(arg_t _)
294{
295 load_image(alternate);
296 return true;
297}
298
299bool ci_navigate_frame(arg_t d)
300{
301 if (prefix > 0)
302 d *= prefix;
303 return !img.multi.animate && img_frame_navigate(&img, d);
304}
305
306bool ci_toggle_animation(arg_t _)
307{
308 bool dirty = false;
309
310 if (img.multi.cnt > 0) {
311 img.multi.animate = !img.multi.animate;
312 if (img.multi.animate) {
313 dirty = img_frame_animate(&img);
314 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
315 } else {
316 reset_timeout(animate);
317 }
318 }
319 return dirty;
320}
321
322bool ci_scroll(arg_t dir)
323{
324 return img_pan(&img, dir, prefix);
325}
326
327bool ci_scroll_to_center(arg_t _)
328{
329 return img_pan_center(&img);
330}
331
332bool ci_scroll_to_edge(arg_t dir)
333{
334 return img_pan_edge(&img, dir);
335}
336
337bool ci_drag(arg_t drag_mode)
338{
339 int x, y, ox, oy;
340 float px, py;
341 XEvent e;
342
343 if ((int)(img.w * img.zoom) <= win.w && (int)(img.h * img.zoom) <= win.h)
344 return false;
345
346 win_set_cursor(&win, drag_mode == DRAG_ABSOLUTE ? CURSOR_DRAG_ABSOLUTE : CURSOR_DRAG_RELATIVE);
347 win_cursor_pos(&win, &x, &y);
348 ox = x;
349 oy = y;
350
351 while (true) {
352 if (drag_mode == DRAG_ABSOLUTE) {
353 px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8)
354 * (win.w - img.w * img.zoom);
355 py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8)
356 * (win.h - img.h * img.zoom);
357 } else {
358 px = img.x + x - ox;
359 py = img.y + y - oy;
360 }
361
362 if (img_pos(&img, px, py)) {
363 img_render(&img);
364 win_draw(&win);
365 }
366 XMaskEvent(win.env.dpy,
367 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
368 if (e.type == ButtonPress || e.type == ButtonRelease)
369 break;
370 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
371 ox = x;
372 oy = y;
373 x = e.xmotion.x;
374 y = e.xmotion.y;
375 }
376 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
377 reset_cursor();
378
379 return true;
380}
381
382bool ci_set_zoom(arg_t zl)
383{
384 return img_zoom_to(&img, (prefix ? prefix : zl) / 100.0);
385}
386
387bool ci_fit_to_win(arg_t sm)
388{
389 return img_fit_win(&img, sm);
390}
391
392bool ci_rotate(arg_t degree)
393{
394 img_rotate(&img, degree);
395 return true;
396}
397
398bool ci_flip(arg_t dir)
399{
400 img_flip(&img, dir);
401 return true;
402}
403
404bool ci_toggle_antialias(arg_t _)
405{
406 img_toggle_antialias(&img);
407 return true;
408}
409
410bool ci_toggle_alpha(arg_t _)
411{
412 img.alpha = !img.alpha;
413 img.dirty = true;
414 return true;
415}
416
417bool ci_slideshow(arg_t _)
418{
419 if (prefix > 0) {
420 img.ss.on = true;
421 img.ss.delay = prefix * 10;
422 set_timeout(slideshow, img.ss.delay * 100, true);
423 } else if (img.ss.on) {
424 img.ss.on = false;
425 reset_timeout(slideshow);
426 } else {
427 img.ss.on = true;
428 }
429 return true;
430}
431
432bool ct_move_sel(arg_t dir)
433{
434 bool dirty = tns_move_selection(&tns, dir, prefix);
435 if (dirty) {
436 close_info();
437 open_info();
438 }
439 return dirty;
440}
441
442bool ct_reload_all(arg_t _)
443{
444 tns_free(&tns);
445 tns_init(&tns, files, &filecnt, &fileidx, &win);
446 tns.dirty = true;
447 return true;
448}
449
450bool ct_scroll(arg_t dir)
451{
452 return tns_scroll(&tns, dir, false);
453}
454
455bool ct_drag_mark_image(arg_t _)
456{
457 int sel;
458
459 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
460 XEvent e;
461 bool on = !(files[sel].flags & FF_MARK);
462
463 while (true) {
464 if (sel >= 0 && mark_image(sel, on))
465 redraw();
466 XMaskEvent(win.env.dpy,
467 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
468 if (e.type == ButtonPress || e.type == ButtonRelease)
469 break;
470 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
471 sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y);
472 }
473 }
474
475 return false;
476}
477
478bool ct_select(arg_t _)
479{
480 int sel;
481 bool dirty = false;
482 static Time firstclick;
483
484 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
485 if (sel != fileidx) {
486 tns_highlight(&tns, fileidx, false);
487 tns_highlight(&tns, sel, true);
488 fileidx = sel;
489 firstclick = xbutton_ev->time;
490 dirty = true;
491 } else if (xbutton_ev->time - firstclick <= TO_DOUBLE_CLICK) {
492 mode = MODE_IMAGE;
493 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
494 load_image(fileidx);
495 dirty = true;
496 } else {
497 firstclick = xbutton_ev->time;
498 }
499 }
500
501 return dirty;
502}