aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar/render.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar/render.c')
-rw-r--r--swaybar/render.c292
1 files changed, 154 insertions, 138 deletions
diff --git a/swaybar/render.c b/swaybar/render.c
index fcc8be1d..879a4e42 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -1,4 +1,3 @@
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>
@@ -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
@@ -53,22 +53,21 @@ static uint32_t render_status_line_error(struct render_context *ctx, double *x)
53 return 0; 53 return 0;
54 } 54 }
55 55
56 uint32_t height = output->height * output->scale; 56 uint32_t height = output->height;
57 57
58 cairo_t *cairo = ctx->cairo; 58 cairo_t *cairo = ctx->cairo;
59 cairo_set_source_u32(cairo, 0xFF0000FF); 59 cairo_set_source_u32(cairo, 0xFF0000FF);
60 60
61 int margin = 3 * output->scale; 61 int margin = 3;
62 double ws_vertical_padding = 62 double ws_vertical_padding = output->bar->config->status_padding;
63 output->bar->config->status_padding * output->scale;
64 63
65 char *font = output->bar->config->font; 64 PangoFontDescription *font = output->bar->config->font_description;
66 int text_width, text_height; 65 int text_width, text_height;
67 get_text_size(cairo, font, &text_width, &text_height, NULL, 66 get_text_size(cairo, font, &text_width, &text_height, NULL,
68 output->scale, false, "%s", error); 67 1, false, "%s", error);
69 68
70 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 69 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
71 uint32_t ideal_surface_height = ideal_height / output->scale; 70 uint32_t ideal_surface_height = ideal_height;
72 if (!output->bar->config->height && 71 if (!output->bar->config->height &&
73 output->height < ideal_surface_height) { 72 output->height < ideal_surface_height) {
74 return ideal_surface_height; 73 return ideal_surface_height;
@@ -78,7 +77,7 @@ static uint32_t render_status_line_error(struct render_context *ctx, double *x)
78 double text_y = height / 2.0 - text_height / 2.0; 77 double text_y = height / 2.0 - text_height / 2.0;
79 cairo_move_to(cairo, *x, (int)floor(text_y)); 78 cairo_move_to(cairo, *x, (int)floor(text_y));
80 choose_text_aa_mode(ctx, 0xFF0000FF); 79 choose_text_aa_mode(ctx, 0xFF0000FF);
81 pango_printf(cairo, font, output->scale, false, "%s", error); 80 render_text(cairo, font, 1, false, "%s", error);
82 *x -= margin; 81 *x -= margin;
83 return output->height; 82 return output->height;
84} 83}
@@ -97,26 +96,25 @@ static uint32_t render_status_line_text(struct render_context *ctx, double *x) {
97 cairo_set_source_u32(cairo, fontcolor); 96 cairo_set_source_u32(cairo, fontcolor);
98 97
99 int text_width, text_height; 98 int text_width, text_height;
100 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 99 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
101 output->scale, config->pango_markup, "%s", text); 100 1, config->pango_markup, "%s", text);
102 101
103 double ws_vertical_padding = config->status_padding * output->scale; 102 double ws_vertical_padding = config->status_padding;
104 int margin = 3 * output->scale; 103 int margin = 3;
105 104
106 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 105 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
107 uint32_t ideal_surface_height = ideal_height / output->scale; 106 uint32_t ideal_surface_height = ideal_height;
108 if (!output->bar->config->height && 107 if (!output->bar->config->height &&
109 output->height < ideal_surface_height) { 108 output->height < ideal_surface_height) {
110 return ideal_surface_height; 109 return ideal_surface_height;
111 } 110 }
112 111
113 *x -= text_width + margin; 112 *x -= text_width + margin;
114 uint32_t height = output->height * output->scale; 113 uint32_t height = output->height;
115 double text_y = height / 2.0 - text_height / 2.0; 114 double text_y = height / 2.0 - text_height / 2.0;
116 cairo_move_to(cairo, *x, (int)floor(text_y)); 115 cairo_move_to(cairo, *x, (int)floor(text_y));
117 choose_text_aa_mode(ctx, fontcolor); 116 choose_text_aa_mode(ctx, fontcolor);
118 pango_printf(cairo, config->font, output->scale, 117 render_text(cairo, config->font_description, 1, config->pango_markup, "%s", text);
119 config->pango_markup, "%s", text);
120 *x -= margin; 118 *x -= margin;
121 return output->height; 119 return output->height;
122} 120}
@@ -161,15 +159,15 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color,
161 159
162static enum hotspot_event_handling block_hotspot_callback( 160static enum hotspot_event_handling block_hotspot_callback(
163 struct swaybar_output *output, struct swaybar_hotspot *hotspot, 161 struct swaybar_output *output, struct swaybar_hotspot *hotspot,
164 double x, double y, uint32_t button, void *data) { 162 double x, double y, uint32_t button, bool released, void *data) {
165 struct i3bar_block *block = data; 163 struct i3bar_block *block = data;
166 struct status_line *status = output->bar->status; 164 struct status_line *status = output->bar->status;
167 return i3bar_block_send_click(status, block, x, y, 165 return i3bar_block_send_click(status, block, x, y,
168 x - (double)hotspot->x / output->scale, 166 x - (double)hotspot->x,
169 y - (double)hotspot->y / output->scale, 167 y - (double)hotspot->y,
170 (double)hotspot->width / output->scale, 168 (double)hotspot->width,
171 (double)hotspot->height / output->scale, 169 (double)hotspot->height,
172 output->scale, button); 170 output->scale, button, released);
173} 171}
174 172
175static void i3bar_block_unref_callback(void *data) { 173static void i3bar_block_unref_callback(void *data) {
@@ -191,17 +189,17 @@ static uint32_t render_status_block(struct render_context *ctx,
191 struct swaybar_output *output = ctx->output; 189 struct swaybar_output *output = ctx->output;
192 struct swaybar_config *config = output->bar->config; 190 struct swaybar_config *config = output->bar->config;
193 int text_width, text_height; 191 int text_width, text_height;
194 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,
195 output->scale, block->markup, "%s", text); 193 block->markup, "%s", text);
196 194
197 int margin = 3 * output->scale; 195 int margin = 3;
198 double ws_vertical_padding = config->status_padding * output->scale; 196 double ws_vertical_padding = config->status_padding;
199 197
200 int width = text_width; 198 int width = text_width;
201 if (block->min_width_str) { 199 if (block->min_width_str) {
202 int w; 200 int w;
203 get_text_size(cairo, config->font, &w, NULL, NULL, 201 get_text_size(cairo, config->font_description, &w, NULL, NULL, 1, block->markup,
204 output->scale, block->markup, "%s", block->min_width_str); 202 "%s", block->min_width_str);
205 block->min_width = w; 203 block->min_width = w;
206 } 204 }
207 if (width < block->min_width) { 205 if (width < block->min_width) {
@@ -210,30 +208,30 @@ static uint32_t render_status_block(struct render_context *ctx,
210 208
211 double block_width = width; 209 double block_width = width;
212 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 210 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
213 uint32_t ideal_surface_height = ideal_height / output->scale; 211 uint32_t ideal_surface_height = ideal_height;
214 if (!output->bar->config->height && 212 if (!output->bar->config->height &&
215 output->height < ideal_surface_height) { 213 output->height < ideal_surface_height) {
216 return ideal_surface_height; 214 return ideal_surface_height;
217 } 215 }
218 216
219 *x -= width; 217 *x -= width;
220 if ((block->border || block->urgent) && block->border_left > 0) { 218 if ((block->border_set || block->urgent) && block->border_left > 0) {
221 *x -= (block->border_left * output->scale + margin); 219 *x -= (block->border_left + margin);
222 block_width += block->border_left * output->scale + margin; 220 block_width += block->border_left + margin;
223 } 221 }
224 if ((block->border || block->urgent) && block->border_right > 0) { 222 if ((block->border_set || block->urgent) && block->border_right > 0) {
225 *x -= (block->border_right * output->scale + margin); 223 *x -= (block->border_right + margin);
226 block_width += block->border_right * output->scale + margin; 224 block_width += block->border_right + margin;
227 } 225 }
228 226
229 int sep_width, sep_height; 227 int sep_width, sep_height;
230 int sep_block_width = block->separator_block_width; 228 int sep_block_width = block->separator_block_width;
231 if (!edge) { 229 if (!edge) {
232 if (config->sep_symbol) { 230 if (config->sep_symbol) {
233 get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, 231 get_text_size(cairo, config->font_description, &sep_width, &sep_height, NULL,
234 output->scale, false, "%s", config->sep_symbol); 232 1, false, "%s", config->sep_symbol);
235 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; 233 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
236 uint32_t _ideal_surface_height = _ideal_height / output->scale; 234 uint32_t _ideal_surface_height = _ideal_height;
237 if (!output->bar->config->height && 235 if (!output->bar->config->height &&
238 output->height < _ideal_surface_height) { 236 output->height < _ideal_surface_height) {
239 return _ideal_surface_height; 237 return _ideal_surface_height;
@@ -244,10 +242,10 @@ static uint32_t render_status_block(struct render_context *ctx,
244 } 242 }
245 *x -= sep_block_width; 243 *x -= sep_block_width;
246 } else if (config->status_edge_padding) { 244 } else if (config->status_edge_padding) {
247 *x -= config->status_edge_padding * output->scale; 245 *x -= config->status_edge_padding;
248 } 246 }
249 247
250 uint32_t height = output->height * output->scale; 248 uint32_t height = output->height;
251 if (output->bar->status->click_events) { 249 if (output->bar->status->click_events) {
252 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); 250 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
253 hotspot->x = *x; 251 hotspot->x = *x;
@@ -275,23 +273,25 @@ static uint32_t render_status_block(struct render_context *ctx,
275 273
276 uint32_t border_color = block->urgent 274 uint32_t border_color = block->urgent
277 ? config->colors.urgent_workspace.border : block->border; 275 ? config->colors.urgent_workspace.border : block->border;
278 if (border_color && block->border_top > 0) { 276 if (block->border_set || block->urgent) {
279 render_sharp_line(cairo, border_color, x_pos, y_pos, 277 if (block->border_top > 0) {
280 block_width, block->border_top * output->scale); 278 render_sharp_line(cairo, border_color, x_pos, y_pos,
281 } 279 block_width, block->border_top);
282 if (border_color && block->border_bottom > 0) { 280 }
283 render_sharp_line(cairo, border_color, x_pos, 281 if (block->border_bottom > 0) {
284 y_pos + render_height - block->border_bottom * output->scale, 282 render_sharp_line(cairo, border_color, x_pos,
285 block_width, block->border_bottom * output->scale); 283 y_pos + render_height - block->border_bottom,
286 } 284 block_width, block->border_bottom);
287 if (border_color && block->border_left > 0) { 285 }
288 render_sharp_line(cairo, border_color, x_pos, y_pos, 286 if (block->border_left > 0) {
289 block->border_left * output->scale, render_height); 287 render_sharp_line(cairo, border_color, x_pos, y_pos,
290 x_pos += block->border_left * output->scale + margin; 288 block->border_left, render_height);
289 }
290 x_pos += block->border_left + margin;
291 } 291 }
292 292
293 double offset = 0; 293 double offset = 0;
294 if (strncmp(block->align, "left", 5) == 0) { 294 if (strncmp(block->align, "left", 4) == 0) {
295 offset = x_pos; 295 offset = x_pos;
296 } else if (strncmp(block->align, "right", 5) == 0) { 296 } else if (strncmp(block->align, "right", 5) == 0) {
297 offset = x_pos + width - text_width; 297 offset = x_pos + width - text_width;
@@ -306,15 +306,16 @@ static uint32_t render_status_block(struct render_context *ctx,
306 color = block->urgent ? config->colors.urgent_workspace.text : color; 306 color = block->urgent ? config->colors.urgent_workspace.text : color;
307 cairo_set_source_u32(cairo, color); 307 cairo_set_source_u32(cairo, color);
308 choose_text_aa_mode(ctx, color); 308 choose_text_aa_mode(ctx, color);
309 pango_printf(cairo, config->font, output->scale, 309 render_text(cairo, config->font_description, 1, block->markup, "%s", text);
310 block->markup, "%s", text);
311 x_pos += width; 310 x_pos += width;
312 311
313 if (block->border && block->border_right > 0) { 312 if (block->border_set || block->urgent) {
314 x_pos += margin; 313 x_pos += margin;
315 render_sharp_line(cairo, border_color, x_pos, y_pos, 314 if (block->border_right > 0) {
316 block->border_right * output->scale, render_height); 315 render_sharp_line(cairo, border_color, x_pos, y_pos,
317 x_pos += block->border_right * output->scale; 316 block->border_right, render_height);
317 }
318 x_pos += block->border_right;
318 } 319 }
319 320
320 if (!edge && block->separator) { 321 if (!edge && block->separator) {
@@ -329,7 +330,7 @@ static uint32_t render_status_block(struct render_context *ctx,
329 double sep_y = height / 2.0 - sep_height / 2.0; 330 double sep_y = height / 2.0 - sep_height / 2.0;
330 cairo_move_to(cairo, offset, (int)floor(sep_y)); 331 cairo_move_to(cairo, offset, (int)floor(sep_y));
331 choose_text_aa_mode(ctx, color); 332 choose_text_aa_mode(ctx, color);
332 pango_printf(cairo, config->font, output->scale, false, 333 render_text(cairo, config->font_description, 1, false,
333 "%s", config->sep_symbol); 334 "%s", config->sep_symbol);
334 } else { 335 } else {
335 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 336 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
@@ -352,18 +353,18 @@ static void predict_status_block_pos(cairo_t *cairo,
352 struct swaybar_config *config = output->bar->config; 353 struct swaybar_config *config = output->bar->config;
353 354
354 int text_width, text_height; 355 int text_width, text_height;
355 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,
356 output->scale, block->markup, "%s", block->full_text); 357 block->markup, "%s", block->full_text);
357 358
358 int margin = 3 * output->scale; 359 int margin = 3;
359 double ws_vertical_padding = config->status_padding * output->scale; 360 double ws_vertical_padding = config->status_padding;
360 361
361 int width = text_width; 362 int width = text_width;
362 363
363 if (block->min_width_str) { 364 if (block->min_width_str) {
364 int w; 365 int w;
365 get_text_size(cairo, config->font, &w, NULL, NULL, 366 get_text_size(cairo, config->font_description, &w, NULL, NULL,
366 output->scale, block->markup, "%s", block->min_width_str); 367 1, block->markup, "%s", block->min_width_str);
367 block->min_width = w; 368 block->min_width = w;
368 } 369 }
369 if (width < block->min_width) { 370 if (width < block->min_width) {
@@ -371,28 +372,28 @@ static void predict_status_block_pos(cairo_t *cairo,
371 } 372 }
372 373
373 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 374 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
374 uint32_t ideal_surface_height = ideal_height / output->scale; 375 uint32_t ideal_surface_height = ideal_height;
375 if (!output->bar->config->height && 376 if (!output->bar->config->height &&
376 output->height < ideal_surface_height) { 377 output->height < ideal_surface_height) {
377 return; 378 return;
378 } 379 }
379 380
380 *x -= width; 381 *x -= width;
381 if ((block->border || block->urgent) && block->border_left > 0) { 382 if ((block->border_set || block->urgent) && block->border_left > 0) {
382 *x -= (block->border_left * output->scale + margin); 383 *x -= (block->border_left + margin);
383 } 384 }
384 if ((block->border || block->urgent) && block->border_right > 0) { 385 if ((block->border_set || block->urgent) && block->border_right > 0) {
385 *x -= (block->border_right * output->scale + margin); 386 *x -= (block->border_right + margin);
386 } 387 }
387 388
388 int sep_width, sep_height; 389 int sep_width, sep_height;
389 int sep_block_width = block->separator_block_width; 390 int sep_block_width = block->separator_block_width;
390 if (!edge) { 391 if (!edge) {
391 if (config->sep_symbol) { 392 if (config->sep_symbol) {
392 get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, 393 get_text_size(cairo, config->font_description, &sep_width, &sep_height, NULL,
393 output->scale, false, "%s", config->sep_symbol); 394 1, false, "%s", config->sep_symbol);
394 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; 395 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
395 uint32_t _ideal_surface_height = _ideal_height / output->scale; 396 uint32_t _ideal_surface_height = _ideal_height;
396 if (!output->bar->config->height && 397 if (!output->bar->config->height &&
397 output->height < _ideal_surface_height) { 398 output->height < _ideal_surface_height) {
398 return; 399 return;
@@ -403,13 +404,13 @@ static void predict_status_block_pos(cairo_t *cairo,
403 } 404 }
404 *x -= sep_block_width; 405 *x -= sep_block_width;
405 } else if (config->status_edge_padding) { 406 } else if (config->status_edge_padding) {
406 *x -= config->status_edge_padding * output->scale; 407 *x -= config->status_edge_padding;
407 } 408 }
408} 409}
409 410
410static double predict_status_line_pos(cairo_t *cairo, 411static double predict_status_line_pos(cairo_t *cairo,
411 struct swaybar_output *output, double x) { 412 struct swaybar_output *output, double x) {
412 bool edge = x == output->width * output->scale; 413 bool edge = x == output->width;
413 struct i3bar_block *block; 414 struct i3bar_block *block;
414 wl_list_for_each(block, &output->bar->status->blocks, link) { 415 wl_list_for_each(block, &output->bar->status->blocks, link) {
415 predict_status_block_pos(cairo, output, block, &x, edge); 416 predict_status_block_pos(cairo, output, block, &x, edge);
@@ -424,24 +425,24 @@ static uint32_t predict_workspace_button_length(cairo_t *cairo,
424 struct swaybar_config *config = output->bar->config; 425 struct swaybar_config *config = output->bar->config;
425 426
426 int text_width, text_height; 427 int text_width, text_height;
427 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,
428 output->scale, config->pango_markup, "%s", ws->label); 429 config->pango_markup, "%s", ws->label);
429 430
430 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 431 int ws_vertical_padding = WS_VERTICAL_PADDING;
431 int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; 432 int ws_horizontal_padding = WS_HORIZONTAL_PADDING;
432 int border_width = BORDER_WIDTH * output->scale; 433 int border_width = BORDER_WIDTH;
433 434
434 uint32_t ideal_height = ws_vertical_padding * 2 + text_height 435 uint32_t ideal_height = ws_vertical_padding * 2 + text_height
435 + border_width * 2; 436 + border_width * 2;
436 uint32_t ideal_surface_height = ideal_height / output->scale; 437 uint32_t ideal_surface_height = ideal_height;
437 if (!output->bar->config->height && 438 if (!output->bar->config->height &&
438 output->height < ideal_surface_height) { 439 output->height < ideal_surface_height) {
439 return 0; 440 return 0;
440 } 441 }
441 442
442 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;
443 if (width < config->workspace_min_width * output->scale) { 444 if (width < config->workspace_min_width) {
444 width = config->workspace_min_width * output->scale; 445 width = config->workspace_min_width;
445 } 446 }
446 return width; 447 return width;
447} 448}
@@ -472,24 +473,24 @@ static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo,
472 } 473 }
473 474
474 int text_width, text_height; 475 int text_width, text_height;
475 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 476 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
476 output->scale, output->bar->mode_pango_markup, 477 1, output->bar->mode_pango_markup,
477 "%s", mode); 478 "%s", mode);
478 479
479 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 480 int ws_vertical_padding = WS_VERTICAL_PADDING;
480 int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; 481 int ws_horizontal_padding = WS_HORIZONTAL_PADDING;
481 int border_width = BORDER_WIDTH * output->scale; 482 int border_width = BORDER_WIDTH;
482 483
483 uint32_t ideal_height = text_height + ws_vertical_padding * 2 484 uint32_t ideal_height = text_height + ws_vertical_padding * 2
484 + border_width * 2; 485 + border_width * 2;
485 uint32_t ideal_surface_height = ideal_height / output->scale; 486 uint32_t ideal_surface_height = ideal_height;
486 if (!output->bar->config->height && 487 if (!output->bar->config->height &&
487 output->height < ideal_surface_height) { 488 output->height < ideal_surface_height) {
488 return 0; 489 return 0;
489 } 490 }
490 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;
491 if (width < config->workspace_min_width * output->scale) { 492 if (width < config->workspace_min_width) {
492 width = config->workspace_min_width * output->scale; 493 width = config->workspace_min_width;
493 } 494 }
494 return width; 495 return width;
495} 496}
@@ -497,7 +498,7 @@ static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo,
497static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x) { 498static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x) {
498 struct swaybar_output *output = ctx->output; 499 struct swaybar_output *output = ctx->output;
499 uint32_t max_height = 0; 500 uint32_t max_height = 0;
500 bool edge = *x == output->width * output->scale; 501 bool edge = *x == output->width;
501 struct i3bar_block *block; 502 struct i3bar_block *block;
502 bool use_short_text = false; 503 bool use_short_text = false;
503 504
@@ -505,7 +506,7 @@ static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x)
505 double reserved_width = 506 double reserved_width =
506 predict_workspace_buttons_length(cairo, output) + 507 predict_workspace_buttons_length(cairo, output) +
507 predict_binding_mode_indicator_length(cairo, output) + 508 predict_binding_mode_indicator_length(cairo, output) +
508 3 * output->scale; // require a bit of space for margin 509 3; // require a bit of space for margin
509 510
510 double predicted_full_pos = 511 double predicted_full_pos =
511 predict_status_line_pos(cairo, output, *x); 512 predict_status_line_pos(cairo, output, *x);
@@ -549,27 +550,27 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx,
549 cairo_t *cairo = ctx->cairo; 550 cairo_t *cairo = ctx->cairo;
550 struct swaybar_config *config = output->bar->config; 551 struct swaybar_config *config = output->bar->config;
551 int text_width, text_height; 552 int text_width, text_height;
552 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 553 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
553 output->scale, output->bar->mode_pango_markup, 554 1, output->bar->mode_pango_markup,
554 "%s", mode); 555 "%s", mode);
555 556
556 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 557 int ws_vertical_padding = WS_VERTICAL_PADDING;
557 int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; 558 int ws_horizontal_padding = WS_HORIZONTAL_PADDING;
558 int border_width = BORDER_WIDTH * output->scale; 559 int border_width = BORDER_WIDTH;
559 560
560 uint32_t ideal_height = text_height + ws_vertical_padding * 2 561 uint32_t ideal_height = text_height + ws_vertical_padding * 2
561 + border_width * 2; 562 + border_width * 2;
562 uint32_t ideal_surface_height = ideal_height / output->scale; 563 uint32_t ideal_surface_height = ideal_height;
563 if (!output->bar->config->height && 564 if (!output->bar->config->height &&
564 output->height < ideal_surface_height) { 565 output->height < ideal_surface_height) {
565 return ideal_surface_height; 566 return ideal_surface_height;
566 } 567 }
567 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;
568 if (width < config->workspace_min_width * output->scale) { 569 if (width < config->workspace_min_width) {
569 width = config->workspace_min_width * output->scale; 570 width = config->workspace_min_width;
570 } 571 }
571 572
572 uint32_t height = output->height * output->scale; 573 uint32_t height = output->height;
573 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 574 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
574 cairo_set_source_u32(cairo, config->colors.binding_mode.background); 575 cairo_set_source_u32(cairo, config->colors.binding_mode.background);
575 ctx->background_color = config->colors.binding_mode.background; 576 ctx->background_color = config->colors.binding_mode.background;
@@ -590,17 +591,22 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx,
590 cairo_set_source_u32(cairo, config->colors.binding_mode.text); 591 cairo_set_source_u32(cairo, config->colors.binding_mode.text);
591 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));
592 choose_text_aa_mode(ctx, config->colors.binding_mode.text); 593 choose_text_aa_mode(ctx, config->colors.binding_mode.text);
593 pango_printf(cairo, config->font, output->scale, 594 render_text(cairo, config->font_description, 1, output->bar->mode_pango_markup,
594 output->bar->mode_pango_markup, "%s", mode); 595 "%s", mode);
595 return output->height; 596 return output->height;
596} 597}
597 598
598static enum hotspot_event_handling workspace_hotspot_callback( 599static enum hotspot_event_handling workspace_hotspot_callback(
599 struct swaybar_output *output, struct swaybar_hotspot *hotspot, 600 struct swaybar_output *output, struct swaybar_hotspot *hotspot,
600 double x, double y, uint32_t button, void *data) { 601 double x, double y, uint32_t button, bool released, void *data) {
601 if (button != BTN_LEFT) { 602 if (button != BTN_LEFT) {
602 return HOTSPOT_PROCESS; 603 return HOTSPOT_PROCESS;
603 } 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 }
604 ipc_send_workspace_command(output->bar, (const char *)data); 610 ipc_send_workspace_command(output->bar, (const char *)data);
605 return HOTSPOT_IGNORE; 611 return HOTSPOT_IGNORE;
606} 612}
@@ -620,28 +626,28 @@ static uint32_t render_workspace_button(struct render_context *ctx,
620 box_colors = config->colors.inactive_workspace; 626 box_colors = config->colors.inactive_workspace;
621 } 627 }
622 628
623 uint32_t height = output->height * output->scale; 629 uint32_t height = output->height;
624 630
625 cairo_t *cairo = ctx->cairo; 631 cairo_t *cairo = ctx->cairo;
626 int text_width, text_height; 632 int text_width, text_height;
627 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 633 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
628 output->scale, config->pango_markup, "%s", ws->label); 634 1, config->pango_markup, "%s", ws->label);
629 635
630 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 636 int ws_vertical_padding = WS_VERTICAL_PADDING;
631 int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; 637 int ws_horizontal_padding = WS_HORIZONTAL_PADDING;
632 int border_width = BORDER_WIDTH * output->scale; 638 int border_width = BORDER_WIDTH;
633 639
634 uint32_t ideal_height = ws_vertical_padding * 2 + text_height 640 uint32_t ideal_height = ws_vertical_padding * 2 + text_height
635 + border_width * 2; 641 + border_width * 2;
636 uint32_t ideal_surface_height = ideal_height / output->scale; 642 uint32_t ideal_surface_height = ideal_height;
637 if (!output->bar->config->height && 643 if (!output->bar->config->height &&
638 output->height < ideal_surface_height) { 644 output->height < ideal_surface_height) {
639 return ideal_surface_height; 645 return ideal_surface_height;
640 } 646 }
641 647
642 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;
643 if (width < config->workspace_min_width * output->scale) { 649 if (width < config->workspace_min_width) {
644 width = config->workspace_min_width * output->scale; 650 width = config->workspace_min_width;
645 } 651 }
646 652
647 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 653 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
@@ -664,7 +670,7 @@ static uint32_t render_workspace_button(struct render_context *ctx,
664 cairo_set_source_u32(cairo, box_colors.text); 670 cairo_set_source_u32(cairo, box_colors.text);
665 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));
666 choose_text_aa_mode(ctx, box_colors.text); 672 choose_text_aa_mode(ctx, box_colors.text);
667 pango_printf(cairo, config->font, output->scale, config->pango_markup, 673 render_text(cairo, config->font_description, 1, config->pango_markup,
668 "%s", ws->label); 674 "%s", ws->label);
669 675
670 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); 676 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
@@ -686,19 +692,10 @@ static uint32_t render_to_cairo(struct render_context *ctx) {
686 struct swaybar_output *output = ctx->output; 692 struct swaybar_output *output = ctx->output;
687 struct swaybar *bar = output->bar; 693 struct swaybar *bar = output->bar;
688 struct swaybar_config *config = bar->config; 694 struct swaybar_config *config = bar->config;
689 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
690 if (output->focused) {
691 ctx->background_color = config->colors.focused_background;
692 } else {
693 ctx->background_color = config->colors.background;
694 }
695
696 cairo_set_source_u32(cairo, ctx->background_color);
697 cairo_paint(cairo);
698 695
699 int th; 696 int th;
700 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, "");
701 uint32_t max_height = (th + WS_VERTICAL_PADDING * 4) / output->scale; 698 uint32_t max_height = (th + WS_VERTICAL_PADDING * 4);
702 /* 699 /*
703 * 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
704 * 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
@@ -706,7 +703,7 @@ static uint32_t render_to_cairo(struct render_context *ctx) {
706 * 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
707 * utilize the available space. 704 * utilize the available space.
708 */ 705 */
709 double x = output->width * output->scale; 706 double x = output->width;
710#if HAVE_TRAY 707#if HAVE_TRAY
711 if (bar->tray) { 708 if (bar->tray) {
712 uint32_t h = render_tray(cairo, output, &x); 709 uint32_t h = render_tray(cairo, output, &x);
@@ -756,34 +753,43 @@ void render_frame(struct swaybar_output *output) {
756 753
757 free_hotspots(&output->hotspots); 754 free_hotspots(&output->hotspots);
758 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
759 struct render_context ctx = { 0 }; 763 struct render_context ctx = { 0 };
760 ctx.output = output; 764 ctx.output = output;
765 // initial background color used for deciding the best way to antialias text
766 ctx.background_color = background_color;
761 767
762 cairo_surface_t *recorder = cairo_recording_surface_create( 768 cairo_surface_t *recorder = cairo_recording_surface_create(
763 CAIRO_CONTENT_COLOR_ALPHA, NULL); 769 CAIRO_CONTENT_COLOR_ALPHA, NULL);
764 cairo_t *cairo = cairo_create(recorder); 770 cairo_t *cairo = cairo_create(recorder);
771 cairo_scale(cairo, output->scale, output->scale);
765 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); 772 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
766 ctx.cairo = cairo; 773 ctx.cairo = cairo;
767 774
768 cairo_font_options_t *fo = cairo_font_options_create(); 775 cairo_font_options_t *fo = cairo_font_options_create();
769 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
770 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY); 776 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
771 ctx.textaa_safe = fo; 777 ctx.textaa_safe = fo;
772 if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) { 778 if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) {
773 ctx.textaa_sharp = ctx.textaa_safe; 779 ctx.textaa_sharp = ctx.textaa_safe;
774 } else { 780 } else {
775 fo = cairo_font_options_create(); 781 fo = cairo_font_options_create();
776 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
777 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); 782 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
778 cairo_font_options_set_subpixel_order(fo, 783 cairo_font_options_set_subpixel_order(fo,
779 to_cairo_subpixel_order(output->subpixel)); 784 to_cairo_subpixel_order(output->subpixel));
780 ctx.textaa_sharp = fo; 785 ctx.textaa_sharp = fo;
781 } 786 }
782 787
783 cairo_save(cairo); 788
784 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); 789 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
790 cairo_set_source_u32(cairo, background_color);
785 cairo_paint(cairo); 791 cairo_paint(cairo);
786 cairo_restore(cairo); 792
787 uint32_t height = render_to_cairo(&ctx); 793 uint32_t height = render_to_cairo(&ctx);
788 int config_height = output->bar->config->height; 794 int config_height = output->bar->config->height;
789 if (config_height > 0) { 795 if (config_height > 0) {
@@ -810,9 +816,7 @@ void render_frame(struct swaybar_output *output) {
810 output->width * output->scale, 816 output->width * output->scale,
811 output->height * output->scale); 817 output->height * output->scale);
812 if (!output->current_buffer) { 818 if (!output->current_buffer) {
813 cairo_surface_destroy(recorder); 819 goto cleanup;
814 cairo_destroy(cairo);
815 return;
816 } 820 }
817 cairo_t *shm = output->current_buffer->cairo; 821 cairo_t *shm = output->current_buffer->cairo;
818 822
@@ -830,6 +834,17 @@ void render_frame(struct swaybar_output *output) {
830 wl_surface_damage(output->surface, 0, 0, 834 wl_surface_damage(output->surface, 0, 0,
831 output->width, output->height); 835 output->width, output->height);
832 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
833 struct wl_callback *frame_callback = wl_surface_frame(output->surface); 848 struct wl_callback *frame_callback = wl_surface_frame(output->surface);
834 wl_callback_add_listener(frame_callback, &output_frame_listener, output); 849 wl_callback_add_listener(frame_callback, &output_frame_listener, output);
835 output->frame_scheduled = true; 850 output->frame_scheduled = true;
@@ -837,6 +852,7 @@ void render_frame(struct swaybar_output *output) {
837 wl_surface_commit(output->surface); 852 wl_surface_commit(output->surface);
838 } 853 }
839 854
855cleanup:
840 if (ctx.textaa_sharp != ctx.textaa_safe) { 856 if (ctx.textaa_sharp != ctx.textaa_safe) {
841 cairo_font_options_destroy(ctx.textaa_sharp); 857 cairo_font_options_destroy(ctx.textaa_sharp);
842 } 858 }