"Fossies" - the Fresh Open Source Software Archive

Member "feh-3.4.1/src/keyevents.c" (29 May 2020, 26811 Bytes) of package /linux/privat/feh-3.4.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "keyevents.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.4_vs_3.4.1.

    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 
   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 
   58 void restore_stdin() {
   59     if (tcsetattr(STDIN_FILENO, TCSANOW, &old_term_settings) == -1)
   60         eprintf("tcsetattr failed");
   61 }
   62 
   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 
   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 
   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 
  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 
  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 
  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 
  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 
  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 
  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 
  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     }
  714     else if (feh_is_kp(EVENT_save_image, state, keysym, button)) {
  715         slideshow_save_image(winwid);
  716     }
  717     else if (feh_is_kp(EVENT_save_filelist, state, keysym, button)) {
  718         if ((winwid->type == WIN_TYPE_THUMBNAIL)
  719                 || (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER))
  720             weprintf("Filelist saving is not supported in thumbnail mode");
  721         else
  722             feh_save_filelist();
  723     }
  724     else if (feh_is_kp(EVENT_size_to_image, state, keysym, button)) {
  725         winwidget_size_to_image(winwid);
  726     }
  727     else if (!opt.no_menus && feh_is_kp(EVENT_toggle_menu, state, keysym, button)) {
  728         winwidget_show_menu(winwid);
  729     }
  730     else if (feh_is_kp(EVENT_close, state, keysym, button)) {
  731         winwidget_destroy(winwid);
  732     }
  733     else if (feh_is_kp(EVENT_orient_1, state, keysym, button)) {
  734         feh_edit_inplace(winwid, 1);
  735     }
  736     else if (feh_is_kp(EVENT_orient_3, state, keysym, button)) {
  737         feh_edit_inplace(winwid, 3);
  738     }
  739     else if (feh_is_kp(EVENT_flip, state, keysym, button)) {
  740         feh_edit_inplace(winwid, INPLACE_EDIT_FLIP);
  741     }
  742     else if (feh_is_kp(EVENT_mirror, state, keysym, button)) {
  743         feh_edit_inplace(winwid, INPLACE_EDIT_MIRROR);
  744     }
  745     else if (feh_is_kp(EVENT_toggle_fullscreen, state, keysym, button)) {
  746 #ifdef HAVE_LIBXINERAMA
  747         if (opt.xinerama && xinerama_screens) {
  748             int i, rect[4];
  749 
  750             winwidget_get_geometry(winwid, rect);
  751             for (i = 0; i < num_xinerama_screens; i++) {
  752                 xinerama_screen = 0;
  753                 if (XY_IN_RECT(rect[0], rect[1],
  754                             xinerama_screens[i].x_org,
  755                             xinerama_screens[i].y_org,
  756                             xinerama_screens[i].width,
  757                             xinerama_screens[i].height)) {
  758                     curr_screen = xinerama_screen = i;
  759                     break;
  760                 }
  761             }
  762             if (opt.xinerama_index >= 0)
  763                 curr_screen = xinerama_screen = opt.xinerama_index;
  764         }
  765 #endif              /* HAVE_LIBXINERAMA */
  766         winwid->full_screen = !winwid->full_screen;
  767         winwidget_destroy_xwin(winwid);
  768         winwidget_create_window(winwid, winwid->im_w, winwid->im_h);
  769         winwidget_render_image(winwid, 1, 0);
  770         winwidget_show(winwid);
  771 #ifdef HAVE_LIBXINERAMA
  772         /* if we have xinerama and we're using it, then full screen the window
  773          * on the head that the window was active on */
  774         if (winwid->full_screen == TRUE && opt.xinerama && xinerama_screens) {
  775             xinerama_screen = curr_screen;
  776             winwidget_move(winwid,
  777                     xinerama_screens[curr_screen].x_org, xinerama_screens[curr_screen].y_org);
  778         }
  779 #endif              /* HAVE_LIBXINERAMA */
  780     }
  781     else if (feh_is_kp(EVENT_reload_plus, state, keysym, button)){
  782         if (opt.reload < SLIDESHOW_RELOAD_MAX)
  783             opt.reload++;
  784         else if (opt.verbose)
  785             weprintf("Cannot set RELOAD higher than %f seconds.", opt.reload);
  786     }
  787     else if (feh_is_kp(EVENT_reload_minus, state, keysym, button)) {
  788         if (opt.reload > 1)
  789             opt.reload--;
  790         else if (opt.verbose)
  791             weprintf("Cannot set RELOAD lower than 1 second.");
  792     }
  793     else if (feh_is_kp(EVENT_toggle_keep_vp, state, keysym, button)) {
  794         opt.keep_zoom_vp = !opt.keep_zoom_vp;
  795     }
  796     else if (feh_is_kp(EVENT_toggle_fixed_geometry, state, keysym, button)) {
  797         if (opt.geom_flags & ((WidthValue | HeightValue))) {
  798             opt.geom_flags &= ~(WidthValue | HeightValue);
  799         } else {
  800             opt.geom_flags |= (WidthValue | HeightValue);
  801             opt.geom_w = winwid->w;
  802             opt.geom_h = winwid->h;
  803         }
  804         winwidget_render_image(winwid, 1, 0);
  805     }
  806     return;
  807 }