aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--swaybar/render.c132
1 files changed, 97 insertions, 35 deletions
diff --git a/swaybar/render.c b/swaybar/render.c
index df066622..ebe127a5 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -23,8 +23,31 @@ static const int WS_HORIZONTAL_PADDING = 5;
static const double WS_VERTICAL_PADDING = 1.5;
static const double BORDER_WIDTH = 1;
-static uint32_t render_status_line_error(cairo_t *cairo,
- struct swaybar_output *output, double *x) {
+struct render_context {
+ cairo_t *cairo;
+ struct swaybar_output *output;
+ cairo_font_options_t *textaa_sharp;
+ cairo_font_options_t *textaa_safe;
+ uint32_t background_color;
+};
+
+static void choose_text_aa_mode(struct render_context *ctx, uint32_t fontcolor) {
+ uint32_t salpha = fontcolor & 0xFF;
+ uint32_t balpha = ctx->background_color & 0xFF;
+
+ // Subpixel antialiasing requires blend be done in cairo, not compositor
+ cairo_font_options_t *fo = salpha == balpha ?
+ ctx->textaa_sharp : ctx->textaa_safe;
+ cairo_set_font_options(ctx->cairo, fo);
+
+ // Color emojis, being semitransparent bitmaps, are leaky with 'SOURCE'
+ cairo_operator_t op = salpha == 0xFF ?
+ CAIRO_OPERATOR_OVER : CAIRO_OPERATOR_SOURCE;
+ cairo_set_operator(ctx->cairo, op);
+}
+
+static uint32_t render_status_line_error(struct render_context *ctx, double *x) {
+ struct swaybar_output *output = ctx->output;
const char *error = output->bar->status->text;
if (!error) {
return 0;
@@ -32,6 +55,7 @@ static uint32_t render_status_line_error(cairo_t *cairo,
uint32_t height = output->height * output->scale;
+ cairo_t *cairo = ctx->cairo;
cairo_set_source_u32(cairo, 0xFF0000FF);
int margin = 3 * output->scale;
@@ -53,21 +77,24 @@ static uint32_t render_status_line_error(cairo_t *cairo,
double text_y = height / 2.0 - text_height / 2.0;
cairo_move_to(cairo, *x, (int)floor(text_y));
+ choose_text_aa_mode(ctx, 0xFF0000FF);
pango_printf(cairo, font, output->scale, false, "%s", error);
*x -= margin;
return output->height;
}
-static uint32_t render_status_line_text(cairo_t *cairo,
- struct swaybar_output *output, double *x) {
+static uint32_t render_status_line_text(struct render_context *ctx, double *x) {
+ struct swaybar_output *output = ctx->output;
const char *text = output->bar->status->text;
if (!text) {
return 0;
}
+ cairo_t *cairo = ctx->cairo;
struct swaybar_config *config = output->bar->config;
- cairo_set_source_u32(cairo, output->focused ?
- config->colors.focused_statusline : config->colors.statusline);
+ uint32_t fontcolor = output->focused ?
+ config->colors.focused_statusline : config->colors.statusline;
+ cairo_set_source_u32(cairo, fontcolor);
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
@@ -87,6 +114,7 @@ static uint32_t render_status_line_text(cairo_t *cairo,
uint32_t height = output->height * output->scale;
double text_y = height / 2.0 - text_height / 2.0;
cairo_move_to(cairo, *x, (int)floor(text_y));
+ choose_text_aa_mode(ctx, fontcolor);
pango_printf(cairo, config->font, output->scale,
config->pango_markup, "%s", text);
*x -= margin;
@@ -96,6 +124,7 @@ static uint32_t render_status_line_text(cairo_t *cairo,
static void render_sharp_rectangle(cairo_t *cairo, uint32_t color,
double x, double y, double width, double height) {
cairo_save(cairo);
+ cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_u32(cairo, color);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE);
cairo_rectangle(cairo, x, y, width, height);
@@ -109,6 +138,7 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color,
render_sharp_rectangle(cairo, color, x, y, width, height);
} else {
cairo_save(cairo);
+ cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_u32(cairo, color);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE);
if (width == 1) {
@@ -146,9 +176,8 @@ static void i3bar_block_unref_callback(void *data) {
i3bar_block_unref(data);
}
-static uint32_t render_status_block(cairo_t *cairo,
- struct swaybar_output *output, struct i3bar_block *block, double *x,
- bool edge, bool use_short_text) {
+static uint32_t render_status_block(struct render_context *ctx,
+ struct i3bar_block *block, double *x, bool edge, bool use_short_text) {
if (!block->full_text || !*block->full_text) {
return 0;
}
@@ -158,8 +187,9 @@ static uint32_t render_status_block(cairo_t *cairo,
text = block->short_text;
}
+ cairo_t *cairo = ctx->cairo;
+ struct swaybar_output *output = ctx->output;
struct swaybar_config *config = output->bar->config;
-
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
output->scale, block->markup, "%s", text);
@@ -240,6 +270,7 @@ static uint32_t render_status_block(cairo_t *cairo,
if (bg_color) {
render_sharp_rectangle(cairo, bg_color, x_pos, y_pos,
block_width, render_height);
+ ctx->background_color = bg_color;
}
uint32_t border_color = block->urgent
@@ -274,6 +305,7 @@ static uint32_t render_status_block(cairo_t *cairo,
color = block->color_set ? block->color : color;
color = block->urgent ? config->colors.urgent_workspace.text : color;
cairo_set_source_u32(cairo, color);
+ choose_text_aa_mode(ctx, color);
pango_printf(cairo, config->font, output->scale,
block->markup, "%s", text);
x_pos += width;
@@ -287,17 +319,20 @@ static uint32_t render_status_block(cairo_t *cairo,
if (!edge && block->separator) {
if (output->focused) {
- cairo_set_source_u32(cairo, config->colors.focused_separator);
+ color = config->colors.focused_separator;
} else {
- cairo_set_source_u32(cairo, config->colors.separator);
+ color = config->colors.separator;
}
+ cairo_set_source_u32(cairo, color);
if (config->sep_symbol) {
offset = x_pos + (sep_block_width - sep_width) / 2;
double sep_y = height / 2.0 - sep_height / 2.0;
cairo_move_to(cairo, offset, (int)floor(sep_y));
+ choose_text_aa_mode(ctx, color);
pango_printf(cairo, config->font, output->scale, false,
"%s", config->sep_symbol);
} else {
+ cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_line_width(cairo, 1);
cairo_move_to(cairo, x_pos + sep_block_width / 2, margin);
cairo_line_to(cairo, x_pos + sep_block_width / 2, height - margin);
@@ -459,13 +494,14 @@ static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo,
return width;
}
-static uint32_t render_status_line_i3bar(cairo_t *cairo,
- struct swaybar_output *output, double *x) {
+static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x) {
+ struct swaybar_output *output = ctx->output;
uint32_t max_height = 0;
bool edge = *x == output->width * output->scale;
struct i3bar_block *block;
bool use_short_text = false;
+ cairo_t *cairo = ctx->cairo;
double reserved_width =
predict_workspace_buttons_length(cairo, output) +
predict_binding_mode_indicator_length(cairo, output) +
@@ -479,7 +515,7 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo,
}
wl_list_for_each(block, &output->bar->status->blocks, link) {
- uint32_t h = render_status_block(cairo, output, block, x, edge,
+ uint32_t h = render_status_block(ctx, block, x, edge,
use_short_text);
max_height = h > max_height ? h : max_height;
edge = false;
@@ -487,29 +523,30 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo,
return max_height;
}
-static uint32_t render_status_line(cairo_t *cairo,
- struct swaybar_output *output, double *x) {
- struct status_line *status = output->bar->status;
+static uint32_t render_status_line(struct render_context *ctx, double *x) {
+ struct status_line *status = ctx->output->bar->status;
switch (status->protocol) {
case PROTOCOL_ERROR:
- return render_status_line_error(cairo, output, x);
+ return render_status_line_error(ctx, x);
case PROTOCOL_TEXT:
- return render_status_line_text(cairo, output, x);
+ return render_status_line_text(ctx, x);
case PROTOCOL_I3BAR:
- return render_status_line_i3bar(cairo, output, x);
+ return render_status_line_i3bar(ctx, x);
case PROTOCOL_UNDEF:
return 0;
}
return 0;
}
-static uint32_t render_binding_mode_indicator(cairo_t *cairo,
- struct swaybar_output *output, double x) {
+static uint32_t render_binding_mode_indicator(struct render_context *ctx,
+ double x) {
+ struct swaybar_output *output = ctx->output;
const char *mode = output->bar->mode;
if (!mode) {
return 0;
}
+ cairo_t *cairo = ctx->cairo;
struct swaybar_config *config = output->bar->config;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
@@ -533,7 +570,9 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
}
uint32_t height = output->height * output->scale;
+ cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_u32(cairo, config->colors.binding_mode.background);
+ ctx->background_color = config->colors.binding_mode.background;
cairo_rectangle(cairo, x, 0, width, height);
cairo_fill(cairo);
@@ -550,6 +589,7 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
double text_y = height / 2.0 - text_height / 2.0;
cairo_set_source_u32(cairo, config->colors.binding_mode.text);
cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
+ choose_text_aa_mode(ctx, config->colors.binding_mode.text);
pango_printf(cairo, config->font, output->scale,
output->bar->mode_pango_markup, "%s", mode);
return output->height;
@@ -565,9 +605,9 @@ static enum hotspot_event_handling workspace_hotspot_callback(
return HOTSPOT_IGNORE;
}
-static uint32_t render_workspace_button(cairo_t *cairo,
- struct swaybar_output *output,
+static uint32_t render_workspace_button(struct render_context *ctx,
struct swaybar_workspace *ws, double *x) {
+ struct swaybar_output *output = ctx->output;
struct swaybar_config *config = output->bar->config;
struct box_colors box_colors;
if (ws->urgent) {
@@ -582,6 +622,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
uint32_t height = output->height * output->scale;
+ cairo_t *cairo = ctx->cairo;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
output->scale, config->pango_markup, "%s", ws->label);
@@ -603,7 +644,9 @@ static uint32_t render_workspace_button(cairo_t *cairo,
width = config->workspace_min_width * output->scale;
}
+ cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_u32(cairo, box_colors.background);
+ ctx->background_color = box_colors.background;
cairo_rectangle(cairo, *x, 0, width, height);
cairo_fill(cairo);
@@ -620,6 +663,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
double text_y = height / 2.0 - text_height / 2.0;
cairo_set_source_u32(cairo, box_colors.text);
cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y));
+ choose_text_aa_mode(ctx, box_colors.text);
pango_printf(cairo, config->font, output->scale, config->pango_markup,
"%s", ws->label);
@@ -637,15 +681,19 @@ static uint32_t render_workspace_button(cairo_t *cairo,
return output->height;
}
-static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
+static uint32_t render_to_cairo(struct render_context *ctx) {
+ cairo_t *cairo = ctx->cairo;
+ struct swaybar_output *output = ctx->output;
struct swaybar *bar = output->bar;
struct swaybar_config *config = bar->config;
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
if (output->focused) {
- cairo_set_source_u32(cairo, config->colors.focused_background);
+ ctx->background_color = config->colors.focused_background;
} else {
- cairo_set_source_u32(cairo, config->colors.background);
+ ctx->background_color = config->colors.background;
}
+
+ cairo_set_source_u32(cairo, ctx->background_color);
cairo_paint(cairo);
int th;
@@ -666,19 +714,19 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
}
#endif
if (bar->status) {
- uint32_t h = render_status_line(cairo, output, &x);
+ uint32_t h = render_status_line(ctx, &x);
max_height = h > max_height ? h : max_height;
}
x = 0;
if (config->workspace_buttons) {
struct swaybar_workspace *ws;
wl_list_for_each(ws, &output->workspaces, link) {
- uint32_t h = render_workspace_button(cairo, output, ws, &x);
+ uint32_t h = render_workspace_button(ctx, ws, &x);
max_height = h > max_height ? h : max_height;
}
}
if (config->binding_mode_indicator) {
- uint32_t h = render_binding_mode_indicator(cairo, output, x);
+ uint32_t h = render_binding_mode_indicator(ctx, x);
max_height = h > max_height ? h : max_height;
}
@@ -708,26 +756,35 @@ void render_frame(struct swaybar_output *output) {
free_hotspots(&output->hotspots);
+ struct render_context ctx = { 0 };
+ ctx.output = output;
+
cairo_surface_t *recorder = cairo_recording_surface_create(
CAIRO_CONTENT_COLOR_ALPHA, NULL);
cairo_t *cairo = cairo_create(recorder);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
+ ctx.cairo = cairo;
+
cairo_font_options_t *fo = cairo_font_options_create();
cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
+ cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
+ ctx.textaa_safe = fo;
if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) {
- cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
+ ctx.textaa_sharp = ctx.textaa_safe;
} else {
+ fo = cairo_font_options_create();
+ cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
cairo_font_options_set_subpixel_order(fo,
to_cairo_subpixel_order(output->subpixel));
+ ctx.textaa_sharp = fo;
}
- cairo_set_font_options(cairo, fo);
- cairo_font_options_destroy(fo);
+
cairo_save(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
cairo_paint(cairo);
cairo_restore(cairo);
- uint32_t height = render_to_cairo(cairo, output);
+ uint32_t height = render_to_cairo(&ctx);
int config_height = output->bar->config->height;
if (config_height > 0) {
height = config_height;
@@ -779,6 +836,11 @@ void render_frame(struct swaybar_output *output) {
wl_surface_commit(output->surface);
}
+
+ if (ctx.textaa_sharp != ctx.textaa_safe) {
+ cairo_font_options_destroy(ctx.textaa_sharp);
+ }
+ cairo_font_options_destroy(ctx.textaa_safe);
cairo_surface_destroy(recorder);
cairo_destroy(cairo);
}