Skip to content

Commit 1f7f6ec

Browse files
committed
Add option to display the actual percentage in the bar
1 parent f7668d9 commit 1f7f6ec

File tree

17 files changed

+371
-10
lines changed

17 files changed

+371
-10
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
steps:
1414
- uses: actions/checkout@v2
1515
- name: Install dependencies
16-
run: apk update && apk add meson wayland-dev musl-dev wayland-protocols gcc inih-dev cmocka-dev
16+
run: apk update && apk add meson wayland-dev musl-dev wayland-protocols gcc inih-dev cmocka-dev freetype-dev
1717
- name: Run tests
1818
run: meson setup test && ninja -C test test
1919

@@ -23,7 +23,7 @@ jobs:
2323
steps:
2424
- uses: actions/checkout@v2
2525
- name: Install dependencies
26-
run: apk update && apk add meson wayland-dev musl-dev wayland-protocols gcc inih-dev cmocka-dev clang19 clang19-extra-tools clang19-analyzer
26+
run: apk update && apk add meson wayland-dev musl-dev wayland-protocols gcc inih-dev cmocka-dev freetype-dev clang19 clang19-extra-tools clang19-analyzer
2727
- name: Run clang-analyzer
2828
if: success() || failure()
2929
run: scan-build meson setup clang-analyzer && scan-build --status-bugs ninja -C clang-analyzer

meson.build

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ rt = cc.find_library('rt')
3838
libm = cc.find_library('m')
3939
seccomp = dependency('libseccomp', required: get_option('seccomp'))
4040
inih = dependency('inih')
41+
freetype2 = dependency('freetype2', required: get_option('text'))
4142

4243
sysconfdir = get_option('sysconfdir')
4344
if not fs.is_absolute(sysconfdir)
@@ -87,13 +88,21 @@ endforeach
8788

8889
wob_sources = ['src/main.c', 'src/image.c', 'src/log.c', 'src/color.c', 'src/config.c', 'src/wob.c', 'src/shm.c', wl_proto_src, wl_proto_headers]
8990
wob_dependencies = [wayland_client, rt, inih, libm]
91+
9092
if seccomp.found()
9193
wob_dependencies += seccomp
9294
wob_sources += 'src/pledge_seccomp.c'
9395
else
9496
wob_sources += 'src/pledge.c'
9597
endif
9698

99+
if freetype2.found()
100+
wob_dependencies += freetype2
101+
wob_sources += 'src/font_freetype.c'
102+
else
103+
wob_sources += 'src/font_stub.c'
104+
endif
105+
97106
executable(
98107
'wob',
99108
wob_sources,

meson_options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ option('man-pages', type: 'feature', value: 'auto', description: 'Generate and i
22
option('seccomp', type: 'feature', value: 'auto', description: 'Use seccomp on Linux')
33
option('tests', type: 'feature', value: 'auto', description: 'Build tests')
44
option('systemd-unit-files', type: 'feature', value: 'enabled', description: 'Install systemd unit files')
5+
option('text', type: 'feature', value: 'auto', description: 'Build with freetype2 text rendering')

src/color.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,32 @@
88

99
#include "color.h"
1010

11+
struct wob_color
12+
wob_color_from_argb8888(uint32_t argb)
13+
{
14+
struct wob_color result = {
15+
.a = (float) (argb >> 24 & 0xFF) / 255.0f,
16+
.r = (float) (argb >> 16 & 0xFF) / 255.0f,
17+
.g = (float) (argb >> 8 & 0xFF) / 255.0f,
18+
.b = (float) (argb & 0xFF) / 255.0f,
19+
};
20+
21+
return result;
22+
}
23+
24+
struct wob_color
25+
wob_color_blend_premultiplied(struct wob_color foreground, struct wob_color background)
26+
{
27+
struct wob_color result = {
28+
.a = foreground.a + background.a * (1 - foreground.a),
29+
.r = foreground.r + background.r * (1 - foreground.a),
30+
.b = foreground.b + background.b * (1 - foreground.a),
31+
.g = foreground.g + background.g * (1 - foreground.a),
32+
};
33+
34+
return result;
35+
}
36+
1137
uint32_t
1238
wob_color_to_argb(const struct wob_color color)
1339
{

src/color.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ struct wob_color {
1414
float b;
1515
};
1616

17+
struct wob_color wob_color_from_argb8888(uint32_t argb);
18+
19+
struct wob_color wob_color_blend_premultiplied(struct wob_color foreground, struct wob_color background);
20+
1721
uint32_t wob_color_to_argb(struct wob_color color);
1822

1923
uint32_t wob_color_to_rgba(struct wob_color color);

src/config.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ handler(void *user, const char *section, const char *name, const char *value)
306306
}
307307
return 1;
308308
}
309+
if (strcmp(name, "font") == 0) {
310+
config->default_style.font_path = strdup(value);
311+
return 1;
312+
}
309313

310314
wob_log_warn("Unknown config key %s", name);
311315
return 1;
@@ -453,6 +457,10 @@ handler(void *user, const char *section, const char *name, const char *value)
453457
}
454458
return 1;
455459
}
460+
if (strcmp(name, "font") == 0) {
461+
style->font_path = strdup(value);
462+
return 1;
463+
}
456464

457465
wob_log_warn("Unknown config key %s", name);
458466
return 1;
@@ -518,6 +526,7 @@ wob_config_create()
518526
config->default_style.overflow_colors.background = (struct wob_color) {.a = 1.0f, .r = 0.0f, .g = 0.0f, .b = 0.0f};
519527
config->default_style.overflow_colors.value = (struct wob_color) {.a = 1.0f, .r = 1.0f, .g = 0.0f, .b = 0.0f};
520528
config->default_style.overflow_colors.border = (struct wob_color) {.a = 1.0f, .r = 1.0f, .g = 1.0f, .b = 1.0f};
529+
config->default_style.font_path = NULL;
521530

522531
return config;
523532
}
@@ -585,6 +594,7 @@ wob_config_debug(struct wob_config *config)
585594
wob_log_debug("config.overflow_colors.background = " WOB_COLOR_PRINTF_FORMAT, WOB_COLOR_PRINTF_RGBA(config->default_style.overflow_colors.background));
586595
wob_log_debug("config.overflow_colors.value = " WOB_COLOR_PRINTF_FORMAT, WOB_COLOR_PRINTF_RGBA(config->default_style.overflow_colors.value));
587596
wob_log_debug("config.overflow_colors.border = " WOB_COLOR_PRINTF_FORMAT, WOB_COLOR_PRINTF_RGBA(config->default_style.overflow_colors.border));
597+
wob_log_debug("config.font = %s", config->default_style.font_path != NULL ? config->default_style.font_path : "<empty>");
588598

589599
struct wob_style *style;
590600
wl_list_for_each (style, &config->styles, link) {
@@ -594,6 +604,7 @@ wob_config_debug(struct wob_config *config)
594604
wob_log_debug("config.style.%s.overflow_colors.background = " WOB_COLOR_PRINTF_FORMAT, style->name, WOB_COLOR_PRINTF_RGBA(style->overflow_colors.background));
595605
wob_log_debug("config.style.%s.overflow_colors.value = " WOB_COLOR_PRINTF_FORMAT, style->name, WOB_COLOR_PRINTF_RGBA(style->overflow_colors.value));
596606
wob_log_debug("config.style.%s.overflow_colors.border = " WOB_COLOR_PRINTF_FORMAT, style->name, WOB_COLOR_PRINTF_RGBA(style->overflow_colors.border));
607+
wob_log_debug("config.style.%s.font = %s", style->name, style->font_path != NULL ? style->font_path : "<empty>");
597608
}
598609

599610
struct wob_output_config *output_config;
@@ -631,9 +642,14 @@ wob_config_destroy(struct wob_config *config)
631642
struct wob_style *style, *style_tmp;
632643
wl_list_for_each_safe (style, style_tmp, &config->styles, link) {
633644
free(style->name);
645+
free(style->font_path);
634646
free(style);
635647
}
636648

649+
if (config->default_style.font_path != NULL) {
650+
free(config->default_style.font_path);
651+
}
652+
637653
free(config);
638654
}
639655

src/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ struct wob_colors {
6363

6464
struct wob_style {
6565
char *name;
66+
char *font_path;
6667
struct wob_colors colors;
6768
struct wob_colors overflow_colors;
6869
struct wl_list link;

src/font.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef FONT_H
2+
#define FONT_H
3+
4+
#include <stddef.h>
5+
6+
#include "color.h"
7+
8+
struct wob_font_manager;
9+
10+
struct wob_font;
11+
12+
struct wob_font_text_dimensions {
13+
int w;
14+
int h;
15+
};
16+
17+
struct wob_font_manager *wob_font_manager_create();
18+
19+
void wob_font_manager_destroy(struct wob_font_manager *);
20+
21+
void wob_font_manager_load_font(struct wob_font_manager *, const char *fpath);
22+
23+
struct wob_font *wob_font_manager_get(struct wob_font_manager *, const char *fpath);
24+
25+
void wob_font_render_text(struct wob_font *font, char *text, int font_size, struct wob_color font_color, uint32_t *argb8888_buffer, size_t argb8888_buffer_size);
26+
27+
struct wob_font_text_dimensions wob_font_render_text_dimensions(struct wob_font *font, char *text, int font_size);
28+
29+
#endif

src/font_freetype.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#define WOB_FILE "font_freetype.c"
2+
3+
#include "font.h"
4+
#include "log.h"
5+
6+
#include <wayland-util.h>
7+
#include <ft2build.h>
8+
#include FT_FREETYPE_H
9+
#include FT_GLYPH_H
10+
11+
FT_Library library;
12+
13+
struct wob_font {
14+
char *name;
15+
FT_Face data;
16+
struct wl_list link;
17+
};
18+
19+
struct wob_font_manager {
20+
struct wl_list fonts;
21+
};
22+
23+
void
24+
draw_glyph(uint32_t *pixels, size_t stride, FT_Bitmap *ft_bitmap, struct wob_color font_color)
25+
{
26+
for (unsigned int row = 0; row < ft_bitmap->rows; row += 1) {
27+
for (unsigned int width = 0; width < ft_bitmap->width; width += 1) {
28+
uint8_t alpha = ft_bitmap->buffer[row * ft_bitmap->width + width];
29+
30+
struct wob_color background = wob_color_from_argb8888(pixels[width]);
31+
struct wob_color foreground = font_color;
32+
33+
foreground.a = alpha / 255.0f;
34+
foreground = wob_color_premultiply_alpha(foreground);
35+
36+
struct wob_color result = wob_color_blend_premultiplied(foreground, background);
37+
38+
pixels[width] = wob_color_to_argb(result);
39+
}
40+
pixels += stride;
41+
}
42+
}
43+
44+
struct wob_font_manager *
45+
wob_font_manager_create()
46+
{
47+
struct wob_font_manager *manager = malloc(sizeof(struct wob_font_manager));
48+
49+
FT_Init_FreeType(&library);
50+
51+
wl_list_init(&manager->fonts);
52+
53+
return manager;
54+
}
55+
56+
void
57+
wob_font_manager_destroy(struct wob_font_manager *manager)
58+
{
59+
struct wob_font *font, *font_tmp;
60+
wl_list_for_each_safe (font, font_tmp, &manager->fonts, link) {
61+
free(font->name);
62+
FT_Done_Face(font->data);
63+
64+
free(font);
65+
}
66+
67+
FT_Done_FreeType(library);
68+
}
69+
70+
void
71+
wob_font_manager_load_font(struct wob_font_manager *manager, const char *fpath)
72+
{
73+
struct wob_font *font = calloc(1, sizeof(struct wob_font));
74+
font->name = strdup(fpath);
75+
FT_New_Face(library, fpath, 0, &font->data);
76+
77+
wl_list_insert(&manager->fonts, &font->link);
78+
}
79+
80+
struct wob_font *
81+
wob_font_manager_get(struct wob_font_manager *manager, const char *fpath)
82+
{
83+
struct wob_font *font;
84+
wl_list_for_each (font, &manager->fonts, link) {
85+
if (strcmp(font->name, fpath) == 0) {
86+
return font;
87+
}
88+
}
89+
90+
return NULL;
91+
}
92+
93+
struct wob_font_text_dimensions
94+
wob_font_render_text_dimensions(struct wob_font *font, char *text, int font_size)
95+
{
96+
struct wob_font_text_dimensions dimensions = {.h = 0, .w = 0};
97+
98+
FT_Face ft_face = font->data;
99+
FT_Set_Pixel_Sizes(ft_face, 0, font_size);
100+
FT_UInt previous = 0;
101+
102+
bool has_kerning = FT_HAS_KERNING(ft_face);
103+
104+
for (char *c = text; *c != '\0'; c += 1) {
105+
FT_UInt glyph_index = FT_Get_Char_Index(ft_face, *c);
106+
FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
107+
108+
FT_Glyph glyph;
109+
FT_Get_Glyph(ft_face->glyph, &glyph);
110+
111+
FT_BBox glyph_bbox;
112+
FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox);
113+
FT_Vector delta;
114+
115+
dimensions.h = glyph_bbox.yMax;
116+
dimensions.w += glyph_bbox.xMax;
117+
118+
if (has_kerning && previous != 0) {
119+
FT_Get_Kerning( ft_face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
120+
dimensions.w += delta.x / 64;
121+
}
122+
123+
previous = glyph_index;
124+
}
125+
126+
return dimensions;
127+
}
128+
129+
void
130+
wob_font_render_text(struct wob_font *font, char *text, int font_size, struct wob_color font_color, uint32_t *argb8888_buffer, size_t argb8888_buffer_size)
131+
{
132+
FT_Face ft_face = font->data;
133+
FT_UInt previous = 0;
134+
FT_Set_Pixel_Sizes(ft_face, 0, font_size);
135+
136+
bool has_kerning = FT_HAS_KERNING(ft_face);
137+
138+
for (const char *c = text; *c != '\0'; c += 1) {
139+
FT_Vector delta;
140+
FT_UInt glyph_index = FT_Get_Char_Index(ft_face, *c);
141+
FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
142+
FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL);
143+
144+
draw_glyph(argb8888_buffer, argb8888_buffer_size, &ft_face->glyph->bitmap, font_color);
145+
146+
argb8888_buffer += ft_face->glyph->advance.x / 64;
147+
if (has_kerning && previous != 0) {
148+
FT_Get_Kerning( ft_face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
149+
argb8888_buffer += delta.x / 64;
150+
}
151+
152+
previous = glyph_index;
153+
}
154+
}

0 commit comments

Comments
 (0)