2 * kmscon - Console Management
3 * Written 2011 by David Herrmann <dh.herrmann@googlemail.com>
8 * This provides the console drawing and manipulation functions. It does not
9 * provide the terminal emulation. It is just an abstraction layer to draw text
10 * to a framebuffer as used by terminals and consoles.
14 * TODO: Avoid using this hack and instead retrieve GL extension
15 * pointers dynamically on initialization.
17 #define GL_GLEXT_PROTOTYPES
30 struct kmscon_char *ch;
33 struct kmscon_console {
41 cairo_surface_t *surf;
42 unsigned char *surf_buf;
46 struct kmscon_cell *cells;
49 int kmscon_console_new(struct kmscon_console **out)
51 struct kmscon_console *con;
56 con = malloc(sizeof(*con));
60 memset(con, 0, sizeof(*con));
63 glGenTextures(1, &con->tex);
69 void kmscon_console_ref(struct kmscon_console *con)
77 static void console_free_cells(struct kmscon_console *con)
82 size = con->lines_x * con->lines_y;
84 for (i = 0; i < size; ++i)
85 kmscon_char_free(con->cells[i].ch);
92 * Drops one reference. If this is the last reference, the whole console is
93 * freed and the associated render-images are destroyed.
95 void kmscon_console_unref(struct kmscon_console *con)
97 if (!con || !con->ref)
104 cairo_destroy(con->cr);
105 cairo_surface_destroy(con->surf);
109 console_free_cells(con);
110 glDeleteTextures(1, &con->tex);
115 * This resets the resolution used for drawing operations. It is recommended to
116 * set this to the size of your framebuffer, howevr, you can set this to
118 * This image-resolution is used internally to render the console fonts. The
119 * kmscon_console_map() function can map this image to any framebuffer size you
120 * want. Therefore, this screen resolution is just a performance and quality
122 * This function must be called before drawing the console, though. Returns 0 on
123 * success, -EINVAL if con, x or y is 0/NULL and -ENOMEM on out-of-mem errors.
125 int kmscon_console_set_res(struct kmscon_console *con, uint32_t x, uint32_t y)
129 cairo_surface_t *surface;
131 cairo_format_t format = CAIRO_FORMAT_ARGB32;
133 if (!con || !x || !y)
136 stride = cairo_format_stride_for_width(format, x);
138 buf = malloc(stride * y);
142 surface = cairo_image_surface_create_for_data(buf, format, x, y,
144 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
149 cr = cairo_create(surface);
150 if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
156 cairo_destroy(con->cr);
157 cairo_surface_destroy(con->surf);
167 glBindTexture(GL_TEXTURE_RECTANGLE, con->tex);
168 glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, con->res_x, con->res_y,
169 0, GL_BGRA, GL_UNSIGNED_BYTE, con->surf_buf);
170 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
177 cairo_surface_destroy(surface);
183 * This redraws the console. It does not clip/copy the image onto any
184 * framebuffer. You must use kmscon_console_map() to do this.
185 * This allows to draw the console once and then map it onto multiple
186 * framebuffers so it is displayed on multiple monitors with different screen
188 * You must have called kmscon_console_set_res() before.
190 void kmscon_console_draw(struct kmscon_console *con)
192 if (!con || !con->cr)
197 cairo_set_operator(con->cr, CAIRO_OPERATOR_OVER);
198 cairo_scale(con->cr, con->res_x, con->res_y);
199 cairo_set_source_rgba(con->cr, 0.0, 0.0, 0.0, 0.0);
200 cairo_paint(con->cr);
202 // TODO: draw console here
204 cairo_restore(con->cr);
208 * This maps the console onto the current GL framebuffer. It expects the
209 * framebuffer to have 0/0 in the middle, -1/-1 in the upper left and 1/1 in the
210 * lower right (default GL settings).
211 * This does not clear the screen, nor does it paint the background. Instead the
212 * background is transparent and blended on top of the framebuffer.
214 * You must have called kmscon_console_draw() before, otherwise this will map an
215 * empty image onto the screen.
217 void kmscon_console_map(struct kmscon_console *con)
219 if (!con || !con->cr)
223 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
224 glEnable(GL_TEXTURE_RECTANGLE);
225 glBindTexture(GL_TEXTURE_RECTANGLE, con->tex);
228 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
230 glTexCoord2f(0.0f, 0.0f);
231 glVertex2f(-1.0f, -1.0f);
233 glTexCoord2f(con->res_x, 0.0f);
234 glVertex2f(1.0f, -1.0f);
236 glTexCoord2f(con->res_x, con->res_y);
237 glVertex2f(1.0f, 1.0f);
239 glTexCoord2f(0.0f, con->res_y);
240 glVertex2f(-1.0f, 1.0f);
245 * Resize console. x/y must not be 0.
246 * This resizes the whole console buffer and recreates all cells. It tries to
247 * preserve as many content from the previous buffer as possible.
249 int kmscon_console_resize(struct kmscon_console *con, uint32_t x, uint32_t y)
251 struct kmscon_cell *cells;
256 if (!con || !size || size < x || size < y)
259 cells = malloc(sizeof(*cells) * size);
263 memset(cells, 0, sizeof(*cells) * size);
265 for (i = 0; i < size; ++i) {
266 ret = kmscon_char_new(&cells[i].ch);
268 for (j = 0; j < i; ++j)
269 kmscon_char_free(cells[j].ch);
274 console_free_cells(con);