From 393e1909b78ffee53d1397237423e1d975edc507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 00:44:51 +0200 Subject: [PATCH 01/12] module/i3: plug valgrind detected memory leak Free previous 'application' string before replacing it with a new one. --- modules/i3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/i3.c b/modules/i3.c index 8f2420b..df642b9 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -395,6 +395,7 @@ handle_window_event(int type, const struct json_object *json, void *_mod) assert(bytes >= 0); application[bytes - 1] = '\0'; + free(ws->window.application); ws->window.application = strdup(application); close(fd); } From b3a5e0b5d79e5b75bd2d02961234b3e1dbee8ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 00:50:11 +0200 Subject: [PATCH 02/12] font: initial port from cairo scaled fonts to raw freetype + pixman --- config.c | 4 +- font.c | 587 ++++++++++++++++++++++++++++++++++++++------- font.h | 70 +++++- meson.build | 5 +- particles/string.c | 175 +++++++------- stride.h | 9 + 6 files changed, 659 insertions(+), 191 deletions(-) create mode 100644 stride.h diff --git a/config.c b/config.c index 5c6eb57..01a985d 100644 --- a/config.c +++ b/config.c @@ -67,7 +67,7 @@ conf_to_color(const struct yml_node *node) struct font * conf_to_font(const struct yml_node *node) { - return font_new(yml_value_as_string(node)); + return font_from_name(yml_value_as_string(node));; } struct deco * @@ -263,7 +263,7 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) * and particles. This allows us to specify a default font and * foreground color at top-level. */ - struct font *font = font_new("sans"); + struct font *font = font_from_name("sans"); struct rgba foreground = (struct rgba){1.0, 1.0, 1.0, 1.0}; /* White */ const struct yml_node *font_node = yml_get_value(bar, "font"); diff --git a/font.c b/font.c index dba1a5b..d61fea6 100644 --- a/font.c +++ b/font.c @@ -1,29 +1,32 @@ #include "font.h" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #define LOG_MODULE "font" #define LOG_ENABLE_DBG 0 #include "log.h" -#include "tllist.h" +#include "stride.h" -struct font { - char *name; - cairo_scaled_font_t *scaled_font; - int ref_counter; -}; +#define min(x, y) ((x) < (y) ? (x) : (y)) -static tll(const struct font *) cache = tll_init(); +static FT_Library ft_lib; +static mtx_t ft_lock; + +static tll(const struct font *) font_cache = tll_init(); + +static const size_t glyph_cache_size = 512; static void __attribute__((constructor)) init(void) { FcInit(); + FT_Init_FreeType(&ft_lib); + mtx_init(&ft_lock, mtx_plain); #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG int raw_version = FcGetVersion(); @@ -40,16 +43,232 @@ init(void) static void __attribute__((destructor)) fini(void) { + assert(tll_length(font_cache) == 0); + + mtx_destroy(&ft_lock); + FT_Done_FreeType(ft_lib); FcFini(); - assert(tll_length(cache) == 0); +} + +static bool +font_destroy_no_free(struct font *font) +{ + assert(font->ref_counter > 0); + if (--font->ref_counter > 0) + return false; + + if (font->face != NULL) { + mtx_lock(&ft_lock); + FT_Done_Face(font->face); + mtx_unlock(&ft_lock); + } + + mtx_destroy(&font->lock); + + if (font->fc_pattern != NULL) + FcPatternDestroy(font->fc_pattern); + if (font->fc_fonts != NULL) + FcFontSetDestroy(font->fc_fonts); + + free(font->name); + + if (font->cache == NULL) + return true; + + for (size_t i = 0; i < glyph_cache_size; i++) { + if (font->cache[i] == NULL) + continue; + + tll_foreach(*font->cache[i], it) { + if (!it->item.valid) + continue; + + void *image = pixman_image_get_data(it->item.pix); + pixman_image_unref(it->item.pix); + free(image); + } + + tll_free(*font->cache[i]); + free(font->cache[i]); + } + free(font->cache); + + tll_foreach(font_cache, it) { + if (it->item == font) { + tll_remove(font_cache, it); + break; + } + } + + return true; +} + +static bool +from_font_set(FcPattern *pattern, FcFontSet *fonts, int start_idx, + struct font *font, bool is_fallback) +{ + memset(font, 0, sizeof(*font)); + + FcChar8 *face_file = NULL; + FcPattern *final_pattern = NULL; + int font_idx = -1; + + for (int i = start_idx; i < fonts->nfont; i++) { + FcPattern *pat = FcFontRenderPrepare(NULL, pattern, fonts->fonts[i]); + assert(pat != NULL); + + if (FcPatternGetString(pat, FC_FT_FACE, 0, &face_file) != FcResultMatch) { + if (FcPatternGetString(pat, FC_FILE, 0, &face_file) != FcResultMatch) { + FcPatternDestroy(pat); + continue; + } + } + + final_pattern = pat; + font_idx = i; + break; + } + + assert(font_idx != -1); + assert(final_pattern != NULL); + + double dpi; + if (FcPatternGetDouble(final_pattern, FC_DPI, 0, &dpi) != FcResultMatch) + dpi = 96; + + double size; + if (FcPatternGetDouble(final_pattern, FC_PIXEL_SIZE, 0, &size)) { + LOG_ERR("%s: failed to get size", face_file); + FcPatternDestroy(final_pattern); + return false; + } + + FcBool scalable; + if (FcPatternGetBool(final_pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch) + scalable = FcTrue; + + double pixel_fixup; + if (FcPatternGetDouble(final_pattern, "pixelsizefixupfactor", 0, &pixel_fixup) != FcResultMatch) + pixel_fixup = 1.; + + LOG_DBG("loading: %s", face_file); + + mtx_lock(&ft_lock); + FT_Face ft_face; + FT_Error ft_err = FT_New_Face(ft_lib, (const char *)face_file, 0, &ft_face); + mtx_unlock(&ft_lock); + if (ft_err != 0) + LOG_ERR("%s: failed to create FreeType face", face_file); + + if ((ft_err = FT_Set_Char_Size(ft_face, size * 64, 0, 0, 0)) != 0) + LOG_WARN("failed to set character size"); + + FcBool fc_hinting; + if (FcPatternGetBool(final_pattern, FC_HINTING,0, &fc_hinting) != FcResultMatch) + fc_hinting = FcTrue; + + FcBool fc_antialias; + if (FcPatternGetBool(final_pattern, FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) + fc_antialias = FcTrue; + + int fc_hintstyle; + if (FcPatternGetInteger(final_pattern, FC_HINT_STYLE, 0, &fc_hintstyle) != FcResultMatch) + fc_hintstyle = FC_HINT_SLIGHT; + + int fc_rgba; + if (FcPatternGetInteger(final_pattern, FC_RGBA, 0, &fc_rgba) != FcResultMatch) + fc_rgba = FC_RGBA_UNKNOWN; + + int load_flags = 0; + if (!fc_antialias) { + if (!fc_hinting || fc_hintstyle == FC_HINT_NONE) + load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL; + else + load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO; + } else { + if (!fc_hinting || fc_hintstyle == FC_HINT_NONE) + load_flags |= FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL; + else if (fc_hinting && fc_hintstyle == FC_HINT_SLIGHT) + load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LIGHT; + else if (fc_rgba == FC_RGBA_RGB || fc_rgba == FC_RGBA_BGR) + load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD; + else if (fc_rgba == FC_RGBA_VRGB || fc_rgba == FC_RGBA_VBGR) + load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD_V; + else + load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL; + } + + FcBool fc_embeddedbitmap; + if (FcPatternGetBool(final_pattern, FC_EMBEDDED_BITMAP, 0, &fc_embeddedbitmap) != FcResultMatch) + fc_embeddedbitmap = FcTrue; + + if (!fc_embeddedbitmap) + load_flags |= FT_LOAD_NO_BITMAP; + + int render_flags = 0; + if (!fc_antialias) + render_flags |= FT_RENDER_MODE_MONO; + else { + if (fc_rgba == FC_RGBA_RGB || fc_rgba == FC_RGBA_BGR) + render_flags |= FT_RENDER_MODE_LCD; + else if (fc_rgba == FC_RGBA_VRGB || fc_rgba == FC_RGBA_VBGR) + render_flags |= FT_RENDER_MODE_LCD_V; + else + render_flags |= FT_RENDER_MODE_NORMAL; + } + + int fc_lcdfilter; + if (FcPatternGetInteger(final_pattern, FC_LCD_FILTER, 0, &fc_lcdfilter) != FcResultMatch) + fc_lcdfilter = FC_LCD_DEFAULT; + + switch (fc_lcdfilter) { + case FC_LCD_NONE: font->lcd_filter = FT_LCD_FILTER_NONE; break; + case FC_LCD_DEFAULT: font->lcd_filter = FT_LCD_FILTER_DEFAULT; break; + case FC_LCD_LIGHT: font->lcd_filter = FT_LCD_FILTER_LIGHT; break; + case FC_LCD_LEGACY: font->lcd_filter = FT_LCD_FILTER_LEGACY; break; + } + + FcPatternDestroy(final_pattern); + + int max_x_advance = ft_face->size->metrics.max_advance / 64; + int height = ft_face->size->metrics.height / 64; + int descent = ft_face->size->metrics.descender / 64; + int ascent = ft_face->size->metrics.ascender / 64; + + mtx_init(&font->lock, mtx_plain); + font->face = ft_face; + font->load_flags = load_flags | FT_LOAD_COLOR; + font->render_flags = render_flags; + font->pixel_size_fixup = scalable ? pixel_fixup : 1.; + font->bgr = fc_rgba == FC_RGBA_BGR || fc_rgba == FC_RGBA_VBGR; + font->fc_idx = font_idx; + font->is_fallback = is_fallback; + font->ref_counter = 1; + + font->fextents.height = height * font->pixel_size_fixup; + font->fextents.descent = -descent * font->pixel_size_fixup; + font->fextents.ascent = ascent * font->pixel_size_fixup; + font->fextents.max_x_advance = max_x_advance * font->pixel_size_fixup; + + LOG_DBG("metrics: height: %d, descent: %d, ascent: %d, x-advance: %d", + height, descent, ascent, max_x_advance); + + if (!is_fallback) { + font->fc_pattern = pattern; + font->fc_fonts = fonts; + font->cache = calloc(glyph_cache_size, sizeof(font->cache[0])); + } + + return true; } struct font * -font_new(const char *name) +font_from_name(const char *name) { - /* Check if font have already been loaded */ - tll_foreach(cache, it) { - if (strcmp(name, it->item->name) == 0) + LOG_DBG("instantiating %s", name); + + tll_foreach(font_cache, it) { + if (strcmp(it->item->name, name) == 0) return font_clone(it->item); } @@ -68,58 +287,273 @@ font_new(const char *name) FcDefaultSubstitute(pattern); FcResult result; - FcPattern *final_pattern = FcFontMatch(NULL, pattern, &result); - FcPatternDestroy(pattern); - - if (final_pattern == NULL) { + FcFontSet *fonts = FcFontSort(NULL, pattern, FcTrue, NULL, &result); + if (result != FcResultMatch) { LOG_ERR("%s: failed to match font", name); - return NULL; - } - - double font_size; - if (FcPatternGetDouble(final_pattern, FC_PIXEL_SIZE, 0, &font_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, font_size, font_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); + FcPatternDestroy(pattern); return NULL; } struct font *font = malloc(sizeof(*font)); - font->name = strdup(name); - font->scaled_font = scaled_font; - font->ref_counter = 1; + if (!from_font_set(pattern, fonts, 0, font, false)) { + free(font); + FcFontSetDestroy(fonts); + FcPatternDestroy(pattern); + return NULL; + } - tll_push_back(cache, font); + font->name = strdup(name); + tll_push_back(font_cache, font); return font; } +static size_t +hash_index(wchar_t wc) +{ + return wc % glyph_cache_size; +} + +static bool +glyph_for_wchar(const struct font *font, wchar_t wc, struct glyph *glyph) +{ + /* + * LCD filter is per library instance. Thus we need to re-set it + * every time... + * + * Also note that many freetype builds lack this feature + * (FT_CONFIG_OPTION_SUBPIXEL_RENDERING must be defined, and isn't + * by default) */ + FT_Error err = FT_Library_SetLcdFilter(ft_lib, font->lcd_filter); + if (err != 0 && err != FT_Err_Unimplemented_Feature) + goto err; + + FT_UInt idx = FT_Get_Char_Index(font->face, wc); + if (idx == 0) { + /* No glyph in this font, try fontconfig fallback fonts */ + + /* Try fontconfig fallback fonts */ + assert(font->fc_pattern != NULL); + assert(font->fc_fonts != NULL); + assert(font->fc_idx != -1); + + for (int i = font->fc_idx + 1; i < font->fc_fonts->nfont; i++) { + struct font fallback; + if (!from_font_set(font->fc_pattern, font->fc_fonts, i, &fallback, true)) + continue; + + if (glyph_for_wchar(&fallback, wc, glyph)) { + LOG_DBG("%C: used fontconfig fallback", wc); + font_destroy_no_free(&fallback); + return true; + } + + font_destroy_no_free(&fallback); + } + + LOG_WARN("%C: no glyph found (in neither the main font, " + "nor any fallback fonts)", wc); + } + + err = FT_Load_Glyph(font->face, idx, font->load_flags); + if (err != 0) { + LOG_ERR("load failed"); + goto err; + } + + err = FT_Render_Glyph(font->face->glyph, font->render_flags); + if (err != 0) + goto err; + + assert(font->face->glyph->format == FT_GLYPH_FORMAT_BITMAP); + + FT_Bitmap *bitmap = &font->face->glyph->bitmap; + if (bitmap->width == 0) + goto err; + + pixman_format_code_t pix_format; + int width; + int rows; + + switch (bitmap->pixel_mode) { + case FT_PIXEL_MODE_MONO: + pix_format = PIXMAN_a1; + width = bitmap->width; + rows = bitmap->rows; + break; + + case FT_PIXEL_MODE_GRAY: + pix_format = PIXMAN_a8; + width = bitmap->width; + rows = bitmap->rows; + break; + + case FT_PIXEL_MODE_LCD: + pix_format = PIXMAN_x8r8g8b8; + width = bitmap->width / 3; + rows = bitmap->rows; + break; + + case FT_PIXEL_MODE_LCD_V: + pix_format = PIXMAN_x8r8g8b8; + width = bitmap->width; + rows = bitmap->rows / 3; + break; + + case FT_PIXEL_MODE_BGRA: + pix_format = PIXMAN_a8r8g8b8; + width = bitmap->width; + rows = bitmap->rows; + break; + + default: + LOG_ERR("unimplemented: FT pixel mode: %d", bitmap->pixel_mode); + goto err; + break; + } + + int stride = stride_for_format_and_width(pix_format, width); + assert(stride >= bitmap->pitch); + + uint8_t *data = malloc(rows * stride); + + /* Convert FT bitmap to pixman image */ + switch (bitmap->pixel_mode) { + case FT_PIXEL_MODE_MONO: + for (size_t r = 0; r < bitmap->rows; r++) { + for (size_t c = 0; c < (bitmap->width + 7) / 8; c++) { + uint8_t v = bitmap->buffer[r * bitmap->pitch + c]; + uint8_t reversed = 0; + for (size_t i = 0; i < min(8, bitmap->width - c * 8); i++) + reversed |= ((v >> (7 - i)) & 1) << i; + + data[r * stride + c] = reversed; + } + } + break; + + case FT_PIXEL_MODE_GRAY: + for (size_t r = 0; r < bitmap->rows; r++) { + for (size_t c = 0; c < bitmap->width; c++) + data[r * stride + c] = bitmap->buffer[r * bitmap->pitch + c]; + } + break; + + case FT_PIXEL_MODE_BGRA: + assert(stride == bitmap->pitch); + memcpy(data, bitmap->buffer, bitmap->rows * bitmap->pitch); + break; + + case FT_PIXEL_MODE_LCD: + for (size_t r = 0; r < bitmap->rows; r++) { + for (size_t c = 0; c < bitmap->width; c += 3) { + unsigned char _r = bitmap->buffer[r * bitmap->pitch + c + (font->bgr ? 2 : 0)]; + unsigned char _g = bitmap->buffer[r * bitmap->pitch + c + 1]; + unsigned char _b = bitmap->buffer[r * bitmap->pitch + c + (font->bgr ? 0 : 2)]; + + uint32_t *p = (uint32_t *)&data[r * stride + 4 * (c / 3)]; + *p = _r << 16 | _g << 8 | _b; + } + } + break; + + case FT_PIXEL_MODE_LCD_V: + /* Unverified */ + for (size_t r = 0; r < bitmap->rows; r += 3) { + for (size_t c = 0; c < bitmap->width; c++) { + unsigned char _r = bitmap->buffer[(r + (font->bgr ? 2 : 0)) * bitmap->pitch + c]; + unsigned char _g = bitmap->buffer[(r + 1) * bitmap->pitch + c]; + unsigned char _b = bitmap->buffer[(r + (font->bgr ? 0 : 2)) * bitmap->pitch + c]; + + uint32_t *p = (uint32_t *)&data[r / 3 * stride + 4 * c]; + *p = _r << 16 | _g << 8 | _b; + } + } + break; + + default: + abort(); + break; + } + + pixman_image_t *pix = pixman_image_create_bits_no_clear( + pix_format, width, rows, (uint32_t *)data, stride); + + if (pix == NULL) { + free(data); + goto err; + } + + pixman_image_set_component_alpha( + pix, + bitmap->pixel_mode == FT_PIXEL_MODE_LCD || + bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V); + + if (font->pixel_size_fixup != 1.) { + struct pixman_transform scale; + pixman_transform_init_scale( + &scale, + pixman_double_to_fixed(1. / font->pixel_size_fixup), + pixman_double_to_fixed(1. / font->pixel_size_fixup)); + pixman_image_set_transform(pix, &scale); + } + + *glyph = (struct glyph){ + .wc = wc, + .cols = wcwidth(wc), + .pix = pix, + .x = font->face->glyph->bitmap_left / font->pixel_size_fixup, + .y = font->face->glyph->bitmap_top * font->pixel_size_fixup, + .x_advance = font->face->glyph->advance.x / 64, + .width = width, + .height = rows, + .valid = true, + }; + + return true; + +err: + *glyph = (struct glyph){ + .wc = wc, + .valid = false, + }; + return false; +} + +const struct glyph * +font_glyph_for_wc(struct font *font, wchar_t wc) +{ + mtx_lock(&font->lock); + + assert(font->cache != NULL); + size_t hash_idx = hash_index(wc); + hash_entry_t *hash_entry = font->cache[hash_idx]; + + if (hash_entry != NULL) { + tll_foreach(*hash_entry, it) { + if (it->item.wc == wc) { + mtx_unlock(&font->lock); + return it->item.valid ? &it->item : NULL; + } + } + } + + struct glyph glyph; + bool got_glyph = glyph_for_wchar(font, wc, &glyph); + + if (hash_entry == NULL) { + hash_entry = calloc(1, sizeof(*hash_entry)); + + assert(font->cache[hash_idx] == NULL); + font->cache[hash_idx] = hash_entry; + } + + assert(hash_entry != NULL); + tll_push_back(*hash_entry, glyph); + + mtx_unlock(&font->lock); + return got_glyph ? &tll_back(*hash_entry) : NULL; +} + struct font * font_clone(const struct font *_font) { @@ -131,33 +565,6 @@ font_clone(const struct font *_font) void font_destroy(struct font *font) { - if (font == NULL) - return; - - assert(font->ref_counter > 0); - if (--font->ref_counter > 0) - return; - - tll_foreach(cache, it) { - if (it->item == font) { - tll_remove(cache, it); - break; - } - } - - cairo_scaled_font_destroy(font->scaled_font); - free(font->name); - free(font); -} - -const char * -font_face(const struct font *font) -{ - return font->name; -} - -cairo_scaled_font_t * -font_scaled_font(const struct font *font) -{ - return font->scaled_font; + if (font_destroy_no_free(font)) + free(font); } diff --git a/font.h b/font.h index 45c8987..3953ac9 100644 --- a/font.h +++ b/font.h @@ -1,15 +1,71 @@ #pragma once #include -#include +#include -#include "color.h" +#include +#include FT_FREETYPE_H +#include FT_LCD_FILTER_H +#include +#include -struct font; +#include "tllist.h" -struct font *font_new(const char *name); +struct glyph { + wchar_t wc; + int cols; + + pixman_image_t *pix; + int x; + int y; + int x_advance; + int width; + int height; + + bool valid; +}; + +typedef tll(struct glyph) hash_entry_t; + +struct font { + char *name; + + FcPattern *fc_pattern; + FcFontSet *fc_fonts; + int fc_idx; + + FT_Face face; + int load_flags; + int render_flags; + FT_LcdFilter lcd_filter; + double pixel_size_fixup; /* Scale factor - should only be used with ARGB32 glyphs */ + bool bgr; /* True for FC_RGBA_BGR and FC_RGBA_VBGR */ + + struct { + int height; + int descent; + int ascent; + int max_x_advance; + } fextents; + + struct { + int position; + int thickness; + } underline; + + struct { + int position; + int thickness; + } strikeout; + + hash_entry_t **cache; + mtx_t lock; + + bool is_fallback; + int ref_counter; +}; + +struct font *font_from_name(const char *name); struct font *font_clone(const struct font *font); +const struct glyph *font_glyph_for_wc(struct font *font, wchar_t wc); void font_destroy(struct font *font); - -const char *font_face(const struct font *font); -cairo_scaled_font_t *font_scaled_font(const struct font *font); diff --git a/meson.build b/meson.build index 34c9c95..f1014a7 100644 --- a/meson.build +++ b/meson.build @@ -36,7 +36,9 @@ endif cc = meson.get_compiler('c') dl = cc.find_library('dl') threads = dependency('threads') +freetype = dependency('freetype2') fontconfig = dependency('fontconfig') +pixman = dependency('pixman-1') cairo = dependency('cairo') cairo_ft = dependency('cairo-ft') yaml = dependency('yaml-0.1') @@ -104,7 +106,7 @@ f00bar = executable( 'tag.c', 'tag.h', 'tllist.h', 'yml.c', 'yml.h', - dependencies: [bar, cairo, cairo_ft, fontconfig, yaml, threads, dl] + + dependencies: [bar, freetype, fontconfig, pixman, cairo, cairo_ft, yaml, threads, dl] + decorations + particles + modules, build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, @@ -122,6 +124,7 @@ install_headers( 'log.h', 'module.h', 'particle.h', + 'stride.h', 'tag.h', 'tllist.h', 'yml.h', diff --git a/particles/string.c b/particles/string.c index a276c75..e4818dc 100644 --- a/particles/string.c +++ b/particles/string.c @@ -19,13 +19,8 @@ struct eprivate { /* Set when instantiating */ char *text; - /* Set in begin_expose() */ - cairo_font_extents_t fextents; - cairo_glyph_t *glyphs; - cairo_text_cluster_t *clusters; - cairo_text_cluster_flags_t cluster_flags; + const struct glyph **glyphs; int num_glyphs; - int num_clusters; }; static void @@ -34,11 +29,7 @@ exposable_destroy(struct exposable *exposable) struct eprivate *e = exposable->private; free(e->text); - if (e->glyphs != NULL) - cairo_glyph_free(e->glyphs); - if (e->clusters != NULL) - cairo_text_cluster_free(e->clusters); - + free(e->glyphs); free(e); exposable_default_destroy(exposable); } @@ -48,48 +39,58 @@ begin_expose(struct exposable *exposable, cairo_t *cr) { struct eprivate *e = exposable->private; - cairo_scaled_font_t *scaled = font_scaled_font(exposable->particle->font); - - cairo_set_scaled_font(cr, scaled); - cairo_font_extents(cr, &e->fextents); + struct font *font = exposable->particle->font; LOG_DBG("%s: ascent=%f, descent=%f, height=%f", - font_face(exposable->particle->font), - e->fextents.ascent, e->fextents.descent, e->fextents.height); + font->name, font->fextents.ascent, + font->fextents.descent, font->fextents.height); - cairo_status_t status = cairo_scaled_font_text_to_glyphs( - scaled, 0, 0, e->text, -1, &e->glyphs, &e->num_glyphs, - &e->clusters, &e->num_clusters, &e->cluster_flags); + size_t chars = mbstowcs(NULL, e->text, 0); + wchar_t wtext[chars + 1]; + mbstowcs(wtext, e->text, chars + 1); - if (status != CAIRO_STATUS_SUCCESS) { - LOG_WARN("failed to convert \"%s\" to glyphs: %s", - e->text, cairo_status_to_string(status)); + e->glyphs = malloc(chars * sizeof(e->glyphs[0])); + e->num_glyphs = 0; - e->num_glyphs = -1; - e->num_clusters = -1; - memset(&e->fextents, 0, sizeof(e->fextents)); - exposable->width = 0; - } else { - cairo_text_extents_t extents; - cairo_scaled_font_glyph_extents( - scaled, e->glyphs, e->num_glyphs, &extents); - - exposable->width = (exposable->particle->left_margin + - extents.x_advance + - exposable->particle->right_margin); + /* Convert text to glyph masks/images. */ + for (size_t i = 0; i < chars; i++) { + const struct glyph *glyph = font_glyph_for_wc(font, wtext[i]); + if (glyph == NULL) + continue; + e->glyphs[e->num_glyphs++] = glyph; } + exposable->width = exposable->particle->left_margin + + exposable->particle->right_margin; + + /* Calculate the size we need to render the glyphs */ + for (int i = 0; i < e->num_glyphs; i++) + exposable->width += e->glyphs[i]->x_advance; + return exposable->width; } +static inline pixman_color_t +color_hex_to_pixman_with_alpha(uint32_t color, uint16_t alpha) +{ + int alpha_div = 0xffff / alpha; + return (pixman_color_t){ + .red = ((color >> 16 & 0xff) | (color >> 8 & 0xff00)) / alpha_div, + .green = ((color >> 8 & 0xff) | (color >> 0 & 0xff00)) / alpha_div, + .blue = ((color >> 0 & 0xff) | (color << 8 & 0xff00)) / alpha_div, + .alpha = alpha, + }; +} + static void expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) { exposable_render_deco(exposable, cr, x, y, height); const struct eprivate *e = exposable->private; + const struct font *font = exposable->particle->font; - if (e->num_glyphs == -1) + if (e->num_glyphs == 0) return; /* @@ -108,63 +109,55 @@ expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) * font family. */ const double baseline = (double)y + - (double)(height + e->fextents.ascent + e->fextents.descent) / 2.0 - - (e->fextents.descent > 0 ? e->fextents.descent : 0); + (double)(height + font->fextents.ascent + font->fextents.descent) / 2.0 - + (font->fextents.descent > 0 ? font->fextents.descent : 0); - /* Adjust glyph offsets */ + /* TODO: get rid of cairo?... */ + cairo_surface_t *surf = cairo_get_target(cr); + cairo_surface_flush(surf); + + pixman_image_t *pix = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, + cairo_image_surface_get_width(surf), + cairo_image_surface_get_height(surf), + (uint32_t *)cairo_image_surface_get_data(surf), + cairo_image_surface_get_stride(surf)); + + uint32_t hex_color = + (uint32_t)(uint8_t)(exposable->particle->foreground.red * 255) << 16 | + (uint32_t)(uint8_t)(exposable->particle->foreground.green * 255) << 8 | + (uint32_t)(uint8_t)(exposable->particle->foreground.blue * 255) << 0; + uint16_t alpha = exposable->particle->foreground.alpha * 65535; + pixman_color_t fg = color_hex_to_pixman_with_alpha(hex_color, alpha); + + x += exposable->particle->left_margin; + + /* Loop glyphs and render them, one by one */ for (int i = 0; i < e->num_glyphs; i++) { - e->glyphs[i].x += x + exposable->particle->left_margin; - e->glyphs[i].y += baseline; + const struct glyph *glyph = e->glyphs[i]; + assert(glyph != NULL); + + if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) { + /* Glyph surface is a pre-rendered image (typically a color emoji...) */ + pixman_image_composite32( + PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0, + x + glyph->x, baseline - glyph->y, + glyph->width, glyph->height); + } else { + /* Glyph surface is an alpha mask */ + pixman_image_t *src = pixman_image_create_solid_fill(&fg); + pixman_image_composite32( + PIXMAN_OP_OVER, src, glyph->pix, pix, 0, 0, 0, 0, + x + glyph->x, baseline - glyph->y, + glyph->width, glyph->height); + pixman_image_unref(src); + } + + x += glyph->x_advance; } - cairo_scaled_font_t *scaled = font_scaled_font(exposable->particle->font); - cairo_set_scaled_font(cr, scaled); - cairo_set_source_rgba(cr, - exposable->particle->foreground.red, - exposable->particle->foreground.green, - exposable->particle->foreground.blue, - exposable->particle->foreground.alpha); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - cairo_show_text_glyphs( - cr, e->text, -1, e->glyphs, e->num_glyphs, - e->clusters, e->num_clusters, e->cluster_flags); - -#if 0 - cairo_text_extents_t extents; - cairo_scaled_font_glyph_extents(scaled, e->glyphs, e->num_glyphs, &extents); - - /* Bar center */ - cairo_set_line_width(cr, 1); - cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0); - cairo_move_to(cr, x, (double)y + (double)height / 2 + 0.5); - cairo_line_to(cr, x + extents.x_advance, (double)y + (double)height / 2 + 0.5); - cairo_stroke(cr); - - /* Ascent */ - cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0); - cairo_move_to(cr, x, baseline - e->fextents.ascent + 0.5); - cairo_line_to(cr, x + extents.x_advance, baseline - e->fextents.ascent + 0.5); - cairo_stroke(cr); - - /* Descent */ - cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0); - cairo_move_to(cr, x, baseline + e->fextents.descent + 0.5); - cairo_line_to(cr, x + extents.x_advance, baseline + e->fextents.descent + 0.5); - cairo_stroke(cr); - - /* Height (!= ascent + descent) */ - cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); - cairo_move_to(cr, x - 3 + 0.5, (double)y + (double)(height - e->fextents.height) / 2); - cairo_line_to(cr, x - 3 + 0.5, (double)y + (double)(height + e->fextents.height) / 2); - cairo_stroke(cr); - - /* Height (ascent + descent) */ - cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0); - cairo_move_to(cr, x - 1 + 0.5, (double)y + (double)(height - (e->fextents.ascent + e->fextents.descent)) / 2); - cairo_line_to(cr, x - 1 + 0.5, (double)y + (double)(height + (e->fextents.ascent + e->fextents.descent)) / 2); - cairo_stroke(cr); -#endif + pixman_image_unref(pix); + cairo_surface_mark_dirty(surf); } static struct exposable * @@ -174,8 +167,8 @@ instantiate(const struct particle *particle, const struct tag_set *tags) struct eprivate *e = calloc(1, sizeof(*e)); e->text = tags_expand_template(p->text, tags); - e->num_glyphs = -1; - e->num_clusters = -1; + e->glyphs = NULL; + e->num_glyphs = 0; if (p->max_len > 0) { const size_t len = strlen(e->text); diff --git a/stride.h b/stride.h new file mode 100644 index 0000000..b2c71a7 --- /dev/null +++ b/stride.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +static inline int +stride_for_format_and_width(pixman_format_code_t format, int width) +{ + return (((PIXMAN_FORMAT_BPP(format) * width + 7) / 8 + 4 - 1) & -4); +} From 54797ffbd84e5ac284c757b7756562decd04be71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 00:51:02 +0200 Subject: [PATCH 03/12] font: remove lock (all rendering happens in the main thread) --- font.c | 11 +---------- font.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/font.c b/font.c index d61fea6..70c498e 100644 --- a/font.c +++ b/font.c @@ -63,8 +63,6 @@ font_destroy_no_free(struct font *font) mtx_unlock(&ft_lock); } - mtx_destroy(&font->lock); - if (font->fc_pattern != NULL) FcPatternDestroy(font->fc_pattern); if (font->fc_fonts != NULL) @@ -235,7 +233,6 @@ from_font_set(FcPattern *pattern, FcFontSet *fonts, int start_idx, int descent = ft_face->size->metrics.descender / 64; int ascent = ft_face->size->metrics.ascender / 64; - mtx_init(&font->lock, mtx_plain); font->face = ft_face; font->load_flags = load_flags | FT_LOAD_COLOR; font->render_flags = render_flags; @@ -522,18 +519,14 @@ err: const struct glyph * font_glyph_for_wc(struct font *font, wchar_t wc) { - mtx_lock(&font->lock); - assert(font->cache != NULL); size_t hash_idx = hash_index(wc); hash_entry_t *hash_entry = font->cache[hash_idx]; if (hash_entry != NULL) { tll_foreach(*hash_entry, it) { - if (it->item.wc == wc) { - mtx_unlock(&font->lock); + if (it->item.wc == wc) return it->item.valid ? &it->item : NULL; - } } } @@ -549,8 +542,6 @@ font_glyph_for_wc(struct font *font, wchar_t wc) assert(hash_entry != NULL); tll_push_back(*hash_entry, glyph); - - mtx_unlock(&font->lock); return got_glyph ? &tll_back(*hash_entry) : NULL; } diff --git a/font.h b/font.h index 3953ac9..9021904 100644 --- a/font.h +++ b/font.h @@ -59,7 +59,6 @@ struct font { } strikeout; hash_entry_t **cache; - mtx_t lock; bool is_fallback; int ref_counter; From 95385863ae2242eee3dacd033f3e6825ac6de2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 00:55:06 +0200 Subject: [PATCH 04/12] particle: remove cairo context from begin_expose() --- bar/bar.c | 6 +++--- module.c | 4 ++-- module.h | 2 +- particle.h | 2 +- particles/dynlist.c | 4 ++-- particles/empty.c | 2 +- particles/list.c | 4 ++-- particles/map.c | 4 ++-- particles/progress-bar.c | 4 ++-- particles/ramp.c | 4 ++-- particles/string.c | 2 +- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/bar/bar.c b/bar/bar.c index 33a76a9..df74d7d 100644 --- a/bar/bar.c +++ b/bar/bar.c @@ -97,7 +97,7 @@ expose(const struct bar *_bar) if (e != NULL) e->destroy(e); - bar->left.exps[i] = module_begin_expose(m, bar->cairo); + bar->left.exps[i] = module_begin_expose(m); } for (size_t i = 0; i < bar->center.count; i++) { @@ -107,7 +107,7 @@ expose(const struct bar *_bar) if (e != NULL) e->destroy(e); - bar->center.exps[i] = module_begin_expose(m, bar->cairo); + bar->center.exps[i] = module_begin_expose(m); } for (size_t i = 0; i < bar->right.count; i++) { @@ -117,7 +117,7 @@ expose(const struct bar *_bar) if (e != NULL) e->destroy(e); - bar->right.exps[i] = module_begin_expose(m, bar->cairo); + bar->right.exps[i] = module_begin_expose(m); } int left_width, center_width, right_width; diff --git a/module.c b/module.c index da27f65..1e80c32 100644 --- a/module.c +++ b/module.c @@ -20,9 +20,9 @@ module_default_destroy(struct module *mod) } struct exposable * -module_begin_expose(struct module *mod, cairo_t *cr) +module_begin_expose(struct module *mod) { struct exposable *e = mod->content(mod); - e->begin_expose(e, cr); + e->begin_expose(e); return e; } diff --git a/module.h b/module.h index d75dbf4..ee2b114 100644 --- a/module.h +++ b/module.h @@ -30,7 +30,7 @@ struct module { struct module *module_common_new(void); void module_default_destroy(struct module *mod); -struct exposable *module_begin_expose(struct module *mod, cairo_t *cr); +struct exposable *module_begin_expose(struct module *mod); /* List of attributes *all* modules implement */ #define MODULE_COMMON_ATTRS \ diff --git a/particle.h b/particle.h index 7fbb1f9..210530f 100644 --- a/particle.h +++ b/particle.h @@ -36,7 +36,7 @@ struct exposable { char *on_click; void (*destroy)(struct exposable *exposable); - int (*begin_expose)(struct exposable *exposable, cairo_t *cr); + int (*begin_expose)(struct exposable *exposable); void (*expose)(const struct exposable *exposable, cairo_t *cr, int x, int y, int height); diff --git a/particles/dynlist.c b/particles/dynlist.c index 289dece..e6a3636 100644 --- a/particles/dynlist.c +++ b/particles/dynlist.c @@ -31,7 +31,7 @@ dynlist_destroy(struct exposable *exposable) } static int -dynlist_begin_expose(struct exposable *exposable, cairo_t *cr) +dynlist_begin_expose(struct exposable *exposable) { const struct private *e = exposable->private; @@ -39,7 +39,7 @@ dynlist_begin_expose(struct exposable *exposable, cairo_t *cr) for (size_t i = 0; i < e->count; i++) { struct exposable *ee = e->exposables[i]; - e->widths[i] = ee->begin_expose(ee, cr); + e->widths[i] = ee->begin_expose(ee); exposable->width += e->left_spacing + e->widths[i] + e->right_spacing; } diff --git a/particles/empty.c b/particles/empty.c index c040814..8b0cb39 100644 --- a/particles/empty.c +++ b/particles/empty.c @@ -6,7 +6,7 @@ #include "../plugin.h" static int -begin_expose(struct exposable *exposable, cairo_t *cr) +begin_expose(struct exposable *exposable) { exposable->width = exposable->particle->left_margin + exposable->particle->right_margin; diff --git a/particles/list.c b/particles/list.c index 420cebd..a47c468 100644 --- a/particles/list.c +++ b/particles/list.c @@ -36,7 +36,7 @@ exposable_destroy(struct exposable *exposable) } static int -begin_expose(struct exposable *exposable, cairo_t *cr) +begin_expose(struct exposable *exposable) { const struct eprivate *e = exposable->private; @@ -44,7 +44,7 @@ begin_expose(struct exposable *exposable, cairo_t *cr) for (size_t i = 0; i < e->count; i++) { struct exposable *ee = e->exposables[i]; - e->widths[i] = ee->begin_expose(ee, cr); + e->widths[i] = ee->begin_expose(ee); exposable->width += e->left_spacing + e->widths[i] + e->right_spacing; } diff --git a/particles/map.c b/particles/map.c index c40632f..a8895cb 100644 --- a/particles/map.c +++ b/particles/map.c @@ -36,13 +36,13 @@ exposable_destroy(struct exposable *exposable) } static int -begin_expose(struct exposable *exposable, cairo_t *cr) +begin_expose(struct exposable *exposable) { struct eprivate *e = exposable->private; exposable->width = ( exposable->particle->left_margin + - e->exposable->begin_expose(e->exposable, cr) + + e->exposable->begin_expose(e->exposable) + exposable->particle->right_margin); return exposable->width; diff --git a/particles/progress-bar.c b/particles/progress-bar.c index 9c1eb6c..762178e 100644 --- a/particles/progress-bar.c +++ b/particles/progress-bar.c @@ -54,7 +54,7 @@ exposable_destroy(struct exposable *exposable) } static int -begin_expose(struct exposable *exposable, cairo_t *cr) +begin_expose(struct exposable *exposable) { struct eprivate *e = exposable->private; @@ -64,7 +64,7 @@ begin_expose(struct exposable *exposable, cairo_t *cr) /* Sub-exposables */ for (size_t i = 0; i < e->count; i++) - exposable->width += e->exposables[i]->begin_expose(e->exposables[i], cr); + exposable->width += e->exposables[i]->begin_expose(e->exposables[i]); return exposable->width; } diff --git a/particles/ramp.c b/particles/ramp.c index 2e0aebe..1f8ef11 100644 --- a/particles/ramp.c +++ b/particles/ramp.c @@ -30,13 +30,13 @@ exposable_destroy(struct exposable *exposable) } static int -begin_expose(struct exposable *exposable, cairo_t *cr) +begin_expose(struct exposable *exposable) { struct eprivate *e = exposable->private; exposable->width = ( exposable->particle->left_margin + - e->exposable->begin_expose(e->exposable, cr) + + e->exposable->begin_expose(e->exposable) + exposable->particle->right_margin); return exposable->width; diff --git a/particles/string.c b/particles/string.c index e4818dc..3ff0aa7 100644 --- a/particles/string.c +++ b/particles/string.c @@ -35,7 +35,7 @@ exposable_destroy(struct exposable *exposable) } static int -begin_expose(struct exposable *exposable, cairo_t *cr) +begin_expose(struct exposable *exposable) { struct eprivate *e = exposable->private; From c11fee4ce3028689109579916aa26f985ecda281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 01:56:58 +0200 Subject: [PATCH 05/12] cairo: replace cairo with pixman in decos, particles and modules All decoration, particle and module interfaces now takes a pixman_image_t parameter, and all drawing is done using pixman APIs. The wayland/xcb backends implement a new interface functions, get_pixman_image(), that should return a pixman image instance that is suitable for rendering. In the wayland backend, the image uses the same backing data as the cairo surface. In the XCB backend, we create a new image each time, and then blit it to the cairo surface at commit time. --- bar/backend.h | 3 ++- bar/bar.c | 45 +++++++++++++---------------------- bar/bar.h | 4 ++-- bar/private.h | 4 ++-- bar/wayland.c | 24 +++++++++++++++++-- bar/xcb.c | 51 ++++++++++++++++++++++++++++++++++++++-- config.c | 40 +++++++++++++++---------------- config.h | 4 ++-- decoration.h | 4 ++-- decorations/background.c | 14 +++++------ decorations/meson.build | 2 +- decorations/stack.c | 4 ++-- decorations/underline.c | 13 +++++----- modules/meson.build | 2 +- particle.c | 6 ++--- particle.h | 10 ++++---- particles/dynlist.c | 4 ++-- particles/empty.c | 4 ++-- particles/list.c | 6 ++--- particles/map.c | 6 ++--- particles/meson.build | 2 +- particles/progress-bar.c | 6 ++--- particles/ramp.c | 6 ++--- particles/string.c | 39 +++--------------------------- 24 files changed, 162 insertions(+), 141 deletions(-) diff --git a/bar/backend.h b/bar/backend.h index c07e069..782bb98 100644 --- a/bar/backend.h +++ b/bar/backend.h @@ -11,7 +11,8 @@ struct backend { void (*expose)(const struct bar *bar), void (*on_mouse)(struct bar *bar, enum mouse_event event, int x, int y)); - void (*commit_surface)(const struct bar *bar); + pixman_image_t *(*get_pixman_image)(const struct bar *bar); + void (*commit_pixman)(const struct bar *bar, pixman_image_t *pix); void (*refresh)(const struct bar *bar); void (*set_cursor)(struct bar *bar, const char *cursor); }; diff --git a/bar/bar.c b/bar/bar.c index df74d7d..be048a3 100644 --- a/bar/bar.c +++ b/bar/bar.c @@ -61,33 +61,21 @@ static void expose(const struct bar *_bar) { const struct private *bar = _bar->private; + pixman_image_t *pix = bar->backend.iface->get_pixman_image(_bar); - double r, g, b, a; - r = bar->background.red; - g = bar->background.green; - b = bar->background.blue; - a = bar->background.alpha; - - cairo_set_source_rgba(bar->cairo, r, g, b, a); - cairo_set_operator(bar->cairo, CAIRO_OPERATOR_SOURCE); - cairo_paint(bar->cairo); + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, &bar->background, 1, + &(pixman_rectangle16_t){0, 0, bar->width, bar->height_with_border}); if (bar->border.width > 0) { - r = bar->border.color.red; - g = bar->border.color.green; - b = bar->border.color.blue; - a = bar->border.color.alpha; - - cairo_set_line_width(bar->cairo, bar->border.width); - cairo_set_source_rgba(bar->cairo, r, g, b, a); - cairo_set_operator(bar->cairo, CAIRO_OPERATOR_OVER); - cairo_rectangle( - bar->cairo, - bar->border.width / 2.0, - bar->border.width / 2.0, - bar->width - bar->border.width, - bar->height_with_border - bar->border.width); - cairo_stroke(bar->cairo); + pixman_image_fill_rectangles( + PIXMAN_OP_OVER, pix, &bar->border.color, 4, + (pixman_rectangle16_t[]){ + {0, 0, bar->width, bar->border.width}, + {0, 0, bar->border.width, bar->height}, + {bar->width - bar->border.width, 0, bar->border.width, bar->height}, + {0, bar->height - bar->border.width, bar->width, bar->border.width}, + }); } for (size_t i = 0; i < bar->left.count; i++) { @@ -127,14 +115,14 @@ expose(const struct bar *_bar) int x = bar->border.width + bar->left_margin - bar->left_spacing; for (size_t i = 0; i < bar->left.count; i++) { const struct exposable *e = bar->left.exps[i]; - e->expose(e, bar->cairo, x + bar->left_spacing, y, bar->height); + e->expose(e, pix, x + bar->left_spacing, y, bar->height); x += bar->left_spacing + e->width + bar->right_spacing; } x = bar->width / 2 - center_width / 2 - bar->left_spacing; for (size_t i = 0; i < bar->center.count; i++) { const struct exposable *e = bar->center.exps[i]; - e->expose(e, bar->cairo, x + bar->left_spacing, y, bar->height); + e->expose(e, pix, x + bar->left_spacing, y, bar->height); x += bar->left_spacing + e->width + bar->right_spacing; } @@ -146,12 +134,11 @@ expose(const struct bar *_bar) for (size_t i = 0; i < bar->right.count; i++) { const struct exposable *e = bar->right.exps[i]; - e->expose(e, bar->cairo, x + bar->left_spacing, y, bar->height); + e->expose(e, pix, x + bar->left_spacing, y, bar->height); x += bar->left_spacing + e->width + bar->right_spacing; } - cairo_surface_flush(bar->cairo_surface); - bar->backend.iface->commit_surface(_bar); + bar->backend.iface->commit_pixman(_bar, pix); } diff --git a/bar/bar.h b/bar/bar.h index 108a972..78e2414 100644 --- a/bar/bar.h +++ b/bar/bar.h @@ -26,11 +26,11 @@ struct bar_config { int left_spacing, right_spacing; int left_margin, right_margin; - struct rgba background; + pixman_color_t background; struct { int width; - struct rgba color; + pixman_color_t color; int left_margin, right_margin; int top_margin, bottom_margin; } border; diff --git a/bar/private.h b/bar/private.h index 0f86e86..c41d4a7 100644 --- a/bar/private.h +++ b/bar/private.h @@ -14,11 +14,11 @@ struct private { int left_spacing, right_spacing; int left_margin, right_margin; - struct rgba background; + pixman_color_t background; struct { int width; - struct rgba color; + pixman_color_t color; int left_margin, right_margin; int top_margin, bottom_margin; } border; diff --git a/bar/wayland.c b/bar/wayland.c index f53bce4..4e65bf2 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -901,12 +901,31 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da ;//printf("nothing more to do\n"); } +static pixman_image_t * +get_pixman_image(const struct bar *_bar) +{ + struct private *bar = _bar->private; + + cairo_surface_t *surf = cairo_get_target(bar->cairo); + cairo_surface_flush(surf); + + return pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, + cairo_image_surface_get_width(surf), + cairo_image_surface_get_height(surf), + (uint32_t *)cairo_image_surface_get_data(surf), + cairo_image_surface_get_stride(surf)); +} + static void -commit_surface(const struct bar *_bar) +commit_pixman(const struct bar *_bar, pixman_image_t *pix) { struct private *bar = _bar->private; struct wayland_backend *backend = bar->backend.data; + pixman_image_unref(pix); + cairo_surface_mark_dirty(cairo_get_target(bar->cairo)); + //printf("commit: %dxl%d\n", backend->width, backend->height); assert(backend->next_buffer != NULL); @@ -973,7 +992,8 @@ const struct backend wayland_backend_iface = { .setup = &setup, .cleanup = &cleanup, .loop = &loop, - .commit_surface = &commit_surface, + .get_pixman_image = &get_pixman_image, + .commit_pixman = &commit_pixman, .refresh = &refresh, .set_cursor = &set_cursor, }; diff --git a/bar/xcb.c b/bar/xcb.c index f2dcd3c..3b71d27 100644 --- a/bar/xcb.c +++ b/bar/xcb.c @@ -370,10 +370,56 @@ loop(struct bar *_bar, } static void -commit_surface(const struct bar *_bar) +free_pixman_bits(pixman_image_t *pix, void *data) +{ + free(data); +} + +static pixman_image_t * +get_pixman_image(const struct bar *_bar) +{ + const struct private *bar = _bar->private; + uint32_t *bits = malloc( + bar->width * bar->height_with_border * sizeof(uint32_t)); + + pixman_image_t *ret = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, + bar->width, + bar->height_with_border, + bits, + bar->width * sizeof(uint32_t)); + + if (ret == NULL) { + free(bits); + return NULL; + } + + pixman_image_set_destroy_function(ret, &free_pixman_bits, bits); + return ret; +} + +static void +commit_pixman(const struct bar *_bar, pixman_image_t *pix) { const struct private *bar = _bar->private; const struct xcb_backend *backend = bar->backend.data; + + /* Blit pixman image to our XCB surface */ + cairo_surface_t *surf = cairo_image_surface_create_for_data( + (unsigned char *)pixman_image_get_data(pix), + CAIRO_FORMAT_ARGB32, + bar->width, + bar->height_with_border, + cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, bar->width)); + + cairo_set_source_surface(bar->cairo, surf, 0, 0); + cairo_set_operator(bar->cairo, CAIRO_OPERATOR_SOURCE); + cairo_paint(bar->cairo); + + cairo_surface_flush(bar->cairo_surface); + cairo_surface_destroy(surf); + pixman_image_unref(pix); + xcb_copy_area(backend->conn, backend->pixmap, backend->win, backend->gc, 0, 0, 0, 0, bar->width, bar->height_with_border); xcb_flush(backend->conn); @@ -430,7 +476,8 @@ const struct backend xcb_backend_iface = { .setup = &setup, .cleanup = &cleanup, .loop = &loop, - .commit_surface = &commit_surface, + .get_pixman_image = &get_pixman_image, + .commit_pixman = &commit_pixman, .refresh = &refresh, .set_cursor = &set_cursor, }; diff --git a/config.c b/config.c index 01a985d..7a885dc 100644 --- a/config.c +++ b/config.c @@ -13,6 +13,10 @@ #include "module.h" #include "plugin.h" +#define LOG_MODULE "config" +#define LOG_ENABLE_DBG 0 +#include "log.h" + static uint8_t hex_nibble(char hex) { @@ -36,7 +40,7 @@ hex_byte(const char hex[2]) return upper << 4 | lower; } -struct rgba +pixman_color_t conf_to_color(const struct yml_node *node) { const char *hex = yml_value_as_string(node); @@ -44,30 +48,26 @@ conf_to_color(const struct yml_node *node) assert(hex != NULL); assert(strlen(hex) == 8); - uint8_t red = hex_byte(&hex[0]); - uint8_t green = hex_byte(&hex[2]); - uint8_t blue = hex_byte(&hex[4]); - uint8_t alpha = hex_byte(&hex[6]); + uint16_t red = hex_byte(&hex[0]); + uint16_t green = hex_byte(&hex[2]); + uint16_t blue = hex_byte(&hex[4]); + uint16_t alpha = hex_byte(&hex[6]); - struct rgba rgba = { - (double)red / 255.0, - (double)green / 255.0, - (double)blue / 255.0, - (double)alpha / 255.0 + alpha |= alpha << 8; + int alpha_div = 0xffff / alpha; + + return (pixman_color_t){ + .red = (red << 8 | red) / alpha_div, + .green = (green << 8 | green) / alpha_div, + .blue = (blue << 8 | blue) / alpha_div, + .alpha = alpha, }; - - assert(rgba.red >= 0.0 && rgba.red <= 1.0); - assert(rgba.green >= 0.0 && rgba.green <= 1.0); - assert(rgba.blue >= 0.0 && rgba.blue <= 1.0); - assert(rgba.alpha >= 0.0 && rgba.alpha <= 1.0); - - return rgba; } struct font * conf_to_font(const struct yml_node *node) { - return font_from_name(yml_value_as_string(node));; + return font_from_name(yml_value_as_string(node)); } struct deco * @@ -155,7 +155,7 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) */ struct font *font = font_node != NULL ? conf_to_font(font_node) : font_clone(inherited.font); - struct rgba foreground = foreground_node != NULL + pixman_color_t foreground = foreground_node != NULL ? conf_to_color(foreground_node) : inherited.foreground; /* Instantiate base/common particle */ @@ -264,7 +264,7 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) * foreground color at top-level. */ struct font *font = font_from_name("sans"); - struct rgba foreground = (struct rgba){1.0, 1.0, 1.0, 1.0}; /* White */ + pixman_color_t foreground = {0xffff, 0xffff, 0xffff, 0xffff}; /* White */ const struct yml_node *font_node = yml_get_value(bar, "font"); if (font_node != NULL) { diff --git a/config.h b/config.h index a909c60..28e3f5a 100644 --- a/config.h +++ b/config.h @@ -14,12 +14,12 @@ struct bar *conf_to_bar(const struct yml_node *bar, enum bar_backend backend); * Utility functions, for e.g. modules */ -struct rgba conf_to_color(const struct yml_node *node); +pixman_color_t conf_to_color(const struct yml_node *node); struct font *conf_to_font(const struct yml_node *node); struct conf_inherit { const struct font *font; - struct rgba foreground; + pixman_color_t foreground; }; struct particle *conf_to_particle( diff --git a/decoration.h b/decoration.h index 78f2f05..efb79e2 100644 --- a/decoration.h +++ b/decoration.h @@ -1,10 +1,10 @@ #pragma once -#include +#include struct deco { void *private; - void (*expose)(const struct deco *deco, cairo_t *cr, + void (*expose)(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height); void (*destroy)(struct deco *deco); }; diff --git a/decorations/background.c b/decorations/background.c index ef7b12b..b3b9ed2 100644 --- a/decorations/background.c +++ b/decorations/background.c @@ -6,7 +6,8 @@ #include "../plugin.h" struct private { - struct rgba color; + //struct rgba color; + pixman_color_t color; }; static void @@ -18,17 +19,16 @@ destroy(struct deco *deco) } static void -expose(const struct deco *deco, cairo_t *cr, int x, int y, int width, int height) +expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height) { const struct private *d = deco->private; - cairo_set_source_rgba( - cr, d->color.red, d->color.green, d->color.blue, d->color.alpha); - cairo_rectangle(cr, x, y, width, height); - cairo_fill(cr); + pixman_image_fill_rectangles( + PIXMAN_OP_OVER, pix, &d->color, 1, + &(pixman_rectangle16_t){x, y, width, height}); } static struct deco * -background_new(struct rgba color) +background_new(pixman_color_t color) { struct private *priv = calloc(1, sizeof(*priv)); priv->color = color; diff --git a/decorations/meson.build b/decorations/meson.build index 1b6daee..f96c80b 100644 --- a/decorations/meson.build +++ b/decorations/meson.build @@ -1,4 +1,4 @@ -deco_sdk = declare_dependency(dependencies: [cairo, cairo_ft]) +deco_sdk = declare_dependency(dependencies: [pixman]) decorations = [] foreach deco : ['background', 'stack', 'underline'] diff --git a/decorations/stack.c b/decorations/stack.c index 3ffaab5..16c58ee 100644 --- a/decorations/stack.c +++ b/decorations/stack.c @@ -24,11 +24,11 @@ destroy(struct deco *deco) } static void -expose(const struct deco *deco, cairo_t *cr, int x, int y, int width, int height) +expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height) { const struct private *d = deco->private; for (size_t i = 0; i < d->count; i++) - d->decos[i]->expose(d->decos[i], cr, x, y, width, height); + d->decos[i]->expose(d->decos[i], pix, x, y, width, height); } static struct deco * diff --git a/decorations/underline.c b/decorations/underline.c index 996d54a..a700bec 100644 --- a/decorations/underline.c +++ b/decorations/underline.c @@ -7,7 +7,7 @@ struct private { int size; - struct rgba color; + pixman_color_t color; }; static void @@ -19,17 +19,16 @@ destroy(struct deco *deco) } static void -expose(const struct deco *deco, cairo_t *cr, int x, int y, int width, int height) +expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height) { const struct private *d = deco->private; - cairo_set_source_rgba( - cr, d->color.red, d->color.green, d->color.blue, d->color.alpha); - cairo_rectangle(cr, x, y + height - d->size, width, d->size); - cairo_fill(cr); + pixman_image_fill_rectangles( + PIXMAN_OP_OVER, pix, &d->color, 1, + &(pixman_rectangle16_t){x, y + height - d->size, width, d->size}); } static struct deco * -underline_new(int size, struct rgba color) +underline_new(int size, pixman_color_t color) { struct private *priv = calloc(1, sizeof(*priv)); priv->size = size; diff --git a/modules/meson.build b/modules/meson.build index b156e18..5986c51 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -1,4 +1,4 @@ -module_sdk = declare_dependency(dependencies: [cairo, cairo_ft, threads]) +module_sdk = declare_dependency(dependencies: [pixman, threads]) modules = [] diff --git a/particle.c b/particle.c index c6e69ad..5c116bb 100644 --- a/particle.c +++ b/particle.c @@ -29,7 +29,7 @@ particle_default_destroy(struct particle *particle) struct particle * particle_common_new(int left_margin, int right_margin, const char *on_click_template, - struct font *font, struct rgba foreground, + struct font *font, pixman_color_t foreground, struct deco *deco) { struct particle *p = calloc(1, sizeof(*p)); @@ -52,11 +52,11 @@ exposable_default_destroy(struct exposable *exposable) void exposable_render_deco(const struct exposable *exposable, - cairo_t *cr, int x, int y, int height) + pixman_image_t *pix, int x, int y, int height) { const struct deco *deco = exposable->particle->deco; if (deco != NULL) - deco->expose(deco, cr, x, y, exposable->width, height); + deco->expose(deco, pix, x, y, exposable->width, height); } diff --git a/particle.h b/particle.h index 210530f..789fd87 100644 --- a/particle.h +++ b/particle.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include "color.h" #include "decoration.h" @@ -14,7 +14,7 @@ struct particle { int left_margin, right_margin; char *on_click_template; - struct rgba foreground; + pixman_color_t foreground; struct font *font; struct deco *deco; @@ -37,7 +37,7 @@ struct exposable { void (*destroy)(struct exposable *exposable); int (*begin_expose)(struct exposable *exposable); - void (*expose)(const struct exposable *exposable, cairo_t *cr, + void (*expose)(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height); void (*on_mouse)(struct exposable *exposable, struct bar *bar, @@ -46,7 +46,7 @@ struct exposable { struct particle *particle_common_new( int left_margin, int right_margin, const char *on_click_template, - struct font *font, struct rgba foreground, struct deco *deco); + struct font *font, pixman_color_t foreground, struct deco *deco); void particle_default_destroy(struct particle *particle); @@ -54,7 +54,7 @@ struct exposable *exposable_common_new( const struct particle *particle, const char *on_click); void exposable_default_destroy(struct exposable *exposable); void exposable_render_deco( - const struct exposable *exposable, cairo_t *cr, int x, int y, int height); + const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height); void exposable_default_on_mouse( struct exposable *exposable, struct bar *bar, diff --git a/particles/dynlist.c b/particles/dynlist.c index e6a3636..c04d610 100644 --- a/particles/dynlist.c +++ b/particles/dynlist.c @@ -49,7 +49,7 @@ dynlist_begin_expose(struct exposable *exposable) } static void -dynlist_expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) +dynlist_expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height) { const struct private *e = exposable->private; @@ -60,7 +60,7 @@ dynlist_expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int for (size_t i = 0; i < e->count; i++) { const struct exposable *ee = e->exposables[i]; - ee->expose(ee, cr, x + left_spacing, y, height); + ee->expose(ee, pix, x + left_spacing, y, height); x += left_spacing + e->widths[i] + right_spacing; } } diff --git a/particles/empty.c b/particles/empty.c index 8b0cb39..e97f929 100644 --- a/particles/empty.c +++ b/particles/empty.c @@ -14,9 +14,9 @@ begin_expose(struct exposable *exposable) } static void -expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) +expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height) { - exposable_render_deco(exposable, cr, x, y, height); + exposable_render_deco(exposable, pix, x, y, height); } static struct exposable * diff --git a/particles/list.c b/particles/list.c index a47c468..720e8a5 100644 --- a/particles/list.c +++ b/particles/list.c @@ -55,11 +55,11 @@ begin_expose(struct exposable *exposable) } static void -expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) +expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height) { const struct eprivate *e = exposable->private; - exposable_render_deco(exposable, cr, x, y, height); + exposable_render_deco(exposable, pix, x, y, height); int left_margin = exposable->particle->left_margin; int left_spacing = e->left_spacing; @@ -68,7 +68,7 @@ expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) x += left_margin - left_spacing; for (size_t i = 0; i < e->count; i++) { const struct exposable *ee = e->exposables[i]; - ee->expose(ee, cr, x + left_spacing, y, height); + ee->expose(ee, pix, x + left_spacing, y, height); x += left_spacing + e->widths[i] + right_spacing; } } diff --git a/particles/map.c b/particles/map.c index a8895cb..2f5c460 100644 --- a/particles/map.c +++ b/particles/map.c @@ -49,13 +49,13 @@ begin_expose(struct exposable *exposable) } static void -expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) +expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height) { struct eprivate *e = exposable->private; - exposable_render_deco(exposable, cr, x, y, height); + exposable_render_deco(exposable, pix, x, y, height); e->exposable->expose( - e->exposable, cr, x + exposable->particle->left_margin, y, height); + e->exposable, pix, x + exposable->particle->left_margin, y, height); } static void diff --git a/particles/meson.build b/particles/meson.build index 2b867c8..837e418 100644 --- a/particles/meson.build +++ b/particles/meson.build @@ -1,4 +1,4 @@ -particle_sdk = declare_dependency(dependencies: [cairo, cairo_ft]) +particle_sdk = declare_dependency(dependencies: [freetype, fontconfig, pixman]) particles = [] foreach particle : ['empty', 'list', 'map', 'progress-bar', 'ramp', 'string'] diff --git a/particles/progress-bar.c b/particles/progress-bar.c index 762178e..e4e1715 100644 --- a/particles/progress-bar.c +++ b/particles/progress-bar.c @@ -70,15 +70,15 @@ begin_expose(struct exposable *exposable) } static void -expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) +expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height) { const struct eprivate *e = exposable->private; - exposable_render_deco(exposable, cr, x, y, height); + exposable_render_deco(exposable, pix, x, y, height); x += exposable->particle->left_margin; for (size_t i = 0; i < e->count; i++) { - e->exposables[i]->expose(e->exposables[i], cr, x, y, height); + e->exposables[i]->expose(e->exposables[i], pix, x, y, height); x += e->exposables[i]->width; } } diff --git a/particles/ramp.c b/particles/ramp.c index 1f8ef11..b513681 100644 --- a/particles/ramp.c +++ b/particles/ramp.c @@ -43,13 +43,13 @@ begin_expose(struct exposable *exposable) } static void -expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) +expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height) { struct eprivate *e = exposable->private; - exposable_render_deco(exposable, cr, x, y, height); + exposable_render_deco(exposable, pix, x, y, height); e->exposable->expose( - e->exposable, cr, x + exposable->particle->left_margin, y, height); + e->exposable, pix, x + exposable->particle->left_margin, y, height); } static void diff --git a/particles/string.c b/particles/string.c index 3ff0aa7..ec1fcdd 100644 --- a/particles/string.c +++ b/particles/string.c @@ -70,22 +70,10 @@ begin_expose(struct exposable *exposable) return exposable->width; } -static inline pixman_color_t -color_hex_to_pixman_with_alpha(uint32_t color, uint16_t alpha) -{ - int alpha_div = 0xffff / alpha; - return (pixman_color_t){ - .red = ((color >> 16 & 0xff) | (color >> 8 & 0xff00)) / alpha_div, - .green = ((color >> 8 & 0xff) | (color >> 0 & 0xff00)) / alpha_div, - .blue = ((color >> 0 & 0xff) | (color << 8 & 0xff00)) / alpha_div, - .alpha = alpha, - }; -} - static void -expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) +expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height) { - exposable_render_deco(exposable, cr, x, y, height); + exposable_render_deco(exposable, pix, x, y, height); const struct eprivate *e = exposable->private; const struct font *font = exposable->particle->font; @@ -112,24 +100,6 @@ expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) (double)(height + font->fextents.ascent + font->fextents.descent) / 2.0 - (font->fextents.descent > 0 ? font->fextents.descent : 0); - /* TODO: get rid of cairo?... */ - cairo_surface_t *surf = cairo_get_target(cr); - cairo_surface_flush(surf); - - pixman_image_t *pix = pixman_image_create_bits_no_clear( - PIXMAN_a8r8g8b8, - cairo_image_surface_get_width(surf), - cairo_image_surface_get_height(surf), - (uint32_t *)cairo_image_surface_get_data(surf), - cairo_image_surface_get_stride(surf)); - - uint32_t hex_color = - (uint32_t)(uint8_t)(exposable->particle->foreground.red * 255) << 16 | - (uint32_t)(uint8_t)(exposable->particle->foreground.green * 255) << 8 | - (uint32_t)(uint8_t)(exposable->particle->foreground.blue * 255) << 0; - uint16_t alpha = exposable->particle->foreground.alpha * 65535; - pixman_color_t fg = color_hex_to_pixman_with_alpha(hex_color, alpha); - x += exposable->particle->left_margin; /* Loop glyphs and render them, one by one */ @@ -145,7 +115,7 @@ expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) glyph->width, glyph->height); } else { /* Glyph surface is an alpha mask */ - pixman_image_t *src = pixman_image_create_solid_fill(&fg); + pixman_image_t *src = pixman_image_create_solid_fill(&exposable->particle->foreground); pixman_image_composite32( PIXMAN_OP_OVER, src, glyph->pix, pix, 0, 0, 0, 0, x + glyph->x, baseline - glyph->y, @@ -155,9 +125,6 @@ expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) x += glyph->x_advance; } - - pixman_image_unref(pix); - cairo_surface_mark_dirty(surf); } static struct exposable * From 01e71590e069b785014939da08fb558d588c94f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 11:46:46 +0200 Subject: [PATCH 06/12] bar: don't use cairo This is trivial in the Wayland backend; just instantiate a pixman pointing to the same mmapped memory as the wayland buffer. In the XCB backend, we change the implementation slightly; instead of rendering via a cairo XCB surface backend (to a server side pixmap), which is then blitted to the window in commit(), we now render to a client-side pixman pixmap, and blit it using xcb_put_image() in commit(). --- bar/backend.h | 3 +- bar/bar.c | 14 ++------ bar/private.h | 17 +--------- bar/wayland.c | 89 ++++++++++++++----------------------------------- bar/xcb.c | 91 ++++++++++++++++----------------------------------- 5 files changed, 58 insertions(+), 156 deletions(-) diff --git a/bar/backend.h b/bar/backend.h index 782bb98..f2681a8 100644 --- a/bar/backend.h +++ b/bar/backend.h @@ -11,8 +11,7 @@ struct backend { void (*expose)(const struct bar *bar), void (*on_mouse)(struct bar *bar, enum mouse_event event, int x, int y)); - pixman_image_t *(*get_pixman_image)(const struct bar *bar); - void (*commit_pixman)(const struct bar *bar, pixman_image_t *pix); + void (*commit)(const struct bar *bar); void (*refresh)(const struct bar *bar); void (*set_cursor)(struct bar *bar, const char *cursor); }; diff --git a/bar/bar.c b/bar/bar.c index be048a3..19ea36d 100644 --- a/bar/bar.c +++ b/bar/bar.c @@ -61,7 +61,7 @@ static void expose(const struct bar *_bar) { const struct private *bar = _bar->private; - pixman_image_t *pix = bar->backend.iface->get_pixman_image(_bar); + pixman_image_t *pix = bar->pix; pixman_image_fill_rectangles( PIXMAN_OP_SRC, pix, &bar->background, 1, @@ -138,7 +138,7 @@ expose(const struct bar *_bar) x += bar->left_spacing + e->width + bar->right_spacing; } - bar->backend.iface->commit_pixman(_bar, pix); + bar->backend.iface->commit(_bar); } @@ -299,14 +299,6 @@ run(struct bar *_bar) bar->backend.iface->cleanup(_bar); - if (bar->cairo) - cairo_destroy(bar->cairo); - if (bar->cairo_surface) { - cairo_device_finish(cairo_surface_get_device(bar->cairo_surface)); - cairo_surface_finish(bar->cairo_surface); - cairo_surface_destroy(bar->cairo_surface); - } - LOG_DBG("bar exiting"); return ret; } @@ -341,8 +333,6 @@ destroy(struct bar *bar) m->destroy(m); } - cairo_debug_reset_static_data(); - free(b->left.mods); free(b->left.exps); free(b->center.mods); diff --git a/bar/private.h b/bar/private.h index c41d4a7..5b9aa2f 100644 --- a/bar/private.h +++ b/bar/private.h @@ -1,8 +1,5 @@ #pragma once -#include -#include - #include "../bar/bar.h" #include "backend.h" @@ -46,22 +43,10 @@ struct private { /* Name of currently active cursor */ char *cursor_name; - cairo_t *cairo; - cairo_surface_t *cairo_surface; + pixman_image_t *pix; struct { void *data; const struct backend *iface; } backend; -#if 0 - /* Backend specifics */ - xcb_connection_t *conn; - - xcb_window_t win; - xcb_colormap_t colormap; - xcb_pixmap_t pixmap; - xcb_gc_t gc; - xcb_cursor_context_t *cursor_ctx; - xcb_cursor_t cursor; -#endif }; diff --git a/bar/wayland.c b/bar/wayland.c index 4e65bf2..a8d14c9 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -10,7 +10,8 @@ #include #include -#include +//#include +#include #include #include @@ -21,6 +22,7 @@ #define LOG_ENABLE_DBG 0 #include "../log.h" #include "../tllist.h" +#include "../stride.h" #include "private.h" @@ -31,8 +33,7 @@ struct buffer { struct wl_buffer *wl_buf; - cairo_surface_t *cairo_surface; - cairo_t *cairo; + pixman_image_t *pix; }; struct monitor { @@ -448,11 +449,10 @@ get_buffer(struct wayland_backend *backend) * No existing buffer available. Create a new one by: * * 1. open a memory backed "file" with memfd_create() - * 2. mmap() the memory file, to be used by the cairo surface + * 2. mmap() the memory file, to be used by the pixman image * 3. create a wayland shm buffer for the same memory file * - * The cairo surface and the wayland buffer are now sharing - * memory. + * The pixman image and the wayland buffer are now sharing memory. */ int pool_fd = -1; @@ -462,8 +462,7 @@ get_buffer(struct wayland_backend *backend) struct wl_shm_pool *pool = NULL; struct wl_buffer *buf = NULL; - cairo_surface_t *cairo_surface = NULL; - cairo_t *cairo = NULL; + pixman_image_t *pix = NULL; /* Backing memory for SHM */ pool_fd = memfd_create("f00bar-wayland-shm-buffer-pool", MFD_CLOEXEC); @@ -473,8 +472,9 @@ get_buffer(struct wayland_backend *backend) } /* Total size */ - const uint32_t stride = cairo_format_stride_for_width( - CAIRO_FORMAT_ARGB32, backend->width); + const uint32_t stride = stride_for_format_and_width( + PIXMAN_a8r8g8b8, backend->width); + size = stride * backend->height; if (ftruncate(pool_fd, size) == -1) { LOG_ERR("failed to truncate SHM pool"); @@ -504,19 +504,10 @@ get_buffer(struct wayland_backend *backend) wl_shm_pool_destroy(pool); pool = NULL; close(pool_fd); pool_fd = -1; - /* Create a cairo surface around the mmapped memory */ - cairo_surface = cairo_image_surface_create_for_data( - mmapped, CAIRO_FORMAT_ARGB32, backend->width, backend->height, stride); - if (cairo_surface_status(cairo_surface) != CAIRO_STATUS_SUCCESS) { - LOG_ERR("failed to create cairo surface: %s", - cairo_status_to_string(cairo_surface_status(cairo_surface))); - goto err; - } - - cairo = cairo_create(cairo_surface); - if (cairo_status(cairo) != CAIRO_STATUS_SUCCESS) { - LOG_ERR("failed to create cairo context: %s", - cairo_status_to_string(cairo_status(cairo))); + pix = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, backend->width, backend->height, (uint32_t *)mmapped, stride); + if (pix == NULL) { + LOG_ERR("failed to create pixman image"); goto err; } @@ -528,9 +519,8 @@ get_buffer(struct wayland_backend *backend) .size = size, .mmapped = mmapped, .wl_buf = buf, - .cairo_surface = cairo_surface, - .cairo = cairo} - ) + .pix = pix, + }) ); struct buffer *ret = &tll_back(backend->buffers); @@ -538,10 +528,8 @@ get_buffer(struct wayland_backend *backend) return ret; err: - if (cairo != NULL) - cairo_destroy(cairo); - if (cairo_surface != NULL) - cairo_surface_destroy(cairo_surface); + if (pix != NULL) + pixman_image_unref(pix); if (buf != NULL) wl_buffer_destroy(buf); if (pool != NULL) @@ -712,9 +700,7 @@ setup(struct bar *_bar) /* Prepare a buffer + cairo context for bar to draw to */ backend->next_buffer = get_buffer(backend); assert(backend->next_buffer != NULL && backend->next_buffer->busy); - - bar->cairo_surface = backend->next_buffer->cairo_surface; - bar->cairo = backend->next_buffer->cairo; + bar->pix = backend->next_buffer->pix; return true; } @@ -728,10 +714,8 @@ cleanup(struct bar *_bar) tll_foreach(backend->buffers, it) { if (it->item.wl_buf != NULL) wl_buffer_destroy(it->item.wl_buf); - if (it->item.cairo != NULL) - cairo_destroy(it->item.cairo); - if (it->item.cairo_surface != NULL) - cairo_surface_destroy(it->item.cairo_surface); + if (it->item.pix != NULL) + pixman_image_unref(it->item.pix); munmap(it->item.mmapped, it->item.size); tll_remove(backend->buffers, it); @@ -778,8 +762,7 @@ cleanup(struct bar *_bar) wl_display_disconnect(backend->display); /* Destroyed when freeing buffer list */ - bar->cairo_surface = NULL; - bar->cairo = NULL; + bar->pix = NULL; } @@ -901,31 +884,12 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da ;//printf("nothing more to do\n"); } -static pixman_image_t * -get_pixman_image(const struct bar *_bar) -{ - struct private *bar = _bar->private; - - cairo_surface_t *surf = cairo_get_target(bar->cairo); - cairo_surface_flush(surf); - - return pixman_image_create_bits_no_clear( - PIXMAN_a8r8g8b8, - cairo_image_surface_get_width(surf), - cairo_image_surface_get_height(surf), - (uint32_t *)cairo_image_surface_get_data(surf), - cairo_image_surface_get_stride(surf)); -} - static void -commit_pixman(const struct bar *_bar, pixman_image_t *pix) +commit(const struct bar *_bar) { struct private *bar = _bar->private; struct wayland_backend *backend = bar->backend.data; - pixman_image_unref(pix); - cairo_surface_mark_dirty(cairo_get_target(bar->cairo)); - //printf("commit: %dxl%d\n", backend->width, backend->height); assert(backend->next_buffer != NULL); @@ -958,9 +922,7 @@ commit_pixman(const struct bar *_bar, pixman_image_t *pix) backend->next_buffer = get_buffer(backend); assert(backend->next_buffer != NULL && backend->next_buffer->busy); - - bar->cairo_surface = backend->next_buffer->cairo_surface; - bar->cairo = backend->next_buffer->cairo; + bar->pix = backend->next_buffer->pix; } static void @@ -992,8 +954,7 @@ const struct backend wayland_backend_iface = { .setup = &setup, .cleanup = &cleanup, .loop = &loop, - .get_pixman_image = &get_pixman_image, - .commit_pixman = &commit_pixman, + .commit = &commit, .refresh = &refresh, .set_cursor = &set_cursor, }; diff --git a/bar/xcb.c b/bar/xcb.c index 3b71d27..e2209dd 100644 --- a/bar/xcb.c +++ b/bar/xcb.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #define LOG_MODULE "bar:xcb" #include "../log.h" +#include "../stride.h" #include "../xcb.h" struct xcb_backend { @@ -27,10 +29,15 @@ struct xcb_backend { xcb_window_t win; xcb_colormap_t colormap; - xcb_pixmap_t pixmap; xcb_gc_t gc; xcb_cursor_context_t *cursor_ctx; xcb_cursor_t cursor; + + uint8_t depth; + void *client_pixmap; + size_t client_pixmap_size; + pixman_image_t *pix; + }; void * @@ -131,6 +138,7 @@ setup(struct bar *_bar) assert(depth == 32 || depth == 24); assert(vis != NULL); + backend->depth = depth; LOG_DBG("using a %hhu-bit visual", depth); backend->colormap = xcb_generate_id(backend->conn); @@ -234,19 +242,20 @@ setup(struct bar *_bar) _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, strut); - backend->pixmap = xcb_generate_id(backend->conn); - xcb_create_pixmap(backend->conn, depth, backend->pixmap, backend->win, - bar->width, bar->height_with_border); - backend->gc = xcb_generate_id(backend->conn); - xcb_create_gc(backend->conn, backend->gc, backend->pixmap, + xcb_create_gc(backend->conn, backend->gc, backend->win, XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES, (const uint32_t []){screen->white_pixel, 0}); - LOG_DBG("cairo: %s", cairo_version_string()); - bar->cairo_surface = cairo_xcb_surface_create( - backend->conn, backend->pixmap, vis, bar->width, bar->height_with_border); - bar->cairo = cairo_create(bar->cairo_surface); + const uint32_t stride = stride_for_format_and_width( + PIXMAN_a8r8g8b8, bar->width); + + backend->client_pixmap_size = stride * bar->height_with_border; + backend->client_pixmap = malloc(backend->client_pixmap_size); + backend->pix = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, bar->width, bar->height_with_border, + (uint32_t *)backend->client_pixmap, stride); + bar->pix = backend->pix; xcb_map_window(backend->conn, backend->win); @@ -274,10 +283,12 @@ cleanup(struct bar *_bar) /* TODO: move to bar.c */ free(bar->cursor_name); + if (backend->pix != NULL) + pixman_image_unref(backend->pix); + free(backend->client_pixmap); + if (backend->gc != 0) xcb_free_gc(backend->conn, backend->gc); - if (backend->pixmap != 0) - xcb_free_pixmap(backend->conn, backend->pixmap); if (backend->win != 0) xcb_destroy_window(backend->conn, backend->win); if (backend->colormap != 0) @@ -370,58 +381,15 @@ loop(struct bar *_bar, } static void -free_pixman_bits(pixman_image_t *pix, void *data) -{ - free(data); -} - -static pixman_image_t * -get_pixman_image(const struct bar *_bar) -{ - const struct private *bar = _bar->private; - uint32_t *bits = malloc( - bar->width * bar->height_with_border * sizeof(uint32_t)); - - pixman_image_t *ret = pixman_image_create_bits_no_clear( - PIXMAN_a8r8g8b8, - bar->width, - bar->height_with_border, - bits, - bar->width * sizeof(uint32_t)); - - if (ret == NULL) { - free(bits); - return NULL; - } - - pixman_image_set_destroy_function(ret, &free_pixman_bits, bits); - return ret; -} - -static void -commit_pixman(const struct bar *_bar, pixman_image_t *pix) +commit(const struct bar *_bar) { const struct private *bar = _bar->private; const struct xcb_backend *backend = bar->backend.data; - /* Blit pixman image to our XCB surface */ - cairo_surface_t *surf = cairo_image_surface_create_for_data( - (unsigned char *)pixman_image_get_data(pix), - CAIRO_FORMAT_ARGB32, - bar->width, - bar->height_with_border, - cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, bar->width)); - - cairo_set_source_surface(bar->cairo, surf, 0, 0); - cairo_set_operator(bar->cairo, CAIRO_OPERATOR_SOURCE); - cairo_paint(bar->cairo); - - cairo_surface_flush(bar->cairo_surface); - cairo_surface_destroy(surf); - pixman_image_unref(pix); - - xcb_copy_area(backend->conn, backend->pixmap, backend->win, backend->gc, - 0, 0, 0, 0, bar->width, bar->height_with_border); + xcb_put_image( + backend->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, backend->win, backend->gc, + bar->width, bar->height_with_border, 0, 0, 0, + backend->depth, backend->client_pixmap_size, backend->client_pixmap); xcb_flush(backend->conn); } @@ -476,8 +444,7 @@ const struct backend xcb_backend_iface = { .setup = &setup, .cleanup = &cleanup, .loop = &loop, - .get_pixman_image = &get_pixman_image, - .commit_pixman = &commit_pixman, + .commit = &commit, .refresh = &refresh, .set_cursor = &set_cursor, }; From 4ce314e328ecf6dd36a5bc60cdcd6c4884706032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 11:52:37 +0200 Subject: [PATCH 07/12] cairo: drop all remaining references to cairo We now use pixman (and freetype + fontconfig) exclusively. --- PKGBUILD | 2 +- PKGBUILD.wayland-only | 2 +- bar/meson.build | 5 ++--- bar/wayland.c | 3 +-- meson.build | 10 +++------- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 682836d..c382108 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -9,7 +9,7 @@ makedepends=('meson' 'ninja' 'scdoc') depends=( 'libxcb' 'xcb-util' 'xcb-util-cursor' 'xcb-util-wm' 'wayland' 'wlroots' - 'freetype2' 'fontconfig' 'cairo' + 'freetype2' 'fontconfig' 'pixman' 'libyaml' 'alsa-lib' 'libudev.so' diff --git a/PKGBUILD.wayland-only b/PKGBUILD.wayland-only index 7efdcc3..e8c9579 100644 --- a/PKGBUILD.wayland-only +++ b/PKGBUILD.wayland-only @@ -10,7 +10,7 @@ provides=('f00bar') makedepends=('meson' 'ninja' 'scdoc') depends=( 'wayland' 'wlroots' - 'freetype2' 'fontconfig' 'cairo' + 'freetype2' 'fontconfig' 'pixman' 'libyaml' 'alsa-lib' 'libudev.so' diff --git a/bar/meson.build b/bar/meson.build index c3b766f..ce8e81c 100644 --- a/bar/meson.build +++ b/bar/meson.build @@ -1,8 +1,7 @@ bar_backends = [] if backend_x11 - bar_x11 = declare_dependency( - sources: ['xcb.c', 'xcb.h'], dependencies: [xcb_stuff, cairo, cairo_ft]) + bar_x11 = declare_dependency(sources: ['xcb.c', 'xcb.h'], dependencies: [xcb_stuff]) bar_backends += [bar_x11] endif @@ -37,7 +36,7 @@ if backend_wayland bar_wayland = declare_dependency( sources: ['wayland.c', 'wayland.h'] + wl_proto_src + wl_proto_headers, - dependencies: [wayland_client, wayland_cursor, cairo, cairo_ft]) + dependencies: [wayland_client, wayland_cursor]) bar_backends += [bar_wayland] endif diff --git a/bar/wayland.c b/bar/wayland.c index a8d14c9..a5be23e 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -10,7 +10,6 @@ #include #include -//#include #include #include #include @@ -697,7 +696,7 @@ setup(struct bar *_bar) //wl_surface_commit(backend->surface); //wl_display_roundtrip(backend->display); - /* Prepare a buffer + cairo context for bar to draw to */ + /* Prepare a buffer + pixman image for bar to draw to */ backend->next_buffer = get_buffer(backend); assert(backend->next_buffer != NULL && backend->next_buffer->busy); bar->pix = backend->next_buffer->pix; diff --git a/meson.build b/meson.build index f1014a7..6849c31 100644 --- a/meson.build +++ b/meson.build @@ -39,8 +39,6 @@ threads = dependency('threads') freetype = dependency('freetype2') fontconfig = dependency('fontconfig') pixman = dependency('pixman-1') -cairo = dependency('cairo') -cairo_ft = dependency('cairo-ft') yaml = dependency('yaml-0.1') # X11/XCB dependencies @@ -50,11 +48,9 @@ xcb_event = dependency('xcb-event', required: get_option('backend-x11')) xcb_ewmh = dependency('xcb-ewmh', required: get_option('backend-x11')) xcb_randr = dependency('xcb-randr', required: get_option('backend-x11')) xcb_render = dependency('xcb-render', required: get_option('backend-x11')) -cairo_xcb = dependency('cairo-xcb', required: get_option('backend-x11')) xcb_errors = dependency('xcb-errors', required: false) backend_x11 = xcb_aux.found() and xcb_cursor.found() and xcb_event.found() and \ - xcb_ewmh.found() and xcb_randr.found() and xcb_render.found() and \ - cairo_xcb.found() + xcb_ewmh.found() and xcb_randr.found() and xcb_render.found() # Wayland dependencies wayland_client = dependency('wayland-client', required: get_option('backend-wayland')) @@ -76,7 +72,7 @@ if backend_x11 xcb_stuff_lib = static_library( 'xcb-stuff', 'xcb.c', 'xcb.h', dependencies: [xcb_aux, xcb_cursor, xcb_event, xcb_ewmh, xcb_randr, - xcb_render, cairo_xcb, xcb_errors], + xcb_render, xcb_errors], c_args: xcb_errors.found() ? '-DHAVE_XCB_ERRORS' : [], pic: plugs_as_libs) @@ -106,7 +102,7 @@ f00bar = executable( 'tag.c', 'tag.h', 'tllist.h', 'yml.c', 'yml.h', - dependencies: [bar, freetype, fontconfig, pixman, cairo, cairo_ft, yaml, threads, dl] + + dependencies: [bar, freetype, fontconfig, pixman, yaml, threads, dl] + decorations + particles + modules, build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, From 5d6df44a79813acaf8203528c25f3c30bc5c7c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 11:59:34 +0200 Subject: [PATCH 08/12] bar: signal abort (to main loop) when backend fails --- bar/bar.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bar/bar.c b/bar/bar.c index 19ea36d..2a59e9a 100644 --- a/bar/bar.c +++ b/bar/bar.c @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -238,6 +239,7 @@ run(struct bar *_bar) if (!bar->backend.iface->setup(_bar)) { bar->backend.iface->cleanup(_bar); + write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t)); return 1; } From 18e9d67d778361ae50449374fed6789c0c02439d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 11:59:48 +0200 Subject: [PATCH 09/12] bar/wayland: fail when we can't find the specified monitor --- bar/wayland.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bar/wayland.c b/bar/wayland.c index a5be23e..23edb81 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -595,6 +595,12 @@ setup(struct bar *_bar) backend->monitor = mon; } + if (backend->monitor == NULL) { + LOG_ERR("failed to find the specified monitor: %s", + bar->monitor != NULL ? bar->monitor : "default"); + return false; + } + backend->surface = wl_compositor_create_surface(backend->compositor); if (backend->surface == NULL) { LOG_ERR("failed to create panel surface"); From f29f96be96f25055210ed53c4c9ac89791151db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 12:08:08 +0200 Subject: [PATCH 10/12] bar/wayland: use preferred monitor if user didn't specify one --- bar/wayland.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bar/wayland.c b/bar/wayland.c index 23edb81..a858260 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -51,6 +51,7 @@ struct monitor { int width_px; int height_px; + bool preferred; int scale; }; @@ -269,6 +270,8 @@ static void output_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + struct monitor *mon = data; + mon->preferred = flags & WL_OUTPUT_MODE_PREFERRED; } static void @@ -588,11 +591,15 @@ setup(struct bar *_bar) mon->name, mon->width_px, mon->height_px, mon->x, mon->y, mon->width_mm, mon->height_mm); - /* TODO: detect primary output when user hasn't specified a monitor */ - if (bar->monitor == NULL) + if (bar->monitor == NULL && mon->preferred) { + /* User didn't specify a monitor, and this is the default one */ backend->monitor = mon; - else if (strcmp(bar->monitor, mon->name) == 0) + } + + else if (bar->monitor != NULL && strcmp(bar->monitor, mon->name) == 0) { + /* User specified a monitor, and this is one */ backend->monitor = mon; + } } if (backend->monitor == NULL) { From e8a1efeeb54323f75ce829ad82044bff415c5f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 12:25:11 +0200 Subject: [PATCH 11/12] meson: add freetype dependency to decorations and modules Fixes build failures when building plugins as shared libraries --- decorations/meson.build | 2 +- modules/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/decorations/meson.build b/decorations/meson.build index f96c80b..b62bdb0 100644 --- a/decorations/meson.build +++ b/decorations/meson.build @@ -1,4 +1,4 @@ -deco_sdk = declare_dependency(dependencies: [pixman]) +deco_sdk = declare_dependency(dependencies: [freetype, pixman]) decorations = [] foreach deco : ['background', 'stack', 'underline'] diff --git a/modules/meson.build b/modules/meson.build index 5986c51..552fc1f 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -1,4 +1,4 @@ -module_sdk = declare_dependency(dependencies: [pixman, threads]) +module_sdk = declare_dependency(dependencies: [freetype, pixman, threads]) modules = [] From e169263851e3adcbc7e8dbbdc88d4cd07bc7c8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 22 Sep 2019 12:29:00 +0200 Subject: [PATCH 12/12] ci: install pixman+freetype+fontconfig instead of cairo --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4491c19..4247e16 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,8 @@ before_script: - echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories - apk update - apk add musl-dev eudev-libs eudev-dev linux-headers meson ninja gcc scdoc - - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev cairo-dev yaml-dev + - apk add pixman-dev freetype-dev fontconfig-dev + - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev yaml-dev - apk add wayland-dev wayland-protocols wlroots-dev - apk add json-c-dev libmpdclient-dev alsa-lib-dev - apk add ttf-dejavu