Krolyxon
Commit ad95012

Branches

Refs →

nsxivcommands.c

498 lines · 9.3 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 return true;
88}
89
90bool cg_toggle_fullscreen(arg_t _)
91{
92 win_toggle_fullscreen(&win);
93 /* redraw after next ConfigureNotify event */
94 set_timeout(redraw, TO_REDRAW_RESIZE, false);
95 if (mode == MODE_IMAGE)
96 img.checkpan = img.dirty = true;
97 else
98 tns.dirty = true;
99 return false;
100}
101
102bool cg_toggle_bar(arg_t _)
103{
104 win_toggle_bar(&win);
105 if (mode == MODE_IMAGE) {
106 if (win.bar.h > 0)
107 open_info();
108 else
109 close_info();
110 img.checkpan = img.dirty = true;
111 } else {
112 tns.dirty = true;
113 }
114 return true;
115}
116
117bool cg_prefix_external(arg_t _)
118{
119 handle_key_handler(true);
120 return false;
121}
122
123bool cg_reload_image(arg_t _)
124{
125 if (mode == MODE_IMAGE) {
126 load_image(fileidx);
127 } else {
128 win_set_cursor(&win, CURSOR_WATCH);
129 if (!tns_load(&tns, fileidx, true, false)) {
130 remove_file(fileidx, false);
131 tns.dirty = true;
132 }
133 }
134 return true;
135}
136
137bool cg_remove_image(arg_t _)
138{
139 remove_file(fileidx, true);
140 if (mode == MODE_IMAGE)
141 load_image(fileidx);
142 else
143 tns.dirty = true;
144 return true;
145}
146
147bool cg_first(arg_t _)
148{
149 if (mode == MODE_IMAGE && fileidx != 0) {
150 load_image(0);
151 return true;
152 } else if (mode == MODE_THUMB && fileidx != 0) {
153 fileidx = 0;
154 tns.dirty = true;
155 return true;
156 } else {
157 return false;
158 }
159}
160
161bool cg_n_or_last(arg_t _)
162{
163 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
164
165 if (mode == MODE_IMAGE && fileidx != n) {
166 load_image(n);
167 return true;
168 } else if (mode == MODE_THUMB && fileidx != n) {
169 fileidx = n;
170 tns.dirty = true;
171 return true;
172 } else {
173 return false;
174 }
175}
176
177bool cg_scroll_screen(arg_t dir)
178{
179 if (mode == MODE_IMAGE)
180 return img_pan(&img, dir, -1);
181 else
182 return tns_scroll(&tns, dir, true);
183}
184
185bool cg_zoom(arg_t d)
186{
187 if (mode == MODE_THUMB)
188 return tns_zoom(&tns, d);
189 else
190 return img_zoom(&img, d);
191}
192
193bool cg_toggle_image_mark(arg_t _)
194{
195 return mark_image(fileidx, !(files[fileidx].flags & FF_MARK));
196}
197
198bool cg_reverse_marks(arg_t _)
199{
200 int i;
201
202 for (i = 0; i < filecnt; i++) {
203 files[i].flags ^= FF_MARK;
204 markcnt += files[i].flags & FF_MARK ? 1 : -1;
205 }
206 if (mode == MODE_THUMB)
207 tns.dirty = true;
208 return true;
209}
210
211bool cg_mark_range(arg_t _)
212{
213 int d = markidx < fileidx ? 1 : -1, end, i;
214 bool dirty = false, on = !!(files[markidx].flags & FF_MARK);
215
216 for (i = markidx + d, end = fileidx + d; i != end; i += d)
217 dirty |= mark_image(i, on);
218 return dirty;
219}
220
221bool cg_unmark_all(arg_t _)
222{
223 int i;
224
225 for (i = 0; i < filecnt; i++)
226 files[i].flags &= ~FF_MARK;
227 markcnt = 0;
228 if (mode == MODE_THUMB)
229 tns.dirty = true;
230 return true;
231}
232
233bool cg_navigate_marked(arg_t n)
234{
235 int d, i;
236 int new = fileidx;
237
238 if (prefix > 0)
239 n *= prefix;
240 d = n > 0 ? 1 : -1;
241 for (i = fileidx + d; n != 0 && i >= 0 && i < filecnt; i += d) {
242 if (files[i].flags & FF_MARK) {
243 n -= d;
244 new = i;
245 }
246 }
247 if (new != fileidx) {
248 if (mode == MODE_IMAGE) {
249 load_image(new);
250 } else {
251 fileidx = new;
252 tns.dirty = true;
253 }
254 return true;
255 } else {
256 return false;
257 }
258}
259
260bool cg_change_gamma(arg_t d)
261{
262 if (img_change_gamma(&img, d * (prefix > 0 ? prefix : 1))) {
263 if (mode == MODE_THUMB)
264 tns.dirty = true;
265 return true;
266 } else {
267 return false;
268 }
269}
270
271bool ci_navigate(arg_t n)
272{
273 if (prefix > 0)
274 n *= prefix;
275 n += fileidx;
276 if (n < 0)
277 n = 0;
278 if (n >= filecnt)
279 n = filecnt - 1;
280
281 if (n != fileidx) {
282 load_image(n);
283 return true;
284 } else {
285 return false;
286 }
287}
288
289bool ci_cursor_navigate(arg_t _)
290{
291 return ci_navigate(nav_button() - 1);
292}
293
294bool ci_alternate(arg_t _)
295{
296 load_image(alternate);
297 return true;
298}
299
300bool ci_navigate_frame(arg_t d)
301{
302 if (prefix > 0)
303 d *= prefix;
304 return !img.multi.animate && img_frame_navigate(&img, d);
305}
306
307bool ci_toggle_animation(arg_t _)
308{
309 bool dirty = false;
310
311 if (img.multi.cnt > 0) {
312 img.multi.animate = !img.multi.animate;
313 if (img.multi.animate) {
314 dirty = img_frame_animate(&img);
315 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
316 } else {
317 reset_timeout(animate);
318 }
319 }
320 return dirty;
321}
322
323bool ci_scroll(arg_t dir)
324{
325 return img_pan(&img, dir, prefix);
326}
327
328bool ci_scroll_to_center(arg_t _)
329{
330 return img_pan_center(&img);
331}
332
333bool ci_scroll_to_edge(arg_t dir)
334{
335 return img_pan_edge(&img, dir);
336}
337
338bool ci_drag(arg_t drag_mode)
339{
340 int x, y, ox, oy;
341 float px, py;
342 XEvent e;
343
344 if ((int)(img.w * img.zoom) <= win.w && (int)(img.h * img.zoom) <= win.h)
345 return false;
346
347 win_set_cursor(&win, drag_mode == DRAG_ABSOLUTE ? CURSOR_DRAG_ABSOLUTE : CURSOR_DRAG_RELATIVE);
348 win_cursor_pos(&win, &x, &y);
349 ox = x;
350 oy = y;
351
352 while (true) {
353 if (drag_mode == DRAG_ABSOLUTE) {
354 px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8)
355 * (win.w - img.w * img.zoom);
356 py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8)
357 * (win.h - img.h * img.zoom);
358 } else {
359 px = img.x + x - ox;
360 py = img.y + y - oy;
361 }
362
363 if (img_pos(&img, px, py)) {
364 img_render(&img);
365 win_draw(&win);
366 }
367 XMaskEvent(win.env.dpy,
368 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
369 if (e.type == ButtonPress || e.type == ButtonRelease)
370 break;
371 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
372 ox = x;
373 oy = y;
374 x = e.xmotion.x;
375 y = e.xmotion.y;
376 }
377 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
378 reset_cursor();
379
380 return true;
381}
382
383bool ci_set_zoom(arg_t zl)
384{
385 return img_zoom_to(&img, (prefix ? prefix : zl) / 100.0);
386}
387
388bool ci_fit_to_win(arg_t sm)
389{
390 return img_fit_win(&img, sm);
391}
392
393bool ci_rotate(arg_t degree)
394{
395 img_rotate(&img, degree);
396 return true;
397}
398
399bool ci_flip(arg_t dir)
400{
401 img_flip(&img, dir);
402 return true;
403}
404
405bool ci_toggle_antialias(arg_t _)
406{
407 img_toggle_antialias(&img);
408 return true;
409}
410
411bool ci_toggle_alpha(arg_t _)
412{
413 img.alpha = !img.alpha;
414 img.dirty = true;
415 return true;
416}
417
418bool ci_slideshow(arg_t _)
419{
420 if (prefix > 0) {
421 img.ss.on = true;
422 img.ss.delay = prefix * 10;
423 set_timeout(slideshow, img.ss.delay * 100, true);
424 } else if (img.ss.on) {
425 img.ss.on = false;
426 reset_timeout(slideshow);
427 } else {
428 img.ss.on = true;
429 }
430 return true;
431}
432
433bool ct_move_sel(arg_t dir)
434{
435 return tns_move_selection(&tns, dir, prefix);
436}
437
438bool ct_reload_all(arg_t _)
439{
440 tns_free(&tns);
441 tns_init(&tns, files, &filecnt, &fileidx, &win);
442 tns.dirty = true;
443 return true;
444}
445
446bool ct_scroll(arg_t dir)
447{
448 return tns_scroll(&tns, dir, false);
449}
450
451bool ct_drag_mark_image(arg_t _)
452{
453 int sel;
454
455 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
456 XEvent e;
457 bool on = !(files[sel].flags & FF_MARK);
458
459 while (true) {
460 if (sel >= 0 && mark_image(sel, on))
461 redraw();
462 XMaskEvent(win.env.dpy,
463 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
464 if (e.type == ButtonPress || e.type == ButtonRelease)
465 break;
466 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
467 sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y);
468 }
469 }
470
471 return false;
472}
473
474bool ct_select(arg_t _)
475{
476 int sel;
477 bool dirty = false;
478 static Time firstclick;
479
480 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
481 if (sel != fileidx) {
482 tns_highlight(&tns, fileidx, false);
483 tns_highlight(&tns, sel, true);
484 fileidx = sel;
485 firstclick = xbutton_ev->time;
486 dirty = true;
487 } else if (xbutton_ev->time - firstclick <= TO_DOUBLE_CLICK) {
488 mode = MODE_IMAGE;
489 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
490 load_image(fileidx);
491 dirty = true;
492 } else {
493 firstclick = xbutton_ev->time;
494 }
495 }
496
497 return dirty;
498}