"Fossies" - the Fresh Open Source Software Archive

Member "feh-3.4.1/src/events.c" (29 May 2020, 21199 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 "events.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 /* events.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 "filelist.h"
   29 #include "winwidget.h"
   30 #include "timers.h"
   31 #include "options.h"
   32 #include "events.h"
   33 #include "thumbnail.h"
   34 
   35 #define FEH_JITTER_OFFSET 2
   36 #define FEH_JITTER_TIME 1
   37 
   38 extern struct __fehkey keys[EVENT_LIST_END];
   39 fehkey *feh_str_to_kb(char *action);
   40 
   41 feh_event_handler *ev_handler[LASTEvent];
   42 
   43 static void feh_event_handle_ButtonPress(XEvent * ev);
   44 static void feh_event_handle_ButtonRelease(XEvent * ev);
   45 static void feh_event_handle_LeaveNotify(XEvent * ev);
   46 static void feh_event_handle_MotionNotify(XEvent * ev);
   47 static void feh_event_handle_ClientMessage(XEvent * ev);
   48 
   49 static void feh_set_bb(unsigned int bb_index, int modifier, char button)
   50 {
   51     keys[bb_index].state  = modifier;
   52     keys[bb_index].button = button;
   53 }
   54 
   55 static void feh_set_parse_bb_partial(fehkey *button, char *binding)
   56 {
   57     char *cur = binding;
   58     int mod = 0;
   59 
   60     if (!*binding) {
   61         button->button = 0;
   62         return;
   63     }
   64 
   65     while (cur[1] == '-') {
   66         switch (cur[0]) {
   67             case 'C':
   68                 mod |= ControlMask;
   69                 break;
   70             case 'S':
   71                 mod |= ShiftMask;
   72                 break;
   73             case '1':
   74                 mod |= Mod1Mask;
   75                 break;
   76             case '4':
   77                 mod |= Mod4Mask;
   78                 break;
   79             default:
   80                 weprintf("buttons: invalid modifier %c in \"%s\"", cur[0], binding);
   81                 break;
   82         }
   83         cur += 2;
   84     }
   85 
   86     button->button = atoi(cur);
   87     button->state  = mod;
   88 }
   89 
   90 /*
   91  * Called after init_keyevents in keyevents.c
   92  * -> no need to memset
   93  */
   94 void init_buttonbindings(void)
   95 {
   96     char *home = NULL;
   97     char *confhome = NULL;
   98     char *confpath = NULL;
   99     char line[128];
  100     char action[32], button[8];
  101     struct __fehkey *cur_bb = NULL;
  102     FILE *conf = NULL;
  103     int read = 0;
  104 
  105     feh_set_bb(EVENT_pan,         0, 1);
  106     feh_set_bb(EVENT_zoom,        0, 2);
  107     feh_set_bb(EVENT_toggle_menu, 0, 3);
  108     feh_set_bb(EVENT_prev_img,    0, 4);
  109     feh_set_bb(EVENT_next_img,    0, 5);
  110     feh_set_bb(EVENT_blur,        4, 1);
  111     feh_set_bb(EVENT_rotate,      4, 2);
  112 
  113     home = getenv("HOME");
  114     confhome = getenv("XDG_CONFIG_HOME");
  115 
  116     if (confhome)
  117         confpath = estrjoin("/", confhome, "feh/buttons", NULL);
  118     else if (home)
  119         confpath = estrjoin("/", home, ".config/feh/buttons", NULL);
  120     else
  121         return;
  122 
  123     conf = fopen(confpath, "r");
  124 
  125     free(confpath);
  126 
  127     if (!conf && ((conf = fopen("/etc/feh/buttons", "r")) == NULL))
  128         return;
  129 
  130     while (fgets(line, sizeof(line), conf)) {
  131         *action = '\0';
  132         *button = '\0';
  133         cur_bb = NULL;
  134 
  135         read = sscanf(line, "%31s %7s\n", (char *) &action, (char *) &button);
  136 
  137         if ((read == EOF) || (read == 0) || (line[0] == '#'))
  138             continue;
  139 
  140         cur_bb = feh_str_to_kb(action);
  141         if (cur_bb == NULL) {
  142             if (!strcmp(action, "reload"))
  143                 cur_bb = &keys[EVENT_reload_image];
  144             else if (!strcmp(action, "menu"))
  145                 cur_bb = &keys[EVENT_toggle_menu];
  146             else if (!strcmp(action, "prev"))
  147                 cur_bb = &keys[EVENT_prev_img];
  148             else if (!strcmp(action, "next"))
  149                 cur_bb = &keys[EVENT_next_img];
  150         }
  151         if (cur_bb)
  152             feh_set_parse_bb_partial(cur_bb, button);
  153         else
  154             weprintf("buttons: Invalid action: %s", action);
  155     }
  156     fclose(conf);
  157 }
  158 
  159 static short feh_is_bb(unsigned int key_index, unsigned int button, unsigned int mod)
  160 {
  161     if ((keys[key_index].state == mod) && (keys[key_index].button == button))
  162         return 1;
  163     return 0;
  164 }
  165 
  166 
  167 void feh_event_init(void)
  168 {
  169     int i;
  170 
  171     for (i = 0; i < LASTEvent; i++)
  172         ev_handler[i] = NULL;
  173 
  174     ev_handler[KeyPress] = feh_event_handle_keypress;
  175     ev_handler[ButtonPress] = feh_event_handle_ButtonPress;
  176     ev_handler[ButtonRelease] = feh_event_handle_ButtonRelease;
  177     ev_handler[ConfigureNotify] = feh_event_handle_ConfigureNotify;
  178     ev_handler[LeaveNotify] = feh_event_handle_LeaveNotify;
  179     ev_handler[MotionNotify] = feh_event_handle_MotionNotify;
  180     ev_handler[ClientMessage] = feh_event_handle_ClientMessage;
  181 
  182     return;
  183 }
  184 
  185 static void feh_event_handle_ButtonPress(XEvent * ev)
  186 {
  187     winwidget winwid = NULL;
  188     unsigned int state, button;
  189 
  190     /* get the heck out if it's a mouse-click on the
  191        cover, we'll hide the menus on release */
  192     if (ev->xbutton.window == menu_cover) {
  193         return;
  194     }
  195 
  196     winwid = winwidget_get_from_window(ev->xbutton.window);
  197     if (winwid == NULL || winwid->caption_entry) {
  198         return;
  199     }
  200 
  201     state = ev->xbutton.state & (ControlMask | ShiftMask | Mod1Mask | Mod4Mask);
  202     button = ev->xbutton.button;
  203 
  204     if (!opt.no_menus && feh_is_bb(EVENT_toggle_menu, button, state)) {
  205         D(("Menu Button Press event\n"));
  206         winwidget_show_menu(winwid);
  207 
  208     } else if (feh_is_bb(EVENT_rotate, button, state)
  209            && (winwid->type != WIN_TYPE_THUMBNAIL)) {
  210         opt.mode = MODE_ROTATE;
  211         winwid->mode = MODE_ROTATE;
  212         D(("rotate starting at %d, %d\n", ev->xbutton.x, ev->xbutton.y));
  213 
  214     } else if (feh_is_bb(EVENT_blur, button, state)
  215            && (winwid->type != WIN_TYPE_THUMBNAIL)) {
  216         opt.mode = MODE_BLUR;
  217         winwid->mode = MODE_BLUR;
  218         D(("blur starting at %d, %d\n", ev->xbutton.x, ev->xbutton.y));
  219 
  220     } else if (feh_is_bb(EVENT_pan, button, state)) {
  221         D(("Next button, but could be pan mode\n"));
  222         opt.mode = MODE_NEXT;
  223         winwid->mode = MODE_NEXT;
  224         D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y));
  225         winwid->click_offset_x = ev->xbutton.x - winwid->im_x;
  226         winwid->click_offset_y = ev->xbutton.y - winwid->im_y;
  227         winwid->click_start_time = time(NULL);
  228 
  229     } else if (feh_is_bb(EVENT_zoom, button, state)) {
  230         D(("Zoom Button Press event\n"));
  231         opt.mode = MODE_ZOOM;
  232         winwid->mode = MODE_ZOOM;
  233         D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y));
  234         winwid->click_offset_x = ev->xbutton.x;
  235         winwid->click_offset_y = ev->xbutton.y;
  236         winwid->old_zoom = winwid->zoom;
  237 
  238         /* required to adjust the image position in zoom mode */
  239         winwid->im_click_offset_x = (winwid->click_offset_x
  240                 - winwid->im_x) / winwid->old_zoom;
  241         winwid->im_click_offset_y = (winwid->click_offset_y
  242                 - winwid->im_y) / winwid->old_zoom;
  243 
  244     } else if (feh_is_bb(EVENT_zoom_in, button, state)) {
  245         D(("Zoom_In Button Press event\n"));
  246         D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y));
  247         winwid->click_offset_x = ev->xbutton.x;
  248         winwid->click_offset_y = ev->xbutton.y;
  249         winwid->old_zoom = winwid->zoom;
  250 
  251         /* required to adjust the image position in zoom mode */
  252         winwid->im_click_offset_x = (winwid->click_offset_x
  253                 - winwid->im_x) / winwid->old_zoom;
  254         winwid->im_click_offset_y = (winwid->click_offset_y
  255                 - winwid->im_y) / winwid->old_zoom;
  256 
  257         /* copied from zoom_in, keyevents.c */
  258         winwid->zoom = winwid->zoom * 1.25;
  259 
  260         if (winwid->zoom > ZOOM_MAX)
  261             winwid->zoom = ZOOM_MAX;
  262 
  263         /* copied from below (ZOOM, feh_event_handle_MotionNotify) */
  264         winwid->im_x = winwid->click_offset_x
  265                 - (winwid->im_click_offset_x * winwid->zoom);
  266         winwid->im_y = winwid->click_offset_y
  267                 - (winwid->im_click_offset_y * winwid->zoom);
  268 
  269         winwidget_sanitise_offsets(winwid);
  270         winwidget_render_image(winwid, 0, 0);
  271 
  272     } else if (feh_is_bb(EVENT_zoom_out, button, state)) {
  273         D(("Zoom_Out Button Press event\n"));
  274         D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y));
  275         winwid->click_offset_x = ev->xbutton.x;
  276         winwid->click_offset_y = ev->xbutton.y;
  277         winwid->old_zoom = winwid->zoom;
  278 
  279         /* required to adjust the image position in zoom mode */
  280         winwid->im_click_offset_x = (winwid->click_offset_x
  281                 - winwid->im_x) / winwid->old_zoom;
  282         winwid->im_click_offset_y = (winwid->click_offset_y
  283                 - winwid->im_y) / winwid->old_zoom;
  284 
  285         /* copied from zoom_out, keyevents.c */
  286         winwid->zoom = winwid->zoom * 0.80;
  287 
  288         if (winwid->zoom < ZOOM_MIN)
  289             winwid->zoom = ZOOM_MIN;
  290 
  291         /* copied from below (ZOOM, feh_event_handle_MotionNotify) */
  292         winwid->im_x = winwid->click_offset_x
  293                 - (winwid->im_click_offset_x * winwid->zoom);
  294         winwid->im_y = winwid->click_offset_y
  295                 - (winwid->im_click_offset_y * winwid->zoom);
  296 
  297         winwidget_sanitise_offsets(winwid);
  298         winwidget_render_image(winwid, 0, 0);
  299 
  300     } else if (feh_is_bb(EVENT_reload_image, button, state)) {
  301         D(("Reload Button Press event\n"));
  302             feh_reload_image(winwid, 0, 1);
  303 
  304     } else if (feh_is_bb(EVENT_prev_img, button, state)) {
  305         D(("Prev Button Press event\n"));
  306         if (winwid->type == WIN_TYPE_SLIDESHOW)
  307             slideshow_change_image(winwid, SLIDE_PREV, 1);
  308 
  309     } else if (feh_is_bb(EVENT_next_img, button, state)) {
  310         D(("Next Button Press event\n"));
  311         if (winwid->type == WIN_TYPE_SLIDESHOW)
  312             slideshow_change_image(winwid, SLIDE_NEXT, 1);
  313 
  314     } else {
  315         D(("Received other ButtonPress event\n"));
  316         feh_event_handle_generic(winwid, state, NoSymbol, button);
  317     }
  318     return;
  319 }
  320 
  321 static void feh_event_handle_ButtonRelease(XEvent * ev)
  322 {
  323     winwidget winwid = NULL;
  324     unsigned int state = ev->xbutton.state & (ControlMask | ShiftMask | Mod1Mask | Mod4Mask);
  325     unsigned int button = ev->xbutton.button;
  326 
  327     if (menu_root) {
  328         /* if menus are open, close them, and execute action if needed */
  329 
  330         if (ev->xbutton.window == menu_cover) {
  331             feh_menu_hide(menu_root, True);
  332         } else if (menu_root) {
  333             feh_menu *m;
  334 
  335             if ((m = feh_menu_get_from_window(ev->xbutton.window))) {
  336                 feh_menu_item *i = NULL;
  337 
  338                 i = feh_menu_find_selected(m);
  339                 feh_menu_item_activate(m, i);
  340             }
  341         }
  342         return;
  343     }
  344 
  345     winwid = winwidget_get_from_window(ev->xbutton.window);
  346     if (winwid == NULL || winwid->caption_entry) {
  347         return;
  348     }
  349 
  350     if (feh_is_bb(EVENT_pan, button, state)) {
  351         if (opt.mode == MODE_PAN) {
  352             D(("Disabling pan mode\n"));
  353             opt.mode = MODE_NORMAL;
  354             winwid->mode = MODE_NORMAL;
  355             winwidget_sanitise_offsets(winwid);
  356             winwidget_render_image(winwid, 0, 0);
  357         } else if (opt.mode == MODE_NEXT) {
  358             opt.mode = MODE_NORMAL;
  359             winwid->mode = MODE_NORMAL;
  360             if (winwid->type == WIN_TYPE_SLIDESHOW)
  361                 slideshow_change_image(winwid, SLIDE_NEXT, 1);
  362             else if (winwid->type == WIN_TYPE_THUMBNAIL) {
  363                 feh_file *thumbfile;
  364                 int x, y;
  365 
  366                 x = ev->xbutton.x;
  367                 y = ev->xbutton.y;
  368                 x -= winwid->im_x;
  369                 y -= winwid->im_y;
  370                 x /= winwid->zoom;
  371                 y /= winwid->zoom;
  372                 thumbfile = feh_thumbnail_get_file_from_coords(x, y);
  373                 if (thumbfile) {
  374                     if (opt.actions[0]) {
  375                         feh_action_run(thumbfile, opt.actions[0], winwid);
  376                         if (!opt.hold_actions[0])
  377                             feh_thumbnail_mark_removed(thumbfile, 0);
  378                     } else {
  379                         feh_thumbnail_show_fullsize(thumbfile);
  380                     }
  381                 }
  382             }
  383         } else {
  384             opt.mode = MODE_NORMAL;
  385             winwid->mode = MODE_NORMAL;
  386         }
  387 
  388     } else if (feh_is_bb(EVENT_rotate, button, state)
  389             || feh_is_bb(EVENT_zoom, button, state)) {
  390         D(("Disabling mode\n"));
  391         opt.mode = MODE_NORMAL;
  392         winwid->mode = MODE_NORMAL;
  393 
  394         if ((feh_is_bb(EVENT_zoom, button, state))
  395                 && (ev->xbutton.x == winwid->click_offset_x)
  396                 && (ev->xbutton.y == winwid->click_offset_y)) {
  397             winwid->zoom = 1.0;
  398             winwidget_center_image(winwid);
  399         } else
  400             winwidget_sanitise_offsets(winwid);
  401 
  402         winwidget_render_image(winwid, 0, 0);
  403 
  404     } else if (feh_is_bb(EVENT_blur, button, state)) {
  405         D(("Disabling Blur mode\n"));
  406         opt.mode = MODE_NORMAL;
  407         winwid->mode = MODE_NORMAL;
  408     }
  409     return;
  410 }
  411 
  412 void feh_event_handle_ConfigureNotify(XEvent * ev)
  413 {
  414     while (XCheckTypedWindowEvent(disp, ev->xconfigure.window, ConfigureNotify, ev));
  415     if (!menu_root) {
  416         winwidget w = winwidget_get_from_window(ev->xconfigure.window);
  417 
  418         if (w) {
  419             D(("configure size %dx%d\n", ev->xconfigure.width, ev->xconfigure.height));
  420             if ((w->w != ev->xconfigure.width)
  421                     || (w->h != ev->xconfigure.height)) {
  422                 D(("assigning size and rerendering\n"));
  423                 w->w = ev->xconfigure.width;
  424                 w->h = ev->xconfigure.height;
  425                 w->had_resize = 1;
  426                 if (opt.geom_flags & WidthValue || opt.geom_flags & HeightValue) {
  427                     opt.geom_w = w->w;
  428                     opt.geom_h = w->h;
  429                 }
  430                 winwidget_render_image(w, 0, 0);
  431             }
  432         }
  433     }
  434 
  435     return;
  436 }
  437 
  438 static void feh_event_handle_LeaveNotify(XEvent * ev)
  439 {
  440     if ((menu_root) && (ev->xcrossing.window == menu_root->win)) {
  441         feh_menu_item *ii;
  442 
  443         D(("It is for a menu\n"));
  444         for (ii = menu_root->items; ii; ii = ii->next) {
  445             if (MENU_ITEM_IS_SELECTED(ii)) {
  446                 D(("Unselecting menu\n"));
  447                 MENU_ITEM_SET_NORMAL(ii);
  448                 menu_root->updates =
  449                     imlib_update_append_rect(menu_root->updates, ii->x, ii->y, ii->w, ii->h);
  450                 menu_root->needs_redraw = 1;
  451             }
  452         }
  453         feh_raise_all_menus();
  454     }
  455 
  456     return;
  457 }
  458 
  459 static void feh_event_handle_MotionNotify(XEvent * ev)
  460 {
  461     winwidget winwid = NULL;
  462     int dx, dy;
  463     int scr_width, scr_height;
  464 
  465     scr_width = scr->width;
  466     scr_height = scr->height;
  467 #ifdef HAVE_LIBXINERAMA
  468     if (opt.xinerama && xinerama_screens) {
  469         scr_width = xinerama_screens[xinerama_screen].width;
  470         scr_height = xinerama_screens[xinerama_screen].height;
  471     }
  472 #endif              /* HAVE_LIBXINERAMA */
  473 
  474     if (menu_root) {
  475         feh_menu *m;
  476         feh_menu_item *selected_item, *mouseover_item;
  477 
  478         D(("motion notify with menus open\n"));
  479         while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev));
  480 
  481         if (ev->xmotion.window == menu_cover) {
  482             return;
  483         } else if ((m = feh_menu_get_from_window(ev->xmotion.window))) {
  484             selected_item = feh_menu_find_selected(m);
  485             mouseover_item = feh_menu_find_at_xy(m, ev->xmotion.x, ev->xmotion.y);
  486 
  487             if (selected_item != mouseover_item) {
  488                 D(("selecting a menu item\n"));
  489                 if (selected_item)
  490                     feh_menu_deselect_selected(m);
  491                 if ((mouseover_item)
  492                         && ((mouseover_item->action)
  493                             || (mouseover_item->submenu)
  494                             || (mouseover_item->func_gen_sub)))
  495                     feh_menu_select(m, mouseover_item);
  496             }
  497             /* check if we are close to the right and/or the bottom edge of the
  498              * screen. If so, and if the menu we are currently over is partially
  499              * hidden, slide the menu to the left and/or up until it is
  500              * fully visible */
  501 
  502             /* FIXME: get this working nicely with xinerama screen edges --
  503              * at the moment it does really funky stuff with
  504              * scr_{width,height} instead of scr->{width,height} -- pabs*/
  505             if (mouseover_item
  506                     && ((scr->width - (ev->xmotion.x + m->x)) <
  507                         m->w || (scr->height - (ev->xmotion.y + m->y)) < m->w)) {
  508                 dx = scr_width - (m->x + m->w);
  509                 dy = scr_height - (m->y + m->h);
  510                 dx = dx < 0 ? dx : 0;
  511                 dy = dy < 0 ? dy : 0;
  512                 dx = m->x + dx < 0 ? -m->x : dx;
  513                 dy = m->y + dy < 0 ? -m->y : dy;
  514                 if (dx || dy)
  515                     feh_menu_slide_all_menus_relative(dx, dy);
  516             }
  517             /* if a submenu is open we want to see that also */
  518             if (mouseover_item && m->next && ((scr->width - (ev->xmotion.x + m->next->x))
  519                         < m->next->w
  520                         || (scr->height -
  521                             (ev->xmotion.y + m->next->y)) < m->next->w)) {
  522                 dx = scr->width - (m->next->x + m->next->w);
  523                 dy = scr->height - (m->next->y + m->next->h);
  524                 dx = dx < 0 ? dx : 0;
  525                 dy = dy < 0 ? dy : 0;
  526                 dx = m->x + dx < 0 ? -m->x : dx;
  527                 dy = m->y + dy < 0 ? -m->y : dy;
  528                 if (dx || dy)
  529                     feh_menu_slide_all_menus_relative(dx, dy);
  530             }
  531         }
  532     } else if (opt.mode == MODE_ZOOM) {
  533         while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev));
  534 
  535         winwid = winwidget_get_from_window(ev->xmotion.window);
  536         if (winwid) {
  537             if (ev->xmotion.x > winwid->click_offset_x)
  538                 winwid->zoom = winwid->old_zoom + (
  539                         ((double) ev->xmotion.x - (double) winwid->click_offset_x)
  540                         / 128.0);
  541             else
  542                 winwid->zoom = winwid->old_zoom - (
  543                         ((double) winwid->click_offset_x - (double) ev->xmotion.x)
  544                         / 128.0);
  545 
  546             if (winwid->zoom < ZOOM_MIN)
  547                 winwid->zoom = ZOOM_MIN;
  548             else if (winwid->zoom > ZOOM_MAX)
  549                 winwid->zoom = ZOOM_MAX;
  550 
  551             /* center around click_offset */
  552             winwid->im_x = winwid->click_offset_x
  553                     - (winwid->im_click_offset_x * winwid->zoom);
  554             winwid->im_y = winwid->click_offset_y
  555                     - (winwid->im_click_offset_y * winwid->zoom);
  556 
  557             winwidget_render_image(winwid, 0, 1);
  558         }
  559     } else if ((opt.mode == MODE_PAN) || (opt.mode == MODE_NEXT)) {
  560         int orig_x, orig_y;
  561 
  562         while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev));
  563         winwid = winwidget_get_from_window(ev->xmotion.window);
  564         if (winwid) {
  565             if (opt.mode == MODE_NEXT) {
  566                 if ((abs(winwid->click_offset_x - (ev->xmotion.x - winwid->im_x)) > FEH_JITTER_OFFSET)
  567                         || (abs(winwid->click_offset_y - (ev->xmotion.y - winwid->im_y)) > FEH_JITTER_OFFSET)
  568                         || (time(NULL) - winwid->click_start_time > FEH_JITTER_TIME)) {
  569                     opt.mode = MODE_PAN;
  570                     winwid->mode = MODE_PAN;
  571                 }
  572                 else
  573                     return;
  574             }
  575             D(("Panning\n"));
  576             orig_x = winwid->im_x;
  577             orig_y = winwid->im_y;
  578 
  579             winwid->im_x = ev->xmotion.x - winwid->click_offset_x;
  580             winwid->im_y = ev->xmotion.y - winwid->click_offset_y;
  581 
  582             winwidget_sanitise_offsets(winwid);
  583 
  584             D(("im_x %d, im_w %d, off %d, mx %d, my %d\n", winwid->im_x,
  585                 winwid->im_w, winwid->click_offset_x, ev->xmotion.x,
  586                 ev->xmotion.y));
  587 
  588             /* XWarpPointer generates a MotionNotify event which we will
  589              * parse. Since that event would undo the effect of the pointer
  590              * warp, we need to change the click_offset to compensate this.
  591              */
  592             if ((winwid->w - ev->xmotion.x <= 1) && (winwid->im_x < 0))
  593             {
  594                 XWarpPointer(disp, None, winwid->win, 0, 0, 0, 0, 3,
  595                     ev->xmotion.y);
  596                 winwid->click_offset_x -= winwid->w - 4;
  597             }
  598             // TODO needlessly warps for certain zoom levels
  599             else if ((ev->xmotion.x <= 1) && (winwid->im_x >
  600                     (winwid->w - winwid->im_w * winwid->zoom)))
  601             {
  602                 XWarpPointer(disp, None, winwid->win, 0, 0, 0, 0,
  603                     winwid->w - 4, ev->xmotion.y);
  604                 winwid->click_offset_x += winwid->w - 4;
  605             }
  606             else if ((winwid->h - ev->xmotion.y <= 1)
  607                     && (winwid->im_y < 0))
  608             {
  609                 XWarpPointer(disp, None, winwid->win, 0, 0, 0, 0,
  610                     ev->xmotion.x, 3);
  611                 winwid->click_offset_y -= winwid->h - 4;
  612             }
  613             // TODO needlessly warps for certain zoomlevels
  614             else if ((ev->xmotion.y <= 1) && (winwid->im_y >
  615                     (winwid->h - winwid->im_h * winwid->zoom)))
  616             {
  617                 XWarpPointer(disp, None, winwid->win, 0, 0, 0, 0,
  618                     ev->xmotion.x, winwid->h - 4);
  619                 winwid->click_offset_y += winwid->h - 4;
  620             }
  621 
  622             if ((winwid->im_x != orig_x)
  623                     || (winwid->im_y != orig_y))
  624                 winwidget_render_image(winwid, 0, 1);
  625         }
  626     } else if (opt.mode == MODE_ROTATE) {
  627         while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev));
  628         winwid = winwidget_get_from_window(ev->xmotion.window);
  629         if (winwid) {
  630             D(("Rotating\n"));
  631             if (!winwid->has_rotated) {
  632                 Imlib_Image temp;
  633 
  634                 temp = gib_imlib_create_rotated_image(winwid->im, 0.0);
  635                 if (temp != NULL) {
  636                     winwid->im_w = gib_imlib_image_get_width(temp);
  637                     winwid->im_h = gib_imlib_image_get_height(temp);
  638                     gib_imlib_free_image_and_decache(temp);
  639                     if (!winwid->full_screen && !opt.geom_flags)
  640                         winwidget_resize(winwid, winwid->im_w, winwid->im_h, 0);
  641                     winwid->has_rotated = 1;
  642                 }
  643             }
  644             winwid->im_angle = (ev->xmotion.x - winwid->w / 2) / ((double) winwid->w / 2) * 3.1415926535;
  645             D(("angle: %f\n", winwid->im_angle));
  646             winwidget_render_image(winwid, 0, 1);
  647         }
  648     } else if (opt.mode == MODE_BLUR) {
  649         while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev));
  650         winwid = winwidget_get_from_window(ev->xmotion.window);
  651         if (winwid) {
  652             Imlib_Image temp, ptr;
  653             signed int blur_radius;
  654 
  655             D(("Blurring\n"));
  656 
  657             temp = gib_imlib_clone_image(winwid->im);
  658             if (temp != NULL) {
  659                 blur_radius = (((double) ev->xmotion.x / winwid->w) * 20) - 10;
  660                 D(("angle: %d\n", blur_radius));
  661                 if (blur_radius > 0)
  662                     gib_imlib_image_sharpen(temp, blur_radius);
  663                 else
  664                     gib_imlib_image_blur(temp, 0 - blur_radius);
  665                 ptr = winwid->im;
  666                 winwid->im = temp;
  667                 winwidget_render_image(winwid, 0, 1);
  668                 gib_imlib_free_image_and_decache(winwid->im);
  669                 winwid->im = ptr;
  670             }
  671         }
  672     } else {
  673         while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev));
  674         winwid = winwidget_get_from_window(ev->xmotion.window);
  675         if ((winwid != NULL) && (winwid->type == WIN_TYPE_THUMBNAIL)) {
  676             feh_thumbnail *thumbnail;
  677             int x, y;
  678 
  679             x = (ev->xbutton.x - winwid->im_x) / winwid->zoom;
  680             y = (ev->xbutton.y - winwid->im_y) / winwid->zoom;
  681             thumbnail = feh_thumbnail_get_thumbnail_from_coords(x, y);
  682             feh_thumbnail_select(winwid, thumbnail);
  683         }
  684     }
  685     return;
  686 }
  687 
  688 static void feh_event_handle_ClientMessage(XEvent * ev)
  689 {
  690     winwidget winwid = NULL;
  691 
  692     if (ev->xclient.format == 32 && ev->xclient.data.l[0] == (signed) wmDeleteWindow) {
  693         winwid = winwidget_get_from_window(ev->xclient.window);
  694         if (winwid)
  695             winwidget_destroy(winwid);
  696     }
  697 
  698     return;
  699 }