initial grid implementation

This allows us to render *something*, even though it's inefficient,
stupid and far far away from the real thing.
This commit is contained in:
Daniel Eklöf 2019-06-13 16:24:35 +02:00
parent acda4d2d31
commit 9ccc8433c3
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
5 changed files with 228 additions and 7 deletions

85
font.c Normal file
View file

@ -0,0 +1,85 @@
#include "font.h"
#include <stdlib.h>
#include <stdbool.h>
#include <fontconfig/fontconfig.h>
#include <cairo-ft.h>
#define LOG_MODULE "font"
#include "log.h"
static void __attribute__((constructor))
init(void)
{
FcInit();
}
static void __attribute__((destructor))
fini(void)
{
FcFini();
}
cairo_scaled_font_t *
font_from_name(const char *name)
{
FcPattern *pattern = FcNameParse((const unsigned char *)name);
if (pattern == NULL) {
LOG_ERR("%s: failed to lookup font", name);
return NULL;
}
if (!FcConfigSubstitute(NULL, pattern, FcMatchPattern)) {
LOG_ERR("%s: failed to do config substitution", name);
FcPatternDestroy(pattern);
return NULL;
}
FcDefaultSubstitute(pattern);
FcResult result;
FcPattern *final_pattern = FcFontMatch(NULL, pattern, &result);
FcPatternDestroy(pattern);
if (final_pattern == NULL) {
LOG_ERR("%s: failed to match font", name);
return NULL;
}
double size;
if (FcPatternGetDouble(final_pattern, FC_PIXEL_SIZE, 0, &size)) {
LOG_ERR("%s: failed to get size", name);
FcPatternDestroy(final_pattern);
return NULL;
}
cairo_font_face_t *face = cairo_ft_font_face_create_for_pattern(
final_pattern);
FcPatternDestroy(final_pattern);
if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS) {
LOG_ERR("%s: failed to create cairo font face", name);
cairo_font_face_destroy(face);
return NULL;
}
cairo_matrix_t matrix, ctm;
cairo_matrix_init_identity(&ctm);
cairo_matrix_init_scale(&matrix, size, size);
cairo_font_options_t *options = cairo_font_options_create();
cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(
face, &matrix, &ctm, options);
cairo_font_options_destroy(options);
cairo_font_face_destroy(face);
if (cairo_scaled_font_status(scaled_font) != CAIRO_STATUS_SUCCESS) {
LOG_ERR("%s: failed to create scaled font", name);
cairo_scaled_font_destroy(scaled_font);
return NULL;
}
return scaled_font;
}

5
font.h Normal file
View file

@ -0,0 +1,5 @@
#pragma once
#include <cairo.h>
cairo_scaled_font_t *font_from_name(const char *name);

135
main.c
View file

@ -15,6 +15,7 @@
#define LOG_ENABLE_DBG 1
#include "log.h"
#include "font.h"
#include "shm.h"
#include "slave.h"
@ -29,29 +30,116 @@ struct wayland {
struct xdg_toplevel *xdg_toplevel;
};
struct cell {
char c;
};
struct grid {
int cols;
int rows;
int cursor;
int cell_width;
int cell_height;
struct cell *cells;
};
struct context {
bool quit;
int ptmx;
cairo_scaled_font_t *font;
cairo_font_extents_t fextents;
int width;
int height;
struct wayland wl;
struct grid grid;
};
static void
resize(struct context *c, int width, int height)
grid_render(struct context *c)
{
LOG_DBG("resize: %dx%d", width, height);
assert(c->width > 0);
assert(c->height > 0);
struct buffer *buf = shm_get_buffer(c->wl.shm, width, height);
struct buffer *buf = shm_get_buffer(c->wl.shm, c->width, c->height);
/* Background */
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(buf->cairo, 1.0, 0.0, 0.0, 1.0);
cairo_set_source_rgba(buf->cairo, 0.0, 0.0, 0.0, 1.0);
cairo_rectangle(buf->cairo, 0, 0, buf->width, buf->height);
cairo_fill(buf->cairo);
/* Grid */
cairo_set_source_rgba(buf->cairo, 1.0, 1.0, 1.0, 1.0);
cairo_set_scaled_font(buf->cairo, c->font);
for (int row = 0; row < c->grid.rows; row++) {
for (int col = 0; col < c->grid.cols; col++) {
int cell_idx = row * c->grid.cols + col;
const struct cell *cell = &c->grid.cells[cell_idx];
int y_ofs = row * c->grid.cell_height + c->fextents.ascent;
int x_ofs = col * c->grid.cell_width;
//LOG_DBG("cell %dx%d: c=0x%02x (%c)", col, row, cell->c, cell->c);
cairo_glyph_t *glyphs = NULL;
int num_glyphs = 0;
cairo_status_t status = cairo_scaled_font_text_to_glyphs(
c->font, x_ofs, y_ofs, &cell->c, 1, &glyphs, &num_glyphs,
NULL, NULL, NULL);
//assert(status == CAIRO_STATUS_SUCCESS);
if (status != CAIRO_STATUS_SUCCESS) {
if (glyphs != NULL)
cairo_glyph_free(glyphs);
continue;
}
cairo_show_glyphs(buf->cairo, glyphs, num_glyphs);
cairo_glyph_free(glyphs);
}
}
wl_surface_attach(c->wl.surface, buf->wl_buf, 0, 0);
wl_surface_damage(c->wl.surface, 0, 0, buf->width, buf->height);
wl_surface_commit(c->wl.surface);
}
static void
resize(struct context *c, int width, int height)
{
if (width == c->width && height == c->height)
return;
c->width = width;
c->height = height;
size_t old_cells_len = c->grid.cols * c->grid.rows;
c->grid.cell_width = (int)ceil(c->fextents.max_x_advance);
c->grid.cell_height = (int)ceil(c->fextents.height);
c->grid.cols = c->width / c->grid.cell_width;
c->grid.rows = c->height / c->grid.cell_height;
c->grid.cells = realloc(c->grid.cells,
c->grid.cols * c->grid.rows * sizeof(c->grid.cells[0]));
size_t new_cells_len = c->grid.cols * c->grid.rows;
if (new_cells_len > old_cells_len) {
memset(&c->grid.cells[old_cells_len], 0,
(new_cells_len - old_cells_len) * sizeof(c->grid.cells[0]));
}
LOG_DBG("resize: %dx%d, grid: cols=%d, rows=%d",
c->width, c->height, c->grid.cols, c->grid.rows);
grid_render(c);
}
static void
shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
{
@ -205,6 +293,17 @@ main(int argc, const char *const *argv)
.wl = {0},
};
const char *font_name = "Dina:size=9";
c.font = font_from_name(font_name);
if (c.font == NULL)
goto out;
cairo_scaled_font_extents(c.font, &c.fextents);
LOG_DBG("height: %.2f, x-advance: %.2f",
c.fextents.height, c.fextents.max_x_advance);
assert(c.fextents.max_y_advance == 0);
if (c.ptmx == -1) {
LOG_ERRNO("failed to open pseudo terminal");
goto out;
@ -306,7 +405,28 @@ main(int argc, const char *const *argv)
break;
}
LOG_DBG("%.*s", (int)count, data);
//LOG_DBG("%.*s", (int)count, data);
for (int i = 0; i < count; i++) {
switch (data[i]) {
case '\r':
c.grid.cursor = c.grid.cursor / c.grid.cols * c.grid.cols;
break;
case '\n':
c.grid.cursor += c.grid.cols;
break;
case '\t':
c.grid.cursor = (c.grid.cursor + 8) / 8 * 8;
break;
default:
c.grid.cells[c.grid.cursor++].c = data[i];
break;
}
}
grid_render(&c);
}
if (fds[1].revents & POLLHUP) {
@ -334,6 +454,11 @@ out:
if (c.wl.display != NULL)
wl_display_disconnect(c.wl.display);
free(c.grid.cells);
if (c.font != NULL)
cairo_scaled_font_destroy(c.font);
if (c.ptmx != -1)
close(c.ptmx);

View file

@ -16,6 +16,10 @@ add_project_arguments(
(is_debug_build ? ['-D_DEBUG'] : []),
language: 'c',
)
cc = meson.get_compiler('c')
math = cc.find_library('m')
fontconfig = dependency('fontconfig')
cairo = dependency('cairo')
cairo_ft = dependency('cairo-ft')
@ -53,11 +57,12 @@ endforeach
executable(
'f00ter',
'font.c', 'font.h',
'log.c', 'log.h',
'main.c',
'shm.c', 'shm.h',
'slave.c', 'slave.h',
'tllist.h',
wl_proto_src + wl_proto_headers,
dependencies: [cairo, cairo_ft, fontconfig, wayland_client, wayland_cursor, xkb],
dependencies: [math, cairo, cairo_ft, fontconfig, wayland_client, wayland_cursor, xkb],
install: true)

View file

@ -53,7 +53,8 @@ slave_spawn(int ptmx)
pts = -1;
/* TODO: exec() */
const char *s = "hello world\n";
sleep(1);
const char *s = "hello\tbla\nfoobar\thaa";
write(STDOUT_FILENO, s, strlen(s));
sleep(1000);