diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-05-19 22:54:50 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-05-21 20:16:56 +1000 |
commit | c08f9bf257c38c92a75988d89fba2d4de6bb2aea (patch) | |
tree | 76ea44c5548301ff4892c44838b783eeeb569c62 | |
parent | Merge pull request #2011 from RyanDwyer/fix-hide-edge-border-bottom (diff) | |
download | sway-c08f9bf257c38c92a75988d89fba2d4de6bb2aea.tar.gz sway-c08f9bf257c38c92a75988d89fba2d4de6bb2aea.tar.zst sway-c08f9bf257c38c92a75988d89fba2d4de6bb2aea.zip |
Implement tabbed layout
-rw-r--r-- | include/sway/tree/container.h | 2 | ||||
-rw-r--r-- | sway/commands/layout.c | 2 | ||||
-rw-r--r-- | sway/desktop/output.c | 192 | ||||
-rw-r--r-- | sway/input/cursor.c | 2 | ||||
-rw-r--r-- | sway/tree/arrange.c | 44 | ||||
-rw-r--r-- | sway/tree/container.c | 267 | ||||
-rw-r--r-- | sway/tree/layout.c | 11 | ||||
-rw-r--r-- | sway/tree/view.c | 1 |
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 | */ |
164 | struct sway_container *container_at(struct sway_container *container, | 164 | struct 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 | ||
602 | static 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 | |||
702 | static 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 | */ |
605 | static void render_container_tabbed(struct sway_output *output, | 749 | static 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 | |||
176 | static 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 | ||
162 | void arrange_children_of(struct sway_container *parent) { | 189 | void 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 | ||
455 | struct sway_container *container_at(struct sway_container *parent, | 455 | static 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 | */ | ||
501 | static 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; | 533 | static 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; | 543 | static 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 | |||
561 | struct 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 | */ | ||
766 | static 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 | |||
702 | void container_notify_child_title_changed(struct sway_container *container) { | 820 | void 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); |