feh_menu *feh_menu_new(void) { feh_menu *m; XSetWindowAttributes attr; feh_menu_list *l; static Imlib_Image bg = NULL; static Imlib_Border border; m = (feh_menu *) emalloc(sizeof(feh_menu)); attr.backing_store = NotUseful; attr.override_redirect = True; attr.colormap = cm; attr.border_pixel = 0; attr.background_pixmap = None; attr.save_under = False; attr.do_not_propagate_mask = True; m->win = XCreateWindow( disp, root, 1, 1, 1, 1, 0, depth, InputOutput, vis, CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWColormap | CWBackPixmap | CWBorderPixel | CWDontPropagate, &attr); XSelectInput(disp, m->win, ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask); m->name = NULL; m->fehwin = NULL; m->pmap = 0; m->x = 0; m->y = 0; m->w = 0; m->h = 0; m->visible = 0; m->items = NULL; m->next = NULL; m->prev = NULL; m->updates = NULL; m->needs_redraw = 1; m->func_free = NULL; m->data = NULL; m->calc = 0; m->bg = NULL; l = emalloc(sizeof(feh_menu_list)); l->menu = m; l->next = menus; menus = l; if (!bg) { feh_load_image_char(&bg, opt.menu_bg); if (bg) { border.left = border.right = border.top = border.bottom = 4; imlib_context_set_image(bg); imlib_image_set_border(&border); } } if (bg) m->bg = gib_imlib_clone_image(bg); return(m); }
static void feh_event_handle_MotionNotify(XEvent * ev) { winwidget winwid = NULL; int dx, dy; int scr_width, scr_height; scr_width = scr->width; scr_height = scr->height; #ifdef HAVE_LIBXINERAMA if (opt.xinerama && xinerama_screens) { scr_width = xinerama_screens[xinerama_screen].width; scr_height = xinerama_screens[xinerama_screen].height; } #endif /* HAVE_LIBXINERAMA */ if (menu_root) { feh_menu *m; feh_menu_item *selected_item, *mouseover_item; D(("motion notify with menus open\n")); while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev)); if (ev->xmotion.window == menu_cover) { return; } else if ((m = feh_menu_get_from_window(ev->xmotion.window))) { selected_item = feh_menu_find_selected(m); mouseover_item = feh_menu_find_at_xy(m, ev->xmotion.x, ev->xmotion.y); if (selected_item != mouseover_item) { D(("selecting a menu item\n")); if (selected_item) feh_menu_deselect_selected(m); if ((mouseover_item) && ((mouseover_item->action) || (mouseover_item->submenu) || (mouseover_item->func_gen_sub))) feh_menu_select(m, mouseover_item); } /* check if we are close to the right and/or the bottom edge of the * screen. If so, and if the menu we are currently over is partially * hidden, slide the menu to the left and/or up until it is * fully visible */ /* FIXME: get this working nicely with xinerama screen edges -- * at the moment it does really funky stuff with * scr_{width,height} instead of scr->{width,height} -- pabs*/ if (mouseover_item && ((scr->width - (ev->xmotion.x + m->x)) < m->w || (scr->height - (ev->xmotion.y + m->y)) < m->w)) { dx = scr_width - (m->x + m->w); dy = scr_height - (m->y + m->h); dx = dx < 0 ? dx : 0; dy = dy < 0 ? dy : 0; if (dx || dy) feh_menu_slide_all_menus_relative(dx, dy); } /* if a submenu is open we want to see that also */ if (mouseover_item && m->next && ((scr->width - (ev->xmotion.x + m->next->x)) < m->next->w || (scr->height - (ev->xmotion.y + m->next->y)) < m->next->w)) { dx = scr->width - (m->next->x + m->next->w); dy = scr->height - (m->next->y + m->next->h); dx = dx < 0 ? dx : 0; dy = dy < 0 ? dy : 0; if (dx || dy) feh_menu_slide_all_menus_relative(dx, dy); } } } else if (opt.mode == MODE_ZOOM) { while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev)); winwid = winwidget_get_from_window(ev->xmotion.window); if (winwid) { if (ev->xmotion.x > winwid->click_offset_x) winwid->zoom = winwid->old_zoom + ( ((double) ev->xmotion.x - (double) winwid->click_offset_x) / 128.0); else winwid->zoom = winwid->old_zoom - ( ((double) winwid->click_offset_x - (double) ev->xmotion.x) / 128.0); if (winwid->zoom < ZOOM_MIN) winwid->zoom = ZOOM_MIN; else if (winwid->zoom > ZOOM_MAX) winwid->zoom = ZOOM_MAX; /* center around click_offset */ winwid->im_x = winwid->click_offset_x - (winwid->im_click_offset_x * winwid->zoom); winwid->im_y = winwid->click_offset_y - (winwid->im_click_offset_y * winwid->zoom); winwidget_render_image(winwid, 0, 1); } } else if ((opt.mode == MODE_PAN) || (opt.mode == MODE_NEXT)) { int orig_x, orig_y; while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev)); winwid = winwidget_get_from_window(ev->xmotion.window); if (winwid) { if (opt.mode == MODE_NEXT) { if ((abs(winwid->click_offset_x - (ev->xmotion.x - winwid->im_x)) > FEH_JITTER_OFFSET) || (abs(winwid->click_offset_y - (ev->xmotion.y - winwid->im_y)) > FEH_JITTER_OFFSET) || (time(NULL) - winwid->click_start_time > FEH_JITTER_TIME)) { opt.mode = MODE_PAN; winwid->mode = MODE_PAN; } else return; } D(("Panning\n")); orig_x = winwid->im_x; orig_y = winwid->im_y; winwid->im_x = ev->xmotion.x - winwid->click_offset_x; winwid->im_y = ev->xmotion.y - winwid->click_offset_y; winwidget_sanitise_offsets(winwid); D(("im_x %d, im_w %d, off %d, mx %d, my %d\n", winwid->im_x, winwid->im_w, winwid->click_offset_x, ev->xmotion.x, ev->xmotion.y)); /* XWarpPointer generates a MotionNotify event which we will * parse. Since that event would undo the effect of the pointer * warp, we need to change the click_offset to compensate this. */ if ((winwid->w - ev->xmotion.x <= 1) && (winwid->im_x < 0)) { XWarpPointer(disp, None, winwid->win, 0, 0, 0, 0, 3, ev->xmotion.y); winwid->click_offset_x -= winwid->w - 4; } // TODO needlessly warps for certain zoom levels else if ((ev->xmotion.x <= 1) && (winwid->im_x > (winwid->w - winwid->im_w * winwid->zoom))) { XWarpPointer(disp, None, winwid->win, 0, 0, 0, 0, winwid->w - 4, ev->xmotion.y); winwid->click_offset_x += winwid->w - 4; } else if ((winwid->h - ev->xmotion.y <= 1) && (winwid->im_y < 0)) { XWarpPointer(disp, None, winwid->win, 0, 0, 0, 0, ev->xmotion.x, 3); winwid->click_offset_y -= winwid->h - 4; } // TODO needlessly warps for certain zoomlevels else if ((ev->xmotion.y <= 1) && (winwid->im_y > (winwid->h - winwid->im_h * winwid->zoom))) { XWarpPointer(disp, None, winwid->win, 0, 0, 0, 0, ev->xmotion.x, winwid->h - 4); winwid->click_offset_y += winwid->h - 4; } if ((winwid->im_x != orig_x) || (winwid->im_y != orig_y)) winwidget_render_image(winwid, 0, 1); } } else if (opt.mode == MODE_ROTATE) { while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev)); winwid = winwidget_get_from_window(ev->xmotion.window); if (winwid) { D(("Rotating\n")); if (!winwid->has_rotated) { Imlib_Image temp; temp = gib_imlib_create_rotated_image(winwid->im, 0.0); winwid->im_w = gib_imlib_image_get_width(temp); winwid->im_h = gib_imlib_image_get_height(temp); gib_imlib_free_image_and_decache(temp); if (!winwid->full_screen && !opt.geom_flags) winwidget_resize(winwid, winwid->im_w, winwid->im_h); winwid->has_rotated = 1; } winwid->im_angle = (ev->xmotion.x - winwid->w / 2) / ((double) winwid->w / 2) * 3.1415926535; D(("angle: %f\n", winwid->im_angle)); winwidget_render_image(winwid, 0, 1); } } else if (opt.mode == MODE_BLUR) { while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev)); winwid = winwidget_get_from_window(ev->xmotion.window); if (winwid) { Imlib_Image temp, ptr; signed int blur_radius; D(("Blurring\n")); temp = gib_imlib_clone_image(winwid->im); blur_radius = (((double) ev->xmotion.x / winwid->w) * 20) - 10; D(("angle: %d\n", blur_radius)); if (blur_radius > 0) gib_imlib_image_sharpen(temp, blur_radius); else gib_imlib_image_blur(temp, 0 - blur_radius); ptr = winwid->im; winwid->im = temp; winwidget_render_image(winwid, 0, 1); gib_imlib_free_image_and_decache(winwid->im); winwid->im = ptr; } } else { while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev)); winwid = winwidget_get_from_window(ev->xmotion.window); if ((winwid != NULL) && (winwid->type == WIN_TYPE_THUMBNAIL)) { feh_thumbnail *thumbnail; int x, y; x = (ev->xbutton.x - winwid->im_x) / winwid->zoom; y = (ev->xbutton.y - winwid->im_y) / winwid->zoom; thumbnail = feh_thumbnail_get_thumbnail_from_coords(x, y); feh_thumbnail_select(winwid, thumbnail); } } return; }