A Simple X Image Viewer
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

328 lines
6.1 KiB

  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_configurenotify(XEvent*);
  31. void update_title();
  32. static void (*handler[LASTEvent])(XEvent*) = {
  33. [KeyPress] = on_keypress,
  34. [ButtonPress] = on_buttonpress,
  35. [ConfigureNotify] = on_configurenotify
  36. };
  37. img_t img;
  38. win_t win;
  39. const char **filenames;
  40. int filecnt, fileidx;
  41. unsigned char timeout;
  42. #define TITLE_LEN 256
  43. char win_title[TITLE_LEN];
  44. void run() {
  45. int xfd;
  46. fd_set fds;
  47. struct timeval t;
  48. XEvent ev;
  49. timeout = 0;
  50. while (1) {
  51. if (timeout) {
  52. t.tv_sec = 0;
  53. t.tv_usec = 250;
  54. xfd = ConnectionNumber(win.env.dpy);
  55. FD_ZERO(&fds);
  56. FD_SET(xfd, &fds);
  57. if (!XPending(win.env.dpy) && !select(xfd + 1, &fds, 0, 0, &t)) {
  58. img_render(&img, &win);
  59. timeout = 0;
  60. }
  61. }
  62. if (!XNextEvent(win.env.dpy, &ev) && handler[ev.type])
  63. handler[ev.type](&ev);
  64. }
  65. }
  66. int main(int argc, char **argv) {
  67. int i;
  68. parse_options(argc, argv);
  69. if (!options->filecnt) {
  70. print_usage();
  71. exit(1);
  72. }
  73. if (!(filenames = (const char**) malloc(options->filecnt * sizeof(char*))))
  74. DIE("could not allocate memory");
  75. fileidx = 0;
  76. filecnt = 0;
  77. for (i = 0; i < options->filecnt; ++i) {
  78. if (!(img_load(&img, options->filenames[i]) < 0))
  79. filenames[filecnt++] = options->filenames[i];
  80. }
  81. if (!filecnt) {
  82. fprintf(stderr, "sxiv: no valid image filename given, aborting\n");
  83. exit(1);
  84. }
  85. win_open(&win);
  86. img_init(&img, &win);
  87. img_load(&img, filenames[fileidx]);
  88. img_render(&img, &win);
  89. update_title();
  90. run();
  91. cleanup();
  92. return 0;
  93. }
  94. void cleanup() {
  95. static int in = 0;
  96. if (!in++) {
  97. img_free(&img);
  98. win_close(&win);
  99. }
  100. }
  101. void on_keypress(XEvent *ev) {
  102. char key;
  103. KeySym keysym;
  104. int changed;
  105. if (!ev)
  106. return;
  107. XLookupString(&ev->xkey, &key, 1, &keysym, NULL);
  108. changed = 0;
  109. switch (keysym) {
  110. case XK_Escape:
  111. cleanup();
  112. exit(2);
  113. case XK_space:
  114. key = 'n';
  115. break;
  116. case XK_BackSpace:
  117. key = 'p';
  118. break;
  119. }
  120. switch (key) {
  121. case 'q':
  122. cleanup();
  123. exit(0);
  124. /* navigate image list */
  125. case 'n':
  126. if (fileidx + 1 < filecnt) {
  127. img_load(&img, filenames[++fileidx]);
  128. changed = 1;
  129. }
  130. break;
  131. case 'p':
  132. if (fileidx > 0) {
  133. img_load(&img, filenames[--fileidx]);
  134. changed = 1;
  135. }
  136. break;
  137. case '[':
  138. if (fileidx != 0) {
  139. fileidx = MAX(0, fileidx - 10);
  140. img_load(&img, filenames[fileidx]);
  141. changed = 1;
  142. }
  143. break;
  144. case ']':
  145. if (fileidx != filecnt - 1) {
  146. fileidx = MIN(fileidx + 10, filecnt - 1);
  147. img_load(&img, filenames[fileidx]);
  148. changed = 1;
  149. }
  150. break;
  151. case 'g':
  152. if (fileidx != 0) {
  153. fileidx = 0;
  154. img_load(&img, filenames[fileidx]);
  155. changed = 1;
  156. }
  157. break;
  158. case 'G':
  159. if (fileidx != filecnt - 1) {
  160. fileidx = filecnt - 1;
  161. img_load(&img, filenames[fileidx]);
  162. changed = 1;
  163. }
  164. break;
  165. /* zooming */
  166. case '+':
  167. case '=':
  168. changed = img_zoom_in(&img);
  169. break;
  170. case '-':
  171. changed = img_zoom_out(&img);
  172. break;
  173. /* panning */
  174. case 'h':
  175. changed = img_pan(&img, &win, PAN_LEFT);
  176. break;
  177. case 'j':
  178. changed = img_pan(&img, &win, PAN_DOWN);
  179. break;
  180. case 'k':
  181. changed = img_pan(&img, &win, PAN_UP);
  182. break;
  183. case 'l':
  184. changed = img_pan(&img, &win, PAN_RIGHT);
  185. break;
  186. /* rotation */
  187. case '<':
  188. changed = img_rotate_left(&img, &win);
  189. break;
  190. case '>':
  191. changed = img_rotate_right(&img, &win);
  192. break;
  193. /* control window */
  194. case 'f':
  195. win_toggle_fullscreen(&win);
  196. break;
  197. /* miscellaneous */
  198. case 'a':
  199. changed = img_toggle_antialias(&img);
  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 Button3:
  223. if (fileidx > 0) {
  224. img_load(&img, filenames[--fileidx]);
  225. changed = 1;
  226. }
  227. break;
  228. case Button4:
  229. if (mask == ControlMask)
  230. changed = img_zoom_in(&img);
  231. else if (mask == ShiftMask)
  232. changed = img_pan(&img, &win, PAN_LEFT);
  233. else
  234. changed = img_pan(&img, &win, PAN_UP);
  235. break;
  236. case Button5:
  237. if (mask == ControlMask)
  238. changed = img_zoom_out(&img);
  239. else if (mask == ShiftMask)
  240. changed = img_pan(&img, &win, PAN_RIGHT);
  241. else
  242. changed = img_pan(&img, &win, PAN_DOWN);
  243. break;
  244. case 6:
  245. changed = img_pan(&img, &win, PAN_LEFT);
  246. break;
  247. case 7:
  248. changed = img_pan(&img, &win, PAN_RIGHT);
  249. break;
  250. }
  251. if (changed) {
  252. img_render(&img, &win);
  253. update_title();
  254. timeout = 0;
  255. }
  256. }
  257. void on_configurenotify(XEvent *ev) {
  258. if (!ev)
  259. return;
  260. if (win_configure(&win, &ev->xconfigure)) {
  261. img.checkpan = 1;
  262. timeout = 1;
  263. }
  264. }
  265. void update_title() {
  266. int n;
  267. n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] <%d%%> %s", fileidx + 1,
  268. filecnt, (int) (img.zoom * 100.0), filenames[fileidx]);
  269. if (n >= TITLE_LEN) {
  270. win_title[TITLE_LEN - 2] = '.';
  271. win_title[TITLE_LEN - 3] = '.';
  272. win_title[TITLE_LEN - 4] = '.';
  273. }
  274. win_set_title(&win, win_title);
  275. }