A Simple X Image Viewer
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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