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.

commands.c 9.0 KiB

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