diff options
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/main.c | 316 |
1 files changed, 240 insertions, 76 deletions
diff --git a/swaybar/main.c b/swaybar/main.c index 747e03de..49aa08cd 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 | ||
59 | list_t *status_line = NULL; | 66 | list_t *status_line = NULL; |
@@ -398,7 +405,185 @@ void bar_ipc_init(int outputi, const char *bar_id) { | |||
398 | ipc_update_workspaces(); | 405 | ipc_update_workspaces(); |
399 | } | 406 | } |
400 | 407 | ||
408 | /** | ||
409 | * Renders a sharp line of any width and height. | ||
410 | * | ||
411 | * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0 | ||
412 | * if the line has a width/height of one pixel, respectively. | ||
413 | */ | ||
414 | void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) { | ||
415 | cairo_set_source_u32(cairo, color); | ||
416 | |||
417 | if (width > 1 && height > 1) { | ||
418 | cairo_rectangle(cairo, x, y, width, height); | ||
419 | cairo_fill(cairo); | ||
420 | } else { | ||
421 | if (width == 1) { | ||
422 | x += 0.5; | ||
423 | height += y; | ||
424 | width = x; | ||
425 | } | ||
426 | |||
427 | if (height == 1) { | ||
428 | y += 0.5; | ||
429 | width += x; | ||
430 | height = y; | ||
431 | } | ||
432 | |||
433 | cairo_move_to(cairo, x, y); | ||
434 | cairo_set_line_width(cairo, 1.0); | ||
435 | cairo_line_to(cairo, width, height); | ||
436 | cairo_stroke(cairo); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | void render_block(struct status_block *block, double *x, bool edge) { | ||
441 | int width, height; | ||
442 | get_text_size(window, &width, &height, "%s", block->full_text); | ||
443 | |||
444 | int textwidth = width; | ||
445 | double block_width = width; | ||
446 | |||
447 | if (width < block->min_width) { | ||
448 | width = block->min_width; | ||
449 | } | ||
450 | |||
451 | *x -= width; | ||
452 | |||
453 | if (block->border != 0 && block->border_left > 0) { | ||
454 | *x -= (block->border_left + margin); | ||
455 | block_width += block->border_left + margin; | ||
456 | } | ||
457 | |||
458 | if (block->border != 0 && block->border_right > 0) { | ||
459 | *x -= (block->border_right + margin); | ||
460 | block_width += block->border_right + margin; | ||
461 | } | ||
462 | |||
463 | // Add separator | ||
464 | if (!edge) { | ||
465 | *x -= block->separator_block_width; | ||
466 | } else { | ||
467 | *x -= margin; | ||
468 | } | ||
469 | |||
470 | double pos = *x; | ||
471 | |||
472 | // render background | ||
473 | if (block->background != 0x0) { | ||
474 | cairo_set_source_u32(window->cairo, block->background); | ||
475 | cairo_rectangle(window->cairo, pos - 0.5, 1, block_width, window->height - 2); | ||
476 | cairo_fill(window->cairo); | ||
477 | } | ||
478 | |||
479 | // render top border | ||
480 | if (block->border != 0 && block->border_top > 0) { | ||
481 | render_sharp_line(window->cairo, block->border, | ||
482 | pos - 0.5, | ||
483 | 1, | ||
484 | block_width, | ||
485 | block->border_top); | ||
486 | } | ||
487 | |||
488 | // render bottom border | ||
489 | if (block->border != 0 && block->border_bottom > 0) { | ||
490 | render_sharp_line(window->cairo, block->border, | ||
491 | pos - 0.5, | ||
492 | window->height - 1 - block->border_bottom, | ||
493 | block_width, | ||
494 | block->border_bottom); | ||
495 | } | ||
496 | |||
497 | // render left border | ||
498 | if (block->border != 0 && block->border_left > 0) { | ||
499 | render_sharp_line(window->cairo, block->border, | ||
500 | pos - 0.5, | ||
501 | 1, | ||
502 | block->border_left, | ||
503 | window->height - 2); | ||
504 | |||
505 | pos += block->border_left + margin; | ||
506 | } | ||
507 | |||
508 | // render text | ||
509 | double offset = 0; | ||
510 | |||
511 | if (strncmp(block->align, "left", 5) == 0) { | ||
512 | offset = pos; | ||
513 | } else if (strncmp(block->align, "right", 5) == 0) { | ||
514 | offset = pos + width - textwidth; | ||
515 | } else if (strncmp(block->align, "center", 6) == 0) { | ||
516 | offset = pos + (width - textwidth) / 2; | ||
517 | } | ||
518 | |||
519 | cairo_move_to(window->cairo, offset, margin); | ||
520 | cairo_set_source_u32(window->cairo, block->color); | ||
521 | pango_printf(window, "%s", block->full_text); | ||
522 | |||
523 | pos += width; | ||
524 | |||
525 | // render right border | ||
526 | if (block->border != 0 && block->border_right > 0) { | ||
527 | pos += margin; | ||
528 | |||
529 | render_sharp_line(window->cairo, block->border, | ||
530 | pos - 0.5, | ||
531 | 1, | ||
532 | block->border_right, | ||
533 | window->height - 2); | ||
534 | |||
535 | pos += block->border_right; | ||
536 | } | ||
537 | |||
538 | // render separator | ||
539 | // TODO: Handle custom separator | ||
540 | if (!edge && block->separator) { | ||
541 | cairo_set_source_u32(window->cairo, colors.separator); | ||
542 | cairo_set_line_width(window->cairo, 1); | ||
543 | cairo_move_to(window->cairo, pos + block->separator_block_width/2, margin); | ||
544 | cairo_line_to(window->cairo, pos + block->separator_block_width/2, window->height - margin); | ||
545 | cairo_stroke(window->cairo); | ||
546 | } | ||
547 | |||
548 | } | ||
549 | |||
550 | void render_workspace_button(struct workspace *ws, double *x) { | ||
551 | int width, height; | ||
552 | get_text_size(window, &width, &height, "%s", ws->name); | ||
553 | struct box_colors box_colors; | ||
554 | if (ws->urgent) { | ||
555 | box_colors = colors.urgent_workspace; | ||
556 | } else if (ws->focused) { | ||
557 | box_colors = colors.focused_workspace; | ||
558 | } else if (ws->visible) { | ||
559 | box_colors = colors.active_workspace; | ||
560 | } else { | ||
561 | box_colors = colors.inactive_workspace; | ||
562 | } | ||
563 | |||
564 | // background | ||
565 | cairo_set_source_u32(window->cairo, box_colors.background); | ||
566 | cairo_rectangle(window->cairo, *x, 1.5, width + ws_hor_padding * 2 - 1, | ||
567 | height + ws_ver_padding * 2); | ||
568 | cairo_fill(window->cairo); | ||
569 | |||
570 | // border | ||
571 | cairo_set_source_u32(window->cairo, box_colors.border); | ||
572 | cairo_rectangle(window->cairo, *x, 1.5, width + ws_hor_padding * 2 - 1, | ||
573 | height + ws_ver_padding * 2); | ||
574 | cairo_stroke(window->cairo); | ||
575 | |||
576 | // text | ||
577 | cairo_set_source_u32(window->cairo, box_colors.text); | ||
578 | cairo_move_to(window->cairo, (int)*x + ws_hor_padding, margin); | ||
579 | pango_printf(window, "%s", ws->name); | ||
580 | |||
581 | *x += width + ws_hor_padding * 2 + ws_spacing; | ||
582 | } | ||
583 | |||
401 | void render() { | 584 | void render() { |
585 | int i; | ||
586 | |||
402 | // Clear | 587 | // Clear |
403 | cairo_save(window->cairo); | 588 | cairo_save(window->cairo); |
404 | cairo_set_operator(window->cairo, CAIRO_OPERATOR_CLEAR); | 589 | cairo_set_operator(window->cairo, CAIRO_OPERATOR_CLEAR); |
@@ -418,49 +603,13 @@ void render() { | |||
418 | cairo_move_to(window->cairo, window->width - margin - width, margin); | 603 | cairo_move_to(window->cairo, window->width - margin - width, margin); |
419 | pango_printf(window, "%s", line); | 604 | pango_printf(window, "%s", line); |
420 | } else if (protocol == I3BAR && status_line) { | 605 | } else if (protocol == I3BAR && status_line) { |
421 | int i, blockpos; | 606 | double pos = window->width - 0.5; |
422 | int moved = 0; | 607 | bool edge = true; |
423 | bool corner = true; | ||
424 | for (i = status_line->length - 1; i >= 0; --i) { | 608 | for (i = status_line->length - 1; i >= 0; --i) { |
425 | struct status_block *block = status_line->items[i]; | 609 | struct status_block *block = status_line->items[i]; |
426 | if (block->full_text && block->full_text[0]) { | 610 | if (block->full_text && block->full_text[0]) { |
427 | get_text_size(window, &width, &height, "%s", block->full_text); | 611 | render_block(block, &pos, edge); |
428 | 612 | edge = false; | |
429 | int textwidth = width; | ||
430 | |||
431 | if (width < block->min_width) { | ||
432 | width = block->min_width; | ||
433 | } | ||
434 | |||
435 | moved += width + block->separator_block_width; | ||
436 | blockpos = window->width - margin - moved; | ||
437 | |||
438 | int offset = 0; | ||
439 | |||
440 | if (strncmp(block->align, "left", 5) == 0) { | ||
441 | offset = blockpos; | ||
442 | } | ||
443 | else if (strncmp(block->align, "right", 5) == 0) { | ||
444 | offset = blockpos + width - textwidth; | ||
445 | } | ||
446 | else if (strncmp(block->align, "center", 6) == 0) { | ||
447 | offset = blockpos + (width - textwidth) / 2; | ||
448 | } | ||
449 | |||
450 | cairo_move_to(window->cairo, offset, margin); | ||
451 | cairo_set_source_u32(window->cairo, block->color); | ||
452 | pango_printf(window, "%s", block->full_text); | ||
453 | if (corner) { | ||
454 | corner = false; | ||
455 | } else if (block->separator) { | ||
456 | cairo_set_source_u32(window->cairo, colors.separator); | ||
457 | cairo_set_line_width(window->cairo, 1); | ||
458 | cairo_move_to(window->cairo, blockpos + width | ||
459 | + block->separator_block_width/2, margin); | ||
460 | cairo_line_to(window->cairo, blockpos + width | ||
461 | + block->separator_block_width/2, window->height - margin); | ||
462 | cairo_stroke(window->cairo); | ||
463 | } | ||
464 | } | 613 | } |
465 | } | 614 | } |
466 | } | 615 | } |
@@ -468,34 +617,9 @@ void render() { | |||
468 | // Workspaces | 617 | // Workspaces |
469 | cairo_set_line_width(window->cairo, 1.0); | 618 | cairo_set_line_width(window->cairo, 1.0); |
470 | double x = 0.5; | 619 | double x = 0.5; |
471 | int i; | ||
472 | for (i = 0; i < workspaces->length; ++i) { | 620 | for (i = 0; i < workspaces->length; ++i) { |
473 | struct workspace *ws = workspaces->items[i]; | 621 | struct workspace *ws = workspaces->items[i]; |
474 | get_text_size(window, &width, &height, "%s", ws->name); | 622 | render_workspace_button(ws, &x); |
475 | struct box_colors box_colors; | ||
476 | if (ws->urgent) { | ||
477 | box_colors = colors.urgent_workspace; | ||
478 | } else if (ws->focused) { | ||
479 | box_colors = colors.focused_workspace; | ||
480 | } else if (ws->visible) { | ||
481 | box_colors = colors.active_workspace; | ||
482 | } else { | ||
483 | box_colors = colors.inactive_workspace; | ||
484 | } | ||
485 | |||
486 | cairo_set_source_u32(window->cairo, box_colors.background); | ||
487 | cairo_rectangle(window->cairo, x, 1.5, width + ws_hor_padding * 2 - 1, height + ws_ver_padding * 2); | ||
488 | cairo_fill(window->cairo); | ||
489 | |||
490 | cairo_set_source_u32(window->cairo, box_colors.border); | ||
491 | cairo_rectangle(window->cairo, x, 1.5, width + ws_hor_padding * 2 - 1, height + ws_ver_padding * 2); | ||
492 | cairo_stroke(window->cairo); | ||
493 | |||
494 | cairo_set_source_u32(window->cairo, box_colors.text); | ||
495 | cairo_move_to(window->cairo, (int)x + ws_hor_padding, margin); | ||
496 | pango_printf(window, "%s", ws->name); | ||
497 | |||
498 | x += width + ws_hor_padding * 2 + ws_spacing; | ||
499 | } | 623 | } |
500 | } | 624 | } |
501 | 625 | ||
@@ -544,6 +668,8 @@ void parse_json(const char *text) { | |||
544 | for (i = 0; i < json_object_array_length(results); ++i) { | 668 | for (i = 0; i < json_object_array_length(results); ++i) { |
545 | json_object *full_text, *short_text, *color, *min_width, *align, *urgent; | 669 | json_object *full_text, *short_text, *color, *min_width, *align, *urgent; |
546 | json_object *name, *instance, *separator, *separator_block_width; | 670 | json_object *name, *instance, *separator, *separator_block_width; |
671 | json_object *background, *border, *border_top, *border_bottom; | ||
672 | json_object *border_left, *border_right; | ||
547 | 673 | ||
548 | json_object *json = json_object_array_get_idx(results, i); | 674 | json_object *json = json_object_array_get_idx(results, i); |
549 | if (!json) { | 675 | if (!json) { |
@@ -560,6 +686,12 @@ void parse_json(const char *text) { | |||
560 | json_object_object_get_ex(json, "instance", &instance); | 686 | json_object_object_get_ex(json, "instance", &instance); |
561 | json_object_object_get_ex(json, "separator", &separator); | 687 | json_object_object_get_ex(json, "separator", &separator); |
562 | json_object_object_get_ex(json, "separator_block_width", &separator_block_width); | 688 | json_object_object_get_ex(json, "separator_block_width", &separator_block_width); |
689 | json_object_object_get_ex(json, "background", &background); | ||
690 | json_object_object_get_ex(json, "border", &border); | ||
691 | json_object_object_get_ex(json, "border_top", &border_top); | ||
692 | json_object_object_get_ex(json, "border_bottom", &border_bottom); | ||
693 | json_object_object_get_ex(json, "border_left", &border_left); | ||
694 | json_object_object_get_ex(json, "border_right", &border_right); | ||
563 | 695 | ||
564 | struct status_block *new = malloc(sizeof(struct status_block)); | 696 | struct status_block *new = malloc(sizeof(struct status_block)); |
565 | memset(new, 0, sizeof(struct status_block)); | 697 | memset(new, 0, sizeof(struct status_block)); |
@@ -574,8 +706,7 @@ void parse_json(const char *text) { | |||
574 | 706 | ||
575 | if (color) { | 707 | if (color) { |
576 | new->color = parse_color(json_object_get_string(color)); | 708 | new->color = parse_color(json_object_get_string(color)); |
577 | } | 709 | } else { |
578 | else { | ||
579 | new->color = colors.statusline; | 710 | new->color = colors.statusline; |
580 | } | 711 | } |
581 | 712 | ||
@@ -583,8 +714,7 @@ void parse_json(const char *text) { | |||
583 | json_type type = json_object_get_type(min_width); | 714 | json_type type = json_object_get_type(min_width); |
584 | if (type == json_type_int) { | 715 | if (type == json_type_int) { |
585 | new->min_width = json_object_get_int(min_width); | 716 | new->min_width = json_object_get_int(min_width); |
586 | } | 717 | } else if (type == json_type_string) { |
587 | else if (type == json_type_string) { | ||
588 | int width, height; | 718 | int width, height; |
589 | get_text_size(window, &width, &height, "%s", json_object_get_string(min_width)); | 719 | get_text_size(window, &width, &height, "%s", json_object_get_string(min_width)); |
590 | new->min_width = width; | 720 | new->min_width = width; |
@@ -593,8 +723,7 @@ void parse_json(const char *text) { | |||
593 | 723 | ||
594 | if (align) { | 724 | if (align) { |
595 | new->align = strdup(json_object_get_string(align)); | 725 | new->align = strdup(json_object_get_string(align)); |
596 | } | 726 | } else { |
597 | else { | ||
598 | new->align = strdup("left"); | 727 | new->align = strdup("left"); |
599 | } | 728 | } |
600 | 729 | ||
@@ -612,18 +741,53 @@ void parse_json(const char *text) { | |||
612 | 741 | ||
613 | if (separator) { | 742 | if (separator) { |
614 | new->separator = json_object_get_int(separator); | 743 | new->separator = json_object_get_int(separator); |
615 | } | 744 | } else { |
616 | else { | ||
617 | new->separator = true; // i3bar spec | 745 | new->separator = true; // i3bar spec |
618 | } | 746 | } |
619 | 747 | ||
620 | if (separator_block_width) { | 748 | if (separator_block_width) { |
621 | new->separator_block_width = json_object_get_int(separator_block_width); | 749 | new->separator_block_width = json_object_get_int(separator_block_width); |
622 | } | 750 | } else { |
623 | else { | ||
624 | new->separator_block_width = 9; // i3bar spec | 751 | new->separator_block_width = 9; // i3bar spec |
625 | } | 752 | } |
626 | 753 | ||
754 | // Airblader features | ||
755 | if (background) { | ||
756 | new->background = parse_color(json_object_get_string(background)); | ||
757 | } else { | ||
758 | new->background = 0x0; // transparent | ||
759 | } | ||
760 | |||
761 | if (border) { | ||
762 | new->border = parse_color(json_object_get_string(border)); | ||
763 | } else { | ||
764 | new->border = 0x0; // transparent | ||
765 | } | ||
766 | |||
767 | if (border_top) { | ||
768 | new->border_top = json_object_get_int(border_top); | ||
769 | } else { | ||
770 | new->border_top = 1; | ||
771 | } | ||
772 | |||
773 | if (border_bottom) { | ||
774 | new->border_bottom = json_object_get_int(border_bottom); | ||
775 | } else { | ||
776 | new->border_bottom = 1; | ||
777 | } | ||
778 | |||
779 | if (border_left) { | ||
780 | new->border_left = json_object_get_int(border_left); | ||
781 | } else { | ||
782 | new->border_left = 1; | ||
783 | } | ||
784 | |||
785 | if (border_right) { | ||
786 | new->border_right = json_object_get_int(border_right); | ||
787 | } else { | ||
788 | new->border_right = 1; | ||
789 | } | ||
790 | |||
627 | list_add(status_line, new); | 791 | list_add(status_line, new); |
628 | } | 792 | } |
629 | 793 | ||