mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-07 04:06:07 -05:00
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:
parent
acda4d2d31
commit
9ccc8433c3
5 changed files with 228 additions and 7 deletions
85
font.c
Normal file
85
font.c
Normal 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
5
font.h
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
cairo_scaled_font_t *font_from_name(const char *name);
|
||||
135
main.c
135
main.c
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
3
slave.c
3
slave.c
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue