fbpdf: add mx and 'x mark commands
[fbpdf.git] / fbpdf.c
blob239151d1ce0cffdf75e98d0db377f9435b83816f
1 /*
2 * fbpdf - a small framebuffer pdf viewer using mupdf
4 * Copyright (C) 2009-2011 Ali Gholami Rudi
6 * This program is released under GNU GPL version 2.
7 */
8 #include <ctype.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <pty.h>
15 #include "draw.h"
16 #include "doc.h"
18 #define MIN(a, b) ((a) < (b) ? (a) : (b))
19 #define MAX(a, b) ((a) > (b) ? (a) : (b))
21 #define PAGESTEPS 8
22 #define CTRLKEY(x) ((x) - 96)
23 #define MAXWIDTH 2
24 #define MAXHEIGHT 3
25 #define PDFCOLS (1 << 11)
26 #define PDFROWS (1 << 12)
28 static fbval_t pbuf[PDFROWS * PDFCOLS];
30 static int num = 1;
31 static struct termios termios;
32 static char filename[256];
33 static int mark[128]; /* page marks */
34 static int zoom = 15;
35 static int rotate;
36 static int head;
37 static int left;
38 static int count;
40 static struct doc *doc;
41 static int pagecount;
43 static void draw(void)
45 int i;
46 for (i = head; i < MIN(head + fb_rows(), PDFROWS); i++)
47 fb_set(i - head, 0, pbuf + i * PDFCOLS + left, fb_cols());
50 static int showpage(int p)
52 if (p < 1 || p > pagecount)
53 return 0;
54 memset(pbuf, 0x00, sizeof(pbuf));
55 doc_draw(doc, pbuf, p, PDFROWS, PDFCOLS, zoom, rotate);
56 num = p;
57 head = 0;
58 draw();
59 return 0;
62 static int readkey(void)
64 unsigned char b;
65 if (read(STDIN_FILENO, &b, 1) <= 0)
66 return -1;
67 return b;
70 static int getcount(int def)
72 int result = count ? count : def;
73 count = 0;
74 return result;
77 static void printinfo(void)
79 printf("\x1b[H");
80 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K",
81 filename, num, pagecount, zoom * 10);
82 fflush(stdout);
85 static void term_setup(void)
87 struct termios newtermios;
88 tcgetattr(STDIN_FILENO, &termios);
89 newtermios = termios;
90 newtermios.c_lflag &= ~ICANON;
91 newtermios.c_lflag &= ~ECHO;
92 tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtermios);
95 static void term_cleanup(void)
97 tcsetattr(STDIN_FILENO, 0, &termios);
100 static void sigcont(int sig)
102 term_setup();
105 static void mainloop(void)
107 int step = fb_rows() / PAGESTEPS;
108 int hstep = fb_cols() / PAGESTEPS;
109 int c, c2;
110 term_setup();
111 signal(SIGCONT, sigcont);
112 showpage(num);
113 while ((c = readkey()) != -1) {
114 int maxhead = PDFROWS - fb_rows();
115 int maxleft = PDFCOLS - fb_cols();
116 switch (c) {
117 case CTRLKEY('f'):
118 case 'J':
119 showpage(num + getcount(1));
120 break;
121 case CTRLKEY('b'):
122 case 'K':
123 showpage(num - getcount(1));
124 break;
125 case 'G':
126 showpage(getcount(pagecount));
127 break;
128 case 'z':
129 zoom = getcount(15);
130 showpage(num);
131 break;
132 case 'r':
133 rotate = getcount(0);
134 showpage(num);
135 break;
136 case 'i':
137 printinfo();
138 break;
139 case 'q':
140 term_cleanup();
141 return;
142 case 27:
143 count = 0;
144 break;
145 case 'm':
146 c2 = readkey();
147 if (isalpha(c2))
148 mark[c2] = num;
149 break;
150 case '`':
151 case '\'':
152 c2 = readkey();
153 if (isalpha(c2) && mark[c2])
154 showpage(mark[c2]);
155 break;
156 default:
157 if (isdigit(c))
158 count = count * 10 + c - '0';
160 switch (c) {
161 case 'j':
162 head += step * getcount(1);
163 break;
164 case 'k':
165 head -= step * getcount(1);
166 break;
167 case 'l':
168 left += hstep * getcount(1);
169 break;
170 case 'h':
171 left -= hstep * getcount(1);
172 break;
173 case 'H':
174 head = 0;
175 break;
176 case 'L':
177 head = maxhead;
178 break;
179 case 'M':
180 head = maxhead / 2;
181 break;
182 case ' ':
183 case CTRL('d'):
184 head += fb_rows() * getcount(1) - step;
185 break;
186 case 127:
187 case CTRL('u'):
188 head -= fb_rows() * getcount(1) - step;
189 break;
190 case CTRLKEY('l'):
191 break;
192 default:
193 /* no need to redraw */
194 continue;
196 head = MAX(0, MIN(maxhead, head));
197 left = MAX(0, MIN(maxleft, left));
198 draw();
202 static char *usage =
203 "usage: fbpdf [-r rotation] [-z zoom x10] [-p page] filename\n";
205 int main(int argc, char *argv[])
207 char *hide = "\x1b[?25l";
208 char *show = "\x1b[?25h";
209 char *clear = "\x1b[2J";
210 int i = 1;
211 if (argc < 2) {
212 printf(usage);
213 return 1;
215 strcpy(filename, argv[argc - 1]);
216 doc = doc_open(filename);
217 if (!doc) {
218 printf("cannot open file\n");
219 return 1;
221 pagecount = doc_pages(doc);
222 while (i + 2 < argc && argv[i][0] == '-') {
223 if (argv[i][1] == 'r')
224 rotate = atoi(argv[i + 1]);
225 if (argv[i][1] == 'z')
226 zoom = atoi(argv[i + 1]);
227 if (argv[i][1] == 'p')
228 num = atoi(argv[i + 1]);
229 i += 2;
232 write(STDIN_FILENO, hide, strlen(hide));
233 write(STDOUT_FILENO, clear, strlen(clear));
234 printinfo();
235 if (fb_init())
236 return 1;
237 if (FBM_BPP(fb_mode()) != sizeof(fbval_t))
238 fprintf(stderr, "fbpdf: fbval_t doesn't match fb depth\n");
239 else
240 mainloop();
241 fb_free();
242 write(STDIN_FILENO, show, strlen(show));
243 printf("\n");
244 doc_close(doc);
245 return 0;