A Simple X Image Viewer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /* sxiv: commands.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
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <sys/wait.h>
  22. #include "commands.h"
  23. #include "image.h"
  24. #include "thumbs.h"
  25. #include "types.h"
  26. #include "util.h"
  27. void cleanup();
  28. void remove_file(int, unsigned char);
  29. void load_image(int);
  30. void redraw();
  31. void hide_cursor();
  32. void animate();
  33. void set_timeout(timeout_f, int, int);
  34. void reset_timeout(timeout_f);
  35. extern appmode_t mode;
  36. extern img_t img;
  37. extern tns_t tns;
  38. extern win_t win;
  39. extern fileinfo_t *files;
  40. extern int filecnt, fileidx;
  41. int it_quit(arg_t a) {
  42. cleanup();
  43. exit(0);
  44. }
  45. int it_switch_mode(arg_t a) {
  46. if (mode == MODE_IMAGE) {
  47. if (!tns.thumbs)
  48. tns_init(&tns, filecnt);
  49. img_close(&img, 0);
  50. win_set_cursor(&win, CURSOR_ARROW);
  51. reset_timeout(hide_cursor);
  52. tns.sel = fileidx;
  53. tns.dirty = 1;
  54. mode = MODE_THUMB;
  55. } else {
  56. load_image(tns.sel);
  57. mode = MODE_IMAGE;
  58. }
  59. return 1;
  60. }
  61. int it_toggle_fullscreen(arg_t a) {
  62. win_toggle_fullscreen(&win);
  63. set_timeout(redraw, TO_REDRAW_RESIZE, 0);
  64. if (mode == MODE_IMAGE)
  65. img.checkpan = 1;
  66. else
  67. tns.dirty = 1;
  68. return 0;
  69. }
  70. int it_reload_image(arg_t a) {
  71. if (mode == MODE_IMAGE) {
  72. load_image(fileidx);
  73. } else if (!tns_load(&tns, tns.sel, &files[tns.sel], True, False)) {
  74. remove_file(tns.sel, 0);
  75. tns.dirty = 1;
  76. if (tns.sel >= tns.cnt)
  77. tns.sel = tns.cnt - 1;
  78. }
  79. return 1;
  80. }
  81. int it_remove_image(arg_t a) {
  82. if (mode == MODE_IMAGE) {
  83. remove_file(fileidx, 1);
  84. load_image(fileidx >= filecnt ? filecnt - 1 : fileidx);
  85. return 1;
  86. } else if (tns.sel < tns.cnt) {
  87. remove_file(tns.sel, 1);
  88. tns.dirty = 1;
  89. if (tns.sel >= tns.cnt)
  90. tns.sel = tns.cnt - 1;
  91. return 1;
  92. } else {
  93. return 0;
  94. }
  95. }
  96. int i_navigate(arg_t a) {
  97. int n = (int) a;
  98. if (mode == MODE_IMAGE) {
  99. n += fileidx;
  100. if (n < 0)
  101. n = 0;
  102. if (n >= filecnt)
  103. n = filecnt - 1;
  104. if (n != fileidx) {
  105. load_image(n);
  106. return 1;
  107. }
  108. }
  109. return 0;
  110. }
  111. int it_first(arg_t a) {
  112. if (mode == MODE_IMAGE && fileidx != 0) {
  113. load_image(0);
  114. return 1;
  115. } else if (mode == MODE_THUMB && tns.sel != 0) {
  116. tns.sel = 0;
  117. tns.dirty = 1;
  118. return 1;
  119. } else {
  120. return 0;
  121. }
  122. }
  123. int it_last(arg_t a) {
  124. if (mode == MODE_IMAGE && fileidx != filecnt - 1) {
  125. load_image(filecnt - 1);
  126. return 1;
  127. } else if (mode == MODE_THUMB && tns.sel != tns.cnt - 1) {
  128. tns.sel = tns.cnt - 1;
  129. tns.dirty = 1;
  130. return 1;
  131. } else {
  132. return 0;
  133. }
  134. }
  135. int i_navigate_frame(arg_t a) {
  136. if (mode == MODE_IMAGE && !img.multi.animate)
  137. return img_frame_navigate(&img, (int) a);
  138. else
  139. return 0;
  140. }
  141. int i_toggle_animation(arg_t a) {
  142. int delay;
  143. if (mode != MODE_IMAGE)
  144. return 0;
  145. if (img.multi.animate) {
  146. reset_timeout(animate);
  147. img.multi.animate = 0;
  148. return 0;
  149. } else {
  150. delay = img_frame_animate(&img, 1);
  151. set_timeout(animate, delay, 1);
  152. return 1;
  153. }
  154. }
  155. int it_move(arg_t a) {
  156. direction_t dir = (direction_t) a;
  157. if (mode == MODE_IMAGE)
  158. return img_pan(&img, &win, dir, 0);
  159. else
  160. return tns_move_selection(&tns, &win, dir);
  161. }
  162. int i_pan_screen(arg_t a) {
  163. direction_t dir = (direction_t) a;
  164. if (mode == MODE_IMAGE)
  165. return img_pan(&img, &win, dir, 1);
  166. else
  167. return 0;
  168. }
  169. int i_pan_edge(arg_t a) {
  170. direction_t dir = (direction_t) a;
  171. if (mode == MODE_IMAGE)
  172. return img_pan_edge(&img, &win, dir);
  173. else
  174. return 0;
  175. }
  176. /* Xlib helper function for i_drag() */
  177. Bool is_motionnotify(Display *d, XEvent *e, XPointer a) {
  178. return e != NULL && e->type == MotionNotify;
  179. }
  180. int i_drag(arg_t a) {
  181. int dx = 0, dy = 0, i, ox, oy, x, y;
  182. unsigned int ui;
  183. Bool dragging = True, next = False;
  184. XEvent e;
  185. Window w;
  186. if (mode != MODE_IMAGE)
  187. return 0;
  188. if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
  189. return 0;
  190. win_set_cursor(&win, CURSOR_HAND);
  191. while (dragging) {
  192. if (!next)
  193. XMaskEvent(win.env.dpy,
  194. ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
  195. switch (e.type) {
  196. case ButtonPress:
  197. case ButtonRelease:
  198. dragging = False;
  199. break;
  200. case MotionNotify:
  201. x = e.xmotion.x;
  202. y = e.xmotion.y;
  203. if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) {
  204. dx += x - ox;
  205. dy += y - oy;
  206. }
  207. ox = x;
  208. oy = y;
  209. break;
  210. }
  211. if (dragging)
  212. next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
  213. if ((!dragging || !next) && (dx != 0 || dy != 0)) {
  214. if (img_move(&img, &win, dx, dy))
  215. img_render(&img, &win);
  216. dx = dy = 0;
  217. }
  218. }
  219. win_set_cursor(&win, CURSOR_ARROW);
  220. set_timeout(hide_cursor, TO_CURSOR_HIDE, 1);
  221. reset_timeout(redraw);
  222. return 0;
  223. }
  224. int i_zoom(arg_t a) {
  225. int scale = (int) a;
  226. if (mode != MODE_IMAGE)
  227. return 0;
  228. if (scale > 0)
  229. return img_zoom_in(&img, &win);
  230. else if (scale < 0)
  231. return img_zoom_out(&img, &win);
  232. else
  233. return img_zoom(&img, &win, 1.0);
  234. }
  235. int i_fit_to_win(arg_t a) {
  236. int ret;
  237. if (mode == MODE_IMAGE) {
  238. if ((ret = img_fit_win(&img, &win)))
  239. img_center(&img, &win);
  240. return ret;
  241. } else {
  242. return 0;
  243. }
  244. }
  245. int i_fit_to_img(arg_t a) {
  246. int ret, x, y;
  247. unsigned int w, h;
  248. if (mode == MODE_IMAGE) {
  249. x = MAX(0, win.x + img.x);
  250. y = MAX(0, win.y + img.y);
  251. w = img.w * img.zoom;
  252. h = img.h * img.zoom;
  253. if ((ret = win_moveresize(&win, x, y, w, h))) {
  254. img.x = x - win.x;
  255. img.y = y - win.y;
  256. }
  257. return ret;
  258. } else {
  259. return 0;
  260. }
  261. }
  262. int i_rotate(arg_t a) {
  263. direction_t dir = (direction_t) a;
  264. if (mode == MODE_IMAGE) {
  265. if (dir == DIR_LEFT) {
  266. img_rotate_left(&img, &win);
  267. return 1;
  268. } else if (dir == DIR_RIGHT) {
  269. img_rotate_right(&img, &win);
  270. return 1;
  271. }
  272. }
  273. return 0;
  274. }
  275. int i_toggle_antialias(arg_t a) {
  276. if (mode == MODE_IMAGE) {
  277. img_toggle_antialias(&img);
  278. return 1;
  279. } else {
  280. return 0;
  281. }
  282. }
  283. int i_toggle_alpha(arg_t a) {
  284. if (mode == MODE_IMAGE) {
  285. img.alpha ^= 1;
  286. return 1;
  287. } else {
  288. return 0;
  289. }
  290. }
  291. int it_open_with(arg_t a) {
  292. const char *prog = (const char*) a;
  293. pid_t pid;
  294. if (!prog || !*prog)
  295. return 0;
  296. if((pid = fork()) == 0) {
  297. execlp(prog, prog,
  298. files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
  299. warn("could not exec: %s", prog);
  300. exit(1);
  301. } else if (pid < 0) {
  302. warn("could not for. program was: %s", prog);
  303. }
  304. return 0;
  305. }
  306. int it_shell_cmd(arg_t a) {
  307. const char *cline = (const char*) a;
  308. char *cn, *cmdline;
  309. const char *co, *fpath;
  310. int fpcnt, fplen, status;
  311. pid_t pid;
  312. if (!cline || !*cline)
  313. return 0;
  314. /* build command line: */
  315. fpcnt = 0;
  316. co = cline - 1;
  317. while ((co = strchr(co + 1, '#')))
  318. fpcnt++;
  319. if (!fpcnt)
  320. return 0;
  321. fpath = files[mode == MODE_IMAGE ? fileidx : tns.sel].path;
  322. fplen = strlen(fpath);
  323. cn = cmdline = (char*) s_malloc((strlen(cline) + fpcnt * (fplen + 2)) *
  324. sizeof(char));
  325. /* replace all '#' with filename: */
  326. for (co = cline; *co; co++) {
  327. if (*co == '#') {
  328. *cn++ = '"';
  329. strcpy(cn, fpath);
  330. cn += fplen;
  331. *cn++ = '"';
  332. } else {
  333. *cn++ = *co;
  334. }
  335. }
  336. *cn = '\0';
  337. win_set_cursor(&win, CURSOR_WATCH);
  338. if ((pid = fork()) == 0) {
  339. execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
  340. warn("could not exec: /bin/sh");
  341. exit(1);
  342. } else if (pid < 0) {
  343. warn("could not fork. command line was: %s", cmdline);
  344. goto end;
  345. }
  346. waitpid(pid, &status, 0);
  347. if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
  348. warn("child exited with non-zero return value: %d. command line was: %s",
  349. WEXITSTATUS(status), cmdline);
  350. if (mode == MODE_IMAGE) {
  351. if (fileidx < tns.cnt)
  352. tns_load(&tns, fileidx, &files[fileidx], False, True);
  353. img_close(&img, 1);
  354. load_image(fileidx);
  355. } else {
  356. if (!tns_load(&tns, tns.sel, &files[tns.sel], True, False)) {
  357. remove_file(tns.sel, 0);
  358. tns.dirty = 1;
  359. if (tns.sel >= tns.cnt)
  360. tns.sel = tns.cnt - 1;
  361. }
  362. }
  363. end:
  364. if (mode == MODE_THUMB)
  365. win_set_cursor(&win, CURSOR_ARROW);
  366. /* else: cursor gets reset in redraw() */
  367. free(cmdline);
  368. return 1;
  369. }