A Simple X Image Viewer
 
 
 
 
 
 

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