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