1 /* keyevents.c
2
3 Copyright (C) 1999-2003 Tom Gilbert.
4 Copyright (C) 2010-2020 Daniel Friesel.
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to
8 deal in the Software without restriction, including without limitation the
9 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 sell copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies of the Software and its documentation and acknowledgment shall be
15 given in the documentation and software packages that this Software was
16 used.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 */
26
27 #include "feh.h"
28 #include "thumbnail.h"
29 #include "filelist.h"
30 #include "winwidget.h"
31 #include "options.h"
32 #include <termios.h>
33
34 struct __fehkey keys[EVENT_LIST_END];
35 struct termios old_term_settings;
36 unsigned char control_via_stdin = 0;
37
setup_stdin()38 void setup_stdin() {
39 struct termios ctrl;
40
41 control_via_stdin = 1;
42
43 if (tcgetattr(STDIN_FILENO, &old_term_settings) == -1)
44 eprintf("tcgetattr failed");
45 if (tcgetattr(STDIN_FILENO, &ctrl) == -1)
46 eprintf("tcgetattr failed");
47
48 ctrl.c_iflag &= ~(PARMRK | ISTRIP
49 | INLCR | IGNCR | IXON);
50 ctrl.c_lflag &= ~(ECHO | ICANON | IEXTEN);
51 ctrl.c_cflag &= ~(CSIZE | PARENB);
52 ctrl.c_cflag |= CS8;
53
54 if (tcsetattr(STDIN_FILENO, TCSANOW, &ctrl) == -1)
55 eprintf("tcsetattr failed");
56 }
57
restore_stdin()58 void restore_stdin() {
59 if (tcsetattr(STDIN_FILENO, TCSANOW, &old_term_settings) == -1)
60 eprintf("tcsetattr failed");
61 }
62
feh_set_kb(char * name,unsigned int s0,unsigned int y0,unsigned int s1,unsigned int y1,unsigned int s2,unsigned int y2)63 static void feh_set_kb(char *name, unsigned int s0, unsigned int y0,
64 unsigned int s1, unsigned int y1, unsigned int s2, unsigned int y2) {
65 static int key_index = 0;
66 fehkey *key = &keys[key_index];
67 key->keystates[0] = s0;
68 key->keystates[1] = s1;
69 key->keystates[2] = s2;
70 key->keysyms[0] = y0;
71 key->keysyms[1] = y1;
72 key->keysyms[2] = y2;
73 key->state = 0;
74 key->button = 0;
75 key->name = name;
76 key_index++;
77 }
78
ignore_space(int keysym)79 static inline int ignore_space(int keysym) {
80 /*
81 * Passing values which do not fit inside a signed 8bit char to isprint,
82 * isspace and the likes is undefined behaviour... which glibc (for some
83 * values) implements as a segmentation fault. So let's not do that.
84 */
85 return ((keysym <= 127) && (keysym >= -128) && isprint(keysym) && !isspace(keysym));
86 }
87
feh_set_parse_kb_partial(fehkey * key,int index,char * ks)88 static void feh_set_parse_kb_partial(fehkey *key, int index, char *ks) {
89 char *cur = ks;
90 int mod = 0;
91
92 if (!*ks) {
93 key->keysyms[index] = 0;
94 return;
95 }
96
97 while (cur[1] == '-') {
98 switch (cur[0]) {
99 case 'C':
100 mod |= ControlMask;
101 break;
102 case 'S':
103 mod |= ShiftMask;
104 break;
105 case '1':
106 mod |= Mod1Mask;
107 break;
108 case '4':
109 mod |= Mod4Mask;
110 break;
111 default:
112 weprintf("keys: invalid modifier %c in \"%s\"", cur[0], ks);
113 break;
114 }
115 cur += 2;
116 }
117
118 key->keysyms[index] = XStringToKeysym(cur);
119 if (ignore_space(key->keysyms[index]))
120 mod &= ~ShiftMask;
121 key->keystates[index] = mod;
122
123 if (key->keysyms[index] == NoSymbol)
124 weprintf("keys: Invalid keysym: %s", cur);
125 }
126
init_keyevents(void)127 void init_keyevents(void) {
128 char *home = NULL;
129 char *confhome = NULL;
130 char *confpath = NULL;
131 char line[128];
132 char action[32], k1[32], k2[32], k3[32];
133 fehkey *cur_kb = NULL;
134 FILE *conf = NULL;
135 int read = 0;
136
137 /*
138 * The feh_set_kb statements must have the same order as the key_action
139 * enum.
140 */
141
142 feh_set_kb("menu_close" , 0, XK_Escape , 0, 0 , 0, 0);
143 feh_set_kb("menu_parent", 0, XK_Left , 0, 0 , 0, 0);
144 feh_set_kb("menu_down", 0, XK_Down , 0, 0 , 0, 0);
145 feh_set_kb("menu_up", 0, XK_Up , 0, 0 , 0, 0);
146 feh_set_kb("menu_child", 0, XK_Right , 0, 0 , 0, 0);
147 feh_set_kb("menu_select", 0, XK_Return , 0, XK_space , 0, 0);
148 feh_set_kb("scroll_left",0, XK_KP_Left , 4, XK_Left , 0, 0);
149 feh_set_kb("scroll_right", 0,XK_KP_Right , 4, XK_Right , 0, 0);
150 feh_set_kb("scroll_down",0, XK_KP_Down , 4, XK_Down , 0, 0);
151 feh_set_kb("scroll_up", 0, XK_KP_Up , 4, XK_Up , 0, 0);
152 feh_set_kb("scroll_left_page" , 8, XK_Left , 0, 0 , 0, 0);
153 feh_set_kb("scroll_right_page", 8, XK_Right, 0, 0 , 0, 0);
154 feh_set_kb("scroll_down_page" , 8, XK_Down , 0, 0 , 0, 0);
155 feh_set_kb("scroll_up_page" , 8, XK_Up , 0, 0 , 0, 0);
156 feh_set_kb("prev_img" , 0, XK_Left , 0, XK_p , 0, XK_BackSpace);
157 feh_set_kb("next_img" , 0, XK_Right , 0, XK_n , 0, XK_space);
158 feh_set_kb("jump_back" , 0, XK_Page_Up , 0, XK_KP_Page_Up, 0, 0);
159 feh_set_kb("jump_fwd" , 0, XK_Page_Down , 0, XK_KP_Page_Down,0,0);
160 feh_set_kb("prev_dir" , 0, XK_bracketleft, 0, 0 , 0, 0);
161 feh_set_kb("next_dir" , 0, XK_bracketright, 0, 0 , 0, 0);
162 feh_set_kb("jump_random" ,0, XK_z , 0, 0 , 0, 0);
163 feh_set_kb("quit" , 0, XK_Escape , 0, XK_q , 0, 0);
164 feh_set_kb("close" , 0, XK_x , 0, 0 , 0, 0);
165 feh_set_kb("remove" , 0, XK_Delete , 0, 0 , 0, 0);
166 feh_set_kb("delete" , 4, XK_Delete , 0, 0 , 0, 0);
167 feh_set_kb("jump_first" , 0, XK_Home , 0, XK_KP_Home , 0, 0);
168 feh_set_kb("jump_last" , 0, XK_End , 0, XK_KP_End , 0, 0);
169 feh_set_kb("action_0" , 0, XK_Return , 0, XK_0 , 0, XK_KP_0);
170 feh_set_kb("action_1" , 0, XK_1 , 0, XK_KP_1 , 0, 0);
171 feh_set_kb("action_2" , 0, XK_2 , 0, XK_KP_2 , 0, 0);
172 feh_set_kb("action_3" , 0, XK_3 , 0, XK_KP_3 , 0, 0);
173 feh_set_kb("action_4" , 0, XK_4 , 0, XK_KP_4 , 0, 0);
174 feh_set_kb("action_5" , 0, XK_5 , 0, XK_KP_5 , 0, 0);
175 feh_set_kb("action_6" , 0, XK_6 , 0, XK_KP_6 , 0, 0);
176 feh_set_kb("action_7" , 0, XK_7 , 0, XK_KP_7 , 0, 0);
177 feh_set_kb("action_8" , 0, XK_8 , 0, XK_KP_8 , 0, 0);
178 feh_set_kb("action_9" , 0, XK_9 , 0, XK_KP_9 , 0, 0);
179 feh_set_kb("zoom_in" , 0, XK_Up , 0, XK_KP_Add , 0, 0);
180 feh_set_kb("zoom_out" , 0, XK_Down , 0, XK_KP_Subtract,0, 0);
181 feh_set_kb("zoom_default" , 0, XK_KP_Multiply, 0, XK_asterisk,0, 0);
182 feh_set_kb("zoom_fit" , 0, XK_KP_Divide , 0, XK_slash , 0, 0);
183 feh_set_kb("zoom_fill" , 0, XK_exclam , 0, 0 , 0, 0);
184 feh_set_kb("size_to_image" , 0, XK_w , 0, 0 , 0, 0);
185 feh_set_kb("render" , 0, XK_KP_Begin , 0, XK_R , 0, 0);
186 feh_set_kb("toggle_actions" , 0, XK_a, 0, 0, 0, 0);
187 feh_set_kb("toggle_aliasing" , 0, XK_A, 0, 0, 0, 0);
188 feh_set_kb("toggle_auto_zoom" , 0, XK_Z, 0, 0, 0, 0);
189 #ifdef HAVE_LIBEXIF
190 feh_set_kb("toggle_exif" , 0, XK_e, 0, 0, 0, 0);
191 #endif
192 feh_set_kb("toggle_filenames" , 0, XK_d, 0, 0, 0, 0);
193 feh_set_kb("toggle_info" , 0, XK_i, 0, 0, 0, 0);
194 feh_set_kb("toggle_pointer" , 0, XK_o, 0, 0, 0, 0);
195 feh_set_kb("toggle_caption" , 0, XK_c, 0, 0, 0, 0);
196 feh_set_kb("toggle_pause" , 0, XK_h, 0, 0, 0, 0);
197 feh_set_kb("toggle_menu" , 0, XK_m, 0, 0, 0, 0);
198 feh_set_kb("toggle_fullscreen" , 0, XK_f, 0, 0, 0, 0);
199 feh_set_kb("reload_image" , 0, XK_r, 0, 0, 0, 0);
200 feh_set_kb("save_image" , 0, XK_s, 0, 0, 0, 0);
201 feh_set_kb("save_filelist" , 0, XK_L, 0, 0, 0, 0);
202 feh_set_kb("orient_1" , 0, XK_greater, 0, 0, 0, 0);
203 feh_set_kb("orient_3" , 0, XK_less, 0, 0, 0, 0);
204 feh_set_kb("flip" , 0, XK_underscore, 0, 0, 0, 0);
205 feh_set_kb("mirror" , 0, XK_bar, 0, 0, 0, 0);
206 feh_set_kb("reload_minus" , 0, XK_minus, 0, 0, 0, 0);
207 feh_set_kb("reload_plus" , 0, XK_plus, 0, 0, 0, 0);
208 feh_set_kb("toggle_keep_vp" , 0, XK_k, 0, 0, 0, 0);
209 feh_set_kb("toggle_fixed_geometry" , 0, XK_g, 0, 0, 0, 0);
210 feh_set_kb("pan" , 0, 0, 0, 0, 0, 0);
211 feh_set_kb("zoom" , 0, 0, 0, 0, 0, 0);
212 feh_set_kb("blur" , 0, 0, 0, 0, 0, 0);
213 feh_set_kb("rotate" , 0, 0, 0, 0, 0, 0);
214
215 home = getenv("HOME");
216 confhome = getenv("XDG_CONFIG_HOME");
217
218 if (confhome)
219 confpath = estrjoin("/", confhome, "feh/keys", NULL);
220 else if (home)
221 confpath = estrjoin("/", home, ".config/feh/keys", NULL);
222 else
223 return;
224
225 conf = fopen(confpath, "r");
226
227 free(confpath);
228
229 if (!conf && ((conf = fopen("/etc/feh/keys", "r")) == NULL))
230 return;
231
232 while (fgets(line, sizeof(line), conf)) {
233 *action = '\0';
234 *k1 = '\0';
235 *k2 = '\0';
236 *k3 = '\0';
237 cur_kb = NULL;
238
239 read = sscanf(line, "%31s %31s %31s %31s\n",
240 (char *) &action, (char *) &k1, (char* ) &k2, (char *) &k3);
241
242 if ((read == EOF) || (read == 0) || (line[0] == '#'))
243 continue;
244
245 cur_kb = feh_str_to_kb(action);
246
247 if (cur_kb) {
248 feh_set_parse_kb_partial(cur_kb, 0, k1);
249 feh_set_parse_kb_partial(cur_kb, 1, k2);
250 feh_set_parse_kb_partial(cur_kb, 2, k3);
251 } else {
252 weprintf("keys: Invalid action: %s", action);
253 }
254 }
255 fclose(conf);
256 }
257
feh_is_kp(unsigned int key_index,unsigned int state,unsigned int sym,unsigned int button)258 static short feh_is_kp(unsigned int key_index, unsigned int state,
259 unsigned int sym, unsigned int button) {
260 int i;
261
262 if (sym != NoSymbol) {
263 for (i = 0; i < 3; i++) {
264 if (
265 (keys[key_index].keysyms[i] == sym) &&
266 (keys[key_index].keystates[i] == state))
267 return 1;
268 else if (keys[key_index].keysyms[i] == 0)
269 return 0;
270 }
271 return 0;
272 }
273 if ((keys[key_index].state == state)
274 && (keys[key_index].button == button)) {
275 return 1;
276 }
277 return 0;
278 }
279
feh_event_invoke_action(winwidget winwid,unsigned char action)280 void feh_event_invoke_action(winwidget winwid, unsigned char action)
281 {
282 struct stat st;
283 if (opt.actions[action]) {
284 if (opt.slideshow) {
285 feh_action_run(FEH_FILE(winwid->file->data), opt.actions[action], winwid);
286
287 if (opt.hold_actions[action])
288 feh_reload_image(winwid, 1, 1);
289 else if (stat(FEH_FILE(winwid->file->data)->filename, &st) == -1)
290 feh_filelist_image_remove(winwid, 0);
291 else
292 slideshow_change_image(winwid, SLIDE_NEXT, 1);
293
294 } else if ((winwid->type == WIN_TYPE_SINGLE)
295 || (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)) {
296 feh_action_run(FEH_FILE(winwid->file->data), opt.actions[action], winwid);
297
298 if (opt.hold_actions[action])
299 feh_reload_image(winwid, 1, 1);
300 else
301 winwidget_destroy(winwid);
302 } else if (winwid->type == WIN_TYPE_THUMBNAIL) {
303 feh_file *thumbfile;
304 thumbfile = feh_thumbnail_get_selected_file();
305
306 if (thumbfile) {
307 feh_action_run(thumbfile, opt.actions[action], winwid);
308
309 if (!opt.hold_actions[action])
310 feh_thumbnail_mark_removed(thumbfile, 0);
311 }
312 }
313 }
314 return;
315 }
316
feh_event_handle_stdin()317 void feh_event_handle_stdin()
318 {
319 char stdin_buf[2];
320 static char is_esc = 0;
321 KeySym keysym = NoSymbol;
322 if (read(STDIN_FILENO, &stdin_buf, 1) == -1) {
323 control_via_stdin = 0;
324 if (isatty(STDIN_FILENO) && getpgrp() == (tcgetpgrp(STDIN_FILENO))) {
325 weprintf("reading a command from stdin failed - disabling control via stdin");
326 restore_stdin();
327 }
328 return;
329 }
330 stdin_buf[1] = '\0';
331
332 // escape?
333 if (stdin_buf[0] == 0x1b) {
334 is_esc = 1;
335 return;
336 }
337 if ((is_esc == 1) && (stdin_buf[0] == '[')) {
338 is_esc = 2;
339 return;
340 }
341
342 if (stdin_buf[0] == ' ')
343 keysym = XK_space;
344 else if (stdin_buf[0] == '\n')
345 keysym = XK_Return;
346 else if ((stdin_buf[0] == '\b') || (stdin_buf[0] == 127))
347 keysym = XK_BackSpace;
348 else if (is_esc == 2) {
349 if (stdin_buf[0] == 'A')
350 keysym = XK_Up;
351 else if (stdin_buf[0] == 'B')
352 keysym = XK_Down;
353 else if (stdin_buf[0] == 'C')
354 keysym = XK_Right;
355 else if (stdin_buf[0] == 'D')
356 keysym = XK_Left;
357 is_esc = 0;
358 }
359 else
360 keysym = XStringToKeysym(stdin_buf);
361
362 if (window_num)
363 feh_event_handle_generic(windows[0], is_esc * Mod1Mask, keysym, 0);
364
365 is_esc = 0;
366 }
367
feh_event_handle_keypress(XEvent * ev)368 void feh_event_handle_keypress(XEvent * ev)
369 {
370 int state;
371 char kbuf[20];
372 KeySym keysym;
373 XKeyEvent *kev;
374 winwidget winwid = NULL;
375 feh_menu_item *selected_item;
376 feh_menu *selected_menu;
377
378 winwid = winwidget_get_from_window(ev->xkey.window);
379
380 /* nuke dupe events, unless we're typing text */
381 if (winwid && !winwid->caption_entry) {
382 while (XCheckTypedWindowEvent(disp, ev->xkey.window, KeyPress, ev));
383 }
384
385 kev = (XKeyEvent *) ev;
386 XLookupString(&ev->xkey, (char *) kbuf, sizeof(kbuf), &keysym, NULL);
387 state = kev->state & (ControlMask | ShiftMask | Mod1Mask | Mod4Mask);
388
389 if (ignore_space(keysym))
390 state &= ~ShiftMask;
391
392 /* menus are showing, so this is a menu control keypress */
393 if (ev->xbutton.window == menu_cover) {
394 selected_item = feh_menu_find_selected_r(menu_root, &selected_menu);
395 if (feh_is_kp(EVENT_menu_close, state, keysym, 0))
396 feh_menu_hide(menu_root, True);
397 else if (feh_is_kp(EVENT_menu_parent, state, keysym, 0))
398 feh_menu_select_parent(selected_menu);
399 else if (feh_is_kp(EVENT_menu_down, state, keysym, 0))
400 feh_menu_select_next(selected_menu, selected_item);
401 else if (feh_is_kp(EVENT_menu_up, state, keysym, 0))
402 feh_menu_select_prev(selected_menu, selected_item);
403 else if (feh_is_kp(EVENT_menu_child, state, keysym, 0))
404 feh_menu_select_submenu(selected_menu);
405 else if (feh_is_kp(EVENT_menu_select, state, keysym, 0))
406 feh_menu_item_activate(selected_menu, selected_item);
407 return;
408 }
409
410 if (winwid == NULL)
411 return;
412
413 feh_event_handle_generic(winwid, state, keysym, 0);
414 }
415
feh_str_to_kb(char * action)416 fehkey *feh_str_to_kb(char *action)
417 {
418 for (unsigned int i = 0; i < EVENT_LIST_END; i++) {
419 if (!strcmp(action, keys[i].name)) {
420 return &keys[i];
421 }
422 }
423 return NULL;
424 }
425
feh_event_handle_generic(winwidget winwid,unsigned int state,KeySym keysym,unsigned int button)426 void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysym, unsigned int button) {
427 int curr_screen = 0;
428
429 if (winwid->caption_entry && (keysym != NoSymbol)) {
430 switch (keysym) {
431 case XK_Return:
432 if (state & ControlMask) {
433 /* insert actual newline */
434 ESTRAPPEND(FEH_FILE(winwid->file->data)->caption, "\n");
435 winwidget_render_image_cached(winwid);
436 } else {
437 /* finish caption entry, write to captions file */
438 FILE *fp;
439 char *caption_filename;
440 caption_filename =
441 build_caption_filename(FEH_FILE(winwid->file->data), 1);
442 winwid->caption_entry = 0;
443 winwidget_render_image_cached(winwid);
444 XFreePixmap(disp, winwid->bg_pmap_cache);
445 winwid->bg_pmap_cache = 0;
446 fp = fopen(caption_filename, "w");
447 if (!fp) {
448 eprintf("couldn't write to captions file %s:", caption_filename);
449 return;
450 }
451 fprintf(fp, "%s", FEH_FILE(winwid->file->data)->caption);
452 free(caption_filename);
453 fclose(fp);
454 }
455 break;
456 case XK_Escape:
457 /* cancel, revert caption */
458 winwid->caption_entry = 0;
459 free(FEH_FILE(winwid->file->data)->caption);
460 FEH_FILE(winwid->file->data)->caption = NULL;
461 winwidget_render_image_cached(winwid);
462 XFreePixmap(disp, winwid->bg_pmap_cache);
463 winwid->bg_pmap_cache = 0;
464 break;
465 case XK_BackSpace:
466 /* backspace */
467 ESTRTRUNC(FEH_FILE(winwid->file->data)->caption, 1);
468 winwidget_render_image_cached(winwid);
469 break;
470 default:
471 if (isascii(keysym)) {
472 /* append to caption */
473 ESTRAPPEND_CHAR(FEH_FILE(winwid->file->data)->caption, keysym);
474 winwidget_render_image_cached(winwid);
475 }
476 break;
477 }
478 return;
479 }
480
481 if (feh_is_kp(EVENT_next_img, state, keysym, button)) {
482 if (opt.slideshow)
483 slideshow_change_image(winwid, SLIDE_NEXT, 1);
484 else if (winwid->type == WIN_TYPE_THUMBNAIL)
485 feh_thumbnail_select_next(winwid, 1);
486 }
487 else if (feh_is_kp(EVENT_prev_img, state, keysym, button)) {
488 if (opt.slideshow)
489 slideshow_change_image(winwid, SLIDE_PREV, 1);
490 else if (winwid->type == WIN_TYPE_THUMBNAIL)
491 feh_thumbnail_select_prev(winwid, 1);
492 }
493 else if (feh_is_kp(EVENT_scroll_right, state, keysym, button)) {
494 winwid->im_x -= opt.scroll_step;;
495 winwidget_sanitise_offsets(winwid);
496 winwidget_render_image(winwid, 0, 1);
497 }
498 else if (feh_is_kp(EVENT_scroll_left, state, keysym, button)) {
499 winwid->im_x += opt.scroll_step;
500 winwidget_sanitise_offsets(winwid);
501 winwidget_render_image(winwid, 0, 1);
502 }
503 else if (feh_is_kp(EVENT_scroll_down, state, keysym, button)) {
504 winwid->im_y -= opt.scroll_step;
505 winwidget_sanitise_offsets(winwid);
506 winwidget_render_image(winwid, 0, 1);
507 }
508 else if (feh_is_kp(EVENT_scroll_up, state, keysym, button)) {
509 winwid->im_y += opt.scroll_step;
510 winwidget_sanitise_offsets(winwid);
511 winwidget_render_image(winwid, 0, 1);
512 }
513 else if (feh_is_kp(EVENT_scroll_right_page, state, keysym, button)) {
514 winwid->im_x -= winwid->w;
515 winwidget_sanitise_offsets(winwid);
516 winwidget_render_image(winwid, 0, 0);
517 }
518 else if (feh_is_kp(EVENT_scroll_left_page, state, keysym, button)) {
519 winwid->im_x += winwid->w;
520 winwidget_sanitise_offsets(winwid);
521 winwidget_render_image(winwid, 0, 0);
522 }
523 else if (feh_is_kp(EVENT_scroll_down_page, state, keysym, button)) {
524 winwid->im_y -= winwid->h;
525 winwidget_sanitise_offsets(winwid);
526 winwidget_render_image(winwid, 0, 0);
527 }
528 else if (feh_is_kp(EVENT_scroll_up_page, state, keysym, button)) {
529 winwid->im_y += winwid->h;
530 winwidget_sanitise_offsets(winwid);
531 winwidget_render_image(winwid, 0, 0);
532 }
533 else if (feh_is_kp(EVENT_jump_back, state, keysym, button)) {
534 if (opt.slideshow)
535 slideshow_change_image(winwid, SLIDE_JUMP_BACK, 1);
536 else if (winwid->type == WIN_TYPE_THUMBNAIL)
537 feh_thumbnail_select_prev(winwid, 10);
538 }
539 else if (feh_is_kp(EVENT_jump_fwd, state, keysym, button)) {
540 if (opt.slideshow)
541 slideshow_change_image(winwid, SLIDE_JUMP_FWD, 1);
542 else if (winwid->type == WIN_TYPE_THUMBNAIL)
543 feh_thumbnail_select_next(winwid, 10);
544 }
545 else if (feh_is_kp(EVENT_next_dir, state, keysym, button)) {
546 if (opt.slideshow)
547 slideshow_change_image(winwid, SLIDE_JUMP_NEXT_DIR, 1);
548 }
549 else if (feh_is_kp(EVENT_prev_dir, state, keysym, button)) {
550 if (opt.slideshow)
551 slideshow_change_image(winwid, SLIDE_JUMP_PREV_DIR, 1);
552 }
553 else if (feh_is_kp(EVENT_quit, state, keysym, button)) {
554 winwidget_destroy_all();
555 }
556 else if (feh_is_kp(EVENT_delete, state, keysym, button)) {
557 if (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)
558 feh_thumbnail_mark_removed(FEH_FILE(winwid->file->data), 1);
559 feh_filelist_image_remove(winwid, 1);
560 }
561 else if (feh_is_kp(EVENT_remove, state, keysym, button)) {
562 if (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)
563 feh_thumbnail_mark_removed(FEH_FILE(winwid->file->data), 0);
564 feh_filelist_image_remove(winwid, 0);
565 }
566 else if (feh_is_kp(EVENT_jump_first, state, keysym, button)) {
567 if (opt.slideshow)
568 slideshow_change_image(winwid, SLIDE_FIRST, 1);
569 }
570 else if (feh_is_kp(EVENT_jump_last, state, keysym, button)) {
571 if (opt.slideshow)
572 slideshow_change_image(winwid, SLIDE_LAST, 1);
573 }
574 else if (feh_is_kp(EVENT_action_0, state, keysym, button)) {
575 feh_event_invoke_action(winwid, 0);
576 }
577 else if (feh_is_kp(EVENT_action_1, state, keysym, button)) {
578 feh_event_invoke_action(winwid, 1);
579 }
580 else if (feh_is_kp(EVENT_action_2, state, keysym, button)) {
581 feh_event_invoke_action(winwid, 2);
582 }
583 else if (feh_is_kp(EVENT_action_3, state, keysym, button)) {
584 feh_event_invoke_action(winwid, 3);
585 }
586 else if (feh_is_kp(EVENT_action_4, state, keysym, button)) {
587 feh_event_invoke_action(winwid, 4);
588 }
589 else if (feh_is_kp(EVENT_action_5, state, keysym, button)) {
590 feh_event_invoke_action(winwid, 5);
591 }
592 else if (feh_is_kp(EVENT_action_6, state, keysym, button)) {
593 feh_event_invoke_action(winwid, 6);
594 }
595 else if (feh_is_kp(EVENT_action_7, state, keysym, button)) {
596 feh_event_invoke_action(winwid, 7);
597 }
598 else if (feh_is_kp(EVENT_action_8, state, keysym, button)) {
599 feh_event_invoke_action(winwid, 8);
600 }
601 else if (feh_is_kp(EVENT_action_9, state, keysym, button)) {
602 feh_event_invoke_action(winwid, 9);
603 }
604 else if (feh_is_kp(EVENT_zoom_in, state, keysym, button)) {
605 winwid->old_zoom = winwid->zoom;
606 winwid->zoom = winwid->zoom * 1.25;
607
608 if (winwid->zoom > ZOOM_MAX)
609 winwid->zoom = ZOOM_MAX;
610
611 winwid->im_x = (winwid->w / 2) - (((winwid->w / 2) - winwid->im_x) /
612 winwid->old_zoom * winwid->zoom);
613 winwid->im_y = (winwid->h / 2) - (((winwid->h / 2) - winwid->im_y) /
614 winwid->old_zoom * winwid->zoom);
615 winwidget_sanitise_offsets(winwid);
616 winwidget_render_image(winwid, 0, 0);
617 }
618 else if (feh_is_kp(EVENT_zoom_out, state, keysym, button)) {
619 winwid->old_zoom = winwid->zoom;
620 winwid->zoom = winwid->zoom * 0.80;
621
622 if (winwid->zoom < ZOOM_MIN)
623 winwid->zoom = ZOOM_MIN;
624
625 winwid->im_x = (winwid->w / 2) - (((winwid->w / 2) - winwid->im_x) /
626 winwid->old_zoom * winwid->zoom);
627 winwid->im_y = (winwid->h / 2) - (((winwid->h / 2) - winwid->im_y) /
628 winwid->old_zoom * winwid->zoom);
629 winwidget_sanitise_offsets(winwid);
630 winwidget_render_image(winwid, 0, 0);
631 }
632 else if (feh_is_kp(EVENT_zoom_default, state, keysym, button)) {
633 winwid->zoom = 1.0;
634 winwidget_center_image(winwid);
635 winwidget_render_image(winwid, 0, 0);
636 }
637 else if (feh_is_kp(EVENT_zoom_fit, state, keysym, button)) {
638 feh_calc_needed_zoom(&winwid->zoom, winwid->im_w, winwid->im_h, winwid->w, winwid->h);
639 winwidget_center_image(winwid);
640 winwidget_render_image(winwid, 0, 0);
641 }
642 else if (feh_is_kp(EVENT_zoom_fill, state, keysym, button)) {
643 int save_zoom = opt.zoom_mode;
644 opt.zoom_mode = ZOOM_MODE_FILL;
645 feh_calc_needed_zoom(&winwid->zoom, winwid->im_w, winwid->im_h, winwid->w, winwid->h);
646 winwidget_center_image(winwid);
647 winwidget_render_image(winwid, 0, 0);
648 opt.zoom_mode = save_zoom;
649 }
650 else if (feh_is_kp(EVENT_render, state, keysym, button)) {
651 if (winwid->type == WIN_TYPE_THUMBNAIL)
652 feh_thumbnail_show_selected();
653 else
654 winwidget_render_image(winwid, 0, 0);
655 }
656 else if (feh_is_kp(EVENT_toggle_actions, state, keysym, button)) {
657 opt.draw_actions = !opt.draw_actions;
658 winwidget_rerender_all(0);
659 }
660 else if (feh_is_kp(EVENT_toggle_aliasing, state, keysym, button)) {
661 opt.force_aliasing = !opt.force_aliasing;
662 winwid->force_aliasing = !winwid->force_aliasing;
663 winwidget_render_image(winwid, 0, 0);
664 }
665 else if (feh_is_kp(EVENT_toggle_auto_zoom, state, keysym, button)) {
666 opt.zoom_mode = (opt.zoom_mode == 0 ? ZOOM_MODE_MAX : 0);
667 winwidget_rerender_all(1);
668 }
669 else if (feh_is_kp(EVENT_toggle_filenames, state, keysym, button)) {
670 opt.draw_filename = !opt.draw_filename;
671 winwidget_rerender_all(0);
672 }
673 #ifdef HAVE_LIBEXIF
674 else if (feh_is_kp(EVENT_toggle_exif, state, keysym, button)) {
675 opt.draw_exif = !opt.draw_exif;
676 winwidget_rerender_all(0);
677 }
678 #endif
679 else if (feh_is_kp(EVENT_toggle_info, state, keysym, button)) {
680 opt.draw_info = !opt.draw_info;
681 winwidget_rerender_all(0);
682 }
683 else if (feh_is_kp(EVENT_toggle_pointer, state, keysym, button)) {
684 winwidget_set_pointer(winwid, opt.hide_pointer);
685 opt.hide_pointer = !opt.hide_pointer;
686 }
687 else if (feh_is_kp(EVENT_jump_random, state, keysym, button)) {
688 if (winwid->type == WIN_TYPE_THUMBNAIL)
689 feh_thumbnail_select_next(winwid, random() % (filelist_len - 1));
690 else
691 slideshow_change_image(winwid, SLIDE_RAND, 1);
692 }
693 else if (feh_is_kp(EVENT_toggle_caption, state, keysym, button)) {
694 if (opt.caption_path && path_is_url(FEH_FILE(winwid->file->data)->filename)) {
695 im_weprintf(winwid, "Caption entry is not supported on URLs");
696 }
697 else if (opt.caption_path) {
698 /*
699 * editing captions in slideshow mode does not make any sense
700 * at all; this is just in case someone accidentally does it...
701 */
702 if (opt.slideshow_delay)
703 opt.paused = 1;
704 winwid->caption_entry = 1;
705 }
706 winwidget_render_image(winwid, 0, 0);
707 }
708 else if (feh_is_kp(EVENT_reload_image, state, keysym, button)) {
709 feh_reload_image(winwid, 0, 0);
710 }
711 else if (feh_is_kp(EVENT_toggle_pause, state, keysym, button)) {
712 slideshow_pause_toggle(winwid);
713 /* We need to re-render the image to update the info string immediately. */
714 winwidget_render_image(winwid, 0, 0);
715 }
716 else if (feh_is_kp(EVENT_save_image, state, keysym, button)) {
717 slideshow_save_image(winwid);
718 }
719 else if (feh_is_kp(EVENT_save_filelist, state, keysym, button)) {
720 if ((winwid->type == WIN_TYPE_THUMBNAIL)
721 || (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER))
722 weprintf("Filelist saving is not supported in thumbnail mode");
723 else
724 feh_save_filelist();
725 }
726 else if (feh_is_kp(EVENT_size_to_image, state, keysym, button)) {
727 winwidget_size_to_image(winwid);
728 }
729 else if (!opt.no_menus && feh_is_kp(EVENT_toggle_menu, state, keysym, button)) {
730 winwidget_show_menu(winwid);
731 }
732 else if (feh_is_kp(EVENT_close, state, keysym, button)) {
733 winwidget_destroy(winwid);
734 }
735 else if (feh_is_kp(EVENT_orient_1, state, keysym, button)) {
736 feh_edit_inplace(winwid, 1);
737 }
738 else if (feh_is_kp(EVENT_orient_3, state, keysym, button)) {
739 feh_edit_inplace(winwid, 3);
740 }
741 else if (feh_is_kp(EVENT_flip, state, keysym, button)) {
742 feh_edit_inplace(winwid, INPLACE_EDIT_FLIP);
743 }
744 else if (feh_is_kp(EVENT_mirror, state, keysym, button)) {
745 feh_edit_inplace(winwid, INPLACE_EDIT_MIRROR);
746 }
747 else if (feh_is_kp(EVENT_toggle_fullscreen, state, keysym, button)) {
748 #ifdef HAVE_LIBXINERAMA
749 if (opt.xinerama && xinerama_screens) {
750 int i, rect[4];
751
752 winwidget_get_geometry(winwid, rect);
753 for (i = 0; i < num_xinerama_screens; i++) {
754 xinerama_screen = 0;
755 if (XY_IN_RECT(rect[0], rect[1],
756 xinerama_screens[i].x_org,
757 xinerama_screens[i].y_org,
758 xinerama_screens[i].width,
759 xinerama_screens[i].height)) {
760 curr_screen = xinerama_screen = i;
761 break;
762 }
763 }
764 if (opt.xinerama_index >= 0)
765 curr_screen = xinerama_screen = opt.xinerama_index;
766 }
767 #endif /* HAVE_LIBXINERAMA */
768 winwid->full_screen = !winwid->full_screen;
769 winwidget_destroy_xwin(winwid);
770 winwidget_create_window(winwid, winwid->im_w, winwid->im_h);
771 winwidget_render_image(winwid, 1, 0);
772 winwidget_show(winwid);
773 #ifdef HAVE_LIBXINERAMA
774 /* if we have xinerama and we're using it, then full screen the window
775 * on the head that the window was active on */
776 if (winwid->full_screen == TRUE && opt.xinerama && xinerama_screens) {
777 xinerama_screen = curr_screen;
778 winwidget_move(winwid,
779 xinerama_screens[curr_screen].x_org, xinerama_screens[curr_screen].y_org);
780 }
781 #endif /* HAVE_LIBXINERAMA */
782 }
783 else if (feh_is_kp(EVENT_reload_plus, state, keysym, button)){
784 if (opt.reload < SLIDESHOW_RELOAD_MAX)
785 opt.reload++;
786 else if (opt.verbose)
787 weprintf("Cannot set RELOAD higher than %f seconds.", opt.reload);
788 }
789 else if (feh_is_kp(EVENT_reload_minus, state, keysym, button)) {
790 if (opt.reload > 1)
791 opt.reload--;
792 else if (opt.verbose)
793 weprintf("Cannot set RELOAD lower than 1 second.");
794 }
795 else if (feh_is_kp(EVENT_toggle_keep_vp, state, keysym, button)) {
796 opt.keep_zoom_vp = !opt.keep_zoom_vp;
797 }
798 else if (feh_is_kp(EVENT_toggle_fixed_geometry, state, keysym, button)) {
799 if (opt.geom_flags & ((WidthValue | HeightValue))) {
800 opt.geom_flags &= ~(WidthValue | HeightValue);
801 } else {
802 opt.geom_flags |= (WidthValue | HeightValue);
803 opt.geom_w = winwid->w;
804 opt.geom_h = winwid->h;
805 }
806 winwidget_render_image(winwid, 1, 0);
807 }
808 return;
809 }
810