This makes mouse panning more direct and faster.master
@@ -1,4 +1,4 @@ | |||||
VERSION := git-20170908 | |||||
VERSION := git-20171004 | |||||
all: sxiv | all: sxiv | ||||
@@ -320,72 +320,41 @@ bool ci_scroll_to_edge(arg_t dir) | |||||
return img_pan_edge(&img, dir); | return img_pan_edge(&img, dir); | ||||
} | } | ||||
/* Xlib helper function for i_drag() */ | |||||
Bool is_motionnotify(Display *d, XEvent *e, XPointer a) | |||||
{ | |||||
return e != NULL && e->type == MotionNotify; | |||||
} | |||||
#define WARP(x,y) \ | |||||
XWarpPointer(win.env.dpy, None, win.xwin, 0, 0, 0, 0, x, y); \ | |||||
ox = x, oy = y; \ | |||||
break | |||||
bool ci_drag(arg_t _) | bool ci_drag(arg_t _) | ||||
{ | { | ||||
int dx = 0, dy = 0, i, ox, oy, x, y; | |||||
int i, x, y; | |||||
float px, py; | |||||
unsigned int ui; | unsigned int ui; | ||||
bool dragging = true, next = false; | |||||
XEvent e; | XEvent e; | ||||
Window w; | Window w; | ||||
if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui)) | |||||
if ((int)(img.w * img.zoom) < win.w && (int)(img.h * img.zoom) < win.h) | |||||
return false; | |||||
if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &x, &y, &ui)) | |||||
return false; | return false; | ||||
win_set_cursor(&win, CURSOR_HAND); | |||||
while (dragging) { | |||||
if (!next) | |||||
XMaskEvent(win.env.dpy, | |||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); | |||||
switch (e.type) { | |||||
case ButtonPress: | |||||
case ButtonRelease: | |||||
dragging = false; | |||||
break; | |||||
case MotionNotify: | |||||
x = e.xmotion.x; | |||||
y = e.xmotion.y; | |||||
/* wrap the mouse around */ | |||||
if (x <= 0) { | |||||
WARP(win.w - 2, y); | |||||
} else if (x >= win.w - 1) { | |||||
WARP(1, y); | |||||
} else if (y <= 0) { | |||||
WARP(x, win.h - 2); | |||||
} else if (y >= win.h - 1) { | |||||
WARP(x, 1); | |||||
} | |||||
dx += x - ox; | |||||
dy += y - oy; | |||||
ox = x; | |||||
oy = y; | |||||
break; | |||||
} | |||||
if (dragging) | |||||
next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None); | |||||
if ((!dragging || !next) && (dx != 0 || dy != 0)) { | |||||
if (img_move(&img, dx, dy)) { | |||||
img_render(&img); | |||||
win_draw(&win); | |||||
} | |||||
dx = dy = 0; | |||||
win_set_cursor(&win, CURSOR_DRAG); | |||||
for (;;) { | |||||
px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8) | |||||
* (win.w - img.w * img.zoom); | |||||
py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8) | |||||
* (win.h - img.h * img.zoom); | |||||
if (img_pos(&img, px, py)) { | |||||
img_render(&img); | |||||
win_draw(&win); | |||||
} | } | ||||
XMaskEvent(win.env.dpy, | |||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); | |||||
if (e.type == ButtonPress || e.type == ButtonRelease) | |||||
break; | |||||
while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e)); | |||||
x = e.xmotion.x; | |||||
y = e.xmotion.y; | |||||
} | } | ||||
win_set_cursor(&win, CURSOR_ARROW); | win_set_cursor(&win, CURSOR_ARROW); | ||||
set_timeout(reset_cursor, TO_CURSOR_HIDE, true); | set_timeout(reset_cursor, TO_CURSOR_HIDE, true); | ||||
reset_timeout(redraw); | |||||
return true; | return true; | ||||
} | } | ||||
@@ -567,15 +567,15 @@ bool img_zoom_out(img_t *img) | |||||
return false; | return false; | ||||
} | } | ||||
bool img_move(img_t *img, float dx, float dy) | |||||
bool img_pos(img_t *img, float x, float y) | |||||
{ | { | ||||
float ox, oy; | float ox, oy; | ||||
ox = img->x; | ox = img->x; | ||||
oy = img->y; | oy = img->y; | ||||
img->x += dx; | |||||
img->y += dy; | |||||
img->x = x; | |||||
img->y = y; | |||||
img_check_pan(img, true); | img_check_pan(img, true); | ||||
@@ -587,6 +587,11 @@ bool img_move(img_t *img, float dx, float dy) | |||||
} | } | ||||
} | } | ||||
bool img_move(img_t *img, float dx, float dy) | |||||
{ | |||||
return img_pos(img, img->x + dx, img->y + dy); | |||||
} | |||||
bool img_pan(img_t *img, direction_t dir, int d) | bool img_pan(img_t *img, direction_t dir, int d) | ||||
{ | { | ||||
/* d < 0: screen-wise | /* d < 0: screen-wise | ||||
@@ -80,6 +80,7 @@ bool img_zoom(img_t*, float); | |||||
bool img_zoom_in(img_t*); | bool img_zoom_in(img_t*); | ||||
bool img_zoom_out(img_t*); | bool img_zoom_out(img_t*); | ||||
bool img_pos(img_t*, float, float); | |||||
bool img_move(img_t*, float, float); | bool img_move(img_t*, float, float); | ||||
bool img_pan(img_t*, direction_t, int); | bool img_pan(img_t*, direction_t, int); | ||||
bool img_pan_edge(img_t*, direction_t); | bool img_pan_edge(img_t*, direction_t); | ||||
@@ -741,6 +741,7 @@ void run(void) | |||||
XPeekEvent(win.env.dpy, &nextev); | XPeekEvent(win.env.dpy, &nextev); | ||||
switch (ev.type) { | switch (ev.type) { | ||||
case ConfigureNotify: | case ConfigureNotify: | ||||
case MotionNotify: | |||||
discard = ev.type == nextev.type; | discard = ev.type == nextev.type; | ||||
break; | break; | ||||
case KeyPress: | case KeyPress: | ||||
@@ -66,7 +66,7 @@ typedef enum { | |||||
typedef enum { | typedef enum { | ||||
CURSOR_ARROW, | CURSOR_ARROW, | ||||
CURSOR_NONE, | CURSOR_NONE, | ||||
CURSOR_HAND, | |||||
CURSOR_DRAG, | |||||
CURSOR_WATCH | CURSOR_WATCH | ||||
} cursor_t; | } cursor_t; | ||||
@@ -37,7 +37,7 @@ enum { | |||||
static Cursor carrow; | static Cursor carrow; | ||||
static Cursor cnone; | static Cursor cnone; | ||||
static Cursor chand; | |||||
static Cursor cdrag; | |||||
static Cursor cwatch; | static Cursor cwatch; | ||||
static GC gc; | static GC gc; | ||||
@@ -210,7 +210,7 @@ void win_open(win_t *win) | |||||
PointerMotionMask | StructureNotifyMask); | PointerMotionMask | StructureNotifyMask); | ||||
carrow = XCreateFontCursor(e->dpy, XC_left_ptr); | carrow = XCreateFontCursor(e->dpy, XC_left_ptr); | ||||
chand = XCreateFontCursor(e->dpy, XC_fleur); | |||||
cdrag = XCreateFontCursor(e->dpy, XC_dotbox); | |||||
cwatch = XCreateFontCursor(e->dpy, XC_watch); | cwatch = XCreateFontCursor(e->dpy, XC_watch); | ||||
if (XAllocNamedColor(e->dpy, DefaultColormap(e->dpy, e->scr), "black", | if (XAllocNamedColor(e->dpy, DefaultColormap(e->dpy, e->scr), "black", | ||||
@@ -277,7 +277,7 @@ CLEANUP void win_close(win_t *win) | |||||
{ | { | ||||
XFreeCursor(win->env.dpy, carrow); | XFreeCursor(win->env.dpy, carrow); | ||||
XFreeCursor(win->env.dpy, cnone); | XFreeCursor(win->env.dpy, cnone); | ||||
XFreeCursor(win->env.dpy, chand); | |||||
XFreeCursor(win->env.dpy, cdrag); | |||||
XFreeCursor(win->env.dpy, cwatch); | XFreeCursor(win->env.dpy, cwatch); | ||||
XFreeGC(win->env.dpy, gc); | XFreeGC(win->env.dpy, gc); | ||||
@@ -465,8 +465,8 @@ void win_set_cursor(win_t *win, cursor_t cursor) | |||||
case CURSOR_NONE: | case CURSOR_NONE: | ||||
XDefineCursor(win->env.dpy, win->xwin, cnone); | XDefineCursor(win->env.dpy, win->xwin, cnone); | ||||
break; | break; | ||||
case CURSOR_HAND: | |||||
XDefineCursor(win->env.dpy, win->xwin, chand); | |||||
case CURSOR_DRAG: | |||||
XDefineCursor(win->env.dpy, win->xwin, cdrag); | |||||
break; | break; | ||||
case CURSOR_WATCH: | case CURSOR_WATCH: | ||||
XDefineCursor(win->env.dpy, win->xwin, cwatch); | XDefineCursor(win->env.dpy, win->xwin, cwatch); | ||||