redraw with ^l
[fbpdf.git] / fbpdf.c
blobc1d505d37b92d528e48bbee6656a6b5108ddd3ad
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <pty.h>
7 #include <cairo/cairo.h>
8 #include <glib/poppler.h>
9 #include "draw.h"
11 #define PAGESTEPS 8
12 #define CTRLKEY(x) ((x) - 96)
13 #define MAXWIDTH 2
14 #define MAXHEIGHT 3
16 static PopplerDocument *doc;
17 static PopplerPage *page;
18 static int num;
19 static cairo_t *cairo;
20 static cairo_surface_t *surface;
21 static char filename[PATH_MAX];
22 static int zoom = 15;
23 static int head;
24 static int left;
25 static int count;
27 static void draw()
29 unsigned char *img = cairo_image_surface_get_data(surface);
30 fbval_t slice[1 << 14];
31 int i, j;
32 int h = MIN(fb_rows(), cairo_image_surface_get_height(surface));
33 int w = MIN(fb_cols(), cairo_image_surface_get_width(surface));
34 int cols = cairo_image_surface_get_width(surface);
35 for (i = head; i < h + head; i++) {
36 for (j = left; j < w + left; j++) {
37 unsigned char *p = img + (i * cols + j) * 4;
38 slice[j - left] = fb_color(*p, *(p + 1), *(p + 2));
40 fb_set(i - head, 0, slice, w);
44 static int load_document(void)
46 char abspath[PATH_MAX];
47 char uri[PATH_MAX + 16];
48 realpath(filename, abspath);
49 snprintf(uri, sizeof(uri), "file://%s", abspath);
50 doc = poppler_document_new_from_file(uri, NULL, NULL);
51 return !doc;
54 static void cleanup_page(void)
56 if (cairo)
57 cairo_destroy(cairo);
58 if (surface)
59 cairo_surface_destroy(surface);
60 if (page)
61 g_object_unref(G_OBJECT(page));
64 static void showpage(int p)
66 if (p < 0 || p >= poppler_document_get_n_pages(doc))
67 return;
68 cleanup_page();
69 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
70 fb_cols() * MAXWIDTH, fb_rows() * MAXHEIGHT);
71 cairo = cairo_create(surface);
72 cairo_scale(cairo, (float) zoom / 10, (float) zoom / 10);
73 cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0);
74 cairo_paint(cairo);
75 num = p;
76 page = poppler_document_get_page(doc, p);
77 poppler_page_render(page, cairo);
78 head = 0;
79 draw();
82 static int readkey(void)
84 unsigned char b;
85 if (read(STDIN_FILENO, &b, 1) <= 0)
86 return -1;
87 return b;
90 static int getcount(int def)
92 int result = count ? count : def;
93 count = 0;
94 return result;
97 static void printinfo(void)
99 printf("\x1b[H");
100 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K",
101 filename, num + 1, poppler_document_get_n_pages(doc), zoom * 10);
102 fflush(stdout);
105 static void mainloop()
107 int step = fb_rows() / PAGESTEPS;
108 int hstep = fb_cols() / PAGESTEPS;
109 struct termios oldtermios, termios;
110 int c;
111 tcgetattr(STDIN_FILENO, &termios);
112 oldtermios = termios;
113 cfmakeraw(&termios);
114 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
115 showpage(0);
116 while ((c = readkey()) != -1) {
117 int maxhead = cairo_image_surface_get_height(surface) - fb_rows();
118 int maxleft = cairo_image_surface_get_width(surface) - fb_cols();
119 switch (c) {
120 case CTRLKEY('f'):
121 case 'J':
122 showpage(num + getcount(1));
123 break;
124 case CTRLKEY('b'):
125 case 'K':
126 showpage(num - getcount(1));
127 break;
128 case 'G':
129 showpage(getcount(poppler_document_get_n_pages(doc)) - 1);
130 break;
131 case 'z':
132 zoom = getcount(15);
133 showpage(num);
134 break;
135 case 'i':
136 printinfo();
137 break;
138 case 'q':
139 tcsetattr(STDIN_FILENO, 0, &oldtermios);
140 return;
141 case 27:
142 count = 0;
143 break;
144 default:
145 if (isdigit(c))
146 count = count * 10 + c - '0';
148 switch (c) {
149 case 'j':
150 head += step * getcount(1);
151 break;
152 case 'k':
153 head -= step * getcount(1);
154 break;
155 case 'l':
156 left += hstep * getcount(1);
157 break;
158 case 'h':
159 left -= hstep * getcount(1);
160 break;
161 case 'H':
162 head = 0;
163 break;
164 case 'L':
165 head = maxhead;
166 break;
167 case 'M':
168 head = maxhead / 2;
169 break;
170 case ' ':
171 head += fb_rows() * getcount(1) - step;
172 break;
173 case '\b':
174 head -= fb_rows() * getcount(1) - step;
175 break;
176 case CTRLKEY('l'):
177 break;
178 default:
179 /* no need to redraw */
180 continue;
182 head = MAX(0, MIN(maxhead, head));
183 left = MAX(0, MIN(maxleft, left));
184 draw();
188 int main(int argc, char* argv[])
190 char *hide = "\x1b[?25l";
191 char *show = "\x1b[?25h";
192 char *clear = "\x1b[2J";
193 if (argc < 2) {
194 printf("usage: fbpdf filename\n");
195 return 1;
197 g_type_init();
198 strcpy(filename, argv[1]);
199 if (load_document()) {
200 printf("cannot open file\n");
201 return 1;
203 write(STDIN_FILENO, hide, strlen(hide));
204 write(STDOUT_FILENO, clear, strlen(clear));
205 printinfo();
206 fb_init();
207 mainloop();
208 cleanup_page();
209 fb_free();
210 if (doc)
211 g_object_unref(G_OBJECT(doc));
212 write(STDIN_FILENO, show, strlen(show));
213 printf("\n");
214 return 0;