nsxivc52c4fa
Mouse-panning while pressing button2
+94 −16
6 files changed
- M Makefile +1 −1
- M image.c +18 −12
- M image.h +1 −0
- M main.c +37 −0
- M window.c +30 −3
- M window.h +7 −0
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | all: sxiv | |
| 2 | 2 | ||
| 3 | − | VERSION=0.3 | |
| 3 | + | VERSION=git-20110129 | |
| 4 | 4 | ||
| 5 | 5 | CC?=gcc | |
| 6 | 6 | PREFIX?=/usr/local | |
| @@ -230,7 +230,7 @@ int img_zoom_out(img_t *img) { | |||
| 230 | 230 | return 0; | |
| 231 | 231 | } | |
| 232 | 232 | ||
| 233 | − | int img_pan(img_t *img, win_t *win, pandir_t dir) { | |
| 233 | + | int img_move(img_t *img, win_t *win, int dx, int dy) { | |
| 234 | 234 | int ox, oy; | |
| 235 | 235 | ||
| 236 | 236 | if (!img || !win) | |
| @@ -239,24 +239,30 @@ int img_pan(img_t *img, win_t *win, pandir_t dir) { | |||
| 239 | 239 | ox = img->x; | |
| 240 | 240 | oy = img->y; | |
| 241 | 241 | ||
| 242 | + | img->x += dx; | |
| 243 | + | img->y += dy; | |
| 244 | + | ||
| 245 | + | img_check_pan(img, win); | |
| 246 | + | ||
| 247 | + | return ox != img->x || oy != img->y; | |
| 248 | + | } | |
| 249 | + | ||
| 250 | + | int img_pan(img_t *img, win_t *win, pandir_t dir) { | |
| 251 | + | if (!img || !win) | |
| 252 | + | return 0; | |
| 253 | + | ||
| 242 | 254 | switch (dir) { | |
| 243 | 255 | case PAN_LEFT: | |
| 244 | − | img->x += win->w / 5; | |
| 245 | − | break; | |
| 256 | + | return img_move(img, win, win->w / 5, 0); | |
| 246 | 257 | case PAN_RIGHT: | |
| 247 | − | img->x -= win->w / 5; | |
| 248 | − | break; | |
| 258 | + | return img_move(img, win, -win->w / 5, 0); | |
| 249 | 259 | case PAN_UP: | |
| 250 | − | img->y += win->h / 5; | |
| 251 | − | break; | |
| 260 | + | return img_move(img, win, 0, win->h / 5); | |
| 252 | 261 | case PAN_DOWN: | |
| 253 | − | img->y -= win->h / 5; | |
| 254 | − | break; | |
| 262 | + | return img_move(img, win, 0, -win->h / 5); | |
| 255 | 263 | } | |
| 256 | 264 | ||
| 257 | − | img_check_pan(img, win); | |
| 258 | − | ||
| 259 | − | return ox != img->x || oy != img->y; | |
| 265 | + | return 0; | |
| 260 | 266 | } | |
| 261 | 267 | ||
| 262 | 268 | int img_rotate(img_t *img, win_t *win, int d) { | |
| @@ -58,6 +58,7 @@ void img_center(img_t*, win_t*); | |||
| 58 | 58 | int img_zoom_in(img_t*); | |
| 59 | 59 | int img_zoom_out(img_t*); | |
| 60 | 60 | ||
| 61 | + | int img_move(img_t*, win_t*, int, int); | |
| 61 | 62 | int img_pan(img_t*, win_t*, pandir_t); | |
| 62 | 63 | ||
| 63 | 64 | int img_rotate_left(img_t*, win_t*); | |
| @@ -31,6 +31,8 @@ | |||
| 31 | 31 | ||
| 32 | 32 | void on_keypress(XEvent*); | |
| 33 | 33 | void on_buttonpress(XEvent*); | |
| 34 | + | void on_buttonrelease(XEvent*); | |
| 35 | + | void on_motionnotify(XEvent*); | |
| 34 | 36 | void on_configurenotify(XEvent*); | |
| 35 | 37 | ||
| 36 | 38 | void update_title(); | |
| @@ -38,6 +40,8 @@ void update_title(); | |||
| 38 | 40 | static void (*handler[LASTEvent])(XEvent*) = { | |
| 39 | 41 | [KeyPress] = on_keypress, | |
| 40 | 42 | [ButtonPress] = on_buttonpress, | |
| 43 | + | [ButtonRelease] = on_buttonrelease, | |
| 44 | + | [MotionNotify] = on_motionnotify, | |
| 41 | 45 | [ConfigureNotify] = on_configurenotify | |
| 42 | 46 | }; | |
| 43 | 47 | ||
| @@ -49,6 +53,9 @@ int filecnt, fileidx; | |||
| 49 | 53 | ||
| 50 | 54 | unsigned char timeout; | |
| 51 | 55 | ||
| 56 | + | int mox; | |
| 57 | + | int moy; | |
| 58 | + | ||
| 52 | 59 | #define TITLE_LEN 256 | |
| 53 | 60 | char win_title[TITLE_LEN]; | |
| 54 | 61 | ||
| @@ -276,6 +283,11 @@ void on_buttonpress(XEvent *ev) { | |||
| 276 | 283 | changed = 1; | |
| 277 | 284 | } | |
| 278 | 285 | break; | |
| 286 | + | case Button2: | |
| 287 | + | mox = ev->xbutton.x; | |
| 288 | + | moy = ev->xbutton.y; | |
| 289 | + | win_set_cursor(&win, CURSOR_HAND); | |
| 290 | + | break; | |
| 279 | 291 | case Button3: | |
| 280 | 292 | if (fileidx > 0) { | |
| 281 | 293 | img_load(&img, filenames[--fileidx]); | |
| @@ -313,6 +325,31 @@ void on_buttonpress(XEvent *ev) { | |||
| 313 | 325 | } | |
| 314 | 326 | } | |
| 315 | 327 | ||
| 328 | + | void on_buttonrelease(XEvent *ev) { | |
| 329 | + | if (!ev) | |
| 330 | + | return; | |
| 331 | + | ||
| 332 | + | if (ev->xbutton.button == Button2) | |
| 333 | + | win_set_cursor(&win, CURSOR_ARROW); | |
| 334 | + | } | |
| 335 | + | ||
| 336 | + | void on_motionnotify(XEvent *ev) { | |
| 337 | + | XMotionEvent *m; | |
| 338 | + | ||
| 339 | + | if (!ev) | |
| 340 | + | return; | |
| 341 | + | ||
| 342 | + | m = &ev->xmotion; | |
| 343 | + | ||
| 344 | + | if (m->x >= 0 && m->x <= win.w && m->y >= 0 && m->y <= win.h) { | |
| 345 | + | if (img_move(&img, &win, m->x - mox, m->y - moy)) | |
| 346 | + | timeout = 1; | |
| 347 | + | ||
| 348 | + | mox = m->x; | |
| 349 | + | moy = m->y; | |
| 350 | + | } | |
| 351 | + | } | |
| 352 | + | ||
| 316 | 353 | void on_configurenotify(XEvent *ev) { | |
| 317 | 354 | if (!ev) | |
| 318 | 355 | return; | |
| @@ -21,12 +21,16 @@ | |||
| 21 | 21 | #include <string.h> | |
| 22 | 22 | ||
| 23 | 23 | #include <X11/Xutil.h> | |
| 24 | + | #include <X11/cursorfont.h> | |
| 24 | 25 | ||
| 25 | 26 | #include "sxiv.h" | |
| 26 | 27 | #include "options.h" | |
| 27 | 28 | #include "window.h" | |
| 28 | 29 | ||
| 29 | − | GC bgc; | |
| 30 | + | static Cursor arrow; | |
| 31 | + | static Cursor hand; | |
| 32 | + | ||
| 33 | + | static GC bgc; | |
| 30 | 34 | ||
| 31 | 35 | void win_open(win_t *win) { | |
| 32 | 36 | win_env_t *e; | |
| @@ -66,8 +70,11 @@ void win_open(win_t *win) { | |||
| 66 | 70 | if (win->xwin == None) | |
| 67 | 71 | DIE("could not create window"); | |
| 68 | 72 | ||
| 69 | − | XSelectInput(e->dpy, win->xwin, | |
| 70 | − | StructureNotifyMask | KeyPressMask | ButtonPressMask); | |
| 73 | + | XSelectInput(e->dpy, win->xwin, StructureNotifyMask | KeyPressMask | | |
| 74 | + | ButtonPressMask | ButtonReleaseMask | Button2MotionMask); | |
| 75 | + | ||
| 76 | + | arrow = XCreateFontCursor(e->dpy, XC_left_ptr); | |
| 77 | + | hand = XCreateFontCursor(e->dpy, XC_fleur); | |
| 71 | 78 | ||
| 72 | 79 | bgc = XCreateGC(e->dpy, win->xwin, 0, None); | |
| 73 | 80 | ||
| @@ -91,6 +98,11 @@ void win_close(win_t *win) { | |||
| 91 | 98 | if (!win) | |
| 92 | 99 | return; | |
| 93 | 100 | ||
| 101 | + | XFreeCursor(win->env.dpy, arrow); | |
| 102 | + | XFreeCursor(win->env.dpy, hand); | |
| 103 | + | ||
| 104 | + | XFreeGC(win->env.dpy, bgc); | |
| 105 | + | ||
| 94 | 106 | XDestroyWindow(win->env.dpy, win->xwin); | |
| 95 | 107 | XCloseDisplay(win->env.dpy); | |
| 96 | 108 | } | |
| @@ -174,3 +186,18 @@ void win_draw(win_t *win) { | |||
| 174 | 186 | XSetWindowBackgroundPixmap(win->env.dpy, win->xwin, win->pm); | |
| 175 | 187 | XClearWindow(win->env.dpy, win->xwin); | |
| 176 | 188 | } | |
| 189 | + | ||
| 190 | + | void win_set_cursor(win_t *win, win_cur_t cursor) { | |
| 191 | + | if (!win) | |
| 192 | + | return; | |
| 193 | + | ||
| 194 | + | switch (cursor) { | |
| 195 | + | case CURSOR_HAND: | |
| 196 | + | XDefineCursor(win->env.dpy, win->xwin, hand); | |
| 197 | + | break; | |
| 198 | + | case CURSOR_ARROW: | |
| 199 | + | default: | |
| 200 | + | XDefineCursor(win->env.dpy, win->xwin, arrow); | |
| 201 | + | break; | |
| 202 | + | } | |
| 203 | + | } | |
| @@ -23,6 +23,11 @@ | |||
| 23 | 23 | ||
| 24 | 24 | #define CLEANMASK(mask) ((mask) & ~LockMask) | |
| 25 | 25 | ||
| 26 | + | typedef enum win_cur_e { | |
| 27 | + | CURSOR_ARROW = 0, | |
| 28 | + | CURSOR_HAND | |
| 29 | + | } win_cur_t; | |
| 30 | + | ||
| 26 | 31 | typedef struct win_env_s { | |
| 27 | 32 | Display *dpy; | |
| 28 | 33 | int scr; | |
| @@ -59,4 +64,6 @@ void win_toggle_fullscreen(win_t*); | |||
| 59 | 64 | void win_clear(win_t*); | |
| 60 | 65 | void win_draw(win_t*); | |
| 61 | 66 | ||
| 67 | + | void win_set_cursor(win_t*, win_cur_t); | |
| 68 | + | ||
| 62 | 69 | #endif /* WINDOW_H */ | |