put the copyright notice inside cnoor.c
[cnoor.git] / txtwin.c
blob101c8551697ff535de25c696470a7e794da1e6e4
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 <pty.h>
12 #include <glib.h>
13 #include <pango/pango.h>
14 #include <pango/pangoft2.h>
16 #include "draw.h"
17 #include "util.h"
19 #define MAXTEXT (1 << 20)
20 #define DPI 196
21 #define PAGESTEPS 8
22 #define CTRLKEY(x) ((x) - 96)
24 struct txtwin {
25 int n;
28 static struct {
29 char name[1 << 4];
30 char desc[1 << 8];
31 } tags[1 << 4] = {
32 {"default", "<span size=\"xx-small\">"}
34 static int ntags = 1;
36 static PangoContext *context;
37 static int width = 1;
38 static int height = 1;
39 static PangoFontMap *fontmap;
40 static FT_Bitmap *bitmap;
41 static char text[MAXTEXT];
42 static char *pos = text;
43 static int count;
45 static FT_Bitmap *create_bitmap(int width, int height)
47 FT_Bitmap *bitmap = g_slice_new(FT_Bitmap);
48 bitmap->width = width;
49 bitmap->pitch = (bitmap->width + 3) & ~3;
50 bitmap->rows = height;
51 bitmap->buffer = g_malloc(bitmap->pitch * bitmap->rows);
52 bitmap->num_grays = 256;
53 bitmap->pixel_mode = ft_pixel_mode_grays;
54 memset(bitmap->buffer, 0, bitmap->pitch * bitmap->rows);
55 return bitmap;
58 static void destroy_bitmap(FT_Bitmap *bitmap)
60 g_free(bitmap->buffer);
61 g_slice_free(FT_Bitmap, bitmap);
64 #define COLORMERGE(f, b, c) ((b) + (((f) - (b)) * (c) >> 8u))
66 static void view_write(int sr)
68 int r, c;
69 fbval_t buf[1 << 14];
70 int nr = MIN(height - sr, fb_rows());
71 int nc = MIN(width, fb_cols());
72 for (r = 0; r < nr; r++) {
73 for (c = 0; c < nc; c++) {
74 int v = bitmap->buffer[(sr + r) * bitmap->pitch + c];
75 int r = COLORMERGE(0xd5, 0x00, 255 - v);
76 int g = COLORMERGE(0xdd, 0x00, 255 - v);
77 int b = COLORMERGE(0xff, 0x00, 255 - v);
78 buf[c] = fb_color(r, g, b);
80 fb_set(r, 0, buf, width);
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 logical_rect;
102 pango_context_set_language(context, pango_language_get_default());
103 pango_context_set_base_dir(context, PANGO_DIRECTION_RTL);
104 layout = make_layout(context, text, -1);
105 pango_layout_get_pixel_extents(layout, NULL, &logical_rect);
106 pango_ft2_render_layout(bitmap, layout, 0, 0);
107 width = MAX(width, MAX(logical_rect.x + logical_rect.width,
108 PANGO_PIXELS(pango_layout_get_width(layout))));
109 height = MAX(logical_rect.y + logical_rect.height,
110 PANGO_PIXELS(pango_layout_get_height(layout)));
111 g_object_unref(layout);
114 static int readkey(void)
116 char b;
117 if (read(STDIN_FILENO, &b, 1) <= 0)
118 return -1;
119 return b;
122 void txtwin_append(struct txtwin *tw, char *s, char *tag)
124 int i;
125 int t = 0;
126 for (i = 0; i < ntags; i++)
127 if (tag && !strcmp(tag, tags[i].name))
128 t = i;
129 snprintf(pos, MAXTEXT - (pos - text),
130 "%s%s</span>", tags[t].desc, s);
131 pos = strchr(pos, '\0');
134 void txtwin_tag(struct txtwin *tw, char *name, char *fg, char *bg, char *font)
136 strcpy(tags[ntags].name, name);
137 snprintf(tags[ntags].desc, sizeof(tags[ntags].desc),
138 "<span font=\"%s\">", font);
139 ntags++;
142 static int getcount(int def)
144 int result = count ? count : def;
145 count = 0;
146 return result;
149 void txtwin_loop(struct txtwin *tw)
151 int step = fb_rows() / PAGESTEPS;
152 int head = 0;
153 int c;
154 struct termios oldtermios, termios;
155 tcgetattr(STDIN_FILENO, &termios);
156 oldtermios = termios;
157 cfmakeraw(&termios);
158 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
159 bitmap = create_bitmap(width, height);
160 do_output(context, text);
161 destroy_bitmap(bitmap);
162 bitmap = create_bitmap(width, height);
163 do_output(context, text);
164 view_write(head);
165 while ((c = readkey()) != -1) {
166 switch (c) {
167 case 27:
168 count = 0;
169 break;
170 case 'q':
171 tcsetattr(STDIN_FILENO, 0, &oldtermios);
172 return;
173 default:
174 if (isdigit(c))
175 count = count * 10 + c - '0';
177 switch (c) {
178 case 'j':
179 head += step * getcount(1);
180 break;
181 case 'k':
182 head -= step * getcount(1);
183 break;
184 case CTRLKEY('f'):
185 case ' ':
186 head += fb_rows() * getcount(1) - step;
187 break;
188 case CTRLKEY('b'):
189 case 127:
190 head -= fb_rows() * getcount(1) - step;
191 break;
192 case CTRLKEY('l'):
193 break;
194 case 'G':
195 if (getcount(0))
196 head = 0;
197 else
198 head = height - fb_rows();
199 break;
200 case '%':
201 if (count)
202 head = height * getcount(0) / 100;
203 break;
204 default:
205 /* no need to redraw */
206 continue;
208 head = MAX(0, MIN(head, height - fb_rows()));
209 view_write(head);
213 void txtwin_gtk_init(int argc, char **argv)
215 char *clear = "\x1b[2J\x1b[H";
216 char *msg = "\t\t\t\t***FBPAN***\n";
217 char *hide = "\x1b[?25l";
218 g_type_init();
219 g_set_prgname("fbpan");
220 setlocale(LC_ALL, "");
221 write(STDIN_FILENO, clear, strlen(clear));
222 write(STDIN_FILENO, msg, strlen(msg));
223 write(STDIN_FILENO, hide, strlen(hide));
224 fb_init();
227 struct txtwin *txtwin_alloc() {
228 fontmap = pango_ft2_font_map_new();
229 pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fontmap), DPI, DPI);
230 context = pango_font_map_create_context(PANGO_FONT_MAP(fontmap));
231 return NULL;
234 void txtwin_free(struct txtwin *tw)
236 char *show = "\x1b[?25h";
237 fb_free();
238 destroy_bitmap(bitmap);
239 g_object_unref(context);
240 g_object_unref(fontmap);
241 write(STDIN_FILENO, show, strlen(show));