Krolyxon
Commit 7a75c42

Branches

Refs →

nsxivcommands.c

493 lines · 9.2 KB · C

1/* Copyright 2011-2020 Bert Muennich
2 * Copyright 2021 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_edge(arg_t dir)
329{
330 return img_pan_edge(&img, dir);
331}
332
333bool ci_drag(arg_t drag_mode)
334{
335 int x, y, ox, oy;
336 float px, py;
337 XEvent e;
338
339 if ((int)(img.w * img.zoom) <= win.w && (int)(img.h * img.zoom) <= win.h)
340 return false;
341
342 win_set_cursor(&win, drag_mode == DRAG_ABSOLUTE ? CURSOR_DRAG_ABSOLUTE : CURSOR_DRAG_RELATIVE);
343 win_cursor_pos(&win, &x, &y);
344 ox = x;
345 oy = y;
346
347 while (true) {
348 if (drag_mode == DRAG_ABSOLUTE) {
349 px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8)
350 * (win.w - img.w * img.zoom);
351 py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8)
352 * (win.h - img.h * img.zoom);
353 } else {
354 px = img.x + x - ox;
355 py = img.y + y - oy;
356 }
357
358 if (img_pos(&img, px, py)) {
359 img_render(&img);
360 win_draw(&win);
361 }
362 XMaskEvent(win.env.dpy,
363 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
364 if (e.type == ButtonPress || e.type == ButtonRelease)
365 break;
366 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
367 ox = x;
368 oy = y;
369 x = e.xmotion.x;
370 y = e.xmotion.y;
371 }
372 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
373 reset_cursor();
374
375 return true;
376}
377
378bool ci_set_zoom(arg_t zl)
379{
380 return img_zoom_to(&img, (prefix ? prefix : zl) / 100.0);
381}
382
383bool ci_fit_to_win(arg_t sm)
384{
385 return img_fit_win(&img, sm);
386}
387
388bool ci_rotate(arg_t degree)
389{
390 img_rotate(&img, degree);
391 return true;
392}
393
394bool ci_flip(arg_t dir)
395{
396 img_flip(&img, dir);
397 return true;
398}
399
400bool ci_toggle_antialias(arg_t _)
401{
402 img_toggle_antialias(&img);
403 return true;
404}
405
406bool ci_toggle_alpha(arg_t _)
407{
408 img.alpha = !img.alpha;
409 img.dirty = true;
410 return true;
411}
412
413bool ci_slideshow(arg_t _)
414{
415 if (prefix > 0) {
416 img.ss.on = true;
417 img.ss.delay = prefix * 10;
418 set_timeout(slideshow, img.ss.delay * 100, true);
419 } else if (img.ss.on) {
420 img.ss.on = false;
421 reset_timeout(slideshow);
422 } else {
423 img.ss.on = true;
424 }
425 return true;
426}
427
428bool ct_move_sel(arg_t dir)
429{
430 return tns_move_selection(&tns, dir, prefix);
431}
432
433bool ct_reload_all(arg_t _)
434{
435 tns_free(&tns);
436 tns_init(&tns, files, &filecnt, &fileidx, &win);
437 tns.dirty = true;
438 return true;
439}
440
441bool ct_scroll(arg_t dir)
442{
443 return tns_scroll(&tns, dir, false);
444}
445
446bool ct_drag_mark_image(arg_t _)
447{
448 int sel;
449
450 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
451 XEvent e;
452 bool on = !(files[sel].flags & FF_MARK);
453
454 while (true) {
455 if (sel >= 0 && mark_image(sel, on))
456 redraw();
457 XMaskEvent(win.env.dpy,
458 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
459 if (e.type == ButtonPress || e.type == ButtonRelease)
460 break;
461 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
462 sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y);
463 }
464 }
465
466 return false;
467}
468
469bool ct_select(arg_t _)
470{
471 int sel;
472 bool dirty = false;
473 static Time firstclick;
474
475 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
476 if (sel != fileidx) {
477 tns_highlight(&tns, fileidx, false);
478 tns_highlight(&tns, sel, true);
479 fileidx = sel;
480 firstclick = xbutton_ev->time;
481 dirty = true;
482 } else if (xbutton_ev->time - firstclick <= TO_DOUBLE_CLICK) {
483 mode = MODE_IMAGE;
484 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
485 load_image(fileidx);
486 dirty = true;
487 } else {
488 firstclick = xbutton_ev->time;
489 }
490 }
491
492 return dirty;
493}