A Simple X Image Viewer
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

531 рядки
9.9 KiB

  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. }