Krolyxon
Commit b42e3ef

Branches

Refs →

nsxivcommands.c

437 lines · 8.0 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;
45
46extern fileinfo_t *files;
47extern int filecnt, fileidx;
48extern int alternate;
49extern int markcnt;
50extern int markidx;
51
52extern int prefix;
53extern bool extprefix;
54
55bool cg_quit(arg_t status)
56{
57 unsigned int i;
58
59 if (options->to_stdout && markcnt > 0) {
60 for (i = 0; i < filecnt; i++) {
61 if (files[i].flags & FF_MARK)
62 printf("%s%c", files[i].name, options->using_null ? '\0' : '\n');
63 }
64 }
65 exit(status);
66}
67
68bool cg_switch_mode(arg_t _)
69{
70 if (mode == MODE_IMAGE) {
71 if (tns.thumbs == NULL)
72 tns_init(&tns, files, &filecnt, &fileidx, &win);
73 img_close(&img, false);
74 reset_timeout(reset_cursor);
75 if (img.ss.on) {
76 img.ss.on = false;
77 reset_timeout(slideshow);
78 }
79 tns.dirty = true;
80 mode = MODE_THUMB;
81 } else {
82 load_image(fileidx);
83 mode = MODE_IMAGE;
84 }
85 return true;
86}
87
88bool cg_toggle_fullscreen(arg_t _)
89{
90 win_toggle_fullscreen(&win);
91 /* redraw after next ConfigureNotify event */
92 set_timeout(redraw, TO_REDRAW_RESIZE, false);
93 if (mode == MODE_IMAGE)
94 img.checkpan = img.dirty = true;
95 else
96 tns.dirty = true;
97 return false;
98}
99
100bool cg_toggle_bar(arg_t _)
101{
102 win_toggle_bar(&win);
103 if (mode == MODE_IMAGE) {
104 if (win.bar.h > 0)
105 open_info();
106 else
107 close_info();
108 img.checkpan = img.dirty = true;
109 } else {
110 tns.dirty = true;
111 }
112 return true;
113}
114
115bool cg_prefix_external(arg_t _)
116{
117 handle_key_handler(true);
118 return false;
119}
120
121bool cg_reload_image(arg_t _)
122{
123 if (mode == MODE_IMAGE) {
124 load_image(fileidx);
125 } else {
126 win_set_cursor(&win, CURSOR_WATCH);
127 if (!tns_load(&tns, fileidx, true, false)) {
128 remove_file(fileidx, false);
129 tns.dirty = true;
130 }
131 }
132 return true;
133}
134
135bool cg_remove_image(arg_t _)
136{
137 remove_file(fileidx, true);
138 if (mode == MODE_IMAGE)
139 load_image(fileidx);
140 else
141 tns.dirty = true;
142 return true;
143}
144
145bool cg_first(arg_t _)
146{
147 if (mode == MODE_IMAGE && fileidx != 0) {
148 load_image(0);
149 return true;
150 } else if (mode == MODE_THUMB && fileidx != 0) {
151 fileidx = 0;
152 tns.dirty = true;
153 return true;
154 } else {
155 return false;
156 }
157}
158
159bool cg_n_or_last(arg_t _)
160{
161 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
162
163 if (mode == MODE_IMAGE && fileidx != n) {
164 load_image(n);
165 return true;
166 } else if (mode == MODE_THUMB && fileidx != n) {
167 fileidx = n;
168 tns.dirty = true;
169 return true;
170 } else {
171 return false;
172 }
173}
174
175bool cg_scroll_screen(arg_t dir)
176{
177 if (mode == MODE_IMAGE)
178 return img_pan(&img, dir, -1);
179 else
180 return tns_scroll(&tns, dir, true);
181}
182
183bool cg_zoom(arg_t d)
184{
185 if (mode == MODE_THUMB)
186 return tns_zoom(&tns, d);
187 else
188 return img_zoom(&img, d);
189}
190
191bool cg_toggle_image_mark(arg_t _)
192{
193 return mark_image(fileidx, !(files[fileidx].flags & FF_MARK));
194}
195
196bool cg_reverse_marks(arg_t _)
197{
198 int i;
199
200 for (i = 0; i < filecnt; i++) {
201 files[i].flags ^= FF_MARK;
202 markcnt += files[i].flags & FF_MARK ? 1 : -1;
203 }
204 if (mode == MODE_THUMB)
205 tns.dirty = true;
206 return true;
207}
208
209bool cg_mark_range(arg_t _)
210{
211 int d = markidx < fileidx ? 1 : -1, end, i;
212 bool dirty = false, on = !!(files[markidx].flags & FF_MARK);
213
214 for (i = markidx + d, end = fileidx + d; i != end; i += d)
215 dirty |= mark_image(i, on);
216 return dirty;
217}
218
219bool cg_unmark_all(arg_t _)
220{
221 int i;
222
223 for (i = 0; i < filecnt; i++)
224 files[i].flags &= ~FF_MARK;
225 markcnt = 0;
226 if (mode == MODE_THUMB)
227 tns.dirty = true;
228 return true;
229}
230
231bool cg_navigate_marked(arg_t n)
232{
233 int d, i;
234 int new = fileidx;
235
236 if (prefix > 0)
237 n *= prefix;
238 d = n > 0 ? 1 : -1;
239 for (i = fileidx + d; n != 0 && i >= 0 && i < filecnt; i += d) {
240 if (files[i].flags & FF_MARK) {
241 n -= d;
242 new = i;
243 }
244 }
245 if (new != fileidx) {
246 if (mode == MODE_IMAGE) {
247 load_image(new);
248 } else {
249 fileidx = new;
250 tns.dirty = true;
251 }
252 return true;
253 } else {
254 return false;
255 }
256}
257
258bool cg_change_gamma(arg_t d)
259{
260 if (img_change_gamma(&img, d * (prefix > 0 ? prefix : 1))) {
261 if (mode == MODE_THUMB)
262 tns.dirty = true;
263 return true;
264 } else {
265 return false;
266 }
267}
268
269bool ci_navigate(arg_t n)
270{
271 if (prefix > 0)
272 n *= prefix;
273 n += fileidx;
274 if (n < 0)
275 n = 0;
276 if (n >= filecnt)
277 n = filecnt - 1;
278
279 if (n != fileidx) {
280 load_image(n);
281 return true;
282 } else {
283 return false;
284 }
285}
286
287bool ci_cursor_navigate(arg_t _)
288{
289 return ci_navigate(nav_button() - 1);
290}
291
292bool ci_alternate(arg_t _)
293{
294 load_image(alternate);
295 return true;
296}
297
298bool ci_navigate_frame(arg_t d)
299{
300 if (prefix > 0)
301 d *= prefix;
302 return !img.multi.animate && img_frame_navigate(&img, d);
303}
304
305bool ci_toggle_animation(arg_t _)
306{
307 bool dirty = false;
308
309 if (img.multi.cnt > 0) {
310 img.multi.animate = !img.multi.animate;
311 if (img.multi.animate) {
312 dirty = img_frame_animate(&img);
313 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
314 } else {
315 reset_timeout(animate);
316 }
317 }
318 return dirty;
319}
320
321bool ci_scroll(arg_t dir)
322{
323 return img_pan(&img, dir, prefix);
324}
325
326bool ci_scroll_to_edge(arg_t dir)
327{
328 return img_pan_edge(&img, dir);
329}
330
331bool ci_drag(arg_t drag_mode)
332{
333 int x, y, ox, oy;
334 float px, py;
335 XEvent e;
336
337 if ((int)(img.w * img.zoom) <= win.w && (int)(img.h * img.zoom) <= win.h)
338 return false;
339
340 win_set_cursor(&win, drag_mode == DRAG_ABSOLUTE ? CURSOR_DRAG_ABSOLUTE : CURSOR_DRAG_RELATIVE);
341 win_cursor_pos(&win, &x, &y);
342 ox = x;
343 oy = y;
344
345 while (true) {
346 if (drag_mode == DRAG_ABSOLUTE) {
347 px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8)
348 * (win.w - img.w * img.zoom);
349 py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8)
350 * (win.h - img.h * img.zoom);
351 } else {
352 px = img.x + x - ox;
353 py = img.y + y - oy;
354 }
355
356 if (img_pos(&img, px, py)) {
357 img_render(&img);
358 win_draw(&win);
359 }
360 XMaskEvent(win.env.dpy,
361 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
362 if (e.type == ButtonPress || e.type == ButtonRelease)
363 break;
364 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
365 ox = x;
366 oy = y;
367 x = e.xmotion.x;
368 y = e.xmotion.y;
369 }
370 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
371 reset_cursor();
372
373 return true;
374}
375
376bool ci_set_zoom(arg_t zl)
377{
378 return img_zoom_to(&img, (prefix ? prefix : zl) / 100.0);
379}
380
381bool ci_fit_to_win(arg_t sm)
382{
383 return img_fit_win(&img, sm);
384}
385
386bool ci_rotate(arg_t degree)
387{
388 img_rotate(&img, degree);
389 return true;
390}
391
392bool ci_flip(arg_t dir)
393{
394 img_flip(&img, dir);
395 return true;
396}
397
398bool ci_toggle_antialias(arg_t _)
399{
400 img_toggle_antialias(&img);
401 return true;
402}
403
404bool ci_toggle_alpha(arg_t _)
405{
406 img.alpha = !img.alpha;
407 img.dirty = true;
408 return true;
409}
410
411bool ci_slideshow(arg_t _)
412{
413 if (prefix > 0) {
414 img.ss.on = true;
415 img.ss.delay = prefix * 10;
416 set_timeout(slideshow, img.ss.delay * 100, true);
417 } else if (img.ss.on) {
418 img.ss.on = false;
419 reset_timeout(slideshow);
420 } else {
421 img.ss.on = true;
422 }
423 return true;
424}
425
426bool ct_move_sel(arg_t dir)
427{
428 return tns_move_selection(&tns, dir, prefix);
429}
430
431bool ct_reload_all(arg_t _)
432{
433 tns_free(&tns);
434 tns_init(&tns, files, &filecnt, &fileidx, &win);
435 tns.dirty = true;
436 return true;
437}