A Simple X Image Viewer
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
14 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /* sxiv: main.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
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <sys/select.h>
  21. #include <X11/Xlib.h>
  22. #include <X11/Xutil.h>
  23. #include <X11/keysym.h>
  24. #include "sxiv.h"
  25. #include "image.h"
  26. #include "options.h"
  27. #include "window.h"
  28. void on_keypress(XEvent*);
  29. void on_buttonpress(XEvent*);
  30. void on_buttonrelease(XEvent*);
  31. void on_motionnotify(XEvent*);
  32. void on_configurenotify(XEvent*);
  33. void update_title();
  34. static void (*handler[LASTEvent])(XEvent*) = {
  35. [KeyPress] = on_keypress,
  36. [ButtonPress] = on_buttonpress,
  37. [ButtonRelease] = on_buttonrelease,
  38. [MotionNotify] = on_motionnotify,
  39. [ConfigureNotify] = on_configurenotify
  40. };
  41. img_t img;
  42. win_t win;
  43. const char **filenames;
  44. int filecnt, fileidx;
  45. unsigned char timeout;
  46. int mox;
  47. int moy;
  48. #define TITLE_LEN 256
  49. char win_title[TITLE_LEN];
  50. void run() {
  51. int xfd;
  52. fd_set fds;
  53. struct timeval t;
  54. XEvent ev;
  55. timeout = 0;
  56. while (1) {
  57. if (timeout) {
  58. t.tv_sec = 0;
  59. t.tv_usec = 250;
  60. xfd = ConnectionNumber(win.env.dpy);
  61. FD_ZERO(&fds);
  62. FD_SET(xfd, &fds);
  63. if (!XPending(win.env.dpy) && !select(xfd + 1, &fds, 0, 0, &t)) {
  64. img_render(&img, &win);
  65. timeout = 0;
  66. }
  67. }
  68. if (!XNextEvent(win.env.dpy, &ev) && handler[ev.type])
  69. handler[ev.type](&ev);
  70. }
  71. }
  72. int main(int argc, char **argv) {
  73. int i;
  74. parse_options(argc, argv);
  75. if (!options->filecnt) {
  76. print_usage();
  77. exit(1);
  78. }
  79. if (!(filenames = (const char**) malloc(options->filecnt * sizeof(char*))))
  80. DIE("could not allocate memory");
  81. fileidx = 0;
  82. filecnt = 0;
  83. for (i = 0; i < options->filecnt; ++i) {
  84. if (!(img_load(&img, options->filenames[i]) < 0))
  85. filenames[filecnt++] = options->filenames[i];
  86. }
  87. if (!filecnt) {
  88. fprintf(stderr, "sxiv: no valid image filename given, aborting\n");
  89. exit(1);
  90. }
  91. win_open(&win);
  92. img_init(&img, &win);
  93. img_load(&img, filenames[fileidx]);
  94. img_render(&img, &win);
  95. update_title();
  96. run();
  97. cleanup();
  98. return 0;
  99. }
  100. void cleanup() {
  101. static int in = 0;
  102. if (!in++) {
  103. img_free(&img);
  104. win_close(&win);
  105. }
  106. }
  107. void on_keypress(XEvent *ev) {
  108. char key;
  109. KeySym keysym;
  110. int changed;
  111. if (!ev)
  112. return;
  113. XLookupString(&ev->xkey, &key, 1, &keysym, NULL);
  114. changed = 0;
  115. switch (keysym) {
  116. case XK_Escape:
  117. cleanup();
  118. exit(2);
  119. case XK_space:
  120. key = 'n';
  121. break;
  122. case XK_BackSpace:
  123. key = 'p';
  124. break;
  125. case XK_Left:
  126. key = 'h';
  127. break;
  128. case XK_Down:
  129. key = 'j';
  130. break;
  131. case XK_Up:
  132. key = 'k';
  133. break;
  134. case XK_Right:
  135. key = 'l';
  136. break;
  137. }
  138. switch (key) {
  139. case 'q':
  140. cleanup();
  141. exit(0);
  142. /* navigate image list */
  143. case 'n':
  144. if (fileidx + 1 < filecnt) {
  145. img_load(&img, filenames[++fileidx]);
  146. changed = 1;
  147. }
  148. break;
  149. case 'p':
  150. if (fileidx > 0) {
  151. img_load(&img, filenames[--fileidx]);
  152. changed = 1;
  153. }
  154. break;
  155. case '[':
  156. if (fileidx != 0) {
  157. fileidx = MAX(0, fileidx - 10);
  158. img_load(&img, filenames[fileidx]);
  159. changed = 1;
  160. }
  161. break;
  162. case ']':
  163. if (fileidx != filecnt - 1) {
  164. fileidx = MIN(fileidx + 10, filecnt - 1);
  165. img_load(&img, filenames[fileidx]);
  166. changed = 1;
  167. }
  168. break;
  169. case 'g':
  170. if (fileidx != 0) {
  171. fileidx = 0;
  172. img_load(&img, filenames[fileidx]);
  173. changed = 1;
  174. }
  175. break;
  176. case 'G':
  177. if (fileidx != filecnt - 1) {
  178. fileidx = filecnt - 1;
  179. img_load(&img, filenames[fileidx]);
  180. changed = 1;
  181. }
  182. break;
  183. /* zooming */
  184. case '+':
  185. case '=':
  186. changed = img_zoom_in(&img);
  187. break;
  188. case '-':
  189. changed = img_zoom_out(&img);
  190. break;
  191. /* panning */
  192. case 'h':
  193. changed = img_pan(&img, &win, PAN_LEFT);
  194. break;
  195. case 'j':
  196. changed = img_pan(&img, &win, PAN_DOWN);
  197. break;
  198. case 'k':
  199. changed = img_pan(&img, &win, PAN_UP);
  200. break;
  201. case 'l':
  202. changed = img_pan(&img, &win, PAN_RIGHT);
  203. break;
  204. /* rotation */
  205. case '<':
  206. changed = img_rotate_left(&img, &win);
  207. break;
  208. case '>':
  209. changed = img_rotate_right(&img, &win);
  210. break;
  211. /* control window */
  212. case 'f':
  213. win_toggle_fullscreen(&win);
  214. break;
  215. /* miscellaneous */
  216. case 'a':
  217. changed = img_toggle_antialias(&img);
  218. break;
  219. }
  220. if (changed) {
  221. img_render(&img, &win);
  222. update_title();
  223. timeout = 0;
  224. }
  225. }
  226. void on_buttonpress(XEvent *ev) {
  227. int changed;
  228. unsigned int mask;
  229. if (!ev)
  230. return;
  231. mask = CLEANMASK(ev->xbutton.state);
  232. changed = 0;
  233. switch (ev->xbutton.button) {
  234. case Button1:
  235. if (fileidx + 1 < filecnt) {
  236. img_load(&img, filenames[++fileidx]);
  237. changed = 1;
  238. }
  239. break;
  240. case Button2:
  241. mox = ev->xbutton.x;
  242. moy = ev->xbutton.y;
  243. win_set_cursor(&win, CURSOR_HAND);
  244. break;
  245. case Button3:
  246. if (fileidx > 0) {
  247. img_load(&img, filenames[--fileidx]);
  248. changed = 1;
  249. }
  250. break;
  251. case Button4:
  252. if (mask == ControlMask)
  253. changed = img_zoom_in(&img);
  254. else if (mask == ShiftMask)
  255. changed = img_pan(&img, &win, PAN_LEFT);
  256. else
  257. changed = img_pan(&img, &win, PAN_UP);
  258. break;
  259. case Button5:
  260. if (mask == ControlMask)
  261. changed = img_zoom_out(&img);
  262. else if (mask == ShiftMask)
  263. changed = img_pan(&img, &win, PAN_RIGHT);
  264. else
  265. changed = img_pan(&img, &win, PAN_DOWN);
  266. break;
  267. case 6:
  268. changed = img_pan(&img, &win, PAN_LEFT);
  269. break;
  270. case 7:
  271. changed = img_pan(&img, &win, PAN_RIGHT);
  272. break;
  273. }
  274. if (changed) {
  275. img_render(&img, &win);
  276. update_title();
  277. timeout = 0;
  278. }
  279. }
  280. void on_buttonrelease(XEvent *ev) {
  281. if (!ev)
  282. return;
  283. if (ev->xbutton.button == Button2)
  284. win_set_cursor(&win, CURSOR_ARROW);
  285. }
  286. void on_motionnotify(XEvent *ev) {
  287. XMotionEvent *m;
  288. if (!ev)
  289. return;
  290. m = &ev->xmotion;
  291. if (m->x >= 0 && m->x <= win.w && m->y >= 0 && m->y <= win.h) {
  292. if (img_move(&img, &win, m->x - mox, m->y - moy))
  293. timeout = 1;
  294. mox = m->x;
  295. moy = m->y;
  296. }
  297. }
  298. void on_configurenotify(XEvent *ev) {
  299. if (!ev)
  300. return;
  301. if (win_configure(&win, &ev->xconfigure)) {
  302. img.checkpan = 1;
  303. timeout = 1;
  304. }
  305. }
  306. void update_title() {
  307. int n;
  308. n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] <%d%%> %s", fileidx + 1,
  309. filecnt, (int) (img.zoom * 100.0), filenames[fileidx]);
  310. if (n >= TITLE_LEN) {
  311. win_title[TITLE_LEN - 2] = '.';
  312. win_title[TITLE_LEN - 3] = '.';
  313. win_title[TITLE_LEN - 4] = '.';
  314. }
  315. win_set_title(&win, win_title);
  316. }