txtwin: mark previous position with '
[cnoor.git] / txtwin.c
blob185ca1cb211b470e7d793eb5147fb63f9aec4878
1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <locale.h>
5 #include <poll.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
11 #include <pty.h>
13 #include <glib.h>
14 #include <pango/pango.h>
15 #include <pango/pangoft2.h>
17 #include "draw.h"
18 #include "config.h"
20 #define MAXTEXT (1 << 20)
21 #define MAXLINE ((MAXTEXT) >> 4)
22 #define DPI 196
23 #define PAGESTEPS 8
24 #define CTRLKEY(x) ((x) - 96)
26 #define CR(a) (((a) >> 16) & 0xff)
27 #define CG(a) (((a) >> 8) & 0xff)
28 #define CB(a) ((a) & 0xff)
29 #define COLORMERGE(f, b, c) ((b) + (((f) - (b)) * (c) >> 8u))
31 static PangoContext *context;
32 static PangoFontMap *fontmap;
33 static FT_Bitmap *bitmap;
34 static char name[128]; /* sura name */
35 static int pcols = 1; /* bitmap width */
36 static int prows = 1; /* bitmap height */
37 static int head;
38 static char text[MAXTEXT];
39 static char *pos = text;
40 static int pos_off;
41 static int count;
42 static int mark[256];
43 static int lnpos[MAXLINE]; /* line offsets as reported by txtwin_line() */
44 static int lnrow[MAXLINE]; /* line row in the layout */
45 static int nlnpos;
47 static void draw(int sr)
49 int r, c;
50 fbval_t buf[1 << 14];
51 int nr = MIN(prows - sr, fb_rows());
52 int nc = MIN(pcols, fb_cols());
53 for (r = 0; r < nr; r++) {
54 for (c = 0; c < nc; c++) {
55 int v = bitmap->buffer[(sr + r) * bitmap->pitch + c];
56 int r = COLORMERGE(CR(COLOR_FG), CR(COLOR_BG), v);
57 int g = COLORMERGE(CG(COLOR_FG), CG(COLOR_BG), v);
58 int b = COLORMERGE(CB(COLOR_FG), CB(COLOR_BG), v);
59 buf[c] = FB_VAL(r, g, b);
61 fb_set(r, 0, buf, pcols);
65 static FT_Bitmap *create_bitmap(int pcols, int prows)
67 FT_Bitmap *bitmap = g_slice_new(FT_Bitmap);
68 bitmap->width = pcols;
69 bitmap->pitch = (bitmap->width + 3) & ~3;
70 bitmap->rows = prows;
71 bitmap->buffer = g_malloc(bitmap->pitch * bitmap->rows);
72 bitmap->num_grays = 256;
73 bitmap->pixel_mode = ft_pixel_mode_grays;
74 memset(bitmap->buffer, 0, bitmap->pitch * bitmap->rows);
75 return bitmap;
78 static void destroy_bitmap(FT_Bitmap *bitmap)
80 g_free(bitmap->buffer);
81 g_slice_free(FT_Bitmap, bitmap);
84 static PangoLayout *make_layout(PangoContext *context, char *text, double size)
86 static PangoFontDescription *font_description;
87 PangoLayout *layout = pango_layout_new(context);
88 pango_layout_set_markup(layout, text, -1);
89 pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
90 pango_layout_set_width(layout, fb_cols() << 10);
91 pango_layout_set_height(layout, -1);
92 pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
93 pango_layout_set_font_description(layout, font_description);
94 pango_font_description_free(font_description);
95 return layout;
98 static void do_output(PangoContext *context, char *text)
100 PangoLayout *layout;
101 PangoRectangle rect;
102 int i;
103 pango_context_set_language(context, pango_language_get_default());
104 pango_context_set_base_dir(context, PANGO_DIRECTION_RTL);
105 layout = make_layout(context, text, -1);
106 pango_layout_get_pixel_extents(layout, NULL, &rect);
107 pango_ft2_render_layout(bitmap, layout, 0, 0);
108 pcols = MAX(pcols, MAX(rect.x + rect.width,
109 PANGO_PIXELS(pango_layout_get_width(layout))));
110 prows = MAX(rect.y + rect.height,
111 PANGO_PIXELS(pango_layout_get_height(layout)));
112 for (i = 0; i < nlnpos; i++) {
113 pango_layout_index_to_pos(layout, lnpos[i], &rect);
114 lnrow[i] = PANGO_PIXELS(rect.y);
116 g_object_unref(layout);
119 static int readkey(void)
121 char b;
122 if (read(0, &b, 1) <= 0)
123 return -1;
124 return (unsigned char) b;
127 void txtwin_append(char *s, char *font)
129 snprintf(pos, MAXTEXT - (pos - text),
130 "<span font=\"%s\">%s</span>", font, s);
131 pos = strchr(pos, '\0');
132 pos_off += strlen(s);
135 void txtwin_line(void)
137 lnpos[nlnpos++] = pos_off;
140 static int getcount(int def)
142 int result = count ? count : def;
143 count = 0;
144 return result;
147 static void printinfo(void)
149 printf("\x1b[H");
150 printf("CNOOR \t\t\t %d%% \t\t\t %s \x1b[K", head * 100 / prows, name);
151 fflush(stdout);
154 static void scroll(int h)
156 mark['\''] = head;
157 head = MAX(0, MIN(h, prows - fb_rows()));
160 static void scroll_rel(int diff)
162 head = MAX(0, MIN(head + diff, prows - fb_rows()));
165 void txtwin_loop(void)
167 int step = fb_rows() / PAGESTEPS;
168 struct termios oldtermios, termios;
169 int c, i;
170 tcgetattr(0, &termios);
171 oldtermios = termios;
172 cfmakeraw(&termios);
173 tcsetattr(0, TCSAFLUSH, &termios);
174 bitmap = create_bitmap(pcols, prows);
175 do_output(context, text);
176 destroy_bitmap(bitmap);
177 bitmap = create_bitmap(pcols, prows);
178 do_output(context, text);
179 draw(head);
180 while ((c = readkey()) >= 0) {
181 switch (c) {
182 case 27:
183 count = 0;
184 break;
185 case 'q':
186 tcsetattr(0, 0, &oldtermios);
187 return;
188 default:
189 if (isdigit(c))
190 count = count * 10 + c - '0';
192 switch (c) {
193 case 'j':
194 scroll_rel(+step * getcount(1));
195 break;
196 case 'k':
197 scroll_rel(-step * getcount(1));
198 break;
199 case CTRLKEY('f'):
200 case ' ':
201 scroll_rel(+fb_rows() * getcount(1) - step);
202 break;
203 case CTRLKEY('b'):
204 case 127:
205 scroll_rel(-fb_rows() * getcount(1) + step);
206 break;
207 case CTRLKEY('l'):
208 break;
209 case 'G':
210 i = getcount(0);
211 if (i > 0 && i < nlnpos)
212 scroll(MIN(lnrow[i - 1], prows - fb_rows()));
213 else
214 scroll(prows - fb_rows());
215 break;
216 case '%':
217 if (count)
218 scroll(prows * getcount(0) / 100);
219 break;
220 case 'i':
221 printinfo();
222 continue;
223 case 'm':
224 mark[readkey()] = head;
225 continue;
226 case '\'':
227 c = readkey();
228 if (mark[c] >= 0)
229 scroll(mark[c]);
230 break;
231 default:
232 /* no need to redraw */
233 continue;
235 draw(head);
239 void txtwin_init(char *sura)
241 setlocale(LC_ALL, "");
242 g_set_prgname("cnoor");
243 fontmap = pango_ft2_font_map_new();
244 pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fontmap), DPI, DPI);
245 context = pango_font_map_create_context(PANGO_FONT_MAP(fontmap));
246 strcpy(name, sura);
247 if (fb_init())
248 exit(1);
249 if (FBM_BPP(fb_mode()) != sizeof(fbval_t)) {
250 fprintf(stderr, "cnoor: fbval_t doesn't match fb depth\n");
251 exit(1);
253 printf("\x1b[2J\x1b[H\x1b[?25l");
254 printinfo();
255 memset(mark, 0xff, sizeof(mark));
258 void txtwin_free(void)
260 fb_free();
261 destroy_bitmap(bitmap);
262 g_object_unref(context);
263 g_object_unref(fontmap);
264 printf("\x1b[?25h\n");