A Simple X Image Viewer
 
 
 
 
 
 

424 lines
8.3 KiB

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