mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-21 05:33:45 -04: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
|
#define LOG_ENABLE_DBG 1
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
#include "font.h"
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
|
|
||||||
|
|
@ -29,29 +30,116 @@ struct wayland {
|
||||||
struct xdg_toplevel *xdg_toplevel;
|
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 {
|
struct context {
|
||||||
bool quit;
|
bool quit;
|
||||||
int ptmx;
|
int ptmx;
|
||||||
|
|
||||||
|
cairo_scaled_font_t *font;
|
||||||
|
cairo_font_extents_t fextents;
|
||||||
|
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
|
||||||
struct wayland wl;
|
struct wayland wl;
|
||||||
|
struct grid grid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void
|
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_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_rectangle(buf->cairo, 0, 0, buf->width, buf->height);
|
||||||
cairo_fill(buf->cairo);
|
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_attach(c->wl.surface, buf->wl_buf, 0, 0);
|
||||||
wl_surface_damage(c->wl.surface, 0, 0, buf->width, buf->height);
|
wl_surface_damage(c->wl.surface, 0, 0, buf->width, buf->height);
|
||||||
wl_surface_commit(c->wl.surface);
|
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
|
static void
|
||||||
shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
|
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},
|
.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) {
|
if (c.ptmx == -1) {
|
||||||
LOG_ERRNO("failed to open pseudo terminal");
|
LOG_ERRNO("failed to open pseudo terminal");
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -306,7 +405,28 @@ main(int argc, const char *const *argv)
|
||||||
break;
|
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) {
|
if (fds[1].revents & POLLHUP) {
|
||||||
|
|
@ -334,6 +454,11 @@ out:
|
||||||
if (c.wl.display != NULL)
|
if (c.wl.display != NULL)
|
||||||
wl_display_disconnect(c.wl.display);
|
wl_display_disconnect(c.wl.display);
|
||||||
|
|
||||||
|
free(c.grid.cells);
|
||||||
|
|
||||||
|
if (c.font != NULL)
|
||||||
|
cairo_scaled_font_destroy(c.font);
|
||||||
|
|
||||||
if (c.ptmx != -1)
|
if (c.ptmx != -1)
|
||||||
close(c.ptmx);
|
close(c.ptmx);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@ add_project_arguments(
|
||||||
(is_debug_build ? ['-D_DEBUG'] : []),
|
(is_debug_build ? ['-D_DEBUG'] : []),
|
||||||
language: 'c',
|
language: 'c',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
math = cc.find_library('m')
|
||||||
|
|
||||||
fontconfig = dependency('fontconfig')
|
fontconfig = dependency('fontconfig')
|
||||||
cairo = dependency('cairo')
|
cairo = dependency('cairo')
|
||||||
cairo_ft = dependency('cairo-ft')
|
cairo_ft = dependency('cairo-ft')
|
||||||
|
|
@ -53,11 +57,12 @@ endforeach
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
'f00ter',
|
'f00ter',
|
||||||
|
'font.c', 'font.h',
|
||||||
'log.c', 'log.h',
|
'log.c', 'log.h',
|
||||||
'main.c',
|
'main.c',
|
||||||
'shm.c', 'shm.h',
|
'shm.c', 'shm.h',
|
||||||
'slave.c', 'slave.h',
|
'slave.c', 'slave.h',
|
||||||
'tllist.h',
|
'tllist.h',
|
||||||
wl_proto_src + wl_proto_headers,
|
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)
|
install: true)
|
||||||
|
|
|
||||||
3
slave.c
3
slave.c
|
|
@ -53,7 +53,8 @@ slave_spawn(int ptmx)
|
||||||
pts = -1;
|
pts = -1;
|
||||||
|
|
||||||
/* TODO: exec() */
|
/* TODO: exec() */
|
||||||
const char *s = "hello world\n";
|
sleep(1);
|
||||||
|
const char *s = "hello\tbla\nfoobar\thaa";
|
||||||
write(STDOUT_FILENO, s, strlen(s));
|
write(STDOUT_FILENO, s, strlen(s));
|
||||||
|
|
||||||
sleep(1000);
|
sleep(1000);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue