A Simple X Image Viewer
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

340 lines
6.2 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. case XK_Left:
  120. key = 'h';
  121. break;
  122. case XK_Down:
  123. key = 'j';
  124. break;
  125. case XK_Up:
  126. key = 'k';
  127. break;
  128. case XK_Right:
  129. key = 'l';
  130. break;
  131. }
  132. switch (key) {
  133. case 'q':
  134. cleanup();
  135. exit(0);
  136. /* navigate image list */
  137. case 'n':
  138. if (fileidx + 1 < filecnt) {
  139. img_load(&img, filenames[++fileidx]);
  140. changed = 1;
  141. }
  142. break;
  143. case 'p':
  144. if (fileidx > 0) {
  145. img_load(&img, filenames[--fileidx]);
  146. changed = 1;
  147. }
  148. break;
  149. case '[':
  150. if (fileidx != 0) {
  151. fileidx = MAX(0, fileidx - 10);
  152. img_load(&img, filenames[fileidx]);
  153. changed = 1;
  154. }
  155. break;
  156. case ']':
  157. if (fileidx != filecnt - 1) {
  158. fileidx = MIN(fileidx + 10, filecnt - 1);
  159. img_load(&img, filenames[fileidx]);
  160. changed = 1;
  161. }
  162. break;
  163. case 'g':
  164. if (fileidx != 0) {
  165. fileidx = 0;
  166. img_load(&img, filenames[fileidx]);
  167. changed = 1;
  168. }
  169. break;
  170. case 'G':
  171. if (fileidx != filecnt - 1) {
  172. fileidx = filecnt - 1;
  173. img_load(&img, filenames[fileidx]);
  174. changed = 1;
  175. }
  176. break;
  177. /* zooming */
  178. case '+':
  179. case '=':
  180. changed = img_zoom_in(&img);
  181. break;
  182. case '-':
  183. changed = img_zoom_out(&img);
  184. break;
  185. /* panning */
  186. case 'h':
  187. changed = img_pan(&img, &win, PAN_LEFT);
  188. break;
  189. case 'j':
  190. changed = img_pan(&img, &win, PAN_DOWN);
  191. break;
  192. case 'k':
  193. changed = img_pan(&img, &win, PAN_UP);
  194. break;
  195. case 'l':
  196. changed = img_pan(&img, &win, PAN_RIGHT);
  197. break;
  198. /* rotation */
  199. case '<':
  200. changed = img_rotate_left(&img, &win);
  201. break;
  202. case '>':
  203. changed = img_rotate_right(&img, &win);
  204. break;
  205. /* control window */
  206. case 'f':
  207. win_toggle_fullscreen(&win);
  208. break;
  209. /* miscellaneous */
  210. case 'a':
  211. changed = img_toggle_antialias(&img);
  212. break;
  213. }
  214. if (changed) {
  215. img_render(&img, &win);
  216. update_title();
  217. timeout = 0;
  218. }
  219. }
  220. void on_buttonpress(XEvent *ev) {
  221. int changed;
  222. unsigned int mask;
  223. if (!ev)
  224. return;
  225. mask = CLEANMASK(ev->xbutton.state);
  226. changed = 0;
  227. switch (ev->xbutton.button) {
  228. case Button1:
  229. if (fileidx + 1 < filecnt) {
  230. img_load(&img, filenames[++fileidx]);
  231. changed = 1;
  232. }
  233. break;
  234. case Button3:
  235. if (fileidx > 0) {
  236. img_load(&img, filenames[--fileidx]);
  237. changed = 1;
  238. }
  239. break;
  240. case Button4:
  241. if (mask == ControlMask)
  242. changed = img_zoom_in(&img);
  243. else if (mask == ShiftMask)
  244. changed = img_pan(&img, &win, PAN_LEFT);
  245. else
  246. changed = img_pan(&img, &win, PAN_UP);
  247. break;
  248. case Button5:
  249. if (mask == ControlMask)
  250. changed = img_zoom_out(&img);
  251. else if (mask == ShiftMask)
  252. changed = img_pan(&img, &win, PAN_RIGHT);
  253. else
  254. changed = img_pan(&img, &win, PAN_DOWN);
  255. break;
  256. case 6:
  257. changed = img_pan(&img, &win, PAN_LEFT);
  258. break;
  259. case 7:
  260. changed = img_pan(&img, &win, PAN_RIGHT);
  261. break;
  262. }
  263. if (changed) {
  264. img_render(&img, &win);
  265. update_title();
  266. timeout = 0;
  267. }
  268. }
  269. void on_configurenotify(XEvent *ev) {
  270. if (!ev)
  271. return;
  272. if (win_configure(&win, &ev->xconfigure)) {
  273. img.checkpan = 1;
  274. timeout = 1;
  275. }
  276. }
  277. void update_title() {
  278. int n;
  279. n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] <%d%%> %s", fileidx + 1,
  280. filecnt, (int) (img.zoom * 100.0), filenames[fileidx]);
  281. if (n >= TITLE_LEN) {
  282. win_title[TITLE_LEN - 2] = '.';
  283. win_title[TITLE_LEN - 3] = '.';
  284. win_title[TITLE_LEN - 4] = '.';
  285. }
  286. win_set_title(&win, win_title);
  287. }