This makes mouse panning more direct and faster.master
@@ -1,4 +1,4 @@ | |||
VERSION := git-20170908 | |||
VERSION := git-20171004 | |||
all: sxiv | |||
@@ -320,72 +320,41 @@ bool ci_scroll_to_edge(arg_t 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 _) | |||
{ | |||
int dx = 0, dy = 0, i, ox, oy, x, y; | |||
int i, x, y; | |||
float px, py; | |||
unsigned int ui; | |||
bool dragging = true, next = false; | |||
XEvent e; | |||
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; | |||
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); | |||
set_timeout(reset_cursor, TO_CURSOR_HIDE, true); | |||
reset_timeout(redraw); | |||
return true; | |||
} | |||
@@ -567,15 +567,15 @@ bool img_zoom_out(img_t *img) | |||
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; | |||
ox = img->x; | |||
oy = img->y; | |||
img->x += dx; | |||
img->y += dy; | |||
img->x = x; | |||
img->y = y; | |||
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) | |||
{ | |||
/* d < 0: screen-wise | |||
@@ -80,6 +80,7 @@ bool img_zoom(img_t*, float); | |||
bool img_zoom_in(img_t*); | |||
bool img_zoom_out(img_t*); | |||
bool img_pos(img_t*, float, float); | |||
bool img_move(img_t*, float, float); | |||
bool img_pan(img_t*, direction_t, int); | |||
bool img_pan_edge(img_t*, direction_t); | |||
@@ -741,6 +741,7 @@ void run(void) | |||
XPeekEvent(win.env.dpy, &nextev); | |||
switch (ev.type) { | |||
case ConfigureNotify: | |||
case MotionNotify: | |||
discard = ev.type == nextev.type; | |||
break; | |||
case KeyPress: | |||
@@ -66,7 +66,7 @@ typedef enum { | |||
typedef enum { | |||
CURSOR_ARROW, | |||
CURSOR_NONE, | |||
CURSOR_HAND, | |||
CURSOR_DRAG, | |||
CURSOR_WATCH | |||
} cursor_t; | |||
@@ -37,7 +37,7 @@ enum { | |||
static Cursor carrow; | |||
static Cursor cnone; | |||
static Cursor chand; | |||
static Cursor cdrag; | |||
static Cursor cwatch; | |||
static GC gc; | |||
@@ -210,7 +210,7 @@ void win_open(win_t *win) | |||
PointerMotionMask | StructureNotifyMask); | |||
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); | |||
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, cnone); | |||
XFreeCursor(win->env.dpy, chand); | |||
XFreeCursor(win->env.dpy, cdrag); | |||
XFreeCursor(win->env.dpy, cwatch); | |||
XFreeGC(win->env.dpy, gc); | |||
@@ -465,8 +465,8 @@ void win_set_cursor(win_t *win, cursor_t cursor) | |||
case CURSOR_NONE: | |||
XDefineCursor(win->env.dpy, win->xwin, cnone); | |||
break; | |||
case CURSOR_HAND: | |||
XDefineCursor(win->env.dpy, win->xwin, chand); | |||
case CURSOR_DRAG: | |||
XDefineCursor(win->env.dpy, win->xwin, cdrag); | |||
break; | |||
case CURSOR_WATCH: | |||
XDefineCursor(win->env.dpy, win->xwin, cwatch); | |||