A Simple X Image Viewer
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
12 лет назад
12 лет назад
12 лет назад
13 лет назад
13 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /* Copyright 2011, 2012 Bert Muennich
  2. *
  3. * This file is part of sxiv.
  4. *
  5. * sxiv is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published
  7. * by the Free Software Foundation; either version 2 of the License,
  8. * or (at your option) any later version.
  9. *
  10. * sxiv is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #define _POSIX_C_SOURCE 200112L
  19. #define _IMAGE_CONFIG
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <sys/wait.h>
  24. #include "commands.h"
  25. #include "image.h"
  26. #include "options.h"
  27. #include "thumbs.h"
  28. #include "util.h"
  29. #include "config.h"
  30. void cleanup(void);
  31. void remove_file(int, bool);
  32. void load_image(int);
  33. void open_info(void);
  34. void redraw(void);
  35. void reset_cursor(void);
  36. void animate(void);
  37. void slideshow(void);
  38. void set_timeout(timeout_f, int, bool);
  39. void reset_timeout(timeout_f);
  40. extern appmode_t mode;
  41. extern img_t img;
  42. extern tns_t tns;
  43. extern win_t win;
  44. extern fileinfo_t *files;
  45. extern int filecnt, fileidx;
  46. extern int alternate;
  47. extern int prefix;
  48. const int ss_delays[] = {
  49. 1, 2, 3, 5, 10, 15, 20, 30, 60, 120, 180, 300, 600
  50. };
  51. cmdreturn_t it_quit(arg_t a)
  52. {
  53. unsigned int i;
  54. if (options->to_stdout) {
  55. for (i = 0; i < filecnt; i++) {
  56. if (files[i].marked)
  57. printf("%s\n", files[i].name);
  58. }
  59. }
  60. cleanup();
  61. exit(EXIT_SUCCESS);
  62. }
  63. cmdreturn_t it_switch_mode(arg_t a)
  64. {
  65. if (mode == MODE_IMAGE) {
  66. if (tns.thumbs == NULL) {
  67. tns_init(&tns, filecnt, &win);
  68. tns.alpha = img.alpha;
  69. }
  70. img_close(&img, false);
  71. reset_timeout(reset_cursor);
  72. if (img.ss.on) {
  73. img.ss.on = false;
  74. reset_timeout(slideshow);
  75. }
  76. tns.sel = fileidx;
  77. tns.dirty = true;
  78. mode = MODE_THUMB;
  79. } else {
  80. load_image(tns.sel);
  81. mode = MODE_IMAGE;
  82. }
  83. return CMD_DIRTY;
  84. }
  85. cmdreturn_t it_toggle_fullscreen(arg_t a)
  86. {
  87. win_toggle_fullscreen(&win);
  88. /* redraw after next ConfigureNotify event */
  89. set_timeout(redraw, TO_REDRAW_RESIZE, false);
  90. if (mode == MODE_IMAGE)
  91. img.checkpan = img.dirty = true;
  92. else
  93. tns.dirty = true;
  94. return CMD_OK;
  95. }
  96. cmdreturn_t it_toggle_bar(arg_t a)
  97. {
  98. win_toggle_bar(&win);
  99. if (mode == MODE_IMAGE) {
  100. img.checkpan = img.dirty = true;
  101. if (win.bar.h > 0)
  102. open_info();
  103. } else {
  104. tns.dirty = true;
  105. }
  106. return CMD_DIRTY;
  107. }
  108. cmdreturn_t t_reload_all(arg_t a)
  109. {
  110. if (mode == MODE_THUMB) {
  111. tns_free(&tns);
  112. tns_init(&tns, filecnt, &win);
  113. return CMD_DIRTY;
  114. } else {
  115. return CMD_INVALID;
  116. }
  117. }
  118. cmdreturn_t it_reload_image(arg_t a)
  119. {
  120. if (mode == MODE_IMAGE) {
  121. load_image(fileidx);
  122. } else {
  123. win_set_cursor(&win, CURSOR_WATCH);
  124. if (!tns_load(&tns, tns.sel, &files[tns.sel], true, false)) {
  125. remove_file(tns.sel, false);
  126. tns.dirty = true;
  127. if (tns.sel >= tns.cnt)
  128. tns.sel = tns.cnt - 1;
  129. }
  130. }
  131. return CMD_DIRTY;
  132. }
  133. cmdreturn_t it_remove_image(arg_t a)
  134. {
  135. if (mode == MODE_IMAGE) {
  136. remove_file(fileidx, true);
  137. load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
  138. return CMD_DIRTY;
  139. } else if (tns.sel < tns.cnt) {
  140. remove_file(tns.sel, true);
  141. tns.dirty = true;
  142. if (tns.sel >= tns.cnt)
  143. tns.sel = tns.cnt - 1;
  144. return CMD_DIRTY;
  145. } else {
  146. return CMD_OK;
  147. }
  148. }
  149. cmdreturn_t i_navigate(arg_t a)
  150. {
  151. long n = (long) a;
  152. if (mode == MODE_IMAGE) {
  153. if (prefix > 0)
  154. n *= prefix;
  155. n += fileidx;
  156. if (n < 0)
  157. n = 0;
  158. if (n >= filecnt)
  159. n = filecnt - 1;
  160. if (n != fileidx) {
  161. load_image(n);
  162. return CMD_DIRTY;
  163. }
  164. }
  165. return CMD_INVALID;
  166. }
  167. cmdreturn_t i_alternate(arg_t a)
  168. {
  169. if (mode == MODE_IMAGE) {
  170. load_image(alternate);
  171. return CMD_DIRTY;
  172. } else {
  173. return CMD_INVALID;
  174. }
  175. }
  176. cmdreturn_t it_first(arg_t a)
  177. {
  178. if (mode == MODE_IMAGE && fileidx != 0) {
  179. load_image(0);
  180. return CMD_DIRTY;
  181. } else if (mode == MODE_THUMB && tns.sel != 0) {
  182. tns.sel = 0;
  183. tns.dirty = true;
  184. return CMD_DIRTY;
  185. } else {
  186. return CMD_OK;
  187. }
  188. }
  189. cmdreturn_t it_n_or_last(arg_t a)
  190. {
  191. int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
  192. if (mode == MODE_IMAGE && fileidx != n) {
  193. load_image(n);
  194. return CMD_DIRTY;
  195. } else if (mode == MODE_THUMB && tns.sel != n) {
  196. tns.sel = n;
  197. tns.dirty = true;
  198. return CMD_DIRTY;
  199. } else {
  200. return CMD_OK;
  201. }
  202. }
  203. cmdreturn_t i_navigate_frame(arg_t a)
  204. {
  205. if (mode != MODE_IMAGE)
  206. return CMD_INVALID;
  207. else
  208. return !img.multi.animate && img_frame_navigate(&img, (long) a);
  209. }
  210. cmdreturn_t i_toggle_animation(arg_t a)
  211. {
  212. if (mode != MODE_IMAGE)
  213. return CMD_INVALID;
  214. if (img.multi.animate) {
  215. reset_timeout(animate);
  216. img.multi.animate = false;
  217. } else if (img_frame_animate(&img, true)) {
  218. set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
  219. }
  220. return CMD_DIRTY;
  221. }
  222. cmdreturn_t it_toggle_image_mark(arg_t a)
  223. {
  224. int sel = mode == MODE_IMAGE ? fileidx : tns.sel;
  225. files[sel].marked = !files[sel].marked;
  226. if (mode == MODE_THUMB)
  227. tns_mark(&tns, sel, files[sel].marked);
  228. return CMD_DIRTY;
  229. }
  230. cmdreturn_t it_reverse_marks(arg_t a)
  231. {
  232. int i, cnt = mode == MODE_IMAGE ? filecnt : tns.cnt;
  233. for (i = 0; i < cnt; i++)
  234. files[i].marked = !files[i].marked;
  235. if (mode == MODE_THUMB)
  236. tns.dirty = true;
  237. return CMD_DIRTY;
  238. }
  239. cmdreturn_t it_navigate_marked(arg_t a)
  240. {
  241. long n = (long) a;
  242. int d, i, cnt, sel, new;
  243. if (mode == MODE_IMAGE)
  244. cnt = filecnt, sel = new = fileidx;
  245. else
  246. cnt = tns.cnt, sel = new = tns.sel;
  247. if (prefix > 0)
  248. n *= prefix;
  249. d = n > 0 ? 1 : -1;
  250. for (i = sel + d; n != 0 && i >= 0 && i < cnt; i += d) {
  251. if (files[i].marked) {
  252. n -= d;
  253. new = i;
  254. }
  255. }
  256. if (new != sel) {
  257. if (mode == MODE_IMAGE) {
  258. load_image(new);
  259. } else {
  260. tns.sel = new;
  261. tns.dirty = true;
  262. }
  263. return CMD_DIRTY;
  264. } else {
  265. return CMD_OK;
  266. }
  267. }
  268. cmdreturn_t it_scroll_move(arg_t a)
  269. {
  270. direction_t dir = (direction_t) a;
  271. if (mode == MODE_IMAGE)
  272. return img_pan(&img, dir, prefix);
  273. else
  274. return tns_move_selection(&tns, dir, prefix);
  275. }
  276. cmdreturn_t it_scroll_screen(arg_t a)
  277. {
  278. direction_t dir = (direction_t) a;
  279. if (mode == MODE_IMAGE)
  280. return img_pan(&img, dir, -1);
  281. else
  282. return tns_scroll(&tns, dir, true);
  283. }
  284. cmdreturn_t i_scroll_to_edge(arg_t a)
  285. {
  286. direction_t dir = (direction_t) a;
  287. if (mode == MODE_IMAGE)
  288. return img_pan_edge(&img, dir);
  289. else
  290. return CMD_INVALID;
  291. }
  292. /* Xlib helper function for i_drag() */
  293. Bool is_motionnotify(Display *d, XEvent *e, XPointer a)
  294. {
  295. return e != NULL && e->type == MotionNotify;
  296. }
  297. #define WARP(x,y) \
  298. XWarpPointer(win.env.dpy, None, win.xwin, 0, 0, 0, 0, x, y); \
  299. ox = x, oy = y; \
  300. break
  301. cmdreturn_t i_drag(arg_t a)
  302. {
  303. int dx = 0, dy = 0, i, ox, oy, x, y;
  304. unsigned int ui;
  305. bool dragging = true, next = false;
  306. XEvent e;
  307. Window w;
  308. if (mode != MODE_IMAGE)
  309. return CMD_INVALID;
  310. if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
  311. return CMD_OK;
  312. win_set_cursor(&win, CURSOR_HAND);
  313. while (dragging) {
  314. if (!next)
  315. XMaskEvent(win.env.dpy,
  316. ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
  317. switch (e.type) {
  318. case ButtonPress:
  319. case ButtonRelease:
  320. dragging = false;
  321. break;
  322. case MotionNotify:
  323. x = e.xmotion.x;
  324. y = e.xmotion.y;
  325. /* wrap the mouse around */
  326. if (x <= 0) {
  327. WARP(win.w - 2, y);
  328. } else if (x >= win.w - 1) {
  329. WARP(1, y);
  330. } else if (y <= 0) {
  331. WARP(x, win.h - 2);
  332. } else if (y >= win.h - 1) {
  333. WARP(x, 1);
  334. }
  335. dx += x - ox;
  336. dy += y - oy;
  337. ox = x;
  338. oy = y;
  339. break;
  340. }
  341. if (dragging)
  342. next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
  343. if ((!dragging || !next) && (dx != 0 || dy != 0)) {
  344. if (img_move(&img, dx, dy)) {
  345. img_render(&img);
  346. win_draw(&win);
  347. }
  348. dx = dy = 0;
  349. }
  350. }
  351. win_set_cursor(&win, CURSOR_ARROW);
  352. set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
  353. reset_timeout(redraw);
  354. return CMD_OK;
  355. }
  356. cmdreturn_t i_zoom(arg_t a)
  357. {
  358. long scale = (long) a;
  359. if (mode != MODE_IMAGE)
  360. return CMD_INVALID;
  361. if (scale > 0)
  362. return img_zoom_in(&img);
  363. else if (scale < 0)
  364. return img_zoom_out(&img);
  365. else
  366. return CMD_OK;
  367. }
  368. cmdreturn_t i_set_zoom(arg_t a)
  369. {
  370. if (mode == MODE_IMAGE)
  371. return img_zoom(&img, (prefix ? prefix : (long) a) / 100.0);
  372. else
  373. return CMD_INVALID;
  374. }
  375. cmdreturn_t i_fit_to_win(arg_t a)
  376. {
  377. cmdreturn_t ret = CMD_INVALID;
  378. scalemode_t sm = (scalemode_t) a;
  379. if (mode == MODE_IMAGE) {
  380. if ((ret = img_fit_win(&img, sm)))
  381. img_center(&img);
  382. }
  383. return ret;
  384. }
  385. cmdreturn_t i_fit_to_img(arg_t a)
  386. {
  387. int x, y;
  388. unsigned int w, h;
  389. cmdreturn_t ret = CMD_INVALID;
  390. if (mode == MODE_IMAGE) {
  391. x = MAX(0, win.x + img.x);
  392. y = MAX(0, win.y + img.y);
  393. w = img.w * img.zoom;
  394. h = img.h * img.zoom;
  395. if ((ret = win_moveresize(&win, x, y, w, h))) {
  396. img.x = x - win.x;
  397. img.y = y - win.y;
  398. img.dirty = true;
  399. }
  400. }
  401. return ret;
  402. }
  403. cmdreturn_t i_rotate(arg_t a)
  404. {
  405. degree_t degree = (degree_t) a;
  406. if (mode == MODE_IMAGE) {
  407. img_rotate(&img, degree);
  408. return CMD_DIRTY;
  409. } else {
  410. return CMD_INVALID;
  411. }
  412. }
  413. cmdreturn_t i_flip(arg_t a)
  414. {
  415. flipdir_t dir = (flipdir_t) a;
  416. if (mode == MODE_IMAGE) {
  417. img_flip(&img, dir);
  418. return CMD_DIRTY;
  419. } else {
  420. return CMD_INVALID;
  421. }
  422. }
  423. cmdreturn_t i_slideshow(arg_t a)
  424. {
  425. if (mode == MODE_IMAGE) {
  426. if (prefix > 0) {
  427. img.ss.on = true;
  428. img.ss.delay = prefix;
  429. set_timeout(slideshow, img.ss.delay * 1000, true);
  430. } else if (img.ss.on) {
  431. img.ss.on = false;
  432. reset_timeout(slideshow);
  433. } else {
  434. img.ss.on = true;
  435. }
  436. return CMD_DIRTY;
  437. } else {
  438. return CMD_INVALID;
  439. }
  440. }
  441. cmdreturn_t i_toggle_antialias(arg_t a)
  442. {
  443. if (mode == MODE_IMAGE) {
  444. img_toggle_antialias(&img);
  445. return CMD_DIRTY;
  446. } else {
  447. return CMD_INVALID;
  448. }
  449. }
  450. cmdreturn_t it_toggle_alpha(arg_t a)
  451. {
  452. img.alpha = tns.alpha = !img.alpha;
  453. if (mode == MODE_IMAGE)
  454. img.dirty = true;
  455. else
  456. tns.dirty = true;
  457. return CMD_DIRTY;
  458. }
  459. cmdreturn_t i_change_gamma(arg_t a)
  460. {
  461. if (mode == MODE_IMAGE) {
  462. return img_change_gamma(&img, (long) a);
  463. } else {
  464. return CMD_INVALID;
  465. }
  466. }