A Simple X Image Viewer
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

487 Zeilen
9.1 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 "thumbs.h"
  27. #include "util.h"
  28. #include "config.h"
  29. void cleanup(void);
  30. void remove_file(int, bool);
  31. void load_image(int);
  32. void redraw(void);
  33. void reset_cursor(void);
  34. void animate(void);
  35. void set_timeout(timeout_f, int, bool);
  36. void reset_timeout(timeout_f);
  37. extern appmode_t mode;
  38. extern img_t img;
  39. extern tns_t tns;
  40. extern win_t win;
  41. extern fileinfo_t *files;
  42. extern int filecnt, fileidx;
  43. extern int alternate;
  44. extern int prefix;
  45. const int ss_delays[] = {
  46. 1, 2, 3, 5, 10, 15, 20, 30, 60, 120, 180, 300, 600
  47. };
  48. bool it_quit(arg_t a)
  49. {
  50. cleanup();
  51. exit(EXIT_SUCCESS);
  52. }
  53. bool it_switch_mode(arg_t a)
  54. {
  55. if (mode == MODE_IMAGE) {
  56. if (tns.thumbs == NULL)
  57. tns_init(&tns, filecnt, &win);
  58. img_close(&img, false);
  59. reset_timeout(reset_cursor);
  60. tns.sel = fileidx;
  61. tns.dirty = true;
  62. mode = MODE_THUMB;
  63. } else {
  64. load_image(tns.sel);
  65. mode = MODE_IMAGE;
  66. }
  67. return true;
  68. }
  69. bool it_toggle_fullscreen(arg_t a)
  70. {
  71. win_toggle_fullscreen(&win);
  72. /* redraw after next ConfigureNotify event */
  73. set_timeout(redraw, TO_REDRAW_RESIZE, false);
  74. if (mode == MODE_IMAGE)
  75. img.checkpan = img.dirty = true;
  76. else
  77. tns.dirty = true;
  78. return false;
  79. }
  80. bool it_toggle_bar(arg_t a)
  81. {
  82. win_toggle_bar(&win);
  83. if (mode == MODE_IMAGE)
  84. img.checkpan = img.dirty = true;
  85. else
  86. tns.dirty = true;
  87. return true;
  88. }
  89. bool t_reload_all(arg_t a)
  90. {
  91. if (mode == MODE_THUMB) {
  92. tns_free(&tns);
  93. tns_init(&tns, filecnt, &win);
  94. return true;
  95. } else {
  96. return false;
  97. }
  98. }
  99. bool it_reload_image(arg_t a)
  100. {
  101. if (mode == MODE_IMAGE) {
  102. load_image(fileidx);
  103. } else {
  104. win_set_cursor(&win, CURSOR_WATCH);
  105. if (!tns_load(&tns, tns.sel, &files[tns.sel], true, false)) {
  106. remove_file(tns.sel, false);
  107. tns.dirty = true;
  108. if (tns.sel >= tns.cnt)
  109. tns.sel = tns.cnt - 1;
  110. }
  111. }
  112. return true;
  113. }
  114. bool it_remove_image(arg_t a)
  115. {
  116. if (mode == MODE_IMAGE) {
  117. remove_file(fileidx, true);
  118. load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
  119. return true;
  120. } else if (tns.sel < tns.cnt) {
  121. remove_file(tns.sel, true);
  122. tns.dirty = true;
  123. if (tns.sel >= tns.cnt)
  124. tns.sel = tns.cnt - 1;
  125. return true;
  126. } else {
  127. return false;
  128. }
  129. }
  130. bool i_navigate(arg_t a)
  131. {
  132. long n = (long) a;
  133. if (mode == MODE_IMAGE) {
  134. if (prefix > 0)
  135. n *= prefix;
  136. n += fileidx;
  137. if (n < 0)
  138. n = 0;
  139. if (n >= filecnt)
  140. n = filecnt - 1;
  141. if (n != fileidx) {
  142. load_image(n);
  143. return true;
  144. }
  145. }
  146. return false;
  147. }
  148. bool i_alternate(arg_t a)
  149. {
  150. if (mode == MODE_IMAGE) {
  151. load_image(alternate);
  152. return true;
  153. } else {
  154. return false;
  155. }
  156. }
  157. bool it_first(arg_t a)
  158. {
  159. if (mode == MODE_IMAGE && fileidx != 0) {
  160. load_image(0);
  161. return true;
  162. } else if (mode == MODE_THUMB && tns.sel != 0) {
  163. tns.sel = 0;
  164. tns.dirty = true;
  165. return true;
  166. } else {
  167. return false;
  168. }
  169. }
  170. bool it_n_or_last(arg_t a)
  171. {
  172. int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
  173. if (mode == MODE_IMAGE && fileidx != n) {
  174. load_image(n);
  175. return true;
  176. } else if (mode == MODE_THUMB && tns.sel != n) {
  177. tns.sel = n;
  178. tns.dirty = true;
  179. return true;
  180. } else {
  181. return false;
  182. }
  183. }
  184. bool i_navigate_frame(arg_t a)
  185. {
  186. if (mode == MODE_IMAGE && !img.multi.animate)
  187. return img_frame_navigate(&img, (long) a);
  188. else
  189. return false;
  190. }
  191. bool i_toggle_animation(arg_t a)
  192. {
  193. if (mode != MODE_IMAGE)
  194. return false;
  195. if (img.multi.animate) {
  196. reset_timeout(animate);
  197. img.multi.animate = false;
  198. } else if (img_frame_animate(&img, true)) {
  199. set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
  200. }
  201. return true;
  202. }
  203. bool it_scroll_move(arg_t a)
  204. {
  205. direction_t dir = (direction_t) a;
  206. if (mode == MODE_IMAGE)
  207. return img_pan(&img, dir, prefix);
  208. else
  209. return tns_move_selection(&tns, dir, prefix);
  210. }
  211. bool it_scroll_screen(arg_t a)
  212. {
  213. direction_t dir = (direction_t) a;
  214. if (mode == MODE_IMAGE)
  215. return img_pan(&img, dir, -1);
  216. else
  217. return tns_scroll(&tns, dir, true);
  218. }
  219. bool i_scroll_to_edge(arg_t a)
  220. {
  221. direction_t dir = (direction_t) a;
  222. if (mode == MODE_IMAGE)
  223. return img_pan_edge(&img, dir);
  224. else
  225. return false;
  226. }
  227. /* Xlib helper function for i_drag() */
  228. Bool is_motionnotify(Display *d, XEvent *e, XPointer a)
  229. {
  230. return e != NULL && e->type == MotionNotify;
  231. }
  232. bool i_drag(arg_t a)
  233. {
  234. int dx = 0, dy = 0, i, ox, oy, x, y;
  235. unsigned int ui;
  236. bool dragging = true, next = false;
  237. XEvent e;
  238. Window w;
  239. if (mode != MODE_IMAGE)
  240. return false;
  241. if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
  242. return false;
  243. win_set_cursor(&win, CURSOR_HAND);
  244. while (dragging) {
  245. if (!next)
  246. XMaskEvent(win.env.dpy,
  247. ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
  248. switch (e.type) {
  249. case ButtonPress:
  250. case ButtonRelease:
  251. dragging = false;
  252. break;
  253. case MotionNotify:
  254. x = e.xmotion.x;
  255. y = e.xmotion.y;
  256. if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) {
  257. dx += x - ox;
  258. dy += y - oy;
  259. }
  260. ox = x;
  261. oy = y;
  262. break;
  263. }
  264. if (dragging)
  265. next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
  266. if ((!dragging || !next) && (dx != 0 || dy != 0)) {
  267. if (img_move(&img, dx, dy)) {
  268. img_render(&img);
  269. win_draw(&win);
  270. }
  271. dx = dy = 0;
  272. }
  273. }
  274. win_set_cursor(&win, CURSOR_ARROW);
  275. set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
  276. reset_timeout(redraw);
  277. return false;
  278. }
  279. bool i_zoom(arg_t a)
  280. {
  281. long scale = (long) a;
  282. if (mode != MODE_IMAGE)
  283. return false;
  284. if (scale > 0)
  285. return img_zoom_in(&img);
  286. else if (scale < 0)
  287. return img_zoom_out(&img);
  288. else
  289. return false;
  290. }
  291. bool i_set_zoom(arg_t a)
  292. {
  293. if (mode == MODE_IMAGE)
  294. return img_zoom(&img, (prefix ? prefix : (long) a) / 100.0);
  295. else
  296. return false;
  297. }
  298. bool i_fit_to_win(arg_t a)
  299. {
  300. bool ret = false;
  301. scalemode_t sm = (scalemode_t) a;
  302. if (mode == MODE_IMAGE) {
  303. if ((ret = img_fit_win(&img, sm)))
  304. img_center(&img);
  305. }
  306. return ret;
  307. }
  308. bool i_fit_to_img(arg_t a)
  309. {
  310. int x, y;
  311. unsigned int w, h;
  312. bool ret = false;
  313. if (mode == MODE_IMAGE) {
  314. x = MAX(0, win.x + img.x);
  315. y = MAX(0, win.y + img.y);
  316. w = img.w * img.zoom;
  317. h = img.h * img.zoom;
  318. if ((ret = win_moveresize(&win, x, y, w, h))) {
  319. img.x = x - win.x;
  320. img.y = y - win.y;
  321. img.dirty = true;
  322. }
  323. }
  324. return ret;
  325. }
  326. bool i_rotate(arg_t a)
  327. {
  328. direction_t dir = (direction_t) a;
  329. if (mode == MODE_IMAGE) {
  330. if (dir == DIR_LEFT) {
  331. img_rotate_left(&img);
  332. return true;
  333. } else if (dir == DIR_RIGHT) {
  334. img_rotate_right(&img);
  335. return true;
  336. }
  337. }
  338. return false;
  339. }
  340. bool i_flip(arg_t a)
  341. {
  342. flipdir_t dir = (flipdir_t) a;
  343. if (mode == MODE_IMAGE) {
  344. img_flip(&img, dir);
  345. return true;
  346. } else {
  347. return false;
  348. }
  349. }
  350. bool i_toggle_antialias(arg_t a)
  351. {
  352. if (mode == MODE_IMAGE) {
  353. img_toggle_antialias(&img);
  354. return true;
  355. } else {
  356. return false;
  357. }
  358. }
  359. bool it_toggle_alpha(arg_t a)
  360. {
  361. img.alpha = tns.alpha = !img.alpha;
  362. if (mode == MODE_IMAGE)
  363. img.dirty = true;
  364. else
  365. tns.dirty = true;
  366. return true;
  367. }
  368. bool it_open_with(arg_t a)
  369. {
  370. const char *prog = (const char*) a;
  371. pid_t pid;
  372. if (prog == NULL || *prog == '\0')
  373. return false;
  374. if ((pid = fork()) == 0) {
  375. execlp(prog, prog,
  376. files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
  377. warn("could not exec: %s", prog);
  378. exit(EXIT_FAILURE);
  379. } else if (pid < 0) {
  380. warn("could not fork. program was: %s", prog);
  381. }
  382. return false;
  383. }
  384. bool it_shell_cmd(arg_t a)
  385. {
  386. int n, status;
  387. const char *cmdline = (const char*) a;
  388. pid_t pid;
  389. if (cmdline == NULL || *cmdline == '\0')
  390. return false;
  391. n = mode == MODE_IMAGE ? fileidx : tns.sel;
  392. if (setenv("SXIV_IMG", files[n].path, 1) < 0) {
  393. warn("could not set env.-variable: SXIV_IMG. command line was: %s",
  394. cmdline);
  395. return false;
  396. }
  397. if ((pid = fork()) == 0) {
  398. execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
  399. warn("could not exec: /bin/sh. command line was: %s", cmdline);
  400. exit(EXIT_FAILURE);
  401. } else if (pid < 0) {
  402. warn("could not fork. command line was: %s", cmdline);
  403. return false;
  404. }
  405. win_set_cursor(&win, CURSOR_WATCH);
  406. waitpid(pid, &status, 0);
  407. if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
  408. warn("child exited with non-zero return value: %d. command line was: %s",
  409. WEXITSTATUS(status), cmdline);
  410. if (mode == MODE_IMAGE) {
  411. img_close(&img, true);
  412. load_image(fileidx);
  413. }
  414. if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) &&
  415. mode == MODE_THUMB)
  416. {
  417. remove_file(tns.sel, false);
  418. tns.dirty = true;
  419. if (tns.sel >= tns.cnt)
  420. tns.sel = tns.cnt - 1;
  421. }
  422. return true;
  423. }