From f5b9815128b6c000bb5d47c339480fa481a5e99d Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 26 Aug 2018 10:16:49 +1000 Subject: [PATCH 1/2] Prepare arrange code for type safe arguments This commit changes the arrange code in a way that will support type safe arguments. The arrange_output et al functions are now public, however I opted not to use them directly yet. I've kept the generic arrange_windows there for convenience until type safety is fully implemented. This means this patch has much less risk of breaking things as it would otherwise. To be type safe, arrange_children_of cannot exist in its previous form because the thing passed to it could be either a workspace or a container. So it's now renamed to arrange_children and accepts a list_t, as well as the parent layout and parent's box. There was some code which checked the grandparent's layout to see if it was tabbed or stacked and adjusted the Y offset of the grandchild accordingly. Accessing the grandparent layout isn't easy when using type safe arguments, and it seemed odd to even need to do this. I determined that this was needed because a child of a tabbed container would have a swayc Y matching the top of the tab bar. I've changed this so a child of a tabbed container will have a swayc Y matching the bottom of the tab bar, which means we don't need to access the grandparent layout. Some tweaks to the rendering and autoconfigure code have been made to implement this, and the container_at code appears to work without needing any changes. arrange_children_of (now arrange_children) would check if the parent had gaps and would copy them to the child, effectively making the workspace's gaps recurse into all children. We can't do this any more without passing has_gaps, gaps_inner and gaps_outer as arguments to arrange_children, so I've changed the add_gaps function to retrieve it from the workspace directly. apply_tabbed_or_stacked_layout has been split into two functions, as it had different logic depending on the layout. Lastly, arrange.h had an unnecessary include of transaction.h. I've removed it, which means I've had to add it to several other files. --- include/sway/tree/arrange.h | 12 ++- sway/desktop/output.c | 1 + sway/desktop/render.c | 8 +- sway/desktop/xdg_shell.c | 1 + sway/desktop/xdg_shell_v6.c | 1 + sway/tree/arrange.c | 197 ++++++++++++++++-------------------- sway/tree/container.c | 4 +- sway/tree/root.c | 1 + sway/tree/view.c | 35 +++---- 9 files changed, 123 insertions(+), 137 deletions(-) diff --git a/include/sway/tree/arrange.h b/include/sway/tree/arrange.h index 346103d3..f47e8db5 100644 --- a/include/sway/tree/arrange.h +++ b/include/sway/tree/arrange.h @@ -1,12 +1,16 @@ #ifndef _SWAY_ARRANGE_H #define _SWAY_ARRANGE_H -#include "sway/desktop/transaction.h" struct sway_container; -/** - * Arrange layout for all the children of the given container. - */ +void arrange_container(struct sway_container *container); + +void arrange_workspace(struct sway_container *workspace); + +void arrange_output(struct sway_container *output); + +void arrange_root(void); + void arrange_windows(struct sway_container *container); #endif diff --git a/sway/desktop/output.c b/sway/desktop/output.c index bbebe453..c228979d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -16,6 +16,7 @@ #include "log.h" #include "config.h" #include "sway/config.h" +#include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/layers.h" diff --git a/sway/desktop/render.c b/sway/desktop/render.c index b5a10370..b52dd196 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -660,7 +660,7 @@ static void render_container_tabbed(struct sway_output *output, pstate->swayc_width - width_gap_adjustment - tab_width * i; } - render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, + render_titlebar(output, damage, child, x, pstate->swayc_y, tab_width, colors, title_texture, marks_texture); if (child == current) { @@ -721,9 +721,9 @@ static void render_container_stacked(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int y = cstate->swayc_y + titlebar_height * i; - render_titlebar(output, damage, child, cstate->swayc_x, y, - cstate->swayc_width, colors, title_texture, marks_texture); + int y = pstate->swayc_y + titlebar_height * i; + render_titlebar(output, damage, child, pstate->swayc_x, y, + pstate->swayc_width, colors, title_texture, marks_texture); if (child == current) { current_colors = colors; diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 7d1824f1..587deb0f 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -8,6 +8,7 @@ #include "log.h" #include "sway/decoration.h" #include "sway/desktop.h" +#include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/server.h" diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 522fddca..175416f3 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -7,6 +7,7 @@ #include "log.h" #include "sway/decoration.h" #include "sway/desktop.h" +#include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/server.h" diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 8d67116a..92f20fcc 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -13,27 +13,18 @@ #include "list.h" #include "log.h" -static void apply_horiz_layout(struct sway_container *parent) { - size_t num_children = parent->children->length; - if (!num_children) { +static void apply_horiz_layout(list_t *children, struct wlr_box *parent) { + if (!children->length) { return; } - size_t parent_offset = 0; - if (parent->parent->layout == L_TABBED) { - parent_offset = container_titlebar_height(); - } else if (parent->parent->layout == L_STACKED) { - parent_offset = container_titlebar_height() * - parent->parent->children->length; - } - size_t parent_height = parent->height - parent_offset; // Calculate total width of children double total_width = 0; - for (size_t i = 0; i < num_children; ++i) { - struct sway_container *child = parent->children->items[i]; + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; if (child->width <= 0) { - if (num_children > 1) { - child->width = parent->width / (num_children - 1); + if (children->length > 1) { + child->width = parent->width / (children->length - 1); } else { child->width = parent->width; } @@ -46,63 +37,48 @@ static void apply_horiz_layout(struct sway_container *parent) { // Resize windows wlr_log(WLR_DEBUG, "Arranging %p horizontally", parent); double child_x = parent->x; - for (size_t i = 0; i < num_children; ++i) { - struct sway_container *child = parent->children->items[i]; - wlr_log(WLR_DEBUG, - "Calculating arrangement for %p:%d (will scale %f by %f)", - child, child->type, child->width, scale); + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; child->x = child_x; - child->y = parent->y + parent_offset; + child->y = parent->y; child->width = floor(child->width * scale); - child->height = parent_height; + child->height = parent->height; child_x += child->width; // Make last child use remaining width of parent - if (i == num_children - 1) { + if (i == children->length - 1) { child->width = parent->x + parent->width - child->x; } container_add_gaps(child); } } -static void apply_vert_layout(struct sway_container *parent) { - size_t num_children = parent->children->length; - if (!num_children) { +static void apply_vert_layout(list_t *children, struct wlr_box *parent) { + if (!children->length) { return; } - size_t parent_offset = 0; - if (parent->parent->layout == L_TABBED) { - parent_offset = container_titlebar_height(); - } else if (parent->parent->layout == L_STACKED) { - parent_offset = - container_titlebar_height() * parent->parent->children->length; - } - size_t parent_height = parent->height + parent_offset; // Calculate total height of children double total_height = 0; - for (size_t i = 0; i < num_children; ++i) { - struct sway_container *child = parent->children->items[i]; + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; if (child->height <= 0) { - if (num_children > 1) { - child->height = parent_height / (num_children - 1); + if (children->length > 1) { + child->height = parent->height / (children->length - 1); } else { - child->height = parent_height; + child->height = parent->height; } } container_remove_gaps(child); total_height += child->height; } - double scale = parent_height / total_height; + double scale = parent->height / total_height; // Resize wlr_log(WLR_DEBUG, "Arranging %p vertically", parent); - double child_y = parent->y + parent_offset; - for (size_t i = 0; i < num_children; ++i) { - struct sway_container *child = parent->children->items[i]; - wlr_log(WLR_DEBUG, - "Calculating arrangement for %p:%d (will scale %f by %f)", - child, child->type, child->height, scale); + double child_y = parent->y; + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; child->x = parent->x; child->y = child_y; child->width = parent->width; @@ -110,28 +86,21 @@ static void apply_vert_layout(struct sway_container *parent) { child_y += child->height; // Make last child use remaining height of parent - if (i == num_children - 1) { - child->height = - parent->y + parent_offset + parent_height - child->y; + if (i == children->length - 1) { + child->height = parent->y + parent->height - child->y; } container_add_gaps(child); } } -static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { - if (!parent->children->length) { +static void apply_tabbed_layout(list_t *children, struct wlr_box *parent) { + if (!children->length) { return; } - size_t parent_offset = 0; - if (parent->parent->layout == L_TABBED) { - parent_offset = container_titlebar_height(); - } else if (parent->parent->layout == L_STACKED) { - parent_offset = - container_titlebar_height() * parent->parent->children->length; - } + size_t parent_offset = container_titlebar_height(); size_t parent_height = parent->height - parent_offset; - for (int i = 0; i < parent->children->length; ++i) { - struct sway_container *child = parent->children->items[i]; + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; container_remove_gaps(child); child->x = parent->x; child->y = parent->y + parent_offset; @@ -141,65 +110,83 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { } } -static void arrange_children_of(struct sway_container *parent); +static void apply_stacked_layout(list_t *children, struct wlr_box *parent) { + if (!children->length) { + return; + } + size_t parent_offset = container_titlebar_height() * children->length; + size_t parent_height = parent->height - parent_offset; + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; + container_remove_gaps(child); + child->x = parent->x; + child->y = parent->y + parent_offset; + child->width = parent->width; + child->height = parent_height; + container_add_gaps(child); + } +} static void arrange_floating(list_t *floating) { for (int i = 0; i < floating->length; ++i) { struct sway_container *floater = floating->items[i]; - if (floater->type == C_VIEW) { - view_autoconfigure(floater->sway_view); - } else { - arrange_children_of(floater); - } - container_set_dirty(floater); + arrange_container(floater); } } -static void arrange_children_of(struct sway_container *parent) { - if (config->reloading) { - return; - } - wlr_log(WLR_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, - parent->name, parent->width, parent->height, parent->x, parent->y); - +static void arrange_children(list_t *children, + enum sway_container_layout layout, struct wlr_box *parent) { // Calculate x, y, width and height of children - switch (parent->layout) { + switch (layout) { case L_HORIZ: - apply_horiz_layout(parent); + apply_horiz_layout(children, parent); break; case L_VERT: - apply_vert_layout(parent); + apply_vert_layout(children, parent); break; case L_TABBED: + apply_tabbed_layout(children, parent); + break; case L_STACKED: - apply_tabbed_or_stacked_layout(parent); + apply_stacked_layout(children, parent); break; case L_NONE: - apply_horiz_layout(parent); + apply_horiz_layout(children, parent); break; } // Recurse into child containers - for (int i = 0; i < parent->children->length; ++i) { - struct sway_container *child = parent->children->items[i]; - if (parent->has_gaps && !child->has_gaps) { - child->has_gaps = true; - child->gaps_inner = parent->gaps_inner; - child->gaps_outer = parent->gaps_outer; - } - if (child->type == C_VIEW) { - view_autoconfigure(child->sway_view); - } else { - arrange_children_of(child); - } - container_set_dirty(child); + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; + arrange_container(child); + } +} + +void arrange_container(struct sway_container *container) { + if (config->reloading) { + return; + } + if (container->type == C_VIEW) { + view_autoconfigure(container->sway_view); + container_set_dirty(container); + return; } + if (!sway_assert(container->type == C_CONTAINER, "Expected a container")) { + return; + } + struct wlr_box box; + container_get_box(container, &box); + arrange_children(container->children, container->layout, &box); + container_set_dirty(container); } -static void arrange_workspace(struct sway_container *workspace) { +void arrange_workspace(struct sway_container *workspace) { if (config->reloading) { return; } + if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { + return; + } struct sway_container *output = workspace->parent; struct wlr_box *area = &output->sway_output->usable_area; wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", @@ -241,22 +228,22 @@ static void arrange_workspace(struct sway_container *workspace) { fs->y = workspace->parent->y; fs->width = workspace->parent->width; fs->height = workspace->parent->height; - if (fs->type == C_VIEW) { - view_autoconfigure(fs->sway_view); - } else { - arrange_children_of(fs); - } - container_set_dirty(fs); + arrange_container(fs); } else { + struct wlr_box box; + container_get_box(workspace, &box); + arrange_children(workspace->children, workspace->layout, &box); arrange_floating(workspace->sway_workspace->floating); - arrange_children_of(workspace); } } -static void arrange_output(struct sway_container *output) { +void arrange_output(struct sway_container *output) { if (config->reloading) { return; } + if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { + return; + } const struct wlr_box *output_box = wlr_output_layout_get_box( root_container.sway_root->output_layout, output->sway_output->wlr_output); @@ -273,7 +260,7 @@ static void arrange_output(struct sway_container *output) { } } -static void arrange_root() { +void arrange_root(void) { if (config->reloading) { return; } @@ -304,12 +291,8 @@ void arrange_windows(struct sway_container *container) { arrange_workspace(container); break; case C_CONTAINER: - arrange_children_of(container); - container_set_dirty(container); - break; case C_VIEW: - view_autoconfigure(container->sway_view); - container_set_dirty(container); + arrange_container(container); break; case C_TYPES: break; diff --git a/sway/tree/container.c b/sway/tree/container.c index 04454ab6..1b193944 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1163,7 +1163,9 @@ void container_add_gaps(struct sway_container *c) { return; } - c->current_gaps = c->has_gaps ? c->gaps_inner : config->gaps_inner; + struct sway_container *ws = container_parent(c, C_WORKSPACE); + + c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner; c->x += c->current_gaps; c->y += c->current_gaps; c->width -= 2 * c->current_gaps; diff --git a/sway/tree/root.c b/sway/tree/root.c index 2dd8f9f2..b42371de 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -3,6 +3,7 @@ #include #include #include +#include "sway/desktop/transaction.h" #include "sway/input/seat.h" #include "sway/output.h" #include "sway/tree/arrange.h" diff --git a/sway/tree/view.c b/sway/tree/view.c index 2870d4f5..1a98c5f2 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -13,6 +13,7 @@ #include "log.h" #include "sway/criteria.h" #include "sway/commands.h" +#include "sway/desktop/transaction.h" #include "sway/ipc-server.h" #include "sway/output.h" #include "sway/input/seat.h" @@ -224,15 +225,13 @@ void view_autoconfigure(struct sway_view *view) { 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 (con->parent->layout == L_TABBED) { - y_offset = container_titlebar_height(); - view->border_top = false; - } else if (con->parent->layout == L_STACKED) { - y_offset = container_titlebar_height() * con->parent->children->length; + // In a tabbed or stacked container, the swayc's y is the bottom of the + // title area. We have to disable any top border because the title bar is + // rendered by the parent. + if (con->parent->layout == L_TABBED || con->parent->layout == L_STACKED) { view->border_top = false; + } else { + y_offset = container_titlebar_height(); } enum sway_container_border border = view->border; @@ -243,17 +242,17 @@ void view_autoconfigure(struct sway_view *view) { switch (border) { case B_NONE: x = con->x; - y = con->y + y_offset; + y = con->y; width = con->width; - height = con->height - y_offset; + height = con->height; break; case B_PIXEL: x = con->x + view->border_thickness * view->border_left; - y = con->y + view->border_thickness * view->border_top + y_offset; + y = con->y + view->border_thickness * view->border_top; width = con->width - view->border_thickness * view->border_left - view->border_thickness * view->border_right; - height = con->height - y_offset + height = con->height - view->border_thickness * view->border_top - view->border_thickness * view->border_bottom; break; @@ -263,15 +262,9 @@ void view_autoconfigure(struct sway_view *view) { width = con->width - view->border_thickness * view->border_left - view->border_thickness * view->border_right; - if (y_offset) { - y = con->y + y_offset; - height = con->height - y_offset - - view->border_thickness * view->border_bottom; - } else { - y = con->y + container_titlebar_height(); - height = con->height - container_titlebar_height() - - view->border_thickness * view->border_bottom; - } + y = con->y + y_offset; + height = con->height - y_offset + - view->border_thickness * view->border_bottom; break; } From 126a82f14ff47925c7f88523ed9abe0ae9aeb7e8 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 28 Aug 2018 23:53:51 +1000 Subject: [PATCH 2/2] Fix gaps issues * In layout command, arrange parent of parent - not sure why this is needed but it is * Remove gap adjustment when rendering * Workspace should use outer gaps, not inner * Add exceptions for tabbed and stacked containers * Don't mess with gap state when splitting a container --- sway/commands/layout.c | 2 +- sway/desktop/render.c | 7 ++----- sway/tree/container.c | 18 ++++++++++++------ sway/tree/workspace.c | 10 +++++++++- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/sway/commands/layout.c b/sway/commands/layout.c index f4e4dda9..a06832de 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -103,7 +103,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) { parent->prev_split_layout = prev; } container_notify_subtree_changed(parent); - arrange_windows(parent); + arrange_windows(parent->parent); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index b52dd196..5556e5b3 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -619,9 +619,7 @@ static void render_container_tabbed(struct sway_output *output, struct sway_container *current = pstate->focused_inactive_child; struct border_colors *current_colors = &config->border_colors.unfocused; - double width_gap_adjustment = 2 * pstate->current_gaps; - int tab_width = - (pstate->swayc_width - width_gap_adjustment) / pstate->children->length; + int tab_width = (pstate->swayc_width) / pstate->children->length; // Render tabs for (int i = 0; i < pstate->children->length; ++i) { @@ -656,8 +654,7 @@ static void render_container_tabbed(struct sway_output *output, // Make last tab use the remaining width of the parent if (i == pstate->children->length - 1) { - tab_width = - pstate->swayc_width - width_gap_adjustment - tab_width * i; + tab_width = pstate->swayc_width - tab_width * i; } render_titlebar(output, damage, child, x, pstate->swayc_y, tab_width, diff --git a/sway/tree/container.c b/sway/tree/container.c index 1b193944..ee019098 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1159,7 +1159,17 @@ void container_add_gaps(struct sway_container *c) { "Expected a container or view")) { return; } - if (c->current_gaps > 0 || c->type != C_VIEW) { + if (c->current_gaps > 0) { + return; + } + // Linear containers don't have gaps because it'd create double gaps + if (c->type == C_CONTAINER && + c->layout != L_TABBED && c->layout != L_STACKED) { + return; + } + // Children of tabbed/stacked containers re-use the gaps of the container + enum sway_container_layout layout = c->parent->layout; + if (layout == L_TABBED || layout == L_STACKED) { return; } @@ -1355,20 +1365,16 @@ struct sway_container *container_split(struct sway_container *child, wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child); - child->type == C_WORKSPACE ? workspace_remove_gaps(child) - : container_remove_gaps(child); - cont->prev_split_layout = L_NONE; cont->width = child->width; cont->height = child->height; cont->x = child->x; cont->y = child->y; + cont->current_gaps = child->current_gaps; struct sway_seat *seat = input_manager_get_default_seat(input_manager); bool set_focus = (seat_get_focus(seat) == child); - container_add_gaps(cont); - if (child->type == C_WORKSPACE) { struct sway_container *workspace = child; while (workspace->children->length) { diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index d930826e..60256336 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -694,7 +694,15 @@ void workspace_add_gaps(struct sway_container *ws) { return; } - ws->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner; + ws->current_gaps = ws->has_gaps ? ws->gaps_outer : config->gaps_outer; + + if (ws->layout == L_TABBED || ws->layout == L_STACKED) { + // We have to add inner gaps for this, because children of tabbed and + // stacked containers don't apply their own gaps - they assume the + // tabbed/stacked container is using gaps. + ws->current_gaps += ws->has_gaps ? ws->gaps_inner : config->gaps_inner; + } + ws->x += ws->current_gaps; ws->y += ws->current_gaps; ws->width -= 2 * ws->current_gaps;