aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/tree/container.h2
-rw-r--r--sway/commands/layout.c2
-rw-r--r--sway/desktop/output.c192
-rw-r--r--sway/input/cursor.c2
-rw-r--r--sway/tree/arrange.c44
-rw-r--r--sway/tree/container.c267
-rw-r--r--sway/tree/layout.c11
-rw-r--r--sway/tree/view.c1
8 files changed, 436 insertions, 85 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index e7e9d944..598a4f3d 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -162,7 +162,7 @@ struct sway_container *container_parent(struct sway_container *container,
162 * is a view and the view contains a surface at those coordinates. 162 * is a view and the view contains a surface at those coordinates.
163 */ 163 */
164struct sway_container *container_at(struct sway_container *container, 164struct sway_container *container_at(struct sway_container *container,
165 double lx, double ly, struct wlr_surface **surface, 165 double ox, double oy, struct wlr_surface **surface,
166 double *sx, double *sy); 166 double *sx, double *sy);
167 167
168/** 168/**
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index bb36bb18..8aa321ae 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -39,6 +39,8 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
39 parent->layout = L_HORIZ; 39 parent->layout = L_HORIZ;
40 } else if (strcasecmp(argv[0], "splitv") == 0) { 40 } else if (strcasecmp(argv[0], "splitv") == 0) {
41 parent->layout = L_VERT; 41 parent->layout = L_VERT;
42 } else if (strcasecmp(argv[0], "tabbed") == 0) {
43 parent->layout = L_TABBED;
42 } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { 44 } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
43 if (parent->layout == L_HORIZ) { 45 if (parent->layout == L_HORIZ) {
44 parent->layout = L_VERT; 46 parent->layout = L_VERT;
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 51c1ffbe..e39ef8db 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -599,12 +599,198 @@ static void render_container_simple(struct sway_output *output,
599 } 599 }
600} 600}
601 601
602static void render_tab(struct sway_output *output, pixman_region32_t *damage,
603 struct sway_container *parent, int child_index,
604 struct border_colors *colors, struct wlr_texture *title_texture) {
605 float output_scale = output->wlr_output->scale;
606 float color[4];
607 struct wlr_box box;
608 bool is_first = (child_index == 0);
609 bool is_last = (child_index == parent->children->length - 1);
610
611 int tab_width = parent->width / parent->children->length;
612 int x = parent->x + tab_width * child_index;
613 // Make last tab use the remaining width of the parent
614 if (is_last) {
615 tab_width = parent->width - tab_width * child_index;
616 }
617
618 // Single pixel bar above title
619 memcpy(&color, colors->border, sizeof(float) * 4);
620 box.x = x;
621 box.y = parent->y;
622 box.width = tab_width;
623 box.height = 1;
624 scale_box(&box, output_scale);
625 render_rect(output->wlr_output, damage, &box, color);
626
627 // Single pixel bar below title
628 memcpy(&color, colors->border, sizeof(float) * 4);
629 box.x = x + config->border_thickness * is_first;
630 box.y = parent->y + config->border_thickness * 2 + config->font_height - 1;
631 box.width = tab_width - config->border_thickness * is_first
632 - config->border_thickness * is_last;
633 box.height = 1;
634 scale_box(&box, output_scale);
635 render_rect(output->wlr_output, damage, &box, color);
636
637 // Title text
638 size_t title_width = 0;
639 if (title_texture) {
640 struct wlr_box texture_box;
641 wlr_texture_get_size(title_texture,
642 &texture_box.width, &texture_box.height);
643 texture_box.x = (x + config->border_thickness) * output_scale;
644 texture_box.y = (parent->y + config->border_thickness) * output_scale;
645
646 float matrix[9];
647 wlr_matrix_project_box(matrix, &texture_box,
648 WL_OUTPUT_TRANSFORM_NORMAL,
649 0.0, output->wlr_output->transform_matrix);
650
651 int available = (tab_width - config->border_thickness * 2)
652 * output_scale;
653 if (texture_box.width > available) {
654 texture_box.width = available;
655 }
656 render_texture(output->wlr_output, damage, title_texture,
657 &texture_box, matrix, 1.0);
658 title_width = texture_box.width;
659 }
660
661 // Title background - above the text
662 memcpy(&color, colors->background, sizeof(float) * 4);
663 box.x = x + config->border_thickness;
664 box.y = parent->y + 1;
665 box.width = tab_width - config->border_thickness * 2;
666 box.height = config->border_thickness - 1;
667 scale_box(&box, output_scale);
668 render_rect(output->wlr_output, damage, &box, color);
669
670 // Title background - below the text
671 box.y = (parent->y + config->border_thickness + config->font_height)
672 * output_scale;
673 render_rect(output->wlr_output, damage, &box, color);
674
675 // Title background - left border
676 box.x = x;
677 box.y = parent->y + 1;
678 box.width = config->border_thickness;
679 box.height = config->border_thickness * 2
680 + config->font_height - 1 - !is_first;
681 scale_box(&box, output_scale);
682 render_rect(output->wlr_output, damage, &box, color);
683
684 // Title background - right border
685 box.x = x + tab_width - config->border_thickness;
686 box.y = parent->y + 1;
687 box.width = config->border_thickness;
688 box.height = config->border_thickness * 2
689 + config->font_height - 1 - !is_last;
690 scale_box(&box, output_scale);
691 render_rect(output->wlr_output, damage, &box, color);
692
693 // Title background - right of text
694 box.x = (x + config->border_thickness) * output_scale + title_width;
695 box.y = (parent->y + config->border_thickness) * output_scale;
696 box.width = (tab_width - config->border_thickness * 2) * output_scale
697 - title_width;
698 box.height = config->font_height * output_scale;
699 render_rect(output->wlr_output, damage, &box, color);
700}
701
702static void render_tab_content(struct sway_output *output,
703 pixman_region32_t *damage, struct sway_container *con,
704 struct border_colors *colors) {
705 struct sway_view *view = con->sway_view;
706 render_view(view, output, damage);
707
708 struct wlr_box box;
709 float output_scale = output->wlr_output->scale;
710 float color[4];
711
712 if (view->border_left) {
713 memcpy(&color, colors->child_border, sizeof(float) * 4);
714 color[3] *= con->alpha;
715 box.x = con->x;
716 box.y = con->y + config->border_thickness * 2 + config->font_height;
717 box.width = view->border_thickness;
718 box.height = view->height;
719 scale_box(&box, output_scale);
720 render_rect(output->wlr_output, damage, &box, color);
721 }
722
723 if (view->border_right) {
724 memcpy(&color, colors->child_border, sizeof(float) * 4);
725 color[3] *= con->alpha;
726 box.x = view->x + view->width;
727 box.y = con->y + config->border_thickness * 2 + config->font_height;
728 box.width = view->border_thickness;
729 box.height = view->height;
730 scale_box(&box, output_scale);
731 render_rect(output->wlr_output, damage, &box, color);
732 }
733
734 if (view->border_bottom) {
735 memcpy(&color, colors->child_border, sizeof(float) * 4);
736 color[3] *= con->alpha;
737 box.x = con->x;
738 box.y = view->y + view->height;
739 box.width = con->width;
740 box.height = view->border_thickness;
741 scale_box(&box, output_scale);
742 render_rect(output->wlr_output, damage, &box, color);
743 }
744}
745
602/** 746/**
603 * Render a container's children using the L_TABBED layout. 747 * Render a container's children using the L_TABBED layout.
604 */ 748 */
605static void render_container_tabbed(struct sway_output *output, 749static void render_container_tabbed(struct sway_output *output,
606 pixman_region32_t *damage, struct sway_container *con) { 750 pixman_region32_t *damage, struct sway_container *con,
607 // TODO 751 bool parent_focused) {
752 if (!con->children->length) {
753 return;
754 }
755 struct sway_seat *seat = input_manager_current_seat(input_manager);
756 struct sway_container *focus = seat_get_focus(seat);
757 struct sway_container *current = seat_get_focus_inactive(seat, con);
758 while (current->parent != con) {
759 current = current->parent;
760 }
761 struct border_colors *current_colors = NULL;
762
763 // Render tabs
764 for (int i = 0; i < con->children->length; ++i) {
765 struct sway_container *child = con->children->items[i];
766 struct border_colors *colors;
767 struct wlr_texture *title_texture;
768
769 if (focus == child || parent_focused) {
770 colors = &config->border_colors.focused;
771 title_texture = child->title_focused;
772 } else if (child == current) {
773 colors = &config->border_colors.focused_inactive;
774 title_texture = child->title_focused_inactive;
775 } else {
776 colors = &config->border_colors.unfocused;
777 title_texture = child->title_unfocused;
778 }
779
780 render_tab(output, damage, con, i, colors, title_texture);
781
782 if (child == current) {
783 current_colors = colors;
784 }
785 }
786
787 // Render surface and left/right/bottom borders
788 if (current->type == C_VIEW) {
789 render_tab_content(output, damage, current, current_colors);
790 } else {
791 render_container(output, damage, current,
792 parent_focused || current == focus);
793 }
608} 794}
609 795
610/** 796/**
@@ -628,7 +814,7 @@ static void render_container(struct sway_output *output,
628 render_container_stacked(output, damage, con); 814 render_container_stacked(output, damage, con);
629 break; 815 break;
630 case L_TABBED: 816 case L_TABBED:
631 render_container_tabbed(output, damage, con); 817 render_container_tabbed(output, damage, con, parent_focused);
632 break; 818 break;
633 case L_FLOATING: 819 case L_FLOATING:
634 // TODO 820 // TODO
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index b0ce8002..e0b987d2 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -108,7 +108,7 @@ static struct sway_container *container_at_coords(
108 } 108 }
109 109
110 struct sway_container *c; 110 struct sway_container *c;
111 if ((c = container_at(ws, x, y, surface, sx, sy))) { 111 if ((c = container_at(ws, ox, oy, surface, sx, sy))) {
112 return c; 112 return c;
113 } 113 }
114 114
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 83bb20fb..8aebc0cc 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -86,6 +86,13 @@ static void apply_horiz_layout(struct sway_container *parent) {
86 if (!num_children) { 86 if (!num_children) {
87 return; 87 return;
88 } 88 }
89 size_t parent_height = parent->height;
90 size_t parent_offset = 0;
91 if (parent->parent->layout == L_TABBED) {
92 parent_offset = config->border_thickness * 2 + config->font_height;
93 parent_height -= parent_offset;
94 }
95
89 // Calculate total width of children 96 // Calculate total width of children
90 double total_width = 0; 97 double total_width = 0;
91 for (size_t i = 0; i < num_children; ++i) { 98 for (size_t i = 0; i < num_children; ++i) {
@@ -111,9 +118,9 @@ static void apply_horiz_layout(struct sway_container *parent) {
111 "Calculating arrangement for %p:%d (will scale %f by %f)", 118 "Calculating arrangement for %p:%d (will scale %f by %f)",
112 child, child->type, child->width, scale); 119 child, child->type, child->width, scale);
113 child->x = child_x; 120 child->x = child_x;
114 child->y = parent->y; 121 child->y = parent->y + parent_offset;
115 child->width = floor(child->width * scale); 122 child->width = floor(child->width * scale);
116 child->height = parent->height; 123 child->height = parent_height;
117 child_x += child->width; 124 child_x += child->width;
118 } 125 }
119 // Make last child use remaining width of parent 126 // Make last child use remaining width of parent
@@ -125,24 +132,31 @@ static void apply_vert_layout(struct sway_container *parent) {
125 if (!num_children) { 132 if (!num_children) {
126 return; 133 return;
127 } 134 }
135 size_t parent_height = parent->height;
136 size_t parent_offset = 0;
137 if (parent->parent->layout == L_TABBED) {
138 parent_offset = config->border_thickness * 2 + config->font_height;
139 parent_height -= parent_offset;
140 }
141
128 // Calculate total height of children 142 // Calculate total height of children
129 double total_height = 0; 143 double total_height = 0;
130 for (size_t i = 0; i < num_children; ++i) { 144 for (size_t i = 0; i < num_children; ++i) {
131 struct sway_container *child = parent->children->items[i]; 145 struct sway_container *child = parent->children->items[i];
132 if (child->height <= 0) { 146 if (child->height <= 0) {
133 if (num_children > 1) { 147 if (num_children > 1) {
134 child->height = parent->height / (num_children - 1); 148 child->height = parent_height / (num_children - 1);
135 } else { 149 } else {
136 child->height = parent->height; 150 child->height = parent_height;
137 } 151 }
138 } 152 }
139 total_height += child->height; 153 total_height += child->height;
140 } 154 }
141 double scale = parent->height / total_height; 155 double scale = parent_height / total_height;
142 156
143 // Resize 157 // Resize
144 wlr_log(L_DEBUG, "Arranging %p vertically", parent); 158 wlr_log(L_DEBUG, "Arranging %p vertically", parent);
145 double child_y = parent->y; 159 double child_y = parent->y + parent_offset;
146 struct sway_container *child; 160 struct sway_container *child;
147 for (size_t i = 0; i < num_children; ++i) { 161 for (size_t i = 0; i < num_children; ++i) {
148 child = parent->children->items[i]; 162 child = parent->children->items[i];
@@ -156,7 +170,20 @@ static void apply_vert_layout(struct sway_container *parent) {
156 child_y += child->height; 170 child_y += child->height;
157 } 171 }
158 // Make last child use remaining height of parent 172 // Make last child use remaining height of parent
159 child->height = parent->y + parent->height - child->y; 173 child->height = parent->y + parent_offset + parent_height - child->y;
174}
175
176static void apply_tabbed_layout(struct sway_container *parent) {
177 if (!parent->children->length) {
178 return;
179 }
180 for (int i = 0; i < parent->children->length; ++i) {
181 struct sway_container *child = parent->children->items[i];
182 child->x = parent->x;
183 child->y = parent->y;
184 child->width = parent->width;
185 child->height = parent->height;
186 }
160} 187}
161 188
162void arrange_children_of(struct sway_container *parent) { 189void arrange_children_of(struct sway_container *parent) {
@@ -189,6 +216,9 @@ void arrange_children_of(struct sway_container *parent) {
189 case L_VERT: 216 case L_VERT:
190 apply_vert_layout(parent); 217 apply_vert_layout(parent);
191 break; 218 break;
219 case L_TABBED:
220 apply_tabbed_layout(parent);
221 break;
192 default: 222 default:
193 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout); 223 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
194 apply_horiz_layout(parent); 224 apply_horiz_layout(parent);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index feaf7647..76a21c19 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -452,80 +452,139 @@ struct sway_container *container_parent(struct sway_container *container,
452 return container; 452 return container;
453} 453}
454 454
455struct sway_container *container_at(struct sway_container *parent, 455static struct sway_container *container_at_view(struct sway_container *swayc,
456 double lx, double ly, 456 double ox, double oy,
457 struct wlr_surface **surface, double *sx, double *sy) { 457 struct wlr_surface **surface, double *sx, double *sy) {
458 list_t *queue = get_bfs_queue(); 458 struct sway_view *sview = swayc->sway_view;
459 if (!queue) { 459 double view_sx = ox - sview->x;
460 double view_sy = oy - sview->y;
461
462 double _sx, _sy;
463 struct wlr_surface *_surface = NULL;
464 switch (sview->type) {
465 case SWAY_VIEW_XWAYLAND:
466 _surface = wlr_surface_surface_at(sview->surface,
467 view_sx, view_sy, &_sx, &_sy);
468 break;
469 case SWAY_VIEW_XDG_SHELL_V6:
470 // the top left corner of the sway container is the
471 // coordinate of the top left corner of the window geometry
472 view_sx += sview->wlr_xdg_surface_v6->geometry.x;
473 view_sy += sview->wlr_xdg_surface_v6->geometry.y;
474
475 _surface = wlr_xdg_surface_v6_surface_at(
476 sview->wlr_xdg_surface_v6,
477 view_sx, view_sy, &_sx, &_sy);
478 break;
479 case SWAY_VIEW_XDG_SHELL:
480 // the top left corner of the sway container is the
481 // coordinate of the top left corner of the window geometry
482 view_sx += sview->wlr_xdg_surface->geometry.x;
483 view_sy += sview->wlr_xdg_surface->geometry.y;
484
485 _surface = wlr_xdg_surface_surface_at(
486 sview->wlr_xdg_surface,
487 view_sx, view_sy, &_sx, &_sy);
488 break;
489 }
490 if (_surface) {
491 *sx = _sx;
492 *sy = _sy;
493 *surface = _surface;
494 }
495 return swayc;
496}
497
498/**
499 * container_at for a container with layout L_TABBED.
500 */
501static struct sway_container *container_at_tabbed(struct sway_container *parent,
502 double ox, double oy,
503 struct wlr_surface **surface, double *sx, double *sy) {
504 if (oy < parent->y || oy > parent->y + parent->height) {
460 return NULL; 505 return NULL;
461 } 506 }
507 struct sway_seat *seat = input_manager_current_seat(input_manager);
462 508
463 list_add(queue, parent); 509 // Tab titles
510 int title_height = config->border_thickness * 2 + config->font_height;
511 if (oy < parent->y + title_height) {
512 int tab_width = parent->width / parent->children->length;
513 int child_index = (ox - parent->x) / tab_width;
514 if (child_index >= parent->children->length) {
515 child_index = parent->children->length - 1;
516 }
517 struct sway_container *child = parent->children->items[child_index];
518 return seat_get_focus_inactive(seat, child);
519 }
464 520
465 struct sway_container *swayc = NULL; 521 // Surfaces
466 while (queue->length) { 522 struct sway_container *current = seat_get_focus_inactive(seat, parent);
467 swayc = queue->items[0]; 523 while (current->parent != parent) {
468 list_del(queue, 0); 524 current = current->parent;
469 if (swayc->type == C_VIEW) { 525 }
470 struct sway_view *sview = swayc->sway_view; 526
471 struct sway_container *soutput = container_parent(swayc, C_OUTPUT); 527 return container_at(current, ox, oy, surface, sx, sy);
472 struct wlr_box *output_box = 528}
473 wlr_output_layout_get_box( 529
474 root_container.sway_root->output_layout, 530/**
475 soutput->sway_output->wlr_output); 531 * container_at for a container with layout L_STACKED.
476 double ox = lx - output_box->x; 532 */
477 double oy = ly - output_box->y; 533static struct sway_container *container_at_stacked(
478 double view_sx = ox - sview->x; 534 struct sway_container *parent, double ox, double oy,
479 double view_sy = oy - sview->y; 535 struct wlr_surface **surface, double *sx, double *sy) {
480 536 // TODO
481 double _sx, _sy; 537 return NULL;
482 struct wlr_surface *_surface; 538}
483 switch (sview->type) { 539
484 case SWAY_VIEW_XWAYLAND: 540/**
485 _surface = wlr_surface_surface_at(sview->surface, 541 * container_at for a container with layout L_HORIZ or L_VERT.
486 view_sx, view_sy, &_sx, &_sy); 542 */
487 break; 543static struct sway_container *container_at_linear(struct sway_container *parent,
488 case SWAY_VIEW_XDG_SHELL_V6: 544 double ox, double oy,
489 // the top left corner of the sway container is the 545 struct wlr_surface **surface, double *sx, double *sy) {
490 // coordinate of the top left corner of the window geometry 546 for (int i = 0; i < parent->children->length; ++i) {
491 view_sx += sview->wlr_xdg_surface_v6->geometry.x; 547 struct sway_container *child = parent->children->items[i];
492 view_sy += sview->wlr_xdg_surface_v6->geometry.y; 548 struct wlr_box box = {
493 549 .x = child->x,
494 _surface = wlr_xdg_surface_v6_surface_at( 550 .y = child->y,
495 sview->wlr_xdg_surface_v6, 551 .width = child->width,
496 view_sx, view_sy, &_sx, &_sy); 552 .height = child->height,
497 break; 553 };
498 case SWAY_VIEW_XDG_SHELL: 554 if (wlr_box_contains_point(&box, ox, oy)) {
499 // the top left corner of the sway container is the 555 return container_at(child, ox, oy, surface, sx, sy);
500 // coordinate of the top left corner of the window geometry
501 view_sx += sview->wlr_xdg_surface->geometry.x;
502 view_sy += sview->wlr_xdg_surface->geometry.y;
503
504 _surface = wlr_xdg_surface_surface_at(
505 sview->wlr_xdg_surface,
506 view_sx, view_sy, &_sx, &_sy);
507 break;
508 }
509 if (_surface) {
510 *sx = _sx;
511 *sy = _sy;
512 *surface = _surface;
513 return swayc;
514 }
515 // Check the view's decorations
516 struct wlr_box swayc_box = {
517 .x = swayc->x,
518 .y = swayc->y,
519 .width = swayc->width,
520 .height = swayc->height,
521 };
522 if (wlr_box_contains_point(&swayc_box, ox, oy)) {
523 return swayc;
524 }
525 } else {
526 list_cat(queue, swayc->children);
527 } 556 }
528 } 557 }
558 return NULL;
559}
560
561struct sway_container *container_at(struct sway_container *parent,
562 double ox, double oy,
563 struct wlr_surface **surface, double *sx, double *sy) {
564 if (!sway_assert(parent->type >= C_WORKSPACE,
565 "Expected workspace or deeper")) {
566 return NULL;
567 }
568 if (parent->type == C_VIEW) {
569 return container_at_view(parent, ox, oy, surface, sx, sy);
570 }
571 if (!parent->children->length) {
572 return NULL;
573 }
574
575 switch (parent->layout) {
576 case L_HORIZ:
577 case L_VERT:
578 return container_at_linear(parent, ox, oy, surface, sx, sy);
579 case L_TABBED:
580 return container_at_tabbed(parent, ox, oy, surface, sx, sy);
581 case L_STACKED:
582 return container_at_stacked(parent, ox, oy, surface, sx, sy);
583 case L_FLOATING:
584 return NULL; // TODO
585 case L_NONE:
586 return NULL;
587 }
529 588
530 return NULL; 589 return NULL;
531} 590}
@@ -699,18 +758,82 @@ void container_calculate_title_height(struct sway_container *container) {
699 container->title_height = height; 758 container->title_height = height;
700} 759}
701 760
761/**
762 * Calculate and return the length of the concatenated child titles.
763 * An example concatenated title is: V[Terminal, Firefox]
764 * If buffer is not NULL, also populate the buffer with the concatenated title.
765 */
766static size_t concatenate_child_titles(struct sway_container *parent,
767 char *buffer) {
768 size_t len = 2; // V[
769 if (buffer) {
770 switch (parent->layout) {
771 case L_VERT:
772 strcpy(buffer, "V[");
773 break;
774 case L_HORIZ:
775 strcpy(buffer, "H[");
776 break;
777 case L_TABBED:
778 strcpy(buffer, "T[");
779 break;
780 case L_STACKED:
781 strcpy(buffer, "S[");
782 break;
783 case L_FLOATING:
784 strcpy(buffer, "F[");
785 break;
786 case L_NONE:
787 strcpy(buffer, "?[");
788 break;
789 }
790 }
791
792 for (int i = 0; i < parent->children->length; ++i) {
793 if (i != 0) {
794 len += 2;
795 if (buffer) {
796 strcat(buffer, ", ");
797 }
798 }
799 struct sway_container *child = parent->children->items[i];
800 if (child->name) {
801 len += strlen(child->name);
802 if (buffer) {
803 strcat(buffer, child->name);
804 }
805 } else {
806 len += 6;
807 if (buffer) {
808 strcat(buffer, "(null)");
809 }
810 }
811 }
812
813 len += 1;
814 if (buffer) {
815 strcat(buffer, "]");
816 }
817 return len;
818}
819
702void container_notify_child_title_changed(struct sway_container *container) { 820void container_notify_child_title_changed(struct sway_container *container) {
703 if (!container || container->type != C_CONTAINER) { 821 if (!container || container->type != C_CONTAINER) {
704 return; 822 return;
705 } 823 }
706 if (container->layout != L_TABBED && container->layout != L_STACKED) {
707 return;
708 }
709 if (container->formatted_title) { 824 if (container->formatted_title) {
710 free(container->formatted_title); 825 free(container->formatted_title);
711 } 826 }
712 // TODO: iterate children and concatenate their titles 827
713 container->formatted_title = strdup(""); 828 size_t len = concatenate_child_titles(container, NULL);
829 char *buffer = calloc(len + 1, sizeof(char));
830 if (!sway_assert(buffer, "Unable to allocate title string")) {
831 return;
832 }
833 concatenate_child_titles(container, buffer);
834
835 container->name = buffer;
836 container->formatted_title = buffer;
714 container_calculate_title_height(container); 837 container_calculate_title_height(container);
715 container_update_title_textures(container); 838 container_update_title_textures(container);
716 container_notify_child_title_changed(container->parent); 839 container_notify_child_title_changed(container->parent);
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index ec1c6fe5..f8acdf6c 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -149,6 +149,8 @@ struct sway_container *container_remove_child(struct sway_container *child) {
149 } 149 }
150 } 150 }
151 child->parent = NULL; 151 child->parent = NULL;
152 container_notify_child_title_changed(parent);
153
152 return parent; 154 return parent;
153} 155}
154 156
@@ -182,6 +184,8 @@ void container_move_to(struct sway_container *container,
182 container_sort_workspaces(new_parent); 184 container_sort_workspaces(new_parent);
183 seat_set_focus(seat, new_parent); 185 seat_set_focus(seat, new_parent);
184 } 186 }
187 container_notify_child_title_changed(old_parent);
188 container_notify_child_title_changed(new_parent);
185 if (old_parent) { 189 if (old_parent) {
186 arrange_children_of(old_parent); 190 arrange_children_of(old_parent);
187 } 191 }
@@ -234,9 +238,9 @@ static bool is_parallel(enum sway_container_layout layout,
234 enum movement_direction dir) { 238 enum movement_direction dir) {
235 switch (layout) { 239 switch (layout) {
236 case L_TABBED: 240 case L_TABBED:
237 case L_STACKED:
238 case L_HORIZ: 241 case L_HORIZ:
239 return dir == MOVE_LEFT || dir == MOVE_RIGHT; 242 return dir == MOVE_LEFT || dir == MOVE_RIGHT;
243 case L_STACKED:
240 case L_VERT: 244 case L_VERT:
241 return dir == MOVE_UP || dir == MOVE_DOWN; 245 return dir == MOVE_UP || dir == MOVE_DOWN;
242 default: 246 default:
@@ -485,6 +489,9 @@ void container_move(struct sway_container *container,
485 } 489 }
486 } 490 }
487 491
492 container_notify_child_title_changed(old_parent);
493 container_notify_child_title_changed(container->parent);
494
488 if (old_parent) { 495 if (old_parent) {
489 seat_set_focus(config->handler_context.seat, old_parent); 496 seat_set_focus(config->handler_context.seat, old_parent);
490 seat_set_focus(config->handler_context.seat, container); 497 seat_set_focus(config->handler_context.seat, container);
@@ -832,6 +839,8 @@ struct sway_container *container_split(struct sway_container *child,
832 container_add_child(cont, child); 839 container_add_child(cont, child);
833 } 840 }
834 841
842 container_notify_child_title_changed(cont);
843
835 return cont; 844 return cont;
836} 845}
837 846
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 192a73c5..636abb25 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -441,6 +441,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
441 input_manager_set_focus(input_manager, cont); 441 input_manager_set_focus(input_manager, cont);
442 442
443 view_update_title(view, false); 443 view_update_title(view, false);
444 container_notify_child_title_changed(view->swayc->parent);
444 view_execute_criteria(view); 445 view_execute_criteria(view);
445 446
446 container_damage_whole(cont); 447 container_damage_whole(cont);