aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar/main.c
diff options
context:
space:
mode:
authorLibravatar Mikkel Oscar Lyderik <mikkeloscar@gmail.com>2015-12-27 13:18:55 +0100
committerLibravatar Mikkel Oscar Lyderik <mikkeloscar@gmail.com>2015-12-27 13:18:55 +0100
commitd21b15a4be35524a2021a61c3ec15d73d412c969 (patch)
tree2f68c3cefd0c2542a594ae09d40eef12e2e835d6 /swaybar/main.c
parentMerge pull request #408 from mikkeloscar/add-focus-sibling (diff)
downloadsway-d21b15a4be35524a2021a61c3ec15d73d412c969.tar.gz
sway-d21b15a4be35524a2021a61c3ec15d73d412c969.tar.zst
sway-d21b15a4be35524a2021a61c3ec15d73d412c969.zip
swaybar: Add support for Airblade i3bar extensions
This extends the i3bar protocol implementation with the following features from @Airblade/i3: * background * border * border_top, border_bottom, border_left, border_right A block will now be rendered like this: ``` (border_left + margin) + width + (margin + border_right) + sep ``` Where `border_left/border_right` and their related margin is only drawn if the `border` is specified and the border has a width > 0 (default is 1). `border_top` and `border_bottom` does not affect the height of the bar (no margin is added), thus it will be drawn behind the text if it is too big. The user should specify a bar height if more space between top/bottom borders are required.
Diffstat (limited to 'swaybar/main.c')
-rw-r--r--swaybar/main.c301
1 files changed, 235 insertions, 66 deletions
diff --git a/swaybar/main.c b/swaybar/main.c
index 434d7363..c9fc7de7 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -54,6 +54,13 @@ struct status_block {
54 char *name, *instance; 54 char *name, *instance;
55 bool separator; 55 bool separator;
56 int separator_block_width; 56 int separator_block_width;
57 // Airblader features
58 uint32_t background;
59 uint32_t border;
60 int border_top;
61 int border_bottom;
62 int border_left;
63 int border_right;
57}; 64};
58 65
59list_t *status_line = NULL; 66list_t *status_line = NULL;
@@ -397,7 +404,185 @@ void bar_ipc_init(int outputi, const char *bar_id) {
397 ipc_update_workspaces(); 404 ipc_update_workspaces();
398} 405}
399 406
407/**
408 * Renders a sharp line of any width and height.
409 *
410 * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0
411 * if the line has a width/height of one pixel, respectively.
412 */
413void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) {
414 cairo_set_source_u32(cairo, color);
415
416 if (width > 1 && height > 1) {
417 cairo_rectangle(cairo, x, y, width, height);
418 cairo_fill(cairo);
419 } else {
420 if (width == 1) {
421 x += 0.5;
422 height += y;
423 width = x;
424 }
425
426 if (height == 1) {
427 y += 0.5;
428 width += x;
429 height = y;
430 }
431
432 cairo_move_to(cairo, x, y);
433 cairo_set_line_width(cairo, 1.0);
434 cairo_line_to(cairo, width, height);
435 cairo_stroke(cairo);
436 }
437}
438
439void render_block(struct status_block *block, double *x, bool edge) {
440 int width, height;
441 get_text_size(window, &width, &height, "%s", block->full_text);
442
443 int textwidth = width;
444 double block_width = width;
445
446 if (width < block->min_width) {
447 width = block->min_width;
448 }
449
450 *x -= width;
451
452 if (block->border != 0 && block->border_left > 0) {
453 *x -= (block->border_left + margin);
454 block_width += block->border_left + margin;
455 }
456
457 if (block->border != 0 && block->border_right > 0) {
458 *x -= (block->border_right + margin);
459 block_width += block->border_right + margin;
460 }
461
462 // Add separator
463 if (!edge) {
464 *x -= block->separator_block_width;
465 } else {
466 *x -= margin;
467 }
468
469 double pos = *x;
470
471 // render background
472 if (block->background != 0x0) {
473 cairo_set_source_u32(window->cairo, block->background);
474 cairo_rectangle(window->cairo, pos - 0.5, 1, block_width, window->height - 2);
475 cairo_fill(window->cairo);
476 }
477
478 // render top border
479 if (block->border != 0 && block->border_top > 0) {
480 render_sharp_line(window->cairo, block->border,
481 pos - 0.5,
482 1,
483 block_width,
484 block->border_top);
485 }
486
487 // render bottom border
488 if (block->border != 0 && block->border_bottom > 0) {
489 render_sharp_line(window->cairo, block->border,
490 pos - 0.5,
491 window->height - 1 - block->border_bottom,
492 block_width,
493 block->border_bottom);
494 }
495
496 // render left border
497 if (block->border != 0 && block->border_left > 0) {
498 render_sharp_line(window->cairo, block->border,
499 pos - 0.5,
500 1,
501 block->border_left,
502 window->height - 2);
503
504 pos += block->border_left + margin;
505 }
506
507 // render text
508 double offset = 0;
509
510 if (strncmp(block->align, "left", 5) == 0) {
511 offset = pos;
512 } else if (strncmp(block->align, "right", 5) == 0) {
513 offset = pos + width - textwidth;
514 } else if (strncmp(block->align, "center", 6) == 0) {
515 offset = pos + (width - textwidth) / 2;
516 }
517
518 cairo_move_to(window->cairo, offset, margin);
519 cairo_set_source_u32(window->cairo, block->color);
520 pango_printf(window, "%s", block->full_text);
521
522 pos += width;
523
524 // render right border
525 if (block->border != 0 && block->border_right > 0) {
526 pos += margin;
527
528 render_sharp_line(window->cairo, block->border,
529 pos - 0.5,
530 1,
531 block->border_right,
532 window->height - 2);
533
534 pos += block->border_right;
535 }
536
537 // render separator
538 // TODO: Handle custom separator
539 if (!edge && block->separator) {
540 cairo_set_source_u32(window->cairo, colors.separator);
541 cairo_set_line_width(window->cairo, 1);
542 cairo_move_to(window->cairo, pos + block->separator_block_width/2, margin);
543 cairo_line_to(window->cairo, pos + block->separator_block_width/2, window->height - margin);
544 cairo_stroke(window->cairo);
545 }
546
547}
548
549void render_workspace_button(struct workspace *ws, double *x) {
550 int width, height;
551 get_text_size(window, &width, &height, "%s", ws->name);
552 struct box_colors box_colors;
553 if (ws->urgent) {
554 box_colors = colors.urgent_workspace;
555 } else if (ws->focused) {
556 box_colors = colors.focused_workspace;
557 } else if (ws->visible) {
558 box_colors = colors.active_workspace;
559 } else {
560 box_colors = colors.inactive_workspace;
561 }
562
563 // background
564 cairo_set_source_u32(window->cairo, box_colors.background);
565 cairo_rectangle(window->cairo, *x, 1.5, width + ws_hor_padding * 2 - 1,
566 height + ws_ver_padding * 2);
567 cairo_fill(window->cairo);
568
569 // border
570 cairo_set_source_u32(window->cairo, box_colors.border);
571 cairo_rectangle(window->cairo, *x, 1.5, width + ws_hor_padding * 2 - 1,
572 height + ws_ver_padding * 2);
573 cairo_stroke(window->cairo);
574
575 // text
576 cairo_set_source_u32(window->cairo, box_colors.text);
577 cairo_move_to(window->cairo, (int)*x + ws_hor_padding, margin);
578 pango_printf(window, "%s", ws->name);
579
580 *x += width + ws_hor_padding * 2 + ws_spacing;
581}
582
400void render() { 583void render() {
584 int i;
585
401 // Clear 586 // Clear
402 cairo_save(window->cairo); 587 cairo_save(window->cairo);
403 cairo_set_operator(window->cairo, CAIRO_OPERATOR_CLEAR); 588 cairo_set_operator(window->cairo, CAIRO_OPERATOR_CLEAR);
@@ -417,49 +602,13 @@ void render() {
417 cairo_move_to(window->cairo, window->width - margin - width, margin); 602 cairo_move_to(window->cairo, window->width - margin - width, margin);
418 pango_printf(window, "%s", line); 603 pango_printf(window, "%s", line);
419 } else if (protocol == I3BAR && status_line) { 604 } else if (protocol == I3BAR && status_line) {
420 int i, blockpos; 605 double pos = window->width - 0.5;
421 int moved = 0; 606 bool edge = true;
422 bool corner = true;
423 for (i = status_line->length - 1; i >= 0; --i) { 607 for (i = status_line->length - 1; i >= 0; --i) {
424 struct status_block *block = status_line->items[i]; 608 struct status_block *block = status_line->items[i];
425 if (block->full_text && block->full_text[0]) { 609 if (block->full_text && block->full_text[0]) {
426 get_text_size(window, &width, &height, "%s", block->full_text); 610 render_block(block, &pos, edge);
427 611 edge = false;
428 int textwidth = width;
429
430 if (width < block->min_width) {
431 width = block->min_width;
432 }
433
434 moved += width + block->separator_block_width;
435 blockpos = window->width - margin - moved;
436
437 int offset = 0;
438
439 if (strncmp(block->align, "left", 5) == 0) {
440 offset = blockpos;
441 }
442 else if (strncmp(block->align, "right", 5) == 0) {
443 offset = blockpos + width - textwidth;
444 }
445 else if (strncmp(block->align, "center", 6) == 0) {
446 offset = blockpos + (width - textwidth) / 2;
447 }
448
449 cairo_move_to(window->cairo, offset, margin);
450 cairo_set_source_u32(window->cairo, block->color);
451 pango_printf(window, "%s", block->full_text);
452 if (corner) {
453 corner = false;
454 } else if (block->separator) {
455 cairo_set_source_u32(window->cairo, colors.separator);
456 cairo_set_line_width(window->cairo, 1);
457 cairo_move_to(window->cairo, blockpos + width
458 + block->separator_block_width/2, margin);
459 cairo_line_to(window->cairo, blockpos + width
460 + block->separator_block_width/2, window->height - margin);
461 cairo_stroke(window->cairo);
462 }
463 } 612 }
464 } 613 }
465 } 614 }
@@ -467,34 +616,9 @@ void render() {
467 // Workspaces 616 // Workspaces
468 cairo_set_line_width(window->cairo, 1.0); 617 cairo_set_line_width(window->cairo, 1.0);
469 double x = 0.5; 618 double x = 0.5;
470 int i;
471 for (i = 0; i < workspaces->length; ++i) { 619 for (i = 0; i < workspaces->length; ++i) {
472 struct workspace *ws = workspaces->items[i]; 620 struct workspace *ws = workspaces->items[i];
473 get_text_size(window, &width, &height, "%s", ws->name); 621 render_workspace_button(ws, &x);
474 struct box_colors box_colors;
475 if (ws->urgent) {
476 box_colors = colors.urgent_workspace;
477 } else if (ws->focused) {
478 box_colors = colors.focused_workspace;
479 } else if (ws->visible) {
480 box_colors = colors.active_workspace;
481 } else {
482 box_colors = colors.inactive_workspace;
483 }
484
485 cairo_set_source_u32(window->cairo, box_colors.background);
486 cairo_rectangle(window->cairo, x, 1.5, width + ws_hor_padding * 2 - 1, height + ws_ver_padding * 2);
487 cairo_fill(window->cairo);
488
489 cairo_set_source_u32(window->cairo, box_colors.border);
490 cairo_rectangle(window->cairo, x, 1.5, width + ws_hor_padding * 2 - 1, height + ws_ver_padding * 2);
491 cairo_stroke(window->cairo);
492
493 cairo_set_source_u32(window->cairo, box_colors.text);
494 cairo_move_to(window->cairo, (int)x + ws_hor_padding, margin);
495 pango_printf(window, "%s", ws->name);
496
497 x += width + ws_hor_padding * 2 + ws_spacing;
498 } 622 }
499} 623}
500 624
@@ -543,6 +667,8 @@ void parse_json(const char *text) {
543 for (i = 0; i < json_object_array_length(results); ++i) { 667 for (i = 0; i < json_object_array_length(results); ++i) {
544 json_object *full_text, *short_text, *color, *min_width, *align, *urgent; 668 json_object *full_text, *short_text, *color, *min_width, *align, *urgent;
545 json_object *name, *instance, *separator, *separator_block_width; 669 json_object *name, *instance, *separator, *separator_block_width;
670 json_object *background, *border, *border_top, *border_bottom;
671 json_object *border_left, *border_right;
546 672
547 json_object *json = json_object_array_get_idx(results, i); 673 json_object *json = json_object_array_get_idx(results, i);
548 if (!json) { 674 if (!json) {
@@ -559,6 +685,12 @@ void parse_json(const char *text) {
559 json_object_object_get_ex(json, "instance", &instance); 685 json_object_object_get_ex(json, "instance", &instance);
560 json_object_object_get_ex(json, "separator", &separator); 686 json_object_object_get_ex(json, "separator", &separator);
561 json_object_object_get_ex(json, "separator_block_width", &separator_block_width); 687 json_object_object_get_ex(json, "separator_block_width", &separator_block_width);
688 json_object_object_get_ex(json, "background", &background);
689 json_object_object_get_ex(json, "border", &border);
690 json_object_object_get_ex(json, "border_top", &border_top);
691 json_object_object_get_ex(json, "border_bottom", &border_bottom);
692 json_object_object_get_ex(json, "border_left", &border_left);
693 json_object_object_get_ex(json, "border_right", &border_right);
562 694
563 struct status_block *new = malloc(sizeof(struct status_block)); 695 struct status_block *new = malloc(sizeof(struct status_block));
564 memset(new, 0, sizeof(struct status_block)); 696 memset(new, 0, sizeof(struct status_block));
@@ -623,6 +755,43 @@ void parse_json(const char *text) {
623 new->separator_block_width = 9; // i3bar spec 755 new->separator_block_width = 9; // i3bar spec
624 } 756 }
625 757
758 // Airblader features
759 if (background) {
760 new->background = parse_color(json_object_get_string(background));
761 } else {
762 new->background = 0x0; // transparent
763 }
764
765 if (border) {
766 new->border = parse_color(json_object_get_string(border));
767 } else {
768 new->border = 0x0; // transparent
769 }
770
771 if (border_top) {
772 new->border_top = json_object_get_int(border_top);
773 } else {
774 new->border_top = 1;
775 }
776
777 if (border_bottom) {
778 new->border_bottom = json_object_get_int(border_bottom);
779 } else {
780 new->border_bottom = 1;
781 }
782
783 if (border_left) {
784 new->border_left = json_object_get_int(border_left);
785 } else {
786 new->border_left = 1;
787 }
788
789 if (border_right) {
790 new->border_right = json_object_get_int(border_right);
791 } else {
792 new->border_right = 1;
793 }
794
626 list_add(status_line, new); 795 list_add(status_line, new);
627 } 796 }
628 797