fbpan backend
[cnoor.git] / txtwin_fbpan.c
blob5541e0d13978ab0a11622f7668a8ff2f11050e9b
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <locale.h>
4 #include <poll.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/wait.h>
9 #include <pty.h>
11 #include <glib.h>
12 #include <pango/pango.h>
13 #include <pango/pangoft2.h>
15 #include "draw.h"
16 #include "util.h"
18 #define MAXTEXT (1 << 20)
19 #define DPI 196
20 #define PAGESTEPS 8
21 #define CTRLKEY(x) ((x) - 96)
23 struct txtwin {
24 int n;
27 static struct {
28 char name[1 << 4];
29 char desc[1 << 8];
30 } tags[1 << 4] = {
31 {"default", "<span size=\"xx-small\">"}
33 static int ntags = 1;
35 static PangoContext *context;
36 static int width = 1;
37 static int height = 1;
38 static PangoFontMap *fontmap;
39 static FT_Bitmap *bitmap;
40 static char text[MAXTEXT];
41 static char *pos = text;
43 static FT_Bitmap *create_bitmap(int width, int height)
45 FT_Bitmap *bitmap = g_slice_new(FT_Bitmap);
46 bitmap->width = width;
47 bitmap->pitch = (bitmap->width + 3) & ~3;
48 bitmap->rows = height;
49 bitmap->buffer = g_malloc(bitmap->pitch * bitmap->rows);
50 bitmap->num_grays = 256;
51 bitmap->pixel_mode = ft_pixel_mode_grays;
52 memset(bitmap->buffer, 0, bitmap->pitch * bitmap->rows);
53 return bitmap;
56 static void destroy_bitmap(FT_Bitmap *bitmap)
58 g_free(bitmap->buffer);
59 g_slice_free(FT_Bitmap, bitmap);
62 #define COLORMERGE(f, b, c) ((b) + (((f) - (b)) * (c) >> 8u))
64 static void view_write(int sr)
66 int r, c;
67 fbval_t buf[1 << 14];
68 int nr = MIN(height - sr, fb_rows());
69 int nc = MIN(width, fb_cols());
70 for (r = 0; r < nr; r++) {
71 for (c = 0; c < nc; c++) {
72 int v = bitmap->buffer[(sr + r) * bitmap->pitch + c];
73 int r = COLORMERGE(0xd5, 0x00, 255 - v);
74 int g = COLORMERGE(0xdd, 0x00, 255 - v);
75 int b = COLORMERGE(0xff, 0x00, 255 - v);
76 buf[c] = fb_color(r, g, b);
78 fb_set(r, 0, buf, width);
82 static PangoLayout *make_layout(PangoContext *context, char *text, double size)
84 static PangoFontDescription *font_description;
85 PangoLayout *layout = pango_layout_new(context);
86 pango_layout_set_markup(layout, text, -1);
87 pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
88 pango_layout_set_width(layout, fb_cols() << 10);
89 pango_layout_set_height(layout, -1);
90 pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
91 pango_layout_set_font_description(layout, font_description);
92 pango_font_description_free(font_description);
93 return layout;
96 static void do_output(PangoContext *context, char *text)
98 PangoLayout *layout;
99 PangoRectangle logical_rect;
100 pango_context_set_language(context, pango_language_get_default());
101 pango_context_set_base_dir(context, PANGO_DIRECTION_RTL);
102 layout = make_layout(context, text, -1);
103 pango_layout_get_pixel_extents(layout, NULL, &logical_rect);
104 pango_ft2_render_layout(bitmap, layout, 0, 0);
105 width = MAX(width, MAX(logical_rect.x + logical_rect.width,
106 PANGO_PIXELS(pango_layout_get_width(layout))));
107 height = MAX(logical_rect.y + logical_rect.height,
108 PANGO_PIXELS(pango_layout_get_height(layout)));
109 g_object_unref(layout);
112 static int readkey(void)
114 char b;
115 if (read(STDIN_FILENO, &b, 1) <= 0)
116 return -1;
117 return b;
120 void txtwin_append(struct txtwin *tw, char *s, char *tag)
122 int i;
123 int t = 0;
124 for (i = 0; i < ntags; i++)
125 if (tag && !strcmp(tag, tags[i].name))
126 t = i;
127 snprintf(pos, MAXTEXT - (pos - text),
128 "%s%s</span>", tags[t].desc, s);
129 pos = strchr(pos, '\0');
132 void txtwin_tag(struct txtwin *tw, char *name, char *fg, char *bg, char *font)
134 strcpy(tags[ntags].name, name);
135 snprintf(tags[ntags].desc, sizeof(tags[ntags].desc),
136 "<span font=\"%s\">", font);
137 ntags++;
140 void txtwin_loop(struct txtwin *tw)
142 int step = fb_rows() / PAGESTEPS;
143 int head = 0;
144 int c;
145 struct termios oldtermios, termios;
146 tcgetattr(STDIN_FILENO, &termios);
147 oldtermios = termios;
148 cfmakeraw(&termios);
149 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
150 bitmap = create_bitmap(width, height);
151 do_output(context, text);
152 destroy_bitmap(bitmap);
153 bitmap = create_bitmap(width, height);
154 do_output(context, text);
155 view_write(head);
156 while ((c = readkey()) != -1) {
157 switch (c) {
158 case 'j':
159 head += step;
160 break;
161 case 'k':
162 head -= step;
163 break;
164 case CTRLKEY('f'):
165 case ' ':
166 head += fb_rows() - step;
167 break;
168 case CTRLKEY('b'):
169 head -= fb_rows() - step;
170 break;
171 case 'G':
172 head = height - fb_rows();
173 break;
174 case 'q':
175 tcsetattr(STDIN_FILENO, 0, &oldtermios);
176 return;
178 head = MAX(0, MIN(head, height - fb_rows()));
179 view_write(head);
183 void txtwin_gtk_init(int argc, char **argv)
185 char *clear = "\x1b[2J\x1b[H";
186 char *msg = "\t\t\t\t***FBPAN***\n";
187 char *hide = "\x1b[?25l";
188 g_type_init();
189 g_set_prgname("fbpan");
190 setlocale(LC_ALL, "");
191 write(STDIN_FILENO, clear, strlen(clear));
192 write(STDIN_FILENO, msg, strlen(msg));
193 write(STDIN_FILENO, hide, strlen(hide));
194 fb_init();
197 struct txtwin *txtwin_alloc() {
198 fontmap = pango_ft2_font_map_new();
199 pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fontmap), DPI, DPI);
200 context = pango_font_map_create_context(PANGO_FONT_MAP(fontmap));
201 return NULL;
204 void txtwin_free(struct txtwin *tw)
206 char *show = "\x1b[?25h";
207 fb_free();
208 destroy_bitmap(bitmap);
209 g_object_unref(context);
210 g_object_unref(fontmap);
211 write(STDIN_FILENO, show, strlen(show));