A Simple X Image Viewer
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
před 14 roky
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /* sxiv: main.c
  2. * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <dirent.h>
  22. #include <sys/select.h>
  23. #include <sys/stat.h>
  24. #include <sys/time.h>
  25. #include <sys/wait.h>
  26. #include <unistd.h>
  27. #include <X11/Xlib.h>
  28. #include <X11/Xutil.h>
  29. #include <X11/keysym.h>
  30. #include "config.h"
  31. #include "image.h"
  32. #include "options.h"
  33. #include "thumbs.h"
  34. #include "util.h"
  35. #include "window.h"
  36. #ifdef EXT_COMMANDS
  37. #include "commands.h"
  38. #endif
  39. typedef enum {
  40. MODE_NORMAL = 0,
  41. MODE_THUMBS
  42. } appmode_t;
  43. void update_title();
  44. int check_append(const char*);
  45. void read_dir_rec(const char*);
  46. void run();
  47. appmode_t mode;
  48. img_t img;
  49. tns_t tns;
  50. win_t win;
  51. #define DNAME_CNT 512
  52. #define FNAME_CNT 1024
  53. const char **filenames;
  54. int filecnt, fileidx;
  55. size_t filesize;
  56. #define TITLE_LEN 256
  57. char win_title[TITLE_LEN];
  58. void cleanup() {
  59. static int in = 0;
  60. if (!in++) {
  61. img_close(&img, 0);
  62. img_free(&img);
  63. tns_free(&tns, &win);
  64. win_close(&win);
  65. }
  66. }
  67. int load_image(int new) {
  68. struct stat fstats;
  69. if (new >= 0 && new < filecnt) {
  70. img_close(&img, 0);
  71. fileidx = new;
  72. if (!stat(filenames[fileidx], &fstats))
  73. filesize = fstats.st_size;
  74. else
  75. filesize = 0;
  76. return img_load(&img, filenames[fileidx]);
  77. } else {
  78. return 0;
  79. }
  80. }
  81. int main(int argc, char **argv) {
  82. int i;
  83. const char *filename;
  84. struct stat fstats;
  85. parse_options(argc, argv);
  86. if (!options->filecnt) {
  87. print_usage();
  88. exit(1);
  89. }
  90. if (options->recursive || options->from_stdin)
  91. filecnt = FNAME_CNT;
  92. else
  93. filecnt = options->filecnt;
  94. filenames = (const char**) s_malloc(filecnt * sizeof(const char*));
  95. fileidx = 0;
  96. if (options->from_stdin) {
  97. while ((filename = readline(stdin))) {
  98. if (!*filename || !check_append(filename))
  99. free((void*) filename);
  100. }
  101. } else {
  102. for (i = 0; i < options->filecnt; ++i) {
  103. filename = options->filenames[i];
  104. if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
  105. if (options->recursive)
  106. read_dir_rec(filename);
  107. else
  108. warn("ignoring directory: %s", filename);
  109. } else {
  110. check_append(filename);
  111. }
  112. }
  113. }
  114. filecnt = fileidx;
  115. fileidx = 0;
  116. if (!filecnt) {
  117. fprintf(stderr, "sxiv: no valid image filename given, aborting\n");
  118. exit(1);
  119. }
  120. win_open(&win);
  121. img_init(&img, &win);
  122. if (options->thumbnails) {
  123. mode = MODE_THUMBS;
  124. tns_init(&tns, filecnt);
  125. win_clear(&win);
  126. win_draw(&win);
  127. } else {
  128. mode = MODE_NORMAL;
  129. tns.thumbs = NULL;
  130. load_image(fileidx);
  131. img_render(&img, &win);
  132. }
  133. update_title();
  134. run();
  135. cleanup();
  136. return 0;
  137. }
  138. void update_title() {
  139. int n;
  140. float size;
  141. const char *unit;
  142. if (mode == MODE_THUMBS) {
  143. n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] %s",
  144. tns.cnt ? tns.sel + 1 : 0, tns.cnt,
  145. tns.cnt ? filenames[tns.sel] : "");
  146. } else {
  147. if (img.im) {
  148. size = filesize;
  149. size_readable(&size, &unit);
  150. n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] <%d%%> (%.2f%s) %s",
  151. fileidx + 1, filecnt, (int) (img.zoom * 100.0), size, unit,
  152. filenames[fileidx]);
  153. } else {
  154. n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] broken: %s",
  155. fileidx + 1, filecnt, filenames[fileidx]);
  156. }
  157. }
  158. if (n >= TITLE_LEN) {
  159. win_title[TITLE_LEN - 2] = '.';
  160. win_title[TITLE_LEN - 3] = '.';
  161. win_title[TITLE_LEN - 4] = '.';
  162. }
  163. win_set_title(&win, win_title);
  164. }
  165. int check_append(const char *filename) {
  166. if (!filename)
  167. return 0;
  168. if (img_check(filename)) {
  169. if (fileidx == filecnt) {
  170. filecnt *= 2;
  171. filenames = (const char**) s_realloc(filenames,
  172. filecnt * sizeof(const char*));
  173. }
  174. filenames[fileidx++] = filename;
  175. return 1;
  176. } else {
  177. return 0;
  178. }
  179. }
  180. int fncmp(const void *a, const void *b) {
  181. return strcoll(*((char* const*) a), *((char* const*) b));
  182. }
  183. void read_dir_rec(const char *dirname) {
  184. char *filename;
  185. const char **dirnames;
  186. int dircnt, diridx;
  187. int fcnt, fstart;
  188. unsigned char first;
  189. size_t len;
  190. DIR *dir;
  191. struct dirent *dentry;
  192. struct stat fstats;
  193. if (!dirname)
  194. return;
  195. dircnt = DNAME_CNT;
  196. diridx = first = 1;
  197. dirnames = (const char**) s_malloc(dircnt * sizeof(const char*));
  198. dirnames[0] = dirname;
  199. fcnt = 0;
  200. fstart = fileidx;
  201. while (diridx > 0) {
  202. dirname = dirnames[--diridx];
  203. if (!(dir = opendir(dirname))) {
  204. warn("could not open directory: %s", dirname);
  205. } else {
  206. while ((dentry = readdir(dir))) {
  207. if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
  208. continue;
  209. len = strlen(dirname) + strlen(dentry->d_name) + 2;
  210. filename = (char*) s_malloc(len * sizeof(char));
  211. snprintf(filename, len, "%s/%s", dirname, dentry->d_name);
  212. if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
  213. if (diridx == dircnt) {
  214. dircnt *= 2;
  215. dirnames = (const char**) s_realloc(dirnames,
  216. dircnt * sizeof(const char*));
  217. }
  218. dirnames[diridx++] = filename;
  219. } else {
  220. if (check_append(filename))
  221. ++fcnt;
  222. else
  223. free(filename);
  224. }
  225. }
  226. closedir(dir);
  227. }
  228. if (!first)
  229. free((void*) dirname);
  230. else
  231. first = 0;
  232. }
  233. if (fcnt > 1)
  234. qsort(filenames + fstart, fcnt, sizeof(char*), fncmp);
  235. free(dirnames);
  236. }
  237. #ifdef EXT_COMMANDS
  238. int run_command(const char *cline, Bool reload) {
  239. int fncnt, fnlen;
  240. char *cn, *cmdline;
  241. const char *co, *fname;
  242. pid_t pid;
  243. int ret, status;
  244. if (!cline || !*cline)
  245. return 0;
  246. fncnt = 0;
  247. co = cline - 1;
  248. while ((co = strchr(co + 1, '#')))
  249. ++fncnt;
  250. if (!fncnt)
  251. return 0;
  252. ret = 0;
  253. fname = filenames[mode == MODE_NORMAL ? fileidx : tns.sel];
  254. fnlen = strlen(fname);
  255. cn = cmdline = (char*) s_malloc((strlen(cline) + fncnt * (fnlen + 2)) *
  256. sizeof(char));
  257. /* replace all '#' with filename */
  258. for (co = cline; *co; ++co) {
  259. if (*co == '#') {
  260. *cn++ = '"';
  261. strcpy(cn, fname);
  262. cn += fnlen;
  263. *cn++ = '"';
  264. } else {
  265. *cn++ = *co;
  266. }
  267. }
  268. *cn = '\0';
  269. if ((pid = fork()) == 0) {
  270. execlp("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
  271. warn("could not exec: /bin/sh");
  272. exit(1);
  273. } else if (pid < 0) {
  274. warn("could not fork. command line was: %s", cmdline);
  275. } else if (reload) {
  276. waitpid(pid, &status, 0);
  277. if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
  278. ret = 1;
  279. else
  280. warn("child exited with non-zero return value: %d. command line was: %s",
  281. WEXITSTATUS(status), cmdline);
  282. }
  283. free(cmdline);
  284. return ret;
  285. }
  286. #endif /* EXT_COMMANDS */
  287. /* event handling */
  288. #define TO_WIN_RESIZE 75000;
  289. #define TO_IMAGE_DRAG 1000;
  290. #define TO_CURSOR_HIDE 1500000;
  291. #define TO_THUMBS_LOAD 75000;
  292. int timo_cursor;
  293. int timo_redraw;
  294. unsigned char drag;
  295. int mox, moy;
  296. void redraw() {
  297. if (mode == MODE_NORMAL)
  298. img_render(&img, &win);
  299. else
  300. tns_render(&tns, &win);
  301. update_title();
  302. timo_redraw = 0;
  303. }
  304. void on_keypress(XKeyEvent *kev) {
  305. int x, y;
  306. unsigned int w, h;
  307. char key;
  308. KeySym ksym;
  309. int changed;
  310. if (!kev)
  311. return;
  312. XLookupString(kev, &key, 1, &ksym, NULL);
  313. changed = 0;
  314. #ifdef EXT_COMMANDS
  315. /* external commands from commands.h */
  316. if (CLEANMASK(kev->state) & ControlMask) {
  317. for (x = 0; x < LEN(commands); ++x) {
  318. if (commands[x].ksym == ksym) {
  319. win_set_cursor(&win, CURSOR_WATCH);
  320. if (run_command(commands[x].cmdline, commands[x].reload)) {
  321. if (mode == MODE_NORMAL) {
  322. img_close(&img, 1);
  323. load_image(fileidx);
  324. tns_load(&tns, &win, fileidx, filenames[fileidx]);
  325. } else {
  326. tns_load(&tns, &win, tns.sel, filenames[tns.sel]);
  327. }
  328. redraw();
  329. }
  330. win_set_cursor(&win, mode == MODE_NORMAL ? CURSOR_NONE : CURSOR_ARROW);
  331. return;
  332. }
  333. }
  334. }
  335. #endif
  336. if (mode == MODE_NORMAL) {
  337. switch (ksym) {
  338. /* navigate image list */
  339. case XK_n:
  340. case XK_space:
  341. if (fileidx + 1 < filecnt)
  342. changed = load_image(fileidx + 1);
  343. break;
  344. case XK_p:
  345. case XK_BackSpace:
  346. if (fileidx > 0)
  347. changed = load_image(fileidx - 1);
  348. break;
  349. case XK_bracketleft:
  350. if (fileidx != 0)
  351. changed = load_image(MAX(0, fileidx - 10));
  352. break;
  353. case XK_bracketright:
  354. if (fileidx != filecnt - 1)
  355. changed = load_image(MIN(fileidx + 10, filecnt - 1));
  356. break;
  357. case XK_g:
  358. if (fileidx != 0)
  359. changed = load_image(0);
  360. break;
  361. case XK_G:
  362. if (fileidx != filecnt - 1)
  363. changed = load_image(filecnt - 1);
  364. break;
  365. /* zooming */
  366. case XK_plus:
  367. case XK_equal:
  368. changed = img_zoom_in(&img);
  369. break;
  370. case XK_minus:
  371. changed = img_zoom_out(&img);
  372. break;
  373. case XK_0:
  374. changed = img_zoom(&img, 1.0);
  375. break;
  376. case XK_w:
  377. if ((changed = img_fit_win(&img, &win)))
  378. img_center(&img, &win);
  379. break;
  380. /* panning */
  381. case XK_h:
  382. case XK_Left:
  383. changed = img_pan(&img, &win, PAN_LEFT);
  384. break;
  385. case XK_j:
  386. case XK_Down:
  387. changed = img_pan(&img, &win, PAN_DOWN);
  388. break;
  389. case XK_k:
  390. case XK_Up:
  391. changed = img_pan(&img, &win, PAN_UP);
  392. break;
  393. case XK_l:
  394. case XK_Right:
  395. changed = img_pan(&img, &win, PAN_RIGHT);
  396. break;
  397. /* rotation */
  398. case XK_less:
  399. img_rotate_left(&img, &win);
  400. changed = 1;
  401. break;
  402. case XK_greater:
  403. img_rotate_right(&img, &win);
  404. changed = 1;
  405. break;
  406. /* control window */
  407. case XK_W:
  408. x = MAX(0, win.x + img.x);
  409. y = MAX(0, win.y + img.y);
  410. w = img.w * img.zoom;
  411. h = img.h * img.zoom;
  412. if ((changed = win_moveresize(&win, x, y, w, h))) {
  413. img.x = x - win.x;
  414. img.y = y - win.y;
  415. }
  416. break;
  417. /* switch to thumbnail mode */
  418. case XK_Return:
  419. if (!tns.thumbs)
  420. tns_init(&tns, filecnt);
  421. img_close(&img, 0);
  422. mode = MODE_THUMBS;
  423. win_set_cursor(&win, CURSOR_ARROW);
  424. timo_cursor = 0;
  425. tns.sel = fileidx;
  426. changed = tns.dirty = 1;
  427. break;
  428. /* miscellaneous */
  429. case XK_a:
  430. img_toggle_antialias(&img);
  431. changed = 1;
  432. break;
  433. case XK_A:
  434. img.alpha ^= 1;
  435. changed = 1;
  436. break;
  437. case XK_r:
  438. changed = load_image(fileidx);
  439. break;
  440. }
  441. } else {
  442. /* thumbnail mode */
  443. switch (ksym) {
  444. /* open selected image */
  445. case XK_Return:
  446. load_image(tns.sel);
  447. mode = MODE_NORMAL;
  448. win_set_cursor(&win, CURSOR_NONE);
  449. changed = 1;
  450. break;
  451. /* move selection */
  452. case XK_h:
  453. case XK_Left:
  454. changed = tns_move_selection(&tns, &win, TNS_LEFT);
  455. break;
  456. case XK_j:
  457. case XK_Down:
  458. changed = tns_move_selection(&tns, &win, TNS_DOWN);
  459. break;
  460. case XK_k:
  461. case XK_Up:
  462. changed = tns_move_selection(&tns, &win, TNS_UP);
  463. break;
  464. case XK_l:
  465. case XK_Right:
  466. changed = tns_move_selection(&tns, &win, TNS_RIGHT);
  467. break;
  468. case XK_g:
  469. if (tns.sel != 0) {
  470. tns.sel = 0;
  471. changed = tns.dirty = 1;
  472. }
  473. break;
  474. case XK_G:
  475. if (tns.sel != tns.cnt - 1) {
  476. tns.sel = tns.cnt - 1;
  477. changed = tns.dirty = 1;
  478. }
  479. }
  480. }
  481. /* common key mappings */
  482. switch (ksym) {
  483. case XK_Escape:
  484. cleanup();
  485. exit(2);
  486. case XK_q:
  487. cleanup();
  488. exit(0);
  489. case XK_f:
  490. win_toggle_fullscreen(&win);
  491. /* render on next configurenotify */
  492. break;
  493. }
  494. if (changed)
  495. redraw();
  496. }
  497. void on_buttonpress(XButtonEvent *bev) {
  498. int changed, sel;
  499. unsigned int mask;
  500. if (!bev)
  501. return;
  502. mask = CLEANMASK(bev->state);
  503. changed = 0;
  504. if (mode == MODE_NORMAL) {
  505. switch (bev->button) {
  506. case Button1:
  507. if (fileidx + 1 < filecnt)
  508. changed = load_image(fileidx + 1);
  509. break;
  510. case Button2:
  511. mox = bev->x;
  512. moy = bev->y;
  513. win_set_cursor(&win, CURSOR_HAND);
  514. timo_cursor = 0;
  515. drag = 1;
  516. break;
  517. case Button3:
  518. if (fileidx > 0)
  519. changed = load_image(fileidx - 1);
  520. break;
  521. case Button4:
  522. if (mask == ControlMask)
  523. changed = img_zoom_in(&img);
  524. else if (mask == ShiftMask)
  525. changed = img_pan(&img, &win, PAN_LEFT);
  526. else
  527. changed = img_pan(&img, &win, PAN_UP);
  528. break;
  529. case Button5:
  530. if (mask == ControlMask)
  531. changed = img_zoom_out(&img);
  532. else if (mask == ShiftMask)
  533. changed = img_pan(&img, &win, PAN_RIGHT);
  534. else
  535. changed = img_pan(&img, &win, PAN_DOWN);
  536. break;
  537. case 6:
  538. changed = img_pan(&img, &win, PAN_LEFT);
  539. break;
  540. case 7:
  541. changed = img_pan(&img, &win, PAN_RIGHT);
  542. break;
  543. }
  544. } else {
  545. /* thumbnail mode */
  546. switch (bev->button) {
  547. case Button1:
  548. if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) {
  549. if (sel == tns.sel) {
  550. load_image(tns.sel);
  551. mode = MODE_NORMAL;
  552. timo_cursor = TO_CURSOR_HIDE;
  553. } else {
  554. tns_highlight(&tns, &win, tns.sel, False);
  555. tns_highlight(&tns, &win, sel, True);
  556. tns.sel = sel;
  557. }
  558. changed = 1;
  559. break;
  560. }
  561. break;
  562. case Button4:
  563. changed = tns_scroll(&tns, TNS_UP);
  564. break;
  565. case Button5:
  566. changed = tns_scroll(&tns, TNS_DOWN);
  567. break;
  568. }
  569. }
  570. if (changed)
  571. redraw();
  572. }
  573. void on_motionnotify(XMotionEvent *mev) {
  574. if (!mev)
  575. return;
  576. if (mev->x >= 0 && mev->x <= win.w && mev->y >= 0 && mev->y <= win.h) {
  577. if (img_move(&img, &win, mev->x - mox, mev->y - moy))
  578. timo_redraw = TO_IMAGE_DRAG;
  579. mox = mev->x;
  580. moy = mev->y;
  581. }
  582. }
  583. void run() {
  584. int xfd, timeout;
  585. fd_set fds;
  586. struct timeval tt, t0, t1;
  587. XEvent ev;
  588. timo_cursor = timo_redraw = 0;
  589. drag = 0;
  590. if (mode == MODE_NORMAL)
  591. timo_cursor = TO_CURSOR_HIDE;
  592. while (1) {
  593. if (mode == MODE_THUMBS && tns.cnt < filecnt) {
  594. win_set_cursor(&win, CURSOR_WATCH);
  595. gettimeofday(&t0, 0);
  596. while (!XPending(win.env.dpy) && tns.cnt < filecnt) {
  597. /* tns.cnt is increased inside tns_load */
  598. tns_load(&tns, &win, tns.cnt, filenames[tns.cnt]);
  599. gettimeofday(&t1, 0);
  600. if (TV_TO_DOUBLE(t1) - TV_TO_DOUBLE(t0) >= 0.25)
  601. break;
  602. }
  603. if (tns.cnt == filecnt)
  604. win_set_cursor(&win, CURSOR_ARROW);
  605. if (!XPending(win.env.dpy)) {
  606. redraw();
  607. continue;
  608. } else {
  609. timo_redraw = TO_THUMBS_LOAD;
  610. }
  611. } else if (timo_cursor || timo_redraw) {
  612. gettimeofday(&t0, 0);
  613. if (timo_cursor && timo_redraw)
  614. timeout = MIN(timo_cursor, timo_redraw);
  615. else if (timo_cursor)
  616. timeout = timo_cursor;
  617. else
  618. timeout = timo_redraw;
  619. tt.tv_sec = timeout / 1000000;
  620. tt.tv_usec = timeout % 1000000;
  621. xfd = ConnectionNumber(win.env.dpy);
  622. FD_ZERO(&fds);
  623. FD_SET(xfd, &fds);
  624. if (!XPending(win.env.dpy))
  625. select(xfd + 1, &fds, 0, 0, &tt);
  626. gettimeofday(&t1, 0);
  627. timeout = MIN((TV_TO_DOUBLE(t1) - TV_TO_DOUBLE(t0)) * 1000000, timeout);
  628. /* timeouts fired? */
  629. if (timo_cursor) {
  630. timo_cursor = MAX(0, timo_cursor - timeout);
  631. if (!timo_cursor)
  632. win_set_cursor(&win, CURSOR_NONE);
  633. }
  634. if (timo_redraw) {
  635. timo_redraw = MAX(0, timo_redraw - timeout);
  636. if (!timo_redraw)
  637. redraw();
  638. }
  639. if (!XPending(win.env.dpy) && (timo_cursor || timo_redraw))
  640. continue;
  641. }
  642. if (!XNextEvent(win.env.dpy, &ev)) {
  643. switch (ev.type) {
  644. case KeyPress:
  645. on_keypress(&ev.xkey);
  646. break;
  647. case ButtonPress:
  648. on_buttonpress(&ev.xbutton);
  649. break;
  650. case ButtonRelease:
  651. if (ev.xbutton.button == Button2) {
  652. drag = 0;
  653. if (mode == MODE_NORMAL) {
  654. win_set_cursor(&win, CURSOR_ARROW);
  655. timo_cursor = TO_CURSOR_HIDE;
  656. }
  657. }
  658. break;
  659. case MotionNotify:
  660. if (drag) {
  661. on_motionnotify(&ev.xmotion);
  662. } else if (mode == MODE_NORMAL) {
  663. if (!timo_cursor)
  664. win_set_cursor(&win, CURSOR_ARROW);
  665. timo_cursor = TO_CURSOR_HIDE;
  666. }
  667. break;
  668. case ConfigureNotify:
  669. if (win_configure(&win, &ev.xconfigure)) {
  670. timo_redraw = TO_WIN_RESIZE;
  671. if (mode == MODE_NORMAL)
  672. img.checkpan = 1;
  673. else
  674. tns.dirty = 1;
  675. }
  676. break;
  677. case ClientMessage:
  678. if ((Atom) ev.xclient.data.l[0] == wm_delete_win)
  679. return;
  680. break;
  681. }
  682. }
  683. }
  684. }