Krolyxon
Commit 6922d5d

Branches

Refs →

nsxivcommands.c

495 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 n = MAX(0, MIN(n, filecnt - 1));
277
278 if (n != fileidx) {
279 load_image(n);
280 return true;
281 } else {
282 return false;
283 }
284}
285
286bool ci_cursor_navigate(arg_t _)
287{
288 return ci_navigate(nav_button() - 1);
289}
290
291bool ci_alternate(arg_t _)
292{
293 load_image(alternate);
294 return true;
295}
296
297bool ci_navigate_frame(arg_t d)
298{
299 if (prefix > 0)
300 d *= prefix;
301 return !img.multi.animate && img_frame_navigate(&img, d);
302}
303
304bool ci_toggle_animation(arg_t _)
305{
306 bool dirty = false;
307
308 if (img.multi.cnt > 0) {
309 img.multi.animate = !img.multi.animate;
310 if (img.multi.animate) {
311 dirty = img_frame_animate(&img);
312 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
313 } else {
314 reset_timeout(animate);
315 }
316 }
317 return dirty;
318}
319
320bool ci_scroll(arg_t dir)
321{
322 return img_pan(&img, dir, prefix);
323}
324
325bool ci_scroll_to_center(arg_t _)
326{
327 return img_pan_center(&img);
328}
329
330bool ci_scroll_to_edge(arg_t dir)
331{
332 return img_pan_edge(&img, dir);
333}
334
335bool ci_drag(arg_t drag_mode)
336{
337 int x, y, ox, oy;
338 float px, py;
339 XEvent e;
340
341 if ((int)(img.w * img.zoom) <= win.w && (int)(img.h * img.zoom) <= win.h)
342 return false;
343
344 win_set_cursor(&win, drag_mode == DRAG_ABSOLUTE ? CURSOR_DRAG_ABSOLUTE : CURSOR_DRAG_RELATIVE);
345 win_cursor_pos(&win, &x, &y);
346 ox = x;
347 oy = y;
348
349 while (true) {
350 if (drag_mode == DRAG_ABSOLUTE) {
351 px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8)
352 * (win.w - img.w * img.zoom);
353 py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8)
354 * (win.h - img.h * img.zoom);
355 } else {
356 px = img.x + x - ox;
357 py = img.y + y - oy;
358 }
359
360 if (img_pos(&img, px, py)) {
361 img_render(&img);
362 win_draw(&win);
363 }
364 XMaskEvent(win.env.dpy,
365 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
366 if (e.type == ButtonPress || e.type == ButtonRelease)
367 break;
368 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
369 ox = x;
370 oy = y;
371 x = e.xmotion.x;
372 y = e.xmotion.y;
373 }
374 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
375 reset_cursor();
376
377 return true;
378}
379
380bool ci_set_zoom(arg_t zl)
381{
382 return img_zoom_to(&img, (prefix ? prefix : zl) / 100.0);
383}
384
385bool ci_fit_to_win(arg_t sm)
386{
387 return img_fit_win(&img, sm);
388}
389
390bool ci_rotate(arg_t degree)
391{
392 img_rotate(&img, degree);
393 return true;
394}
395
396bool ci_flip(arg_t dir)
397{
398 img_flip(&img, dir);
399 return true;
400}
401
402bool ci_toggle_antialias(arg_t _)
403{
404 img_toggle_antialias(&img);
405 return true;
406}
407
408bool ci_toggle_alpha(arg_t _)
409{
410 img.alpha = !img.alpha;
411 img.dirty = true;
412 return true;
413}
414
415bool ci_slideshow(arg_t _)
416{
417 if (prefix > 0) {
418 img.ss.on = true;
419 img.ss.delay = prefix * 10;
420 set_timeout(slideshow, img.ss.delay * 100, true);
421 } else if (img.ss.on) {
422 img.ss.on = false;
423 reset_timeout(slideshow);
424 } else {
425 img.ss.on = true;
426 }
427 return true;
428}
429
430bool ct_move_sel(arg_t dir)
431{
432 return tns_move_selection(&tns, dir, prefix);
433}
434
435bool ct_reload_all(arg_t _)
436{
437 tns_free(&tns);
438 tns_init(&tns, files, &filecnt, &fileidx, &win);
439 tns.dirty = true;
440 return true;
441}
442
443bool ct_scroll(arg_t dir)
444{
445 return tns_scroll(&tns, dir, false);
446}
447
448bool ct_drag_mark_image(arg_t _)
449{
450 int sel;
451
452 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
453 XEvent e;
454 bool on = !(files[sel].flags & FF_MARK);
455
456 while (true) {
457 if (sel >= 0 && mark_image(sel, on))
458 redraw();
459 XMaskEvent(win.env.dpy,
460 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
461 if (e.type == ButtonPress || e.type == ButtonRelease)
462 break;
463 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
464 sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y);
465 }
466 }
467
468 return false;
469}
470
471bool ct_select(arg_t _)
472{
473 int sel;
474 bool dirty = false;
475 static Time firstclick;
476
477 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
478 if (sel != fileidx) {
479 tns_highlight(&tns, fileidx, false);
480 tns_highlight(&tns, sel, true);
481 fileidx = sel;
482 firstclick = xbutton_ev->time;
483 dirty = true;
484 } else if (xbutton_ev->time - firstclick <= TO_DOUBLE_CLICK) {
485 mode = MODE_IMAGE;
486 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
487 load_image(fileidx);
488 dirty = true;
489 } else {
490 firstclick = xbutton_ev->time;
491 }
492 }
493
494 return dirty;
495}