diff options
| -rw-r--r-- | config.h | 19 | ||||
| -rw-r--r-- | drw.c | 204 | ||||
| -rw-r--r-- | drw.h | 38 | ||||
| -rw-r--r-- | swt.c | 77 |
4 files changed, 269 insertions, 69 deletions
@@ -1,12 +1,27 @@ /* See LICENSE file for copyright and license details. */ +#include "drw.h" + /* * appearance * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -static char *font = "/usr/share/fonts/TTF/Sauce Code Pro Bold Nerd Font Complete.ttf"; -static int fontsize = 12; +static FontPath fonts[] = { + { + "/usr/share/fonts/TTF/Sauce Code Pro Nerd Font Complete.ttf", /* Normal */ + "/usr/share/fonts/TTF/Sauce Code Pro Italic Nerd Font Complete.ttf", /* Italic */ + "/usr/share/fonts/TTF/Sauce Code Pro Bold Nerd Font Complete.ttf", /* Bold */ + "/usr/share/fonts/TTF/Sauce Code Pro Bold Italic Nerd Font Complete.ttf", /* Bold-Italic */ + }, + { + "/usr/share/fonts/gnu-free/FreeMono.otf", /* Normal */ + "/usr/share/fonts/gnu-free/FreeMonoOblique.otf", /* Italic */ + "/usr/share/fonts/gnu-free/FreeMonoBold.otf", /* Bold */ + "/usr/share/fonts/gnu-free/FreeMonoBoldOblique.otf" /* Bold-Italic */ + }, +}; +static int fontsize = 32; static int borderpx = 2; /* @@ -1,6 +1,9 @@ +#include <stdint.h> #include <sys/mman.h> #include <unistd.h> #include <math.h> +#include <memory.h> +#include <stdlib.h> #include <grapheme.h> #include "drw.h" @@ -10,6 +13,10 @@ static Color to_color(uint32_t color); static uint32_t to_uint32_t(Color color); static void draw_bitmap(Canvas *canvas, FT_Bitmap *bitmap, unsigned x, unsigned y, uint32_t color); +static void init_font(Font *font); +static FontFamily *create_font_family(FontPath fontpath); +static void free_font_family(FontFamily *fontfamily); +static Font *get_font_with_charcode(FontCache *fontcache, uint_least32_t charcode); Color @@ -112,40 +119,114 @@ draw_rect(Canvas *canvas, unsigned x, unsigned y, unsigned width, unsigned heigh } } -Font * -create_font(const char *fontpath, unsigned size) + +FontCache * +create_font_cache(FontPath *fontpath, int size, unsigned fontsize) { - FT_Error error; - Font * font; + FontCache *fontcache = malloc(sizeof(FontCache)); + FontCacheElement *current; + Font *font; + int i; + + fontcache->fontsize = fontsize; + fontcache->fonttype = FONT_NORMAL; + + if (size == 0) { + die("fontcache has to contain at least one font"); + } + + fontcache->first = malloc(sizeof(FontCacheElement)); + current = fontcache->first; + current->family = create_font_family(fontpath[0]); + current->next = 0; + + for (i = 1; i < size; ++i) { + current->next = malloc(sizeof(FontCacheElement)); + current = current->next; + current->family = create_font_family(fontpath[i]); + current->next = 0; + } + + font_cache_generate_box(fontcache); + + return fontcache; +} + + +void +font_cache_generate_box(FontCache *fontcache) +{ + Font *font = get_font_with_charcode(fontcache, 0); + FT_Set_Pixel_Sizes(font->face, 0, fontcache->fontsize); + fprintf(stderr, "fontsize: %i\n", fontcache->fontsize); + fontcache->box.width = (font->face->bbox.xMax - font->face->bbox.xMin) >> 6; + fontcache->box.height = (font->face->size->metrics.height) >> 6; + fprintf(stderr, "width: %i, height: %i\n", fontcache->box.width, fontcache->box.height); +} + + +void +free_font_cache(FontCache *fontcache) +{ + FontCacheElement *current = fontcache->first; + FontCacheElement *next; - font = malloc(sizeof(Font)); + for (; current; current = next) { + next = current->next; + free_font_family(current->family); + free(current); + } + + free(fontcache); +} + + +FontFamily * +create_font_family(FontPath fontpath) +{ + int i; + FontFamily *fontfamily = malloc(sizeof(FontFamily)); + + for (i = 0; i < FONT_TYPE_SIZE; ++i) { + if (fontpath[i]) { + (*fontfamily)[i].path = fontpath[i]; + (*fontfamily)[i].loaded = 0; + } + } + + return fontfamily; +} + +void +free_font_family(FontFamily *fontfamily) +{ + int i; + for (i = 0; i < FONT_TYPE_SIZE; ++i) { + if ((*fontfamily)[i].loaded) { + FT_Done_Face((*fontfamily)[i].face); + FT_Done_FreeType((*fontfamily)[i].library); + } + } +} + + +void +init_font(Font *font) +{ + FT_Error error; error = FT_Init_FreeType(&font->library); if (error) die("cannot init library"); - error = FT_New_Face(font->library, fontpath, 0, &font->face); + error = FT_New_Face(font->library, font->path, 0, &font->face); if (error) die("cannot open face"); - error = FT_Set_Pixel_Sizes(font->face, 0, size); - if (error) - die("cannot set char size"); - error = FT_Select_Charmap(font->face, ft_encoding_unicode); if (error) die("cannot set unicode"); - - return font; -} - -void -free_font(Font *font) -{ - FT_Done_Face(font->face); - FT_Done_FreeType(font->library); - free(font); } @@ -196,69 +277,98 @@ draw_bitmap(Canvas *canvas, FT_Bitmap *bitmap, unsigned x, unsigned y, uint32_t } } +Font * +get_font_with_charcode(FontCache *fontcache, uint_least32_t charcode) +{ + FT_UInt glyph_index; + FontCacheElement *element = fontcache->first; + Font *font; + + for (; element; element = element->next) { + font = &(*element->family)[fontcache->fonttype]; + if (!font->loaded) { + init_font(font); + font->loaded = 1; + } + + glyph_index = FT_Get_Char_Index(font->face, charcode); + + if (glyph_index) + return font; + } + + font = fontcache->first->family[fontcache->fonttype]; + init_font(font); + font->loaded = 1; + return font; +} + unsigned -draw_font(Canvas *canvas, Font *font, const char *text, unsigned x, unsigned y, uint32_t color) +draw_char(Canvas *canvas, FontCache *fontcache, uint_least32_t charcode, unsigned x, unsigned y, uint32_t color) { FT_GlyphSlot slot; FT_Error error; FT_UInt glyph_index; FT_UInt previous = 0; - uint_least32_t charcode; - FT_Bool has_kerning = FT_HAS_KERNING(font->face); + FT_Bool has_kerning; FT_Vector delta; + Font *current_font; - slot = font->face->glyph; - - for (; *text;) { - text += grapheme_decode_utf8(text, sizeof(uint_least32_t), &charcode); + current_font = get_font_with_charcode(fontcache, charcode); + FT_Set_Pixel_Sizes(current_font->face, 0, fontcache->fontsize); - glyph_index = FT_Get_Char_Index(font->face, charcode); + slot = current_font->face->glyph; + glyph_index = FT_Get_Char_Index(current_font->face, charcode); - if (has_kerning && previous && glyph_index) { - FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); - x += delta.x >> 6; - } + has_kerning = FT_HAS_KERNING(current_font->face); + if (has_kerning && previous && glyph_index) { + FT_Get_Kerning(current_font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); + x += delta.x >> 6; + } - error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER); - if (error) { - fprintf(stderr, "warning: char not loaded, skipping...\n"); - continue; - } + error = FT_Load_Glyph(current_font->face, glyph_index, FT_LOAD_RENDER); + if (error) { + fprintf(stderr, "warning: char not loaded, skipping...\n"); + return x; + } - draw_bitmap(canvas, &slot->bitmap, x + slot->bitmap_left, y - slot->bitmap_top, color); + draw_bitmap(canvas, &slot->bitmap, x + slot->bitmap_left, y - slot->bitmap_top, color); - x += slot->advance.x >> 6; - } + x += slot->advance.x >> 6; return x; } unsigned -font_width(Font *font, const char *text) +font_width(FontCache *fontcache, const char *text) { FT_GlyphSlot slot; FT_Error error; FT_UInt glyph_index; FT_UInt previous = 0; uint_least32_t charcode; - FT_Bool has_kerning = FT_HAS_KERNING(font->face); + FT_Bool has_kerning; FT_Vector delta; unsigned x = 0; - - slot = font->face->glyph; + Font *current_font; for (; *text;) { text += grapheme_decode_utf8(text, sizeof(uint_least32_t), &charcode); - glyph_index = FT_Get_Char_Index(font->face, charcode); + current_font = get_font_with_charcode(fontcache, charcode); + FT_Set_Pixel_Sizes(current_font->face, 0, fontcache->fontsize); + + slot = current_font->face->glyph; + glyph_index = FT_Get_Char_Index(current_font->face, charcode); + has_kerning = FT_HAS_KERNING(current_font->face); if (has_kerning && previous && glyph_index) { - FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); + FT_Get_Kerning(current_font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); x += delta.x >> 6; } - error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER); + error = FT_Load_Glyph(current_font->face, glyph_index, FT_LOAD_RENDER); if (error) { fprintf(stderr, "warning: char not loaded, skipping...\n"); continue; @@ -18,10 +18,39 @@ typedef struct { } Canvas; typedef struct { + const char *path; + int loaded; FT_Library library; FT_Face face; } Font; +enum FontType { + FONT_NORMAL, + FONT_ITALIC, + FONT_BOLD, + FONT_BOLD_ITALIC, + FONT_TYPE_SIZE +}; + +typedef Font FontFamily[FONT_TYPE_SIZE]; +typedef char *FontPath[FONT_TYPE_SIZE]; + +struct FontCacheElement_; +typedef struct FontCacheElement_ { + FontFamily *family; + struct FontCacheElement_ *next; +} FontCacheElement; + +typedef struct { + FontCacheElement *first; + unsigned fontsize; + unsigned fonttype; + struct { + unsigned width; + unsigned height; + } box; +} FontCache; + typedef struct { uint8_t r; uint8_t g; @@ -36,9 +65,10 @@ void free_drw(Canvas *canvas); void draw_rect(Canvas *canvas, unsigned x, unsigned y, unsigned width, unsigned height, uint32_t color); void draw_point(Canvas *canvas, unsigned x, unsigned y, uint32_t color); -Font* create_font(const char *fontpath, unsigned size); -void free_font(Font *font); -unsigned draw_font(Canvas *canvas, Font *font, const char *text, unsigned x, unsigned y, uint32_t color); -unsigned font_width(Font *font, const char *text); +FontCache *create_font_cache(FontPath *fontpath, int size, unsigned fontsize); +void font_cache_generate_box(FontCache *fontcache); +void free_font_cache(FontCache *fontcache); +unsigned draw_char(Canvas *canvas, FontCache *fontcache, uint_least32_t charcode, unsigned x, unsigned y, uint32_t color); +unsigned font_width(FontCache *fontcache, const char *text); #endif @@ -34,18 +34,15 @@ char *argv0; typedef struct { unsigned width; unsigned height; + int geometry_changed; struct { struct wl_surface *wl; struct xdg_surface *xdg; struct xdg_toplevel *toplevel; } surface; Canvas *canvas; - Font *font; + FontCache *fontcache; int mode; - struct { - int x; - int y; - } cursor; } Window; @@ -156,10 +153,31 @@ void wclipcopy() { void wdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) { fprintf(stderr, "DRAW CURSOR: cx: %i, cy: %i, ox: %i, oy: %i\n", cx, cy, ox, oy); - draw_rect(win.canvas, win.cursor.x * fontsize, win.cursor.y * fontsize, fontsize, fontsize, 0x0); - draw_rect(win.canvas, cx * fontsize, cy * fontsize, fontsize, fontsize, 0xffffffff); - win.cursor.x = cx; - win.cursor.y = cy; + + draw_rect( + win.canvas, + ox * win.fontcache->box.width, + oy * win.fontcache->box.height, + win.fontcache->box.width, + win.fontcache->box.height, + 0x0 + ); + draw_char( + win.canvas, + win.fontcache, + og.u, + ox * win.fontcache->box.width, + oy * win.fontcache->box.height + win.fontcache->fontsize, + 0xffffffff + ); + draw_rect( + win.canvas, + cx * win.fontcache->box.width, + cy * win.fontcache->box.height, + win.fontcache->box.width, + win.fontcache->box.height, + 0xffffffff + ); } @@ -167,9 +185,26 @@ void wdrawline(Line line, int x1, int y1, int x2) { int x; fprintf(stderr, "DRAW LINE: x1: %i, y1: %i, x2: %i\n"); - /*for (x = x1; x < x2; x++) { - fprintf(stderr, " line: %s\n", line[x]); - }*/ + draw_rect( + win.canvas, + x1 * win.fontcache->box.width, + y1 * win.fontcache->box.height, + (x2 - x1) * win.fontcache->box.width, + win.fontcache->box.height, + 0 + ); + + fprintf(stderr, " line: "); + for (x = x1; x < x2; x++) { + draw_char( + win.canvas, + win.fontcache, + line[x].u, + x * win.fontcache->box.width, + y1 * win.fontcache->box.height + win.fontcache->fontsize, + 0xffffffff + ); + } } @@ -262,14 +297,20 @@ commit_surface() void surface_configure(void *data, struct xdg_surface *surface, uint32_t serial) { + int first_canvas = win.canvas == 0; xdg_surface_ack_configure(surface, serial); - if (win.canvas != 0) { - free_drw(win.canvas); + if (win.geometry_changed || first_canvas) { + if (win.canvas != 0) { + free_drw(win.canvas); + } + win.canvas = create_drw(client.shm, win.width, win.height); + draw(); + win.geometry_changed = 0; } - win.canvas = create_drw(client.shm, win.width, win.height); - draw_frame(); + if (first_canvas) + draw_frame(); commit_surface(); } @@ -277,6 +318,9 @@ surface_configure(void *data, struct xdg_surface *surface, uint32_t serial) void toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *clients) { + if (width != win.width && height != win.height) + win.geometry_changed = 1; + if (width == 0 || height == 0) { win.width = 800; win.height = 600; @@ -471,6 +515,7 @@ pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axi void setup() { + win.fontcache = create_font_cache(fonts, sizeof(fonts) / sizeof(FontPath), fontsize); client.kb.repeat.timer = timerfd_create(CLOCK_MONOTONIC, 0); client.kb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); client.display = wl_display_connect(0); |