A Simple X Image Viewer
 
 
 
 
 
 

401 lines
7.9 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 it_move(arg_t a) {
  134. direction_t dir = (direction_t) a;
  135. if (mode == MODE_IMAGE)
  136. return img_pan(&img, &win, dir, 0);
  137. else
  138. return tns_move_selection(&tns, &win, dir);
  139. }
  140. int i_pan_screen(arg_t a) {
  141. direction_t dir = (direction_t) a;
  142. if (mode == MODE_IMAGE)
  143. return img_pan(&img, &win, dir, 1);
  144. else
  145. return 0;
  146. }
  147. int i_pan_edge(arg_t a) {
  148. direction_t dir = (direction_t) a;
  149. if (mode == MODE_IMAGE)
  150. return img_pan_edge(&img, &win, dir);
  151. else
  152. return 0;
  153. }
  154. /* Xlib helper function for i_drag() */
  155. Bool is_motionnotify(Display *d, XEvent *e, XPointer a) {
  156. return e != NULL && e->type == MotionNotify;
  157. }
  158. int i_drag(arg_t a) {
  159. int dx = 0, dy = 0, i, ox, oy, x, y;
  160. unsigned int ui;
  161. Bool dragging = True, next = False;
  162. XEvent e;
  163. Window w;
  164. if (mode != MODE_IMAGE)
  165. return 0;
  166. if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
  167. return 0;
  168. win_set_cursor(&win, CURSOR_HAND);
  169. while (dragging) {
  170. if (!next)
  171. XMaskEvent(win.env.dpy,
  172. ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
  173. switch (e.type) {
  174. case ButtonPress:
  175. case ButtonRelease:
  176. dragging = False;
  177. break;
  178. case MotionNotify:
  179. x = e.xmotion.x;
  180. y = e.xmotion.y;
  181. if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) {
  182. dx += x - ox;
  183. dy += y - oy;
  184. }
  185. ox = x;
  186. oy = y;
  187. break;
  188. }
  189. if (dragging)
  190. next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
  191. if ((!dragging || !next) && (dx != 0 || dy != 0)) {
  192. if (img_move(&img, &win, dx, dy))
  193. img_render(&img, &win);
  194. dx = dy = 0;
  195. }
  196. }
  197. win_set_cursor(&win, CURSOR_ARROW);
  198. timo_cursor = TO_CURSOR_HIDE;
  199. timo_redraw = 0;
  200. return 0;
  201. }
  202. int i_zoom(arg_t a) {
  203. int scale = (int) a;
  204. if (mode != MODE_IMAGE)
  205. return 0;
  206. if (scale > 0)
  207. return img_zoom_in(&img, &win);
  208. else if (scale < 0)
  209. return img_zoom_out(&img, &win);
  210. else
  211. return img_zoom(&img, &win, 1.0);
  212. }
  213. int i_fit_to_win(arg_t a) {
  214. int ret;
  215. if (mode == MODE_IMAGE) {
  216. if ((ret = img_fit_win(&img, &win)))
  217. img_center(&img, &win);
  218. return ret;
  219. } else {
  220. return 0;
  221. }
  222. }
  223. int i_fit_to_img(arg_t a) {
  224. int ret, x, y;
  225. unsigned int w, h;
  226. if (mode == MODE_IMAGE) {
  227. x = MAX(0, win.x + img.x);
  228. y = MAX(0, win.y + img.y);
  229. w = img.w * img.zoom;
  230. h = img.h * img.zoom;
  231. if ((ret = win_moveresize(&win, x, y, w, h))) {
  232. img.x = x - win.x;
  233. img.y = y - win.y;
  234. }
  235. return ret;
  236. } else {
  237. return 0;
  238. }
  239. }
  240. int i_rotate(arg_t a) {
  241. direction_t dir = (direction_t) a;
  242. if (mode == MODE_IMAGE) {
  243. if (dir == DIR_LEFT) {
  244. img_rotate_left(&img, &win);
  245. return 1;
  246. } else if (dir == DIR_RIGHT) {
  247. img_rotate_right(&img, &win);
  248. return 1;
  249. }
  250. }
  251. return 0;
  252. }
  253. int i_toggle_antialias(arg_t a) {
  254. if (mode == MODE_IMAGE) {
  255. img_toggle_antialias(&img);
  256. return 1;
  257. } else {
  258. return 0;
  259. }
  260. }
  261. int i_toggle_alpha(arg_t a) {
  262. if (mode == MODE_IMAGE) {
  263. img.alpha ^= 1;
  264. return 1;
  265. } else {
  266. return 0;
  267. }
  268. }
  269. int it_open_with(arg_t a) {
  270. const char *prog = (const char*) a;
  271. pid_t pid;
  272. if (!prog || !*prog)
  273. return 0;
  274. if((pid = fork()) == 0) {
  275. execlp(prog, prog,
  276. files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL);
  277. warn("could not exec: %s", prog);
  278. exit(1);
  279. } else if (pid < 0) {
  280. warn("could not for. program was: %s", prog);
  281. }
  282. return 0;
  283. }
  284. int it_shell_cmd(arg_t a) {
  285. const char *cline = (const char*) a;
  286. char *cn, *cmdline;
  287. const char *co, *fpath;
  288. int fpcnt, fplen, status;
  289. pid_t pid;
  290. if (!cline || !*cline)
  291. return 0;
  292. /* build command line: */
  293. fpcnt = 0;
  294. co = cline - 1;
  295. while ((co = strchr(co + 1, '#')))
  296. fpcnt++;
  297. if (!fpcnt)
  298. return 0;
  299. fpath = files[mode == MODE_IMAGE ? fileidx : tns.sel].path;
  300. fplen = strlen(fpath);
  301. cn = cmdline = (char*) s_malloc((strlen(cline) + fpcnt * (fplen + 2)) *
  302. sizeof(char));
  303. /* replace all '#' with filename: */
  304. for (co = cline; *co; co++) {
  305. if (*co == '#') {
  306. *cn++ = '"';
  307. strcpy(cn, fpath);
  308. cn += fplen;
  309. *cn++ = '"';
  310. } else {
  311. *cn++ = *co;
  312. }
  313. }
  314. *cn = '\0';
  315. win_set_cursor(&win, CURSOR_WATCH);
  316. if ((pid = fork()) == 0) {
  317. execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
  318. warn("could not exec: /bin/sh");
  319. exit(1);
  320. } else if (pid < 0) {
  321. warn("could not fork. command line was: %s", cmdline);
  322. goto end;
  323. }
  324. waitpid(pid, &status, 0);
  325. if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
  326. warn("child exited with non-zero return value: %d. command line was: %s",
  327. WEXITSTATUS(status), cmdline);
  328. if (mode == MODE_IMAGE) {
  329. if (fileidx < tns.cnt)
  330. tns_load(&tns, fileidx, &files[fileidx], False, True);
  331. img_close(&img, 1);
  332. load_image(fileidx);
  333. } else {
  334. if (!tns_load(&tns, tns.sel, &files[tns.sel], True, False)) {
  335. remove_file(tns.sel, 0);
  336. tns.dirty = 1;
  337. if (tns.sel >= tns.cnt)
  338. tns.sel = tns.cnt - 1;
  339. }
  340. }
  341. end:
  342. if (mode == MODE_THUMB)
  343. win_set_cursor(&win, CURSOR_ARROW);
  344. /* else: cursor gets reset in redraw() */
  345. free(cmdline);
  346. return 1;
  347. }