A Simple X Image Viewer
 
 
 
 
 
 

259 line
5.6 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
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <sys/stat.h>
  22. #include "events.h"
  23. #include "image.h"
  24. #include "options.h"
  25. #include "thumbs.h"
  26. #include "types.h"
  27. #include "util.h"
  28. #include "window.h"
  29. enum {
  30. TITLE_LEN = 256,
  31. FNAME_CNT = 1024
  32. };
  33. appmode_t mode;
  34. img_t img;
  35. tns_t tns;
  36. win_t win;
  37. fileinfo_t *files;
  38. int filecnt, fileidx;
  39. size_t filesize;
  40. char win_title[TITLE_LEN];
  41. void cleanup() {
  42. static int in = 0;
  43. if (!in++) {
  44. img_close(&img, 0);
  45. tns_free(&tns);
  46. win_close(&win);
  47. }
  48. }
  49. void check_add_file(char *filename) {
  50. if (!filename || !*filename)
  51. return;
  52. if (access(filename, R_OK)) {
  53. warn("could not open file: %s", filename);
  54. return;
  55. }
  56. if (fileidx == filecnt) {
  57. filecnt *= 2;
  58. files = (fileinfo_t*) s_realloc(files, filecnt * sizeof(fileinfo_t));
  59. }
  60. if (*filename != '/') {
  61. files[fileidx].path = absolute_path(filename);
  62. if (!files[fileidx].path) {
  63. warn("could not get absolute path of file: %s\n", filename);
  64. return;
  65. }
  66. }
  67. files[fileidx].name = s_strdup(filename);
  68. if (*filename == '/')
  69. files[fileidx].path = files[fileidx].name;
  70. fileidx++;
  71. }
  72. void remove_file(int n, unsigned char silent) {
  73. if (n < 0 || n >= filecnt)
  74. return;
  75. if (filecnt == 1) {
  76. if (!silent)
  77. fprintf(stderr, "sxiv: no more files to display, aborting\n");
  78. cleanup();
  79. exit(!silent);
  80. }
  81. if (n + 1 < filecnt) {
  82. if (files[n].path != files[n].name)
  83. free((void*) files[n].path);
  84. free((void*) files[n].name);
  85. memmove(files + n, files + n + 1, (filecnt - n - 1) * sizeof(fileinfo_t));
  86. }
  87. if (n + 1 < tns.cnt) {
  88. memmove(tns.thumbs + n, tns.thumbs + n + 1, (tns.cnt - n - 1) *
  89. sizeof(thumb_t));
  90. memset(tns.thumbs + tns.cnt - 1, 0, sizeof(thumb_t));
  91. }
  92. filecnt--;
  93. if (n < tns.cnt)
  94. tns.cnt--;
  95. }
  96. void load_image(int new) {
  97. struct stat fstats;
  98. if (new < 0 || new >= filecnt)
  99. return;
  100. /* cursor is reset in redraw() */
  101. win_set_cursor(&win, CURSOR_WATCH);
  102. img_close(&img, 0);
  103. while (!img_load(&img, &files[new])) {
  104. remove_file(new, 0);
  105. if (new >= filecnt)
  106. new = filecnt - 1;
  107. }
  108. fileidx = new;
  109. if (!stat(files[new].path, &fstats))
  110. filesize = fstats.st_size;
  111. else
  112. filesize = 0;
  113. }
  114. void update_title() {
  115. int n;
  116. float size;
  117. const char *unit;
  118. if (mode == MODE_THUMB) {
  119. n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] %s",
  120. tns.cnt ? tns.sel + 1 : 0, tns.cnt,
  121. tns.cnt ? files[tns.sel].name : "");
  122. } else {
  123. size = filesize;
  124. size_readable(&size, &unit);
  125. n = snprintf(win_title, TITLE_LEN,
  126. "sxiv: [%d/%d] <%d%%> <%dx%d> (%.2f%s) %s",
  127. fileidx + 1, filecnt, (int) (img.zoom * 100.0), img.w, img.h,
  128. size, unit, files[fileidx].name);
  129. }
  130. if (n >= TITLE_LEN) {
  131. for (n = 0; n < 3; n++)
  132. win_title[TITLE_LEN - n - 2] = '.';
  133. }
  134. win_set_title(&win, win_title);
  135. }
  136. int fncmp(const void *a, const void *b) {
  137. return strcoll(((fileinfo_t*) a)->name, ((fileinfo_t*) b)->name);
  138. }
  139. int main(int argc, char **argv) {
  140. int i, len, start;
  141. size_t n;
  142. char *filename;
  143. struct stat fstats;
  144. r_dir_t dir;
  145. parse_options(argc, argv);
  146. if (options->clean_cache) {
  147. tns_init(&tns, 0);
  148. tns_clean_cache(&tns);
  149. exit(0);
  150. }
  151. if (!options->filecnt) {
  152. print_usage();
  153. exit(1);
  154. }
  155. if (options->recursive || options->from_stdin)
  156. filecnt = FNAME_CNT;
  157. else
  158. filecnt = options->filecnt;
  159. files = (fileinfo_t*) s_malloc(filecnt * sizeof(fileinfo_t));
  160. fileidx = 0;
  161. /* build file list: */
  162. if (options->from_stdin) {
  163. filename = NULL;
  164. while ((len = getline(&filename, &n, stdin)) > 0) {
  165. if (filename[len-1] == '\n')
  166. filename[len-1] = '\0';
  167. check_add_file(filename);
  168. }
  169. } else {
  170. for (i = 0; i < options->filecnt; i++) {
  171. filename = options->filenames[i];
  172. if (stat(filename, &fstats) || !S_ISDIR(fstats.st_mode)) {
  173. check_add_file(filename);
  174. } else {
  175. if (!options->recursive) {
  176. warn("ignoring directory: %s", filename);
  177. continue;
  178. }
  179. if (r_opendir(&dir, filename)) {
  180. warn("could not open directory: %s", filename);
  181. continue;
  182. }
  183. start = fileidx;
  184. printf("reading dir: %s\n", filename);
  185. while ((filename = r_readdir(&dir))) {
  186. check_add_file(filename);
  187. free((void*) filename);
  188. }
  189. r_closedir(&dir);
  190. if (fileidx - start > 1)
  191. qsort(files + start, fileidx - start, sizeof(fileinfo_t), fncmp);
  192. }
  193. }
  194. }
  195. if (!fileidx) {
  196. fprintf(stderr, "sxiv: no valid image file given, aborting\n");
  197. exit(1);
  198. }
  199. filecnt = fileidx;
  200. fileidx = options->startnum < filecnt ? options->startnum : 0;
  201. win_init(&win);
  202. img_init(&img, &win);
  203. if (options->thumbnails) {
  204. mode = MODE_THUMB;
  205. tns_init(&tns, filecnt);
  206. while (!tns_load(&tns, 0, &files[0], False, False))
  207. remove_file(0, 0);
  208. tns.cnt = 1;
  209. } else {
  210. mode = MODE_IMAGE;
  211. tns.thumbs = NULL;
  212. load_image(fileidx);
  213. }
  214. win_open(&win);
  215. run();
  216. cleanup();
  217. return 0;
  218. }