aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar/render.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar/render.c')
-rw-r--r--swaybar/render.c416
1 files changed, 247 insertions, 169 deletions
diff --git a/swaybar/render.c b/swaybar/render.c
index df066622..879a4e42 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -1,11 +1,10 @@
1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 1#include <assert.h>
3#include <linux/input-event-codes.h> 2#include <linux/input-event-codes.h>
4#include <limits.h> 3#include <limits.h>
5#include <stdlib.h> 4#include <stdlib.h>
6#include <stdint.h> 5#include <stdint.h>
7#include <string.h> 6#include <string.h>
8#include "cairo.h" 7#include "cairo_util.h"
9#include "pango.h" 8#include "pango.h"
10#include "pool-buffer.h" 9#include "pool-buffer.h"
11#include "swaybar/bar.h" 10#include "swaybar/bar.h"
@@ -14,6 +13,7 @@
14#include "swaybar/ipc.h" 13#include "swaybar/ipc.h"
15#include "swaybar/render.h" 14#include "swaybar/render.h"
16#include "swaybar/status_line.h" 15#include "swaybar/status_line.h"
16#include "log.h"
17#if HAVE_TRAY 17#if HAVE_TRAY
18#include "swaybar/tray/tray.h" 18#include "swaybar/tray/tray.h"
19#endif 19#endif
@@ -23,28 +23,51 @@ static const int WS_HORIZONTAL_PADDING = 5;
23static const double WS_VERTICAL_PADDING = 1.5; 23static const double WS_VERTICAL_PADDING = 1.5;
24static const double BORDER_WIDTH = 1; 24static const double BORDER_WIDTH = 1;
25 25
26static uint32_t render_status_line_error(cairo_t *cairo, 26struct render_context {
27 struct swaybar_output *output, double *x) { 27 cairo_t *cairo;
28 struct swaybar_output *output;
29 cairo_font_options_t *textaa_sharp;
30 cairo_font_options_t *textaa_safe;
31 uint32_t background_color;
32};
33
34static void choose_text_aa_mode(struct render_context *ctx, uint32_t fontcolor) {
35 uint32_t salpha = fontcolor & 0xFF;
36 uint32_t balpha = ctx->background_color & 0xFF;
37
38 // Subpixel antialiasing requires blend be done in cairo, not compositor
39 cairo_font_options_t *fo = salpha == balpha ?
40 ctx->textaa_sharp : ctx->textaa_safe;
41 cairo_set_font_options(ctx->cairo, fo);
42
43 // Color emojis, being semitransparent bitmaps, are leaky with 'SOURCE'
44 cairo_operator_t op = salpha == 0xFF ?
45 CAIRO_OPERATOR_OVER : CAIRO_OPERATOR_SOURCE;
46 cairo_set_operator(ctx->cairo, op);
47}
48
49static uint32_t render_status_line_error(struct render_context *ctx, double *x) {
50 struct swaybar_output *output = ctx->output;
28 const char *error = output->bar->status->text; 51 const char *error = output->bar->status->text;
29 if (!error) { 52 if (!error) {
30 return 0; 53 return 0;
31 } 54 }
32 55
33 uint32_t height = output->height * output->scale; 56 uint32_t height = output->height;
34 57
58 cairo_t *cairo = ctx->cairo;
35 cairo_set_source_u32(cairo, 0xFF0000FF); 59 cairo_set_source_u32(cairo, 0xFF0000FF);
36 60
37 int margin = 3 * output->scale; 61 int margin = 3;
38 double ws_vertical_padding = 62 double ws_vertical_padding = output->bar->config->status_padding;
39 output->bar->config->status_padding * output->scale;
40 63
41 char *font = output->bar->config->font; 64 PangoFontDescription *font = output->bar->config->font_description;
42 int text_width, text_height; 65 int text_width, text_height;
43 get_text_size(cairo, font, &text_width, &text_height, NULL, 66 get_text_size(cairo, font, &text_width, &text_height, NULL,
44 output->scale, false, "%s", error); 67 1, false, "%s", error);
45 68
46 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 69 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
47 uint32_t ideal_surface_height = ideal_height / output->scale; 70 uint32_t ideal_surface_height = ideal_height;
48 if (!output->bar->config->height && 71 if (!output->bar->config->height &&
49 output->height < ideal_surface_height) { 72 output->height < ideal_surface_height) {
50 return ideal_surface_height; 73 return ideal_surface_height;
@@ -53,42 +76,45 @@ static uint32_t render_status_line_error(cairo_t *cairo,
53 76
54 double text_y = height / 2.0 - text_height / 2.0; 77 double text_y = height / 2.0 - text_height / 2.0;
55 cairo_move_to(cairo, *x, (int)floor(text_y)); 78 cairo_move_to(cairo, *x, (int)floor(text_y));
56 pango_printf(cairo, font, output->scale, false, "%s", error); 79 choose_text_aa_mode(ctx, 0xFF0000FF);
80 render_text(cairo, font, 1, false, "%s", error);
57 *x -= margin; 81 *x -= margin;
58 return output->height; 82 return output->height;
59} 83}
60 84
61static uint32_t render_status_line_text(cairo_t *cairo, 85static uint32_t render_status_line_text(struct render_context *ctx, double *x) {
62 struct swaybar_output *output, double *x) { 86 struct swaybar_output *output = ctx->output;
63 const char *text = output->bar->status->text; 87 const char *text = output->bar->status->text;
64 if (!text) { 88 if (!text) {
65 return 0; 89 return 0;
66 } 90 }
67 91
92 cairo_t *cairo = ctx->cairo;
68 struct swaybar_config *config = output->bar->config; 93 struct swaybar_config *config = output->bar->config;
69 cairo_set_source_u32(cairo, output->focused ? 94 uint32_t fontcolor = output->focused ?
70 config->colors.focused_statusline : config->colors.statusline); 95 config->colors.focused_statusline : config->colors.statusline;
96 cairo_set_source_u32(cairo, fontcolor);
71 97
72 int text_width, text_height; 98 int text_width, text_height;
73 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 99 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
74 output->scale, config->pango_markup, "%s", text); 100 1, config->pango_markup, "%s", text);
75 101
76 double ws_vertical_padding = config->status_padding * output->scale; 102 double ws_vertical_padding = config->status_padding;
77 int margin = 3 * output->scale; 103 int margin = 3;
78 104
79 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 105 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
80 uint32_t ideal_surface_height = ideal_height / output->scale; 106 uint32_t ideal_surface_height = ideal_height;
81 if (!output->bar->config->height && 107 if (!output->bar->config->height &&
82 output->height < ideal_surface_height) { 108 output->height < ideal_surface_height) {
83 return ideal_surface_height; 109 return ideal_surface_height;
84 } 110 }
85 111
86 *x -= text_width + margin; 112 *x -= text_width + margin;
87 uint32_t height = output->height * output->scale; 113 uint32_t height = output->height;
88 double text_y = height / 2.0 - text_height / 2.0; 114 double text_y = height / 2.0 - text_height / 2.0;
89 cairo_move_to(cairo, *x, (int)floor(text_y)); 115 cairo_move_to(cairo, *x, (int)floor(text_y));
90 pango_printf(cairo, config->font, output->scale, 116 choose_text_aa_mode(ctx, fontcolor);
91 config->pango_markup, "%s", text); 117 render_text(cairo, config->font_description, 1, config->pango_markup, "%s", text);
92 *x -= margin; 118 *x -= margin;
93 return output->height; 119 return output->height;
94} 120}
@@ -96,6 +122,7 @@ static uint32_t render_status_line_text(cairo_t *cairo,
96static void render_sharp_rectangle(cairo_t *cairo, uint32_t color, 122static void render_sharp_rectangle(cairo_t *cairo, uint32_t color,
97 double x, double y, double width, double height) { 123 double x, double y, double width, double height) {
98 cairo_save(cairo); 124 cairo_save(cairo);
125 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
99 cairo_set_source_u32(cairo, color); 126 cairo_set_source_u32(cairo, color);
100 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE); 127 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE);
101 cairo_rectangle(cairo, x, y, width, height); 128 cairo_rectangle(cairo, x, y, width, height);
@@ -109,6 +136,7 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color,
109 render_sharp_rectangle(cairo, color, x, y, width, height); 136 render_sharp_rectangle(cairo, color, x, y, width, height);
110 } else { 137 } else {
111 cairo_save(cairo); 138 cairo_save(cairo);
139 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
112 cairo_set_source_u32(cairo, color); 140 cairo_set_source_u32(cairo, color);
113 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE); 141 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE);
114 if (width == 1) { 142 if (width == 1) {
@@ -131,24 +159,23 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color,
131 159
132static enum hotspot_event_handling block_hotspot_callback( 160static enum hotspot_event_handling block_hotspot_callback(
133 struct swaybar_output *output, struct swaybar_hotspot *hotspot, 161 struct swaybar_output *output, struct swaybar_hotspot *hotspot,
134 double x, double y, uint32_t button, void *data) { 162 double x, double y, uint32_t button, bool released, void *data) {
135 struct i3bar_block *block = data; 163 struct i3bar_block *block = data;
136 struct status_line *status = output->bar->status; 164 struct status_line *status = output->bar->status;
137 return i3bar_block_send_click(status, block, x, y, 165 return i3bar_block_send_click(status, block, x, y,
138 x - (double)hotspot->x / output->scale, 166 x - (double)hotspot->x,
139 y - (double)hotspot->y / output->scale, 167 y - (double)hotspot->y,
140 (double)hotspot->width / output->scale, 168 (double)hotspot->width,
141 (double)hotspot->height / output->scale, 169 (double)hotspot->height,
142 output->scale, button); 170 output->scale, button, released);
143} 171}
144 172
145static void i3bar_block_unref_callback(void *data) { 173static void i3bar_block_unref_callback(void *data) {
146 i3bar_block_unref(data); 174 i3bar_block_unref(data);
147} 175}
148 176
149static uint32_t render_status_block(cairo_t *cairo, 177static uint32_t render_status_block(struct render_context *ctx,
150 struct swaybar_output *output, struct i3bar_block *block, double *x, 178 struct i3bar_block *block, double *x, bool edge, bool use_short_text) {
151 bool edge, bool use_short_text) {
152 if (!block->full_text || !*block->full_text) { 179 if (!block->full_text || !*block->full_text) {
153 return 0; 180 return 0;
154 } 181 }
@@ -158,20 +185,21 @@ static uint32_t render_status_block(cairo_t *cairo,
158 text = block->short_text; 185 text = block->short_text;
159 } 186 }
160 187
188 cairo_t *cairo = ctx->cairo;
189 struct swaybar_output *output = ctx->output;
161 struct swaybar_config *config = output->bar->config; 190 struct swaybar_config *config = output->bar->config;
162
163 int text_width, text_height; 191 int text_width, text_height;
164 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 192 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1,
165 output->scale, block->markup, "%s", text); 193 block->markup, "%s", text);
166 194
167 int margin = 3 * output->scale; 195 int margin = 3;
168 double ws_vertical_padding = config->status_padding * output->scale; 196 double ws_vertical_padding = config->status_padding;
169 197
170 int width = text_width; 198 int width = text_width;
171 if (block->min_width_str) { 199 if (block->min_width_str) {
172 int w; 200 int w;
173 get_text_size(cairo, config->font, &w, NULL, NULL, 201 get_text_size(cairo, config->font_description, &w, NULL, NULL, 1, block->markup,
174 output->scale, block->markup, "%s", block->min_width_str); 202 "%s", block->min_width_str);
175 block->min_width = w; 203 block->min_width = w;
176 } 204 }
177 if (width < block->min_width) { 205 if (width < block->min_width) {
@@ -180,30 +208,30 @@ static uint32_t render_status_block(cairo_t *cairo,
180 208
181 double block_width = width; 209 double block_width = width;
182 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 210 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
183 uint32_t ideal_surface_height = ideal_height / output->scale; 211 uint32_t ideal_surface_height = ideal_height;
184 if (!output->bar->config->height && 212 if (!output->bar->config->height &&
185 output->height < ideal_surface_height) { 213 output->height < ideal_surface_height) {
186 return ideal_surface_height; 214 return ideal_surface_height;
187 } 215 }
188 216
189 *x -= width; 217 *x -= width;
190 if ((block->border || block->urgent) && block->border_left > 0) { 218 if ((block->border_set || block->urgent) && block->border_left > 0) {
191 *x -= (block->border_left * output->scale + margin); 219 *x -= (block->border_left + margin);
192 block_width += block->border_left * output->scale + margin; 220 block_width += block->border_left + margin;
193 } 221 }
194 if ((block->border || block->urgent) && block->border_right > 0) { 222 if ((block->border_set || block->urgent) && block->border_right > 0) {
195 *x -= (block->border_right * output->scale + margin); 223 *x -= (block->border_right + margin);
196 block_width += block->border_right * output->scale + margin; 224 block_width += block->border_right + margin;
197 } 225 }
198 226
199 int sep_width, sep_height; 227 int sep_width, sep_height;
200 int sep_block_width = block->separator_block_width; 228 int sep_block_width = block->separator_block_width;
201 if (!edge) { 229 if (!edge) {
202 if (config->sep_symbol) { 230 if (config->sep_symbol) {
203 get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, 231 get_text_size(cairo, config->font_description, &sep_width, &sep_height, NULL,
204 output->scale, false, "%s", config->sep_symbol); 232 1, false, "%s", config->sep_symbol);
205 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; 233 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
206 uint32_t _ideal_surface_height = _ideal_height / output->scale; 234 uint32_t _ideal_surface_height = _ideal_height;
207 if (!output->bar->config->height && 235 if (!output->bar->config->height &&
208 output->height < _ideal_surface_height) { 236 output->height < _ideal_surface_height) {
209 return _ideal_surface_height; 237 return _ideal_surface_height;
@@ -214,10 +242,10 @@ static uint32_t render_status_block(cairo_t *cairo,
214 } 242 }
215 *x -= sep_block_width; 243 *x -= sep_block_width;
216 } else if (config->status_edge_padding) { 244 } else if (config->status_edge_padding) {
217 *x -= config->status_edge_padding * output->scale; 245 *x -= config->status_edge_padding;
218 } 246 }
219 247
220 uint32_t height = output->height * output->scale; 248 uint32_t height = output->height;
221 if (output->bar->status->click_events) { 249 if (output->bar->status->click_events) {
222 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); 250 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
223 hotspot->x = *x; 251 hotspot->x = *x;
@@ -240,27 +268,30 @@ static uint32_t render_status_block(cairo_t *cairo,
240 if (bg_color) { 268 if (bg_color) {
241 render_sharp_rectangle(cairo, bg_color, x_pos, y_pos, 269 render_sharp_rectangle(cairo, bg_color, x_pos, y_pos,
242 block_width, render_height); 270 block_width, render_height);
271 ctx->background_color = bg_color;
243 } 272 }
244 273
245 uint32_t border_color = block->urgent 274 uint32_t border_color = block->urgent
246 ? config->colors.urgent_workspace.border : block->border; 275 ? config->colors.urgent_workspace.border : block->border;
247 if (border_color && block->border_top > 0) { 276 if (block->border_set || block->urgent) {
248 render_sharp_line(cairo, border_color, x_pos, y_pos, 277 if (block->border_top > 0) {
249 block_width, block->border_top * output->scale); 278 render_sharp_line(cairo, border_color, x_pos, y_pos,
250 } 279 block_width, block->border_top);
251 if (border_color && block->border_bottom > 0) { 280 }
252 render_sharp_line(cairo, border_color, x_pos, 281 if (block->border_bottom > 0) {
253 y_pos + render_height - block->border_bottom * output->scale, 282 render_sharp_line(cairo, border_color, x_pos,
254 block_width, block->border_bottom * output->scale); 283 y_pos + render_height - block->border_bottom,
255 } 284 block_width, block->border_bottom);
256 if (border_color && block->border_left > 0) { 285 }
257 render_sharp_line(cairo, border_color, x_pos, y_pos, 286 if (block->border_left > 0) {
258 block->border_left * output->scale, render_height); 287 render_sharp_line(cairo, border_color, x_pos, y_pos,
259 x_pos += block->border_left * output->scale + margin; 288 block->border_left, render_height);
289 }
290 x_pos += block->border_left + margin;
260 } 291 }
261 292
262 double offset = 0; 293 double offset = 0;
263 if (strncmp(block->align, "left", 5) == 0) { 294 if (strncmp(block->align, "left", 4) == 0) {
264 offset = x_pos; 295 offset = x_pos;
265 } else if (strncmp(block->align, "right", 5) == 0) { 296 } else if (strncmp(block->align, "right", 5) == 0) {
266 offset = x_pos + width - text_width; 297 offset = x_pos + width - text_width;
@@ -274,30 +305,35 @@ static uint32_t render_status_block(cairo_t *cairo,
274 color = block->color_set ? block->color : color; 305 color = block->color_set ? block->color : color;
275 color = block->urgent ? config->colors.urgent_workspace.text : color; 306 color = block->urgent ? config->colors.urgent_workspace.text : color;
276 cairo_set_source_u32(cairo, color); 307 cairo_set_source_u32(cairo, color);
277 pango_printf(cairo, config->font, output->scale, 308 choose_text_aa_mode(ctx, color);
278 block->markup, "%s", text); 309 render_text(cairo, config->font_description, 1, block->markup, "%s", text);
279 x_pos += width; 310 x_pos += width;
280 311
281 if (block->border && block->border_right > 0) { 312 if (block->border_set || block->urgent) {
282 x_pos += margin; 313 x_pos += margin;
283 render_sharp_line(cairo, border_color, x_pos, y_pos, 314 if (block->border_right > 0) {
284 block->border_right * output->scale, render_height); 315 render_sharp_line(cairo, border_color, x_pos, y_pos,
285 x_pos += block->border_right * output->scale; 316 block->border_right, render_height);
317 }
318 x_pos += block->border_right;
286 } 319 }
287 320
288 if (!edge && block->separator) { 321 if (!edge && block->separator) {
289 if (output->focused) { 322 if (output->focused) {
290 cairo_set_source_u32(cairo, config->colors.focused_separator); 323 color = config->colors.focused_separator;
291 } else { 324 } else {
292 cairo_set_source_u32(cairo, config->colors.separator); 325 color = config->colors.separator;
293 } 326 }
327 cairo_set_source_u32(cairo, color);
294 if (config->sep_symbol) { 328 if (config->sep_symbol) {
295 offset = x_pos + (sep_block_width - sep_width) / 2; 329 offset = x_pos + (sep_block_width - sep_width) / 2;
296 double sep_y = height / 2.0 - sep_height / 2.0; 330 double sep_y = height / 2.0 - sep_height / 2.0;
297 cairo_move_to(cairo, offset, (int)floor(sep_y)); 331 cairo_move_to(cairo, offset, (int)floor(sep_y));
298 pango_printf(cairo, config->font, output->scale, false, 332 choose_text_aa_mode(ctx, color);
333 render_text(cairo, config->font_description, 1, false,
299 "%s", config->sep_symbol); 334 "%s", config->sep_symbol);
300 } else { 335 } else {
336 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
301 cairo_set_line_width(cairo, 1); 337 cairo_set_line_width(cairo, 1);
302 cairo_move_to(cairo, x_pos + sep_block_width / 2, margin); 338 cairo_move_to(cairo, x_pos + sep_block_width / 2, margin);
303 cairo_line_to(cairo, x_pos + sep_block_width / 2, height - margin); 339 cairo_line_to(cairo, x_pos + sep_block_width / 2, height - margin);
@@ -317,18 +353,18 @@ static void predict_status_block_pos(cairo_t *cairo,
317 struct swaybar_config *config = output->bar->config; 353 struct swaybar_config *config = output->bar->config;
318 354
319 int text_width, text_height; 355 int text_width, text_height;
320 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 356 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1,
321 output->scale, block->markup, "%s", block->full_text); 357 block->markup, "%s", block->full_text);
322 358
323 int margin = 3 * output->scale; 359 int margin = 3;
324 double ws_vertical_padding = config->status_padding * output->scale; 360 double ws_vertical_padding = config->status_padding;
325 361
326 int width = text_width; 362 int width = text_width;
327 363
328 if (block->min_width_str) { 364 if (block->min_width_str) {
329 int w; 365 int w;
330 get_text_size(cairo, config->font, &w, NULL, NULL, 366 get_text_size(cairo, config->font_description, &w, NULL, NULL,
331 output->scale, block->markup, "%s", block->min_width_str); 367 1, block->markup, "%s", block->min_width_str);
332 block->min_width = w; 368 block->min_width = w;
333 } 369 }
334 if (width < block->min_width) { 370 if (width < block->min_width) {
@@ -336,28 +372,28 @@ static void predict_status_block_pos(cairo_t *cairo,
336 } 372 }
337 373
338 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 374 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
339 uint32_t ideal_surface_height = ideal_height / output->scale; 375 uint32_t ideal_surface_height = ideal_height;
340 if (!output->bar->config->height && 376 if (!output->bar->config->height &&
341 output->height < ideal_surface_height) { 377 output->height < ideal_surface_height) {
342 return; 378 return;
343 } 379 }
344 380
345 *x -= width; 381 *x -= width;
346 if ((block->border || block->urgent) && block->border_left > 0) { 382 if ((block->border_set || block->urgent) && block->border_left > 0) {
347 *x -= (block->border_left * output->scale + margin); 383 *x -= (block->border_left + margin);
348 } 384 }
349 if ((block->border || block->urgent) && block->border_right > 0) { 385 if ((block->border_set || block->urgent) && block->border_right > 0) {
350 *x -= (block->border_right * output->scale + margin); 386 *x -= (block->border_right + margin);
351 } 387 }
352 388
353 int sep_width, sep_height; 389 int sep_width, sep_height;
354 int sep_block_width = block->separator_block_width; 390 int sep_block_width = block->separator_block_width;
355 if (!edge) { 391 if (!edge) {
356 if (config->sep_symbol) { 392 if (config->sep_symbol) {
357 get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, 393 get_text_size(cairo, config->font_description, &sep_width, &sep_height, NULL,
358 output->scale, false, "%s", config->sep_symbol); 394 1, false, "%s", config->sep_symbol);
359 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; 395 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
360 uint32_t _ideal_surface_height = _ideal_height / output->scale; 396 uint32_t _ideal_surface_height = _ideal_height;
361 if (!output->bar->config->height && 397 if (!output->bar->config->height &&
362 output->height < _ideal_surface_height) { 398 output->height < _ideal_surface_height) {
363 return; 399 return;
@@ -368,13 +404,13 @@ static void predict_status_block_pos(cairo_t *cairo,
368 } 404 }
369 *x -= sep_block_width; 405 *x -= sep_block_width;
370 } else if (config->status_edge_padding) { 406 } else if (config->status_edge_padding) {
371 *x -= config->status_edge_padding * output->scale; 407 *x -= config->status_edge_padding;
372 } 408 }
373} 409}
374 410
375static double predict_status_line_pos(cairo_t *cairo, 411static double predict_status_line_pos(cairo_t *cairo,
376 struct swaybar_output *output, double x) { 412 struct swaybar_output *output, double x) {
377 bool edge = x == output->width * output->scale; 413 bool edge = x == output->width;
378 struct i3bar_block *block; 414 struct i3bar_block *block;
379 wl_list_for_each(block, &output->bar->status->blocks, link) { 415 wl_list_for_each(block, &output->bar->status->blocks, link) {
380 predict_status_block_pos(cairo, output, block, &x, edge); 416 predict_status_block_pos(cairo, output, block, &x, edge);
@@ -389,24 +425,24 @@ static uint32_t predict_workspace_button_length(cairo_t *cairo,
389 struct swaybar_config *config = output->bar->config; 425 struct swaybar_config *config = output->bar->config;
390 426
391 int text_width, text_height; 427 int text_width, text_height;
392 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 428 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1,
393 output->scale, config->pango_markup, "%s", ws->label); 429 config->pango_markup, "%s", ws->label);
394 430
395 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 431 int ws_vertical_padding = WS_VERTICAL_PADDING;
396 int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; 432 int ws_horizontal_padding = WS_HORIZONTAL_PADDING;
397 int border_width = BORDER_WIDTH * output->scale; 433 int border_width = BORDER_WIDTH;
398 434
399 uint32_t ideal_height = ws_vertical_padding * 2 + text_height 435 uint32_t ideal_height = ws_vertical_padding * 2 + text_height
400 + border_width * 2; 436 + border_width * 2;
401 uint32_t ideal_surface_height = ideal_height / output->scale; 437 uint32_t ideal_surface_height = ideal_height;
402 if (!output->bar->config->height && 438 if (!output->bar->config->height &&
403 output->height < ideal_surface_height) { 439 output->height < ideal_surface_height) {
404 return 0; 440 return 0;
405 } 441 }
406 442
407 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; 443 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
408 if (width < config->workspace_min_width * output->scale) { 444 if (width < config->workspace_min_width) {
409 width = config->workspace_min_width * output->scale; 445 width = config->workspace_min_width;
410 } 446 }
411 return width; 447 return width;
412} 448}
@@ -437,39 +473,40 @@ static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo,
437 } 473 }
438 474
439 int text_width, text_height; 475 int text_width, text_height;
440 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 476 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
441 output->scale, output->bar->mode_pango_markup, 477 1, output->bar->mode_pango_markup,
442 "%s", mode); 478 "%s", mode);
443 479
444 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 480 int ws_vertical_padding = WS_VERTICAL_PADDING;
445 int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; 481 int ws_horizontal_padding = WS_HORIZONTAL_PADDING;
446 int border_width = BORDER_WIDTH * output->scale; 482 int border_width = BORDER_WIDTH;
447 483
448 uint32_t ideal_height = text_height + ws_vertical_padding * 2 484 uint32_t ideal_height = text_height + ws_vertical_padding * 2
449 + border_width * 2; 485 + border_width * 2;
450 uint32_t ideal_surface_height = ideal_height / output->scale; 486 uint32_t ideal_surface_height = ideal_height;
451 if (!output->bar->config->height && 487 if (!output->bar->config->height &&
452 output->height < ideal_surface_height) { 488 output->height < ideal_surface_height) {
453 return 0; 489 return 0;
454 } 490 }
455 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; 491 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
456 if (width < config->workspace_min_width * output->scale) { 492 if (width < config->workspace_min_width) {
457 width = config->workspace_min_width * output->scale; 493 width = config->workspace_min_width;
458 } 494 }
459 return width; 495 return width;
460} 496}
461 497
462static uint32_t render_status_line_i3bar(cairo_t *cairo, 498static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x) {
463 struct swaybar_output *output, double *x) { 499 struct swaybar_output *output = ctx->output;
464 uint32_t max_height = 0; 500 uint32_t max_height = 0;
465 bool edge = *x == output->width * output->scale; 501 bool edge = *x == output->width;
466 struct i3bar_block *block; 502 struct i3bar_block *block;
467 bool use_short_text = false; 503 bool use_short_text = false;
468 504
505 cairo_t *cairo = ctx->cairo;
469 double reserved_width = 506 double reserved_width =
470 predict_workspace_buttons_length(cairo, output) + 507 predict_workspace_buttons_length(cairo, output) +
471 predict_binding_mode_indicator_length(cairo, output) + 508 predict_binding_mode_indicator_length(cairo, output) +
472 3 * output->scale; // require a bit of space for margin 509 3; // require a bit of space for margin
473 510
474 double predicted_full_pos = 511 double predicted_full_pos =
475 predict_status_line_pos(cairo, output, *x); 512 predict_status_line_pos(cairo, output, *x);
@@ -479,7 +516,7 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo,
479 } 516 }
480 517
481 wl_list_for_each(block, &output->bar->status->blocks, link) { 518 wl_list_for_each(block, &output->bar->status->blocks, link) {
482 uint32_t h = render_status_block(cairo, output, block, x, edge, 519 uint32_t h = render_status_block(ctx, block, x, edge,
483 use_short_text); 520 use_short_text);
484 max_height = h > max_height ? h : max_height; 521 max_height = h > max_height ? h : max_height;
485 edge = false; 522 edge = false;
@@ -487,53 +524,56 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo,
487 return max_height; 524 return max_height;
488} 525}
489 526
490static uint32_t render_status_line(cairo_t *cairo, 527static uint32_t render_status_line(struct render_context *ctx, double *x) {
491 struct swaybar_output *output, double *x) { 528 struct status_line *status = ctx->output->bar->status;
492 struct status_line *status = output->bar->status;
493 switch (status->protocol) { 529 switch (status->protocol) {
494 case PROTOCOL_ERROR: 530 case PROTOCOL_ERROR:
495 return render_status_line_error(cairo, output, x); 531 return render_status_line_error(ctx, x);
496 case PROTOCOL_TEXT: 532 case PROTOCOL_TEXT:
497 return render_status_line_text(cairo, output, x); 533 return render_status_line_text(ctx, x);
498 case PROTOCOL_I3BAR: 534 case PROTOCOL_I3BAR:
499 return render_status_line_i3bar(cairo, output, x); 535 return render_status_line_i3bar(ctx, x);
500 case PROTOCOL_UNDEF: 536 case PROTOCOL_UNDEF:
501 return 0; 537 return 0;
502 } 538 }
503 return 0; 539 return 0;
504} 540}
505 541
506static uint32_t render_binding_mode_indicator(cairo_t *cairo, 542static uint32_t render_binding_mode_indicator(struct render_context *ctx,
507 struct swaybar_output *output, double x) { 543 double x) {
544 struct swaybar_output *output = ctx->output;
508 const char *mode = output->bar->mode; 545 const char *mode = output->bar->mode;
509 if (!mode) { 546 if (!mode) {
510 return 0; 547 return 0;
511 } 548 }
512 549
550 cairo_t *cairo = ctx->cairo;
513 struct swaybar_config *config = output->bar->config; 551 struct swaybar_config *config = output->bar->config;
514 int text_width, text_height; 552 int text_width, text_height;
515 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 553 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
516 output->scale, output->bar->mode_pango_markup, 554 1, output->bar->mode_pango_markup,
517 "%s", mode); 555 "%s", mode);
518 556
519 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 557 int ws_vertical_padding = WS_VERTICAL_PADDING;
520 int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; 558 int ws_horizontal_padding = WS_HORIZONTAL_PADDING;
521 int border_width = BORDER_WIDTH * output->scale; 559 int border_width = BORDER_WIDTH;
522 560
523 uint32_t ideal_height = text_height + ws_vertical_padding * 2 561 uint32_t ideal_height = text_height + ws_vertical_padding * 2
524 + border_width * 2; 562 + border_width * 2;
525 uint32_t ideal_surface_height = ideal_height / output->scale; 563 uint32_t ideal_surface_height = ideal_height;
526 if (!output->bar->config->height && 564 if (!output->bar->config->height &&
527 output->height < ideal_surface_height) { 565 output->height < ideal_surface_height) {
528 return ideal_surface_height; 566 return ideal_surface_height;
529 } 567 }
530 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; 568 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
531 if (width < config->workspace_min_width * output->scale) { 569 if (width < config->workspace_min_width) {
532 width = config->workspace_min_width * output->scale; 570 width = config->workspace_min_width;
533 } 571 }
534 572
535 uint32_t height = output->height * output->scale; 573 uint32_t height = output->height;
574 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
536 cairo_set_source_u32(cairo, config->colors.binding_mode.background); 575 cairo_set_source_u32(cairo, config->colors.binding_mode.background);
576 ctx->background_color = config->colors.binding_mode.background;
537 cairo_rectangle(cairo, x, 0, width, height); 577 cairo_rectangle(cairo, x, 0, width, height);
538 cairo_fill(cairo); 578 cairo_fill(cairo);
539 579
@@ -550,24 +590,30 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
550 double text_y = height / 2.0 - text_height / 2.0; 590 double text_y = height / 2.0 - text_height / 2.0;
551 cairo_set_source_u32(cairo, config->colors.binding_mode.text); 591 cairo_set_source_u32(cairo, config->colors.binding_mode.text);
552 cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); 592 cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
553 pango_printf(cairo, config->font, output->scale, 593 choose_text_aa_mode(ctx, config->colors.binding_mode.text);
554 output->bar->mode_pango_markup, "%s", mode); 594 render_text(cairo, config->font_description, 1, output->bar->mode_pango_markup,
595 "%s", mode);
555 return output->height; 596 return output->height;
556} 597}
557 598
558static enum hotspot_event_handling workspace_hotspot_callback( 599static enum hotspot_event_handling workspace_hotspot_callback(
559 struct swaybar_output *output, struct swaybar_hotspot *hotspot, 600 struct swaybar_output *output, struct swaybar_hotspot *hotspot,
560 double x, double y, uint32_t button, void *data) { 601 double x, double y, uint32_t button, bool released, void *data) {
561 if (button != BTN_LEFT) { 602 if (button != BTN_LEFT) {
562 return HOTSPOT_PROCESS; 603 return HOTSPOT_PROCESS;
563 } 604 }
605 if (released) {
606 // Since we handle the pressed event, also handle the released event
607 // to block it from falling through to a binding in the bar
608 return HOTSPOT_IGNORE;
609 }
564 ipc_send_workspace_command(output->bar, (const char *)data); 610 ipc_send_workspace_command(output->bar, (const char *)data);
565 return HOTSPOT_IGNORE; 611 return HOTSPOT_IGNORE;
566} 612}
567 613
568static uint32_t render_workspace_button(cairo_t *cairo, 614static uint32_t render_workspace_button(struct render_context *ctx,
569 struct swaybar_output *output,
570 struct swaybar_workspace *ws, double *x) { 615 struct swaybar_workspace *ws, double *x) {
616 struct swaybar_output *output = ctx->output;
571 struct swaybar_config *config = output->bar->config; 617 struct swaybar_config *config = output->bar->config;
572 struct box_colors box_colors; 618 struct box_colors box_colors;
573 if (ws->urgent) { 619 if (ws->urgent) {
@@ -580,30 +626,33 @@ static uint32_t render_workspace_button(cairo_t *cairo,
580 box_colors = config->colors.inactive_workspace; 626 box_colors = config->colors.inactive_workspace;
581 } 627 }
582 628
583 uint32_t height = output->height * output->scale; 629 uint32_t height = output->height;
584 630
631 cairo_t *cairo = ctx->cairo;
585 int text_width, text_height; 632 int text_width, text_height;
586 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 633 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
587 output->scale, config->pango_markup, "%s", ws->label); 634 1, config->pango_markup, "%s", ws->label);
588 635
589 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 636 int ws_vertical_padding = WS_VERTICAL_PADDING;
590 int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; 637 int ws_horizontal_padding = WS_HORIZONTAL_PADDING;
591 int border_width = BORDER_WIDTH * output->scale; 638 int border_width = BORDER_WIDTH;
592 639
593 uint32_t ideal_height = ws_vertical_padding * 2 + text_height 640 uint32_t ideal_height = ws_vertical_padding * 2 + text_height
594 + border_width * 2; 641 + border_width * 2;
595 uint32_t ideal_surface_height = ideal_height / output->scale; 642 uint32_t ideal_surface_height = ideal_height;
596 if (!output->bar->config->height && 643 if (!output->bar->config->height &&
597 output->height < ideal_surface_height) { 644 output->height < ideal_surface_height) {
598 return ideal_surface_height; 645 return ideal_surface_height;
599 } 646 }
600 647
601 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; 648 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
602 if (width < config->workspace_min_width * output->scale) { 649 if (width < config->workspace_min_width) {
603 width = config->workspace_min_width * output->scale; 650 width = config->workspace_min_width;
604 } 651 }
605 652
653 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
606 cairo_set_source_u32(cairo, box_colors.background); 654 cairo_set_source_u32(cairo, box_colors.background);
655 ctx->background_color = box_colors.background;
607 cairo_rectangle(cairo, *x, 0, width, height); 656 cairo_rectangle(cairo, *x, 0, width, height);
608 cairo_fill(cairo); 657 cairo_fill(cairo);
609 658
@@ -620,7 +669,8 @@ static uint32_t render_workspace_button(cairo_t *cairo,
620 double text_y = height / 2.0 - text_height / 2.0; 669 double text_y = height / 2.0 - text_height / 2.0;
621 cairo_set_source_u32(cairo, box_colors.text); 670 cairo_set_source_u32(cairo, box_colors.text);
622 cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y)); 671 cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y));
623 pango_printf(cairo, config->font, output->scale, config->pango_markup, 672 choose_text_aa_mode(ctx, box_colors.text);
673 render_text(cairo, config->font_description, 1, config->pango_markup,
624 "%s", ws->label); 674 "%s", ws->label);
625 675
626 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); 676 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
@@ -637,20 +687,15 @@ static uint32_t render_workspace_button(cairo_t *cairo,
637 return output->height; 687 return output->height;
638} 688}
639 689
640static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) { 690static uint32_t render_to_cairo(struct render_context *ctx) {
691 cairo_t *cairo = ctx->cairo;
692 struct swaybar_output *output = ctx->output;
641 struct swaybar *bar = output->bar; 693 struct swaybar *bar = output->bar;
642 struct swaybar_config *config = bar->config; 694 struct swaybar_config *config = bar->config;
643 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
644 if (output->focused) {
645 cairo_set_source_u32(cairo, config->colors.focused_background);
646 } else {
647 cairo_set_source_u32(cairo, config->colors.background);
648 }
649 cairo_paint(cairo);
650 695
651 int th; 696 int th;
652 get_text_size(cairo, config->font, NULL, &th, NULL, output->scale, false, ""); 697 get_text_size(cairo, config->font_description, NULL, &th, NULL, 1, false, "");
653 uint32_t max_height = (th + WS_VERTICAL_PADDING * 4) / output->scale; 698 uint32_t max_height = (th + WS_VERTICAL_PADDING * 4);
654 /* 699 /*
655 * Each render_* function takes the actual height of the bar, and returns 700 * Each render_* function takes the actual height of the bar, and returns
656 * the ideal height. If the actual height is too short, the render function 701 * the ideal height. If the actual height is too short, the render function
@@ -658,7 +703,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
658 * height is too tall, the render function should adapt its drawing to 703 * height is too tall, the render function should adapt its drawing to
659 * utilize the available space. 704 * utilize the available space.
660 */ 705 */
661 double x = output->width * output->scale; 706 double x = output->width;
662#if HAVE_TRAY 707#if HAVE_TRAY
663 if (bar->tray) { 708 if (bar->tray) {
664 uint32_t h = render_tray(cairo, output, &x); 709 uint32_t h = render_tray(cairo, output, &x);
@@ -666,19 +711,19 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
666 } 711 }
667#endif 712#endif
668 if (bar->status) { 713 if (bar->status) {
669 uint32_t h = render_status_line(cairo, output, &x); 714 uint32_t h = render_status_line(ctx, &x);
670 max_height = h > max_height ? h : max_height; 715 max_height = h > max_height ? h : max_height;
671 } 716 }
672 x = 0; 717 x = 0;
673 if (config->workspace_buttons) { 718 if (config->workspace_buttons) {
674 struct swaybar_workspace *ws; 719 struct swaybar_workspace *ws;
675 wl_list_for_each(ws, &output->workspaces, link) { 720 wl_list_for_each(ws, &output->workspaces, link) {
676 uint32_t h = render_workspace_button(cairo, output, ws, &x); 721 uint32_t h = render_workspace_button(ctx, ws, &x);
677 max_height = h > max_height ? h : max_height; 722 max_height = h > max_height ? h : max_height;
678 } 723 }
679 } 724 }
680 if (config->binding_mode_indicator) { 725 if (config->binding_mode_indicator) {
681 uint32_t h = render_binding_mode_indicator(cairo, output, x); 726 uint32_t h = render_binding_mode_indicator(ctx, x);
682 max_height = h > max_height ? h : max_height; 727 max_height = h > max_height ? h : max_height;
683 } 728 }
684 729
@@ -708,26 +753,44 @@ void render_frame(struct swaybar_output *output) {
708 753
709 free_hotspots(&output->hotspots); 754 free_hotspots(&output->hotspots);
710 755
756 uint32_t background_color;
757 if (output->focused) {
758 background_color = output->bar->config->colors.focused_background;
759 } else {
760 background_color = output->bar->config->colors.background;
761 }
762
763 struct render_context ctx = { 0 };
764 ctx.output = output;
765 // initial background color used for deciding the best way to antialias text
766 ctx.background_color = background_color;
767
711 cairo_surface_t *recorder = cairo_recording_surface_create( 768 cairo_surface_t *recorder = cairo_recording_surface_create(
712 CAIRO_CONTENT_COLOR_ALPHA, NULL); 769 CAIRO_CONTENT_COLOR_ALPHA, NULL);
713 cairo_t *cairo = cairo_create(recorder); 770 cairo_t *cairo = cairo_create(recorder);
771 cairo_scale(cairo, output->scale, output->scale);
714 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); 772 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
773 ctx.cairo = cairo;
774
715 cairo_font_options_t *fo = cairo_font_options_create(); 775 cairo_font_options_t *fo = cairo_font_options_create();
716 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); 776 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
777 ctx.textaa_safe = fo;
717 if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) { 778 if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) {
718 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY); 779 ctx.textaa_sharp = ctx.textaa_safe;
719 } else { 780 } else {
781 fo = cairo_font_options_create();
720 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); 782 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
721 cairo_font_options_set_subpixel_order(fo, 783 cairo_font_options_set_subpixel_order(fo,
722 to_cairo_subpixel_order(output->subpixel)); 784 to_cairo_subpixel_order(output->subpixel));
785 ctx.textaa_sharp = fo;
723 } 786 }
724 cairo_set_font_options(cairo, fo); 787
725 cairo_font_options_destroy(fo); 788
726 cairo_save(cairo); 789 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
727 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); 790 cairo_set_source_u32(cairo, background_color);
728 cairo_paint(cairo); 791 cairo_paint(cairo);
729 cairo_restore(cairo); 792
730 uint32_t height = render_to_cairo(cairo, output); 793 uint32_t height = render_to_cairo(&ctx);
731 int config_height = output->bar->config->height; 794 int config_height = output->bar->config->height;
732 if (config_height > 0) { 795 if (config_height > 0) {
733 height = config_height; 796 height = config_height;
@@ -753,9 +816,7 @@ void render_frame(struct swaybar_output *output) {
753 output->width * output->scale, 816 output->width * output->scale,
754 output->height * output->scale); 817 output->height * output->scale);
755 if (!output->current_buffer) { 818 if (!output->current_buffer) {
756 cairo_surface_destroy(recorder); 819 goto cleanup;
757 cairo_destroy(cairo);
758 return;
759 } 820 }
760 cairo_t *shm = output->current_buffer->cairo; 821 cairo_t *shm = output->current_buffer->cairo;
761 822
@@ -773,12 +834,29 @@ void render_frame(struct swaybar_output *output) {
773 wl_surface_damage(output->surface, 0, 0, 834 wl_surface_damage(output->surface, 0, 0,
774 output->width, output->height); 835 output->width, output->height);
775 836
837 uint32_t bg_alpha = background_color & 0xFF;
838 if (bg_alpha == 0xFF) {
839 struct wl_region *region =
840 wl_compositor_create_region(output->bar->compositor);
841 wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
842 wl_surface_set_opaque_region(output->surface, region);
843 wl_region_destroy(region);
844 } else {
845 wl_surface_set_opaque_region(output->surface, NULL);
846 }
847
776 struct wl_callback *frame_callback = wl_surface_frame(output->surface); 848 struct wl_callback *frame_callback = wl_surface_frame(output->surface);
777 wl_callback_add_listener(frame_callback, &output_frame_listener, output); 849 wl_callback_add_listener(frame_callback, &output_frame_listener, output);
778 output->frame_scheduled = true; 850 output->frame_scheduled = true;
779 851
780 wl_surface_commit(output->surface); 852 wl_surface_commit(output->surface);
781 } 853 }
854
855cleanup:
856 if (ctx.textaa_sharp != ctx.textaa_safe) {
857 cairo_font_options_destroy(ctx.textaa_sharp);
858 }
859 cairo_font_options_destroy(ctx.textaa_safe);
782 cairo_surface_destroy(recorder); 860 cairo_surface_destroy(recorder);
783 cairo_destroy(cairo); 861 cairo_destroy(cairo);
784} 862}