From c08f9bf257c38c92a75988d89fba2d4de6bb2aea Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 19 May 2018 22:54:50 +1000 Subject: Implement tabbed layout --- sway/desktop/output.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 3 deletions(-) (limited to 'sway/desktop') 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, } } +static void render_tab(struct sway_output *output, pixman_region32_t *damage, + struct sway_container *parent, int child_index, + struct border_colors *colors, struct wlr_texture *title_texture) { + float output_scale = output->wlr_output->scale; + float color[4]; + struct wlr_box box; + bool is_first = (child_index == 0); + bool is_last = (child_index == parent->children->length - 1); + + int tab_width = parent->width / parent->children->length; + int x = parent->x + tab_width * child_index; + // Make last tab use the remaining width of the parent + if (is_last) { + tab_width = parent->width - tab_width * child_index; + } + + // Single pixel bar above title + memcpy(&color, colors->border, sizeof(float) * 4); + box.x = x; + box.y = parent->y; + box.width = tab_width; + box.height = 1; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + + // Single pixel bar below title + memcpy(&color, colors->border, sizeof(float) * 4); + box.x = x + config->border_thickness * is_first; + box.y = parent->y + config->border_thickness * 2 + config->font_height - 1; + box.width = tab_width - config->border_thickness * is_first + - config->border_thickness * is_last; + box.height = 1; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + + // Title text + size_t title_width = 0; + if (title_texture) { + struct wlr_box texture_box; + wlr_texture_get_size(title_texture, + &texture_box.width, &texture_box.height); + texture_box.x = (x + config->border_thickness) * output_scale; + texture_box.y = (parent->y + config->border_thickness) * output_scale; + + float matrix[9]; + wlr_matrix_project_box(matrix, &texture_box, + WL_OUTPUT_TRANSFORM_NORMAL, + 0.0, output->wlr_output->transform_matrix); + + int available = (tab_width - config->border_thickness * 2) + * output_scale; + if (texture_box.width > available) { + texture_box.width = available; + } + render_texture(output->wlr_output, damage, title_texture, + &texture_box, matrix, 1.0); + title_width = texture_box.width; + } + + // Title background - above the text + memcpy(&color, colors->background, sizeof(float) * 4); + box.x = x + config->border_thickness; + box.y = parent->y + 1; + box.width = tab_width - config->border_thickness * 2; + box.height = config->border_thickness - 1; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + + // Title background - below the text + box.y = (parent->y + config->border_thickness + config->font_height) + * output_scale; + render_rect(output->wlr_output, damage, &box, color); + + // Title background - left border + box.x = x; + box.y = parent->y + 1; + box.width = config->border_thickness; + box.height = config->border_thickness * 2 + + config->font_height - 1 - !is_first; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + + // Title background - right border + box.x = x + tab_width - config->border_thickness; + box.y = parent->y + 1; + box.width = config->border_thickness; + box.height = config->border_thickness * 2 + + config->font_height - 1 - !is_last; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + + // Title background - right of text + box.x = (x + config->border_thickness) * output_scale + title_width; + box.y = (parent->y + config->border_thickness) * output_scale; + box.width = (tab_width - config->border_thickness * 2) * output_scale + - title_width; + box.height = config->font_height * output_scale; + render_rect(output->wlr_output, damage, &box, color); +} + +static void render_tab_content(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + struct border_colors *colors) { + struct sway_view *view = con->sway_view; + render_view(view, output, damage); + + struct wlr_box box; + float output_scale = output->wlr_output->scale; + float color[4]; + + if (view->border_left) { + memcpy(&color, colors->child_border, sizeof(float) * 4); + color[3] *= con->alpha; + box.x = con->x; + box.y = con->y + config->border_thickness * 2 + config->font_height; + box.width = view->border_thickness; + box.height = view->height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } + + if (view->border_right) { + memcpy(&color, colors->child_border, sizeof(float) * 4); + color[3] *= con->alpha; + box.x = view->x + view->width; + box.y = con->y + config->border_thickness * 2 + config->font_height; + box.width = view->border_thickness; + box.height = view->height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } + + if (view->border_bottom) { + memcpy(&color, colors->child_border, sizeof(float) * 4); + color[3] *= con->alpha; + box.x = con->x; + box.y = view->y + view->height; + box.width = con->width; + box.height = view->border_thickness; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } +} + /** * Render a container's children using the L_TABBED layout. */ static void render_container_tabbed(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con) { - // TODO + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + if (!con->children->length) { + return; + } + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct sway_container *current = seat_get_focus_inactive(seat, con); + while (current->parent != con) { + current = current->parent; + } + struct border_colors *current_colors = NULL; + + // Render tabs + for (int i = 0; i < con->children->length; ++i) { + struct sway_container *child = con->children->items[i]; + struct border_colors *colors; + struct wlr_texture *title_texture; + + if (focus == child || parent_focused) { + colors = &config->border_colors.focused; + title_texture = child->title_focused; + } else if (child == current) { + colors = &config->border_colors.focused_inactive; + title_texture = child->title_focused_inactive; + } else { + colors = &config->border_colors.unfocused; + title_texture = child->title_unfocused; + } + + render_tab(output, damage, con, i, colors, title_texture); + + if (child == current) { + current_colors = colors; + } + } + + // Render surface and left/right/bottom borders + if (current->type == C_VIEW) { + render_tab_content(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current == focus); + } } /** @@ -628,7 +814,7 @@ static void render_container(struct sway_output *output, render_container_stacked(output, damage, con); break; case L_TABBED: - render_container_tabbed(output, damage, con); + render_container_tabbed(output, damage, con, parent_focused); break; case L_FLOATING: // TODO -- cgit v1.2.3 From efc07fb3d45e07529e3817b4a1598f2c3256d600 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 20 May 2018 09:11:55 +1000 Subject: Don't track damage for views on inactive tabs --- include/sway/input/seat.h | 6 ++++++ include/sway/tree/view.h | 6 ++++++ sway/desktop/output.c | 9 ++------- sway/input/seat.c | 12 ++++++++++++ sway/tree/container.c | 5 +---- sway/tree/view.c | 25 +++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 11 deletions(-) (limited to 'sway/desktop') 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 @@ -94,6 +94,12 @@ struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, struct sway_container *container); +/** + * Return the immediate child of container which was most recently focused. + */ +struct sway_container *seat_get_active_child(struct sway_seat *seat, + struct sway_container *container); + /** * Iterate over the focus-inactive children of the container calling the * function on each. 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); void view_update_marks_textures(struct sway_view *view); +/** + * Returns true if there's a possibility the view may be rendered on screen. + * Intended for damage tracking. + */ +bool view_is_visible(struct sway_view *view); + #endif diff --git a/sway/desktop/output.c b/sway/desktop/output.c index e39ef8db..6d5777f3 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -754,10 +754,7 @@ static void render_container_tabbed(struct sway_output *output, } struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_focus_inactive(seat, con); - while (current->parent != con) { - current = current->parent; - } + struct sway_container *current = seat_get_active_child(seat, con); struct border_colors *current_colors = NULL; // Render tabs @@ -1082,9 +1079,7 @@ static void output_damage_view(struct sway_output *output, return; } - struct sway_container *workspace = container_parent(view->swayc, - C_WORKSPACE); - if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { + if (!view_is_visible(view)) { return; } 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, return seat_get_focus_by_type(seat, container, C_TYPES); } +struct sway_container *seat_get_active_child(struct sway_seat *seat, + struct sway_container *container) { + struct sway_container *focus = seat_get_focus_inactive(seat, container); + if (!focus) { + return NULL; + } + while (focus->parent != container) { + focus = focus->parent; + } + return focus; +} + struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { if (!seat->has_focus) { return NULL; diff --git a/sway/tree/container.c b/sway/tree/container.c index 62dca487..5c1f42c2 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -522,10 +522,7 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent, } // Surfaces - struct sway_container *current = seat_get_focus_inactive(seat, parent); - while (current->parent != parent) { - current = current->parent; - } + struct sway_container *current = seat_get_active_child(seat, parent); return container_at(current, ox, oy, surface, sx, sy); } diff --git a/sway/tree/view.c b/sway/tree/view.c index 636abb25..51316507 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -865,3 +865,28 @@ void view_update_marks_textures(struct sway_view *view) { &config->border_colors.urgent); container_damage_whole(view->swayc); } + +bool view_is_visible(struct sway_view *view) { + if (!view->swayc) { + return false; + } + // Check view isn't in a tabbed or stacked container on an inactive tab + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *container = view->swayc; + while (container->type != C_WORKSPACE) { + if (container->parent->layout == L_TABBED || + container->parent->layout == L_STACKED) { + if (seat_get_active_child(seat, container->parent) != container) { + return false; + } + } + container = container->parent; + } + // Check view isn't hidden by another fullscreen view + struct sway_container *workspace = container; + if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { + return false; + } + // Check the workspace is visible + return workspace_is_visible(workspace); +} -- cgit v1.2.3 From 5ab4930185d32c5ac1adbf56f7b74525a2bab98d Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 20 May 2018 15:34:08 +1000 Subject: Fix tab border issues --- sway/desktop/output.c | 60 ++++++++++++++++++++++++++------------------------- sway/tree/view.c | 35 ++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 36 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 6d5777f3..c052cafb 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -709,37 +709,39 @@ static void render_tab_content(struct sway_output *output, float output_scale = output->wlr_output->scale; float color[4]; - if (view->border_left) { - memcpy(&color, colors->child_border, sizeof(float) * 4); - color[3] *= con->alpha; - box.x = con->x; - box.y = con->y + config->border_thickness * 2 + config->font_height; - box.width = view->border_thickness; - box.height = view->height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - } + if (view->border != B_NONE) { + if (view->border_left) { + memcpy(&color, colors->child_border, sizeof(float) * 4); + color[3] *= con->alpha; + box.x = con->x; + box.y = con->y + config->border_thickness * 2 + config->font_height; + box.width = view->border_thickness; + box.height = view->height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } - if (view->border_right) { - memcpy(&color, colors->child_border, sizeof(float) * 4); - color[3] *= con->alpha; - box.x = view->x + view->width; - box.y = con->y + config->border_thickness * 2 + config->font_height; - box.width = view->border_thickness; - box.height = view->height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - } + if (view->border_right) { + memcpy(&color, colors->child_border, sizeof(float) * 4); + color[3] *= con->alpha; + box.x = view->x + view->width; + box.y = con->y + config->border_thickness * 2 + config->font_height; + box.width = view->border_thickness; + box.height = view->height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } - if (view->border_bottom) { - memcpy(&color, colors->child_border, sizeof(float) * 4); - color[3] *= con->alpha; - box.x = con->x; - box.y = view->y + view->height; - box.width = con->width; - box.height = view->border_thickness; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); + if (view->border_bottom) { + memcpy(&color, colors->child_border, sizeof(float) * 4); + color[3] *= con->alpha; + box.x = con->x; + box.y = view->y + view->height; + box.width = con->width; + box.height = view->border_thickness; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } } } diff --git a/sway/tree/view.c b/sway/tree/view.c index 51316507..64597c02 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -167,32 +167,53 @@ void view_autoconfigure(struct sway_view *view) { double x, y, width, height; x = y = width = height = 0; + double y_offset = 0; + + // In a tabbed or stacked container, the swayc's y is the top of the title + // area. We have to offset the surface y by the height of the title bar, and + // disable any top border because we'll always have the title bar. + if (view->swayc->parent->layout == L_TABBED) { + y_offset = config->border_thickness * 2 + config->font_height; + view->border_top = 0; + } else if (view->swayc->parent->layout == L_STACKED) { + y_offset = config->border_thickness * 2 + config->font_height; + y_offset *= view->swayc->parent->children->length; + view->border_top = 0; + } + switch (view->border) { case B_NONE: x = view->swayc->x; - y = view->swayc->y; + y = view->swayc->y + y_offset; width = view->swayc->width; - height = view->swayc->height; + height = view->swayc->height - y_offset; break; case B_PIXEL: x = view->swayc->x + view->border_thickness * view->border_left; - y = view->swayc->y + view->border_thickness * view->border_top; + y = view->swayc->y + view->border_thickness * view->border_top + y_offset; width = view->swayc->width - view->border_thickness * view->border_left - view->border_thickness * view->border_right; - height = view->swayc->height + height = view->swayc->height - y_offset - view->border_thickness * view->border_top - view->border_thickness * view->border_bottom; break; case B_NORMAL: // Height is: border + title height + border + view height + border x = view->swayc->x + view->border_thickness * view->border_left; - y = view->swayc->y + config->font_height + view->border_thickness * 2; width = view->swayc->width - view->border_thickness * view->border_left - view->border_thickness * view->border_right; - height = view->swayc->height - config->font_height - - view->border_thickness * (2 + view->border_bottom); + if (y_offset) { + y = view->swayc->y + y_offset; + height = view->swayc->height - y_offset + - view->border_thickness * view->border_bottom; + } else { + y = view->swayc->y + config->font_height + view->border_thickness * 2 + + y_offset; + height = view->swayc->height - config->font_height + - view->border_thickness * (2 + view->border_bottom); + } break; } -- cgit v1.2.3 From 90607dc32970a422f375234539cd6d6182ee89d1 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 20 May 2018 23:16:51 +1000 Subject: Add left/right borders to tabs --- sway/desktop/output.c | 53 +++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index c052cafb..829029a7 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -605,13 +605,11 @@ static void render_tab(struct sway_output *output, pixman_region32_t *damage, float output_scale = output->wlr_output->scale; float color[4]; struct wlr_box box; - bool is_first = (child_index == 0); - bool is_last = (child_index == parent->children->length - 1); int tab_width = parent->width / parent->children->length; int x = parent->x + tab_width * child_index; // Make last tab use the remaining width of the parent - if (is_last) { + if (child_index == parent->children->length - 1) { tab_width = parent->width - tab_width * child_index; } @@ -625,22 +623,29 @@ static void render_tab(struct sway_output *output, pixman_region32_t *damage, render_rect(output->wlr_output, damage, &box, color); // Single pixel bar below title - memcpy(&color, colors->border, sizeof(float) * 4); - box.x = x + config->border_thickness * is_first; - box.y = parent->y + config->border_thickness * 2 + config->font_height - 1; - box.width = tab_width - config->border_thickness * is_first - - config->border_thickness * is_last; - box.height = 1; + box.y = (parent->y + config->border_thickness * 2 + config->font_height - 1) + * output_scale; + render_rect(output->wlr_output, damage, &box, color); + + // Single pixel bar on left + box.x = x; + box.y = parent->y + 1; + box.width = 1; + box.height = config->border_thickness * 2 + config->font_height - 2; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); + // Single pixel bar on right + box.x = (x + tab_width - 1) * output_scale; + render_rect(output->wlr_output, damage, &box, color); + // Title text size_t title_width = 0; if (title_texture) { struct wlr_box texture_box; wlr_texture_get_size(title_texture, &texture_box.width, &texture_box.height); - texture_box.x = (x + config->border_thickness) * output_scale; + texture_box.x = (x + 1 + config->border_thickness) * output_scale; texture_box.y = (parent->y + config->border_thickness) * output_scale; float matrix[9]; @@ -648,7 +653,7 @@ static void render_tab(struct sway_output *output, pixman_region32_t *damage, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, output->wlr_output->transform_matrix); - int available = (tab_width - config->border_thickness * 2) + int available = (tab_width - config->border_thickness * 2 - 2) * output_scale; if (texture_box.width > available) { texture_box.width = available; @@ -660,9 +665,9 @@ static void render_tab(struct sway_output *output, pixman_region32_t *damage, // Title background - above the text memcpy(&color, colors->background, sizeof(float) * 4); - box.x = x + config->border_thickness; + box.x = x + 1; box.y = parent->y + 1; - box.width = tab_width - config->border_thickness * 2; + box.width = tab_width - 2; box.height = config->border_thickness - 1; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); @@ -672,28 +677,18 @@ static void render_tab(struct sway_output *output, pixman_region32_t *damage, * output_scale; render_rect(output->wlr_output, damage, &box, color); - // Title background - left border - box.x = x; - box.y = parent->y + 1; - box.width = config->border_thickness; - box.height = config->border_thickness * 2 - + config->font_height - 1 - !is_first; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - - // Title background - right border - box.x = x + tab_width - config->border_thickness; - box.y = parent->y + 1; + // Title background - left of text + box.x = x + 1; + box.y = parent->y + config->border_thickness; box.width = config->border_thickness; - box.height = config->border_thickness * 2 - + config->font_height - 1 - !is_last; + box.height = config->font_height; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); // Title background - right of text - box.x = (x + config->border_thickness) * output_scale + title_width; + box.x = (x + 1 + config->border_thickness) * output_scale + title_width; box.y = (parent->y + config->border_thickness) * output_scale; - box.width = (tab_width - config->border_thickness * 2) * output_scale + box.width = (tab_width - config->border_thickness - 2) * output_scale - title_width; box.height = config->font_height * output_scale; render_rect(output->wlr_output, damage, &box, color); -- cgit v1.2.3 From 048b29527b8b0ec9c6cd9d0439b74bf73f4f6e2d Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 21 May 2018 08:29:52 +1000 Subject: Pre-multiply alpha for tab decorations --- sway/desktop/output.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 829029a7..551e96fc 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -602,6 +602,7 @@ static void render_container_simple(struct sway_output *output, static void render_tab(struct sway_output *output, pixman_region32_t *damage, struct sway_container *parent, int child_index, struct border_colors *colors, struct wlr_texture *title_texture) { + struct sway_container *con = parent->children->items[child_index]; float output_scale = output->wlr_output->scale; float color[4]; struct wlr_box box; @@ -615,6 +616,7 @@ static void render_tab(struct sway_output *output, pixman_region32_t *damage, // Single pixel bar above title memcpy(&color, colors->border, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); box.x = x; box.y = parent->y; box.width = tab_width; @@ -665,6 +667,7 @@ static void render_tab(struct sway_output *output, pixman_region32_t *damage, // Title background - above the text memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); box.x = x + 1; box.y = parent->y + 1; box.width = tab_width - 2; @@ -707,7 +710,7 @@ static void render_tab_content(struct sway_output *output, if (view->border != B_NONE) { if (view->border_left) { memcpy(&color, colors->child_border, sizeof(float) * 4); - color[3] *= con->alpha; + premultiply_alpha(color, con->alpha); box.x = con->x; box.y = con->y + config->border_thickness * 2 + config->font_height; box.width = view->border_thickness; @@ -718,7 +721,7 @@ static void render_tab_content(struct sway_output *output, if (view->border_right) { memcpy(&color, colors->child_border, sizeof(float) * 4); - color[3] *= con->alpha; + premultiply_alpha(color, con->alpha); box.x = view->x + view->width; box.y = con->y + config->border_thickness * 2 + config->font_height; box.width = view->border_thickness; @@ -729,7 +732,7 @@ static void render_tab_content(struct sway_output *output, if (view->border_bottom) { memcpy(&color, colors->child_border, sizeof(float) * 4); - color[3] *= con->alpha; + premultiply_alpha(color, con->alpha); box.x = con->x; box.y = view->y + view->height; box.width = con->width; -- cgit v1.2.3