diff options
-rw-r--r-- | include/sway/input/seat.h | 6 | ||||
-rw-r--r-- | include/sway/tree/container.h | 2 | ||||
-rw-r--r-- | include/sway/tree/view.h | 6 | ||||
-rw-r--r-- | sway/commands/layout.c | 2 | ||||
-rw-r--r-- | sway/desktop/output.c | 193 | ||||
-rw-r--r-- | sway/input/cursor.c | 2 | ||||
-rw-r--r-- | sway/input/seat.c | 12 | ||||
-rw-r--r-- | sway/tree/arrange.c | 44 | ||||
-rw-r--r-- | sway/tree/container.c | 276 | ||||
-rw-r--r-- | sway/tree/layout.c | 11 | ||||
-rw-r--r-- | sway/tree/view.c | 61 |
11 files changed, 520 insertions, 95 deletions
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index ff76841e..2e4da438 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -95,6 +95,12 @@ struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, | |||
95 | struct sway_container *container); | 95 | struct sway_container *container); |
96 | 96 | ||
97 | /** | 97 | /** |
98 | * Return the immediate child of container which was most recently focused. | ||
99 | */ | ||
100 | struct sway_container *seat_get_active_child(struct sway_seat *seat, | ||
101 | struct sway_container *container); | ||
102 | |||
103 | /** | ||
98 | * Iterate over the focus-inactive children of the container calling the | 104 | * Iterate over the focus-inactive children of the container calling the |
99 | * function on each. | 105 | * function on each. |
100 | */ | 106 | */ |
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/include/sway/tree/view.h b/include/sway/tree/view.h index 951912d0..0fb8f1b3 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -274,4 +274,10 @@ bool view_has_mark(struct sway_view *view, char *mark); | |||
274 | 274 | ||
275 | void view_update_marks_textures(struct sway_view *view); | 275 | void view_update_marks_textures(struct sway_view *view); |
276 | 276 | ||
277 | /** | ||
278 | * Returns true if there's a possibility the view may be rendered on screen. | ||
279 | * Intended for damage tracking. | ||
280 | */ | ||
281 | bool view_is_visible(struct sway_view *view); | ||
282 | |||
277 | #endif | 283 | #endif |
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..551e96fc 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -599,12 +599,195 @@ 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 | struct sway_container *con = parent->children->items[child_index]; | ||
606 | float output_scale = output->wlr_output->scale; | ||
607 | float color[4]; | ||
608 | struct wlr_box box; | ||
609 | |||
610 | int tab_width = parent->width / parent->children->length; | ||
611 | int x = parent->x + tab_width * child_index; | ||
612 | // Make last tab use the remaining width of the parent | ||
613 | if (child_index == parent->children->length - 1) { | ||
614 | tab_width = parent->width - tab_width * child_index; | ||
615 | } | ||
616 | |||
617 | // Single pixel bar above title | ||
618 | memcpy(&color, colors->border, sizeof(float) * 4); | ||
619 | premultiply_alpha(color, con->alpha); | ||
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 | box.y = (parent->y + config->border_thickness * 2 + config->font_height - 1) | ||
629 | * output_scale; | ||
630 | render_rect(output->wlr_output, damage, &box, color); | ||
631 | |||
632 | // Single pixel bar on left | ||
633 | box.x = x; | ||
634 | box.y = parent->y + 1; | ||
635 | box.width = 1; | ||
636 | box.height = config->border_thickness * 2 + config->font_height - 2; | ||
637 | scale_box(&box, output_scale); | ||
638 | render_rect(output->wlr_output, damage, &box, color); | ||
639 | |||
640 | // Single pixel bar on right | ||
641 | box.x = (x + tab_width - 1) * output_scale; | ||
642 | render_rect(output->wlr_output, damage, &box, color); | ||
643 | |||
644 | // Title text | ||
645 | size_t title_width = 0; | ||
646 | if (title_texture) { | ||
647 | struct wlr_box texture_box; | ||
648 | wlr_texture_get_size(title_texture, | ||
649 | &texture_box.width, &texture_box.height); | ||
650 | texture_box.x = (x + 1 + config->border_thickness) * output_scale; | ||
651 | texture_box.y = (parent->y + config->border_thickness) * output_scale; | ||
652 | |||
653 | float matrix[9]; | ||
654 | wlr_matrix_project_box(matrix, &texture_box, | ||
655 | WL_OUTPUT_TRANSFORM_NORMAL, | ||
656 | 0.0, output->wlr_output->transform_matrix); | ||
657 | |||
658 | int available = (tab_width - config->border_thickness * 2 - 2) | ||
659 | * output_scale; | ||
660 | if (texture_box.width > available) { | ||
661 | texture_box.width = available; | ||
662 | } | ||
663 | render_texture(output->wlr_output, damage, title_texture, | ||
664 | &texture_box, matrix, 1.0); | ||
665 | title_width = texture_box.width; | ||
666 | } | ||
667 | |||
668 | // Title background - above the text | ||
669 | memcpy(&color, colors->background, sizeof(float) * 4); | ||
670 | premultiply_alpha(color, con->alpha); | ||
671 | box.x = x + 1; | ||
672 | box.y = parent->y + 1; | ||
673 | box.width = tab_width - 2; | ||
674 | box.height = config->border_thickness - 1; | ||
675 | scale_box(&box, output_scale); | ||
676 | render_rect(output->wlr_output, damage, &box, color); | ||
677 | |||
678 | // Title background - below the text | ||
679 | box.y = (parent->y + config->border_thickness + config->font_height) | ||
680 | * output_scale; | ||
681 | render_rect(output->wlr_output, damage, &box, color); | ||
682 | |||
683 | // Title background - left of text | ||
684 | box.x = x + 1; | ||
685 | box.y = parent->y + config->border_thickness; | ||
686 | box.width = config->border_thickness; | ||
687 | box.height = config->font_height; | ||
688 | scale_box(&box, output_scale); | ||
689 | render_rect(output->wlr_output, damage, &box, color); | ||
690 | |||
691 | // Title background - right of text | ||
692 | box.x = (x + 1 + config->border_thickness) * output_scale + title_width; | ||
693 | box.y = (parent->y + config->border_thickness) * output_scale; | ||
694 | box.width = (tab_width - config->border_thickness - 2) * output_scale | ||
695 | - title_width; | ||
696 | box.height = config->font_height * output_scale; | ||
697 | render_rect(output->wlr_output, damage, &box, color); | ||
698 | } | ||
699 | |||
700 | static void render_tab_content(struct sway_output *output, | ||
701 | pixman_region32_t *damage, struct sway_container *con, | ||
702 | struct border_colors *colors) { | ||
703 | struct sway_view *view = con->sway_view; | ||
704 | render_view(view, output, damage); | ||
705 | |||
706 | struct wlr_box box; | ||
707 | float output_scale = output->wlr_output->scale; | ||
708 | float color[4]; | ||
709 | |||
710 | if (view->border != B_NONE) { | ||
711 | if (view->border_left) { | ||
712 | memcpy(&color, colors->child_border, sizeof(float) * 4); | ||
713 | premultiply_alpha(color, con->alpha); | ||
714 | box.x = con->x; | ||
715 | box.y = con->y + config->border_thickness * 2 + config->font_height; | ||
716 | box.width = view->border_thickness; | ||
717 | box.height = view->height; | ||
718 | scale_box(&box, output_scale); | ||
719 | render_rect(output->wlr_output, damage, &box, color); | ||
720 | } | ||
721 | |||
722 | if (view->border_right) { | ||
723 | memcpy(&color, colors->child_border, sizeof(float) * 4); | ||
724 | premultiply_alpha(color, con->alpha); | ||
725 | box.x = view->x + view->width; | ||
726 | box.y = con->y + config->border_thickness * 2 + config->font_height; | ||
727 | box.width = view->border_thickness; | ||
728 | box.height = view->height; | ||
729 | scale_box(&box, output_scale); | ||
730 | render_rect(output->wlr_output, damage, &box, color); | ||
731 | } | ||
732 | |||
733 | if (view->border_bottom) { | ||
734 | memcpy(&color, colors->child_border, sizeof(float) * 4); | ||
735 | premultiply_alpha(color, con->alpha); | ||
736 | box.x = con->x; | ||
737 | box.y = view->y + view->height; | ||
738 | box.width = con->width; | ||
739 | box.height = view->border_thickness; | ||
740 | scale_box(&box, output_scale); | ||
741 | render_rect(output->wlr_output, damage, &box, color); | ||
742 | } | ||
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_active_child(seat, con); | ||
758 | struct border_colors *current_colors = NULL; | ||
759 | |||
760 | // Render tabs | ||
761 | for (int i = 0; i < con->children->length; ++i) { | ||
762 | struct sway_container *child = con->children->items[i]; | ||
763 | struct border_colors *colors; | ||
764 | struct wlr_texture *title_texture; | ||
765 | |||
766 | if (focus == child || parent_focused) { | ||
767 | colors = &config->border_colors.focused; | ||
768 | title_texture = child->title_focused; | ||
769 | } else if (child == current) { | ||
770 | colors = &config->border_colors.focused_inactive; | ||
771 | title_texture = child->title_focused_inactive; | ||
772 | } else { | ||
773 | colors = &config->border_colors.unfocused; | ||
774 | title_texture = child->title_unfocused; | ||
775 | } | ||
776 | |||
777 | render_tab(output, damage, con, i, colors, title_texture); | ||
778 | |||
779 | if (child == current) { | ||
780 | current_colors = colors; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | // Render surface and left/right/bottom borders | ||
785 | if (current->type == C_VIEW) { | ||
786 | render_tab_content(output, damage, current, current_colors); | ||
787 | } else { | ||
788 | render_container(output, damage, current, | ||
789 | parent_focused || current == focus); | ||
790 | } | ||
608 | } | 791 | } |
609 | 792 | ||
610 | /** | 793 | /** |
@@ -628,7 +811,7 @@ static void render_container(struct sway_output *output, | |||
628 | render_container_stacked(output, damage, con); | 811 | render_container_stacked(output, damage, con); |
629 | break; | 812 | break; |
630 | case L_TABBED: | 813 | case L_TABBED: |
631 | render_container_tabbed(output, damage, con); | 814 | render_container_tabbed(output, damage, con, parent_focused); |
632 | break; | 815 | break; |
633 | case L_FLOATING: | 816 | case L_FLOATING: |
634 | // TODO | 817 | // TODO |
@@ -896,9 +1079,7 @@ static void output_damage_view(struct sway_output *output, | |||
896 | return; | 1079 | return; |
897 | } | 1080 | } |
898 | 1081 | ||
899 | struct sway_container *workspace = container_parent(view->swayc, | 1082 | if (!view_is_visible(view)) { |
900 | C_WORKSPACE); | ||
901 | if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { | ||
902 | return; | 1083 | return; |
903 | } | 1084 | } |
904 | 1085 | ||
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/input/seat.c b/sway/input/seat.c index 7d541f6e..7a3e928a 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -718,6 +718,18 @@ struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | |||
718 | return seat_get_focus_by_type(seat, container, C_TYPES); | 718 | return seat_get_focus_by_type(seat, container, C_TYPES); |
719 | } | 719 | } |
720 | 720 | ||
721 | struct sway_container *seat_get_active_child(struct sway_seat *seat, | ||
722 | struct sway_container *container) { | ||
723 | struct sway_container *focus = seat_get_focus_inactive(seat, container); | ||
724 | if (!focus) { | ||
725 | return NULL; | ||
726 | } | ||
727 | while (focus->parent != container) { | ||
728 | focus = focus->parent; | ||
729 | } | ||
730 | return focus; | ||
731 | } | ||
732 | |||
721 | struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { | 733 | struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { |
722 | if (!seat->has_focus) { | 734 | if (!seat->has_focus) { |
723 | return NULL; | 735 | return NULL; |
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..5d88325f 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -452,79 +452,138 @@ 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 | if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { |
459 | if (!queue) { | ||
460 | return NULL; | 459 | return NULL; |
461 | } | 460 | } |
461 | struct sway_view *sview = swayc->sway_view; | ||
462 | double view_sx = ox - sview->x; | ||
463 | double view_sy = oy - sview->y; | ||
462 | 464 | ||
463 | list_add(queue, parent); | 465 | double _sx, _sy; |
466 | struct wlr_surface *_surface = NULL; | ||
467 | switch (sview->type) { | ||
468 | case SWAY_VIEW_XWAYLAND: | ||
469 | _surface = wlr_surface_surface_at(sview->surface, | ||
470 | view_sx, view_sy, &_sx, &_sy); | ||
471 | break; | ||
472 | case SWAY_VIEW_XDG_SHELL_V6: | ||
473 | // the top left corner of the sway container is the | ||
474 | // coordinate of the top left corner of the window geometry | ||
475 | view_sx += sview->wlr_xdg_surface_v6->geometry.x; | ||
476 | view_sy += sview->wlr_xdg_surface_v6->geometry.y; | ||
477 | |||
478 | _surface = wlr_xdg_surface_v6_surface_at( | ||
479 | sview->wlr_xdg_surface_v6, | ||
480 | view_sx, view_sy, &_sx, &_sy); | ||
481 | break; | ||
482 | case SWAY_VIEW_XDG_SHELL: | ||
483 | // the top left corner of the sway container is the | ||
484 | // coordinate of the top left corner of the window geometry | ||
485 | view_sx += sview->wlr_xdg_surface->geometry.x; | ||
486 | view_sy += sview->wlr_xdg_surface->geometry.y; | ||
487 | |||
488 | _surface = wlr_xdg_surface_surface_at( | ||
489 | sview->wlr_xdg_surface, | ||
490 | view_sx, view_sy, &_sx, &_sy); | ||
491 | break; | ||
492 | } | ||
493 | if (_surface) { | ||
494 | *sx = _sx; | ||
495 | *sy = _sy; | ||
496 | *surface = _surface; | ||
497 | } | ||
498 | return swayc; | ||
499 | } | ||
464 | 500 | ||
465 | struct sway_container *swayc = NULL; | 501 | /** |
466 | while (queue->length) { | 502 | * container_at for a container with layout L_TABBED. |
467 | swayc = queue->items[0]; | 503 | */ |
468 | list_del(queue, 0); | 504 | static struct sway_container *container_at_tabbed(struct sway_container *parent, |
469 | if (swayc->type == C_VIEW) { | 505 | double ox, double oy, |
470 | struct sway_view *sview = swayc->sway_view; | 506 | struct wlr_surface **surface, double *sx, double *sy) { |
471 | struct sway_container *soutput = container_parent(swayc, C_OUTPUT); | 507 | if (oy < parent->y || oy > parent->y + parent->height) { |
472 | struct wlr_box *output_box = | 508 | return NULL; |
473 | wlr_output_layout_get_box( | 509 | } |
474 | root_container.sway_root->output_layout, | 510 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
475 | soutput->sway_output->wlr_output); | 511 | |
476 | double ox = lx - output_box->x; | 512 | // Tab titles |
477 | double oy = ly - output_box->y; | 513 | int title_height = config->border_thickness * 2 + config->font_height; |
478 | double view_sx = ox - sview->x; | 514 | if (oy < parent->y + title_height) { |
479 | double view_sy = oy - sview->y; | 515 | int tab_width = parent->width / parent->children->length; |
480 | 516 | int child_index = (ox - parent->x) / tab_width; | |
481 | double _sx, _sy; | 517 | if (child_index >= parent->children->length) { |
482 | struct wlr_surface *_surface; | 518 | child_index = parent->children->length - 1; |
483 | switch (sview->type) { | ||
484 | case SWAY_VIEW_XWAYLAND: | ||
485 | _surface = wlr_surface_surface_at(sview->surface, | ||
486 | view_sx, view_sy, &_sx, &_sy); | ||
487 | break; | ||
488 | case SWAY_VIEW_XDG_SHELL_V6: | ||
489 | // the top left corner of the sway container is the | ||
490 | // coordinate of the top left corner of the window geometry | ||
491 | view_sx += sview->wlr_xdg_surface_v6->geometry.x; | ||
492 | view_sy += sview->wlr_xdg_surface_v6->geometry.y; | ||
493 | |||
494 | _surface = wlr_xdg_surface_v6_surface_at( | ||
495 | sview->wlr_xdg_surface_v6, | ||
496 | view_sx, view_sy, &_sx, &_sy); | ||
497 | break; | ||
498 | case SWAY_VIEW_XDG_SHELL: | ||
499 | // the top left corner of the sway container is the | ||
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 | } | 519 | } |
520 | struct sway_container *child = parent->children->items[child_index]; | ||
521 | return seat_get_focus_inactive(seat, child); | ||
522 | } | ||
523 | |||
524 | // Surfaces | ||
525 | struct sway_container *current = seat_get_active_child(seat, parent); | ||
526 | |||
527 | return container_at(current, ox, oy, surface, sx, sy); | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * container_at for a container with layout L_STACKED. | ||
532 | */ | ||
533 | static struct sway_container *container_at_stacked( | ||
534 | struct sway_container *parent, double ox, double oy, | ||
535 | struct wlr_surface **surface, double *sx, double *sy) { | ||
536 | // TODO | ||
537 | return NULL; | ||
538 | } | ||
539 | |||
540 | /** | ||
541 | * container_at for a container with layout L_HORIZ or L_VERT. | ||
542 | */ | ||
543 | static struct sway_container *container_at_linear(struct sway_container *parent, | ||
544 | double ox, double oy, | ||
545 | struct wlr_surface **surface, double *sx, double *sy) { | ||
546 | for (int i = 0; i < parent->children->length; ++i) { | ||
547 | struct sway_container *child = parent->children->items[i]; | ||
548 | struct wlr_box box = { | ||
549 | .x = child->x, | ||
550 | .y = child->y, | ||
551 | .width = child->width, | ||
552 | .height = child->height, | ||
553 | }; | ||
554 | if (wlr_box_contains_point(&box, ox, oy)) { | ||
555 | return container_at(child, ox, oy, surface, sx, sy); | ||
556 | } | ||
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; | ||
528 | } | 587 | } |
529 | 588 | ||
530 | return NULL; | 589 | return NULL; |
@@ -699,18 +758,91 @@ 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, "D["); | ||
788 | break; | ||
789 | } | ||
790 | } | ||
791 | |||
792 | for (int i = 0; i < parent->children->length; ++i) { | ||
793 | if (i != 0) { | ||
794 | len += 1; | ||
795 | if (buffer) { | ||
796 | strcat(buffer, " "); | ||
797 | } | ||
798 | } | ||
799 | struct sway_container *child = parent->children->items[i]; | ||
800 | const char *identifier = NULL; | ||
801 | if (child->type == C_VIEW) { | ||
802 | identifier = view_get_class(child->sway_view); | ||
803 | if (!identifier) { | ||
804 | identifier = view_get_app_id(child->sway_view); | ||
805 | } | ||
806 | } else { | ||
807 | identifier = child->name; | ||
808 | } | ||
809 | if (identifier) { | ||
810 | len += strlen(identifier); | ||
811 | if (buffer) { | ||
812 | strcat(buffer, identifier); | ||
813 | } | ||
814 | } else { | ||
815 | len += 6; | ||
816 | if (buffer) { | ||
817 | strcat(buffer, "(null)"); | ||
818 | } | ||
819 | } | ||
820 | } | ||
821 | |||
822 | len += 1; | ||
823 | if (buffer) { | ||
824 | strcat(buffer, "]"); | ||
825 | } | ||
826 | return len; | ||
827 | } | ||
828 | |||
702 | void container_notify_child_title_changed(struct sway_container *container) { | 829 | void container_notify_child_title_changed(struct sway_container *container) { |
703 | if (!container || container->type != C_CONTAINER) { | 830 | if (!container || container->type != C_CONTAINER) { |
704 | return; | 831 | return; |
705 | } | 832 | } |
706 | if (container->layout != L_TABBED && container->layout != L_STACKED) { | ||
707 | return; | ||
708 | } | ||
709 | if (container->formatted_title) { | 833 | if (container->formatted_title) { |
710 | free(container->formatted_title); | 834 | free(container->formatted_title); |
711 | } | 835 | } |
712 | // TODO: iterate children and concatenate their titles | 836 | |
713 | container->formatted_title = strdup(""); | 837 | size_t len = concatenate_child_titles(container, NULL); |
838 | char *buffer = calloc(len + 1, sizeof(char)); | ||
839 | if (!sway_assert(buffer, "Unable to allocate title string")) { | ||
840 | return; | ||
841 | } | ||
842 | concatenate_child_titles(container, buffer); | ||
843 | |||
844 | container->name = buffer; | ||
845 | container->formatted_title = buffer; | ||
714 | container_calculate_title_height(container); | 846 | container_calculate_title_height(container); |
715 | container_update_title_textures(container); | 847 | container_update_title_textures(container); |
716 | container_notify_child_title_changed(container->parent); | 848 | 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..64597c02 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -167,32 +167,53 @@ void view_autoconfigure(struct sway_view *view) { | |||
167 | 167 | ||
168 | double x, y, width, height; | 168 | double x, y, width, height; |
169 | x = y = width = height = 0; | 169 | x = y = width = height = 0; |
170 | double y_offset = 0; | ||
171 | |||
172 | // In a tabbed or stacked container, the swayc's y is the top of the title | ||
173 | // area. We have to offset the surface y by the height of the title bar, and | ||
174 | // disable any top border because we'll always have the title bar. | ||
175 | if (view->swayc->parent->layout == L_TABBED) { | ||
176 | y_offset = config->border_thickness * 2 + config->font_height; | ||
177 | view->border_top = 0; | ||
178 | } else if (view->swayc->parent->layout == L_STACKED) { | ||
179 | y_offset = config->border_thickness * 2 + config->font_height; | ||
180 | y_offset *= view->swayc->parent->children->length; | ||
181 | view->border_top = 0; | ||
182 | } | ||
183 | |||
170 | switch (view->border) { | 184 | switch (view->border) { |
171 | case B_NONE: | 185 | case B_NONE: |
172 | x = view->swayc->x; | 186 | x = view->swayc->x; |
173 | y = view->swayc->y; | 187 | y = view->swayc->y + y_offset; |
174 | width = view->swayc->width; | 188 | width = view->swayc->width; |
175 | height = view->swayc->height; | 189 | height = view->swayc->height - y_offset; |
176 | break; | 190 | break; |
177 | case B_PIXEL: | 191 | case B_PIXEL: |
178 | x = view->swayc->x + view->border_thickness * view->border_left; | 192 | x = view->swayc->x + view->border_thickness * view->border_left; |
179 | y = view->swayc->y + view->border_thickness * view->border_top; | 193 | y = view->swayc->y + view->border_thickness * view->border_top + y_offset; |
180 | width = view->swayc->width | 194 | width = view->swayc->width |
181 | - view->border_thickness * view->border_left | 195 | - view->border_thickness * view->border_left |
182 | - view->border_thickness * view->border_right; | 196 | - view->border_thickness * view->border_right; |
183 | height = view->swayc->height | 197 | height = view->swayc->height - y_offset |
184 | - view->border_thickness * view->border_top | 198 | - view->border_thickness * view->border_top |
185 | - view->border_thickness * view->border_bottom; | 199 | - view->border_thickness * view->border_bottom; |
186 | break; | 200 | break; |
187 | case B_NORMAL: | 201 | case B_NORMAL: |
188 | // Height is: border + title height + border + view height + border | 202 | // Height is: border + title height + border + view height + border |
189 | x = view->swayc->x + view->border_thickness * view->border_left; | 203 | x = view->swayc->x + view->border_thickness * view->border_left; |
190 | y = view->swayc->y + config->font_height + view->border_thickness * 2; | ||
191 | width = view->swayc->width | 204 | width = view->swayc->width |
192 | - view->border_thickness * view->border_left | 205 | - view->border_thickness * view->border_left |
193 | - view->border_thickness * view->border_right; | 206 | - view->border_thickness * view->border_right; |
194 | height = view->swayc->height - config->font_height | 207 | if (y_offset) { |
195 | - view->border_thickness * (2 + view->border_bottom); | 208 | y = view->swayc->y + y_offset; |
209 | height = view->swayc->height - y_offset | ||
210 | - view->border_thickness * view->border_bottom; | ||
211 | } else { | ||
212 | y = view->swayc->y + config->font_height + view->border_thickness * 2 | ||
213 | + y_offset; | ||
214 | height = view->swayc->height - config->font_height | ||
215 | - view->border_thickness * (2 + view->border_bottom); | ||
216 | } | ||
196 | break; | 217 | break; |
197 | } | 218 | } |
198 | 219 | ||
@@ -441,6 +462,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
441 | input_manager_set_focus(input_manager, cont); | 462 | input_manager_set_focus(input_manager, cont); |
442 | 463 | ||
443 | view_update_title(view, false); | 464 | view_update_title(view, false); |
465 | container_notify_child_title_changed(view->swayc->parent); | ||
444 | view_execute_criteria(view); | 466 | view_execute_criteria(view); |
445 | 467 | ||
446 | container_damage_whole(cont); | 468 | container_damage_whole(cont); |
@@ -864,3 +886,28 @@ void view_update_marks_textures(struct sway_view *view) { | |||
864 | &config->border_colors.urgent); | 886 | &config->border_colors.urgent); |
865 | container_damage_whole(view->swayc); | 887 | container_damage_whole(view->swayc); |
866 | } | 888 | } |
889 | |||
890 | bool view_is_visible(struct sway_view *view) { | ||
891 | if (!view->swayc) { | ||
892 | return false; | ||
893 | } | ||
894 | // Check view isn't in a tabbed or stacked container on an inactive tab | ||
895 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
896 | struct sway_container *container = view->swayc; | ||
897 | while (container->type != C_WORKSPACE) { | ||
898 | if (container->parent->layout == L_TABBED || | ||
899 | container->parent->layout == L_STACKED) { | ||
900 | if (seat_get_active_child(seat, container->parent) != container) { | ||
901 | return false; | ||
902 | } | ||
903 | } | ||
904 | container = container->parent; | ||
905 | } | ||
906 | // Check view isn't hidden by another fullscreen view | ||
907 | struct sway_container *workspace = container; | ||
908 | if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { | ||
909 | return false; | ||
910 | } | ||
911 | // Check the workspace is visible | ||
912 | return workspace_is_visible(workspace); | ||
913 | } | ||