From 69265ad34cd218e1f9e47ad3db6f6aff574c8fd5 Mon Sep 17 00:00:00 2001 From: Josip Janzic Date: Sat, 31 Aug 2019 11:16:10 +0200 Subject: [PATCH 1/4] Add new command to set titlebar position --- include/sway/commands.h | 1 + include/sway/config.h | 6 ++++++ sway/commands.c | 1 + sway/commands/titlebar_position.c | 30 ++++++++++++++++++++++++++++++ sway/config.c | 1 + sway/meson.build | 1 + 6 files changed, 40 insertions(+) create mode 100644 sway/commands/titlebar_position.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 270585870..a19b0ccfe 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -190,6 +190,7 @@ sway_cmd cmd_title_align; sway_cmd cmd_title_format; sway_cmd cmd_titlebar_border_thickness; sway_cmd cmd_titlebar_padding; +sway_cmd cmd_titlebar_position; sway_cmd cmd_unbindcode; sway_cmd cmd_unbindswitch; sway_cmd cmd_unbindgesture; diff --git a/include/sway/config.h b/include/sway/config.h index f9da19675..64e7d2f06 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -473,6 +473,11 @@ enum xwayland_mode { XWAYLAND_MODE_IMMEDIATE, }; +enum titlebar_position { + TITLEBAR_TOP, + TITLEBAR_BOTTOM +}; + /** * The configuration struct. The result of loading a config file. */ @@ -534,6 +539,7 @@ struct sway_config { bool show_marks; enum alignment title_align; bool primary_selection; + enum titlebar_position titlebar_position; bool tiling_drag; int tiling_drag_threshold; diff --git a/sway/commands.c b/sway/commands.c index 55eda183c..884d7ce8e 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -93,6 +93,7 @@ static const struct cmd_handler handlers[] = { { "title_align", cmd_title_align }, { "titlebar_border_thickness", cmd_titlebar_border_thickness }, { "titlebar_padding", cmd_titlebar_padding }, + { "titlebar_position", cmd_titlebar_position }, { "unbindcode", cmd_unbindcode }, { "unbindgesture", cmd_unbindgesture }, { "unbindswitch", cmd_unbindswitch }, diff --git a/sway/commands/titlebar_position.c b/sway/commands/titlebar_position.c new file mode 100644 index 000000000..4c53e1f56 --- /dev/null +++ b/sway/commands/titlebar_position.c @@ -0,0 +1,30 @@ +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/output.h" +#include "sway/tree/arrange.h" +#include "sway/tree/root.h" + +struct cmd_results *cmd_titlebar_position(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "titlebar_position", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (strcmp(argv[0], "top") == 0) { + config->titlebar_position = TITLEBAR_TOP; + } else if (strcmp(argv[0], "bottom") == 0) { + config->titlebar_position = TITLEBAR_BOTTOM; + } else { + return cmd_results_new(CMD_INVALID, + "Expected 'titlebar_position top|bottom'"); + } + + arrange_root(); + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_whole(output); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} + diff --git a/sway/config.c b/sway/config.c index 8c8c148d9..a7022a42e 100644 --- a/sway/config.c +++ b/sway/config.c @@ -271,6 +271,7 @@ static void config_defaults(struct sway_config *config) { config->reading = false; config->show_marks = true; config->title_align = ALIGN_LEFT; + config->titlebar_position = TITLEBAR_TOP; config->tiling_drag = true; config->tiling_drag_threshold = 9; config->primary_selection = true; diff --git a/sway/meson.build b/sway/meson.build index 3abd778db..3f8de9545 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -117,6 +117,7 @@ sway_sources = files( 'commands/title_format.c', 'commands/titlebar_border_thickness.c', 'commands/titlebar_padding.c', + 'commands/titlebar_position.c', 'commands/unmark.c', 'commands/urgent.c', 'commands/workspace.c', From 543e4de017dd03f3838af661e2443b55263d37f0 Mon Sep 17 00:00:00 2001 From: Josip Janzic Date: Sat, 31 Aug 2019 11:16:22 +0200 Subject: [PATCH 2/4] Document titlebar_position command --- sway/sway.5.scd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 78d7d2316..fca87853b 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -849,6 +849,10 @@ The default colors are: to _yes_, the marks will be shown on the _left_ side instead of the _right_ side. + +*titlebar_position* top|bottom + Sets the titlebar position. + *unbindswitch* : Removes a binding for when changes to . From a8d905ce0595351a473fc71d736569411da9e7c2 Mon Sep 17 00:00:00 2001 From: Josip Janzic Date: Wed, 16 Oct 2019 19:34:16 +0200 Subject: [PATCH 3/4] Conditional rendering of bottom border --- sway/desktop/render.c | 66 +++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index c4c0004e7..4b4abeff7 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -376,21 +376,6 @@ static void render_view(struct render_context *ctx, scale_box(&box, output_scale); render_rect(ctx, &box, color); } - - if (state->border_bottom) { - if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_VERT) { - memcpy(&color, colors->indicator, sizeof(float) * 4); - } else { - memcpy(&color, colors->child_border, sizeof(float) * 4); - } - premultiply_alpha(color, con->alpha); - box.x = floor(state->x); - box.y = floor(state->content_y + state->content_height); - box.width = state->width; - box.height = state->border_thickness; - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - } } /** @@ -670,6 +655,37 @@ static void render_top_border(struct render_context *ctx, struct sway_container render_rect(ctx, &box, color); } +/** + * Render the bottom border line for a view using "border pixel". + */ +static void render_bottom_border(struct render_context *ctx, struct sway_container *con, + struct border_colors *colors) { + struct sway_container_state *state = &con->current; + if (!state->border_bottom) { + return; + } + struct wlr_box box; + float color[4]; + float output_scale = ctx->output->wlr_output->scale; + + list_t *siblings = container_get_current_siblings(con); + enum sway_container_layout layout = + container_current_parent_layout(con); + + if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_VERT) { + memcpy(&color, colors->indicator, sizeof(float) * 4); + } else { + memcpy(&color, colors->child_border, sizeof(float) * 4); + } + premultiply_alpha(color, con->alpha); + box.x = floor(state->x); + box.y = floor(state->content_y + state->content_height); + box.width = state->width; + box.height = state->border_thickness; + scale_box(&box, output_scale); + render_rect(ctx, &box, color); +} + struct parent_data { enum sway_container_layout layout; struct wlr_box box; @@ -724,6 +740,11 @@ static void render_containers_linear(struct render_context *ctx, struct parent_d render_top_border(ctx, child, colors); } render_view(ctx, child, colors); + if (config->titlebar_position != TITLEBAR_BOTTOM) { + render_bottom_border(ctx, child, colors); + } else { + render_top_border(ctx, child, colors); + } } else { render_container(ctx, child, parent->focused || child->current.focused); @@ -801,6 +822,11 @@ static void render_containers_tabbed(struct render_context *ctx, struct parent_d // Render surface and left/right/bottom borders if (current->view) { render_view(ctx, current, current_colors); + if (config->titlebar_position != TITLEBAR_BOTTOM) { + render_bottom_border(ctx, current, current_colors); + } else { + render_top_border(ctx, current, current_colors); + } } else { render_container(ctx, current, parent->focused || current->current.focused); @@ -862,6 +888,11 @@ static void render_containers_stacked(struct render_context *ctx, struct parent_ // Render surface and left/right/bottom borders if (current->view) { + if (titlebar_is_on_top) { + render_bottom_border(ctx, current, current_colors); + } else { + render_top_border(ctx, current, current_colors); + } render_view(ctx, current, current_colors); } else { render_container(ctx, current, @@ -956,6 +987,11 @@ static void render_floating_container(struct render_context *ctx, } else if (con->current.border == B_PIXEL) { render_top_border(ctx, con, colors); } + if (config->titlebar_position != TITLEBAR_BOTTOM) { + render_bottom_border(ctx, con, colors); + } else { + render_top_border(ctx, con, colors); + } render_view(ctx, con, colors); } else { render_container(ctx, con, con->current.focused); From e98e01c30156b7a5dae3bb4d3e177a059dde68c9 Mon Sep 17 00:00:00 2001 From: Josip Janzic Date: Wed, 16 Oct 2019 19:34:55 +0200 Subject: [PATCH 4/4] Render titlebar at the right position based on configuration --- sway/desktop/render.c | 32 +++++++++++++++++++++------- sway/tree/container.c | 9 ++++++-- sway/tree/view.c | 49 ++++++++++++++++++++++++++++++++----------- 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 4b4abeff7..6e78b2f9d 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -733,8 +733,12 @@ static void render_containers_linear(struct render_context *ctx, struct parent_d } if (state->border == B_NORMAL) { - render_titlebar(ctx, child, floor(state->x), - floor(state->y), state->width, colors, + int y = state->y; + if (config->titlebar_position == TITLEBAR_BOTTOM) { + y += state->height - container_titlebar_height(); + } + render_titlebar(ctx, child, floor(state->x), floor(y), + state->width, colors, title_texture, marks_texture); } else if (state->border == B_PIXEL) { render_top_border(ctx, child, colors); @@ -810,8 +814,11 @@ static void render_containers_tabbed(struct render_context *ctx, struct parent_d if (i == parent->children->length - 1) { tab_width = parent->box.width - tab_width * i; } - - render_titlebar(ctx, child, x, parent->box.y, tab_width, + int y = parent->box.y; + if (config->titlebar_position == TITLEBAR_BOTTOM) { + y += parent->box.height - container_titlebar_height(); + } + render_titlebar(ctx, child, x, y, tab_width, colors, title_texture, marks_texture); if (child == current) { @@ -843,6 +850,7 @@ static void render_containers_stacked(struct render_context *ctx, struct parent_ struct sway_container *current = parent->active_child; struct border_colors *current_colors = &config->border_colors.unfocused; size_t titlebar_height = container_titlebar_height(); + bool titlebar_is_on_top = config->titlebar_position == TITLEBAR_TOP; // Render titles for (int i = 0; i < parent->children->length; ++i) { @@ -877,9 +885,13 @@ static void render_containers_stacked(struct render_context *ctx, struct parent_ marks_texture = child->marks_unfocused; } - int y = parent->box.y + titlebar_height * i; - render_titlebar(ctx, child, parent->box.x, y, - parent->box.width, colors, title_texture, marks_texture); + int titlebar_y = parent->box.y + titlebar_height * i; + if (!titlebar_is_on_top) { + titlebar_y = parent->box.height - titlebar_height * (parent->children->length - i) - (child->pending.border_thickness * child->pending.border_bottom); + } + render_titlebar(ctx, child, parent->box.x, + titlebar_y, parent->box.width, colors, title_texture, + marks_texture); if (child == current) { current_colors = colors; @@ -981,8 +993,12 @@ static void render_floating_container(struct render_context *ctx, } if (con->current.border == B_NORMAL) { + int titlebar_y = con->current.y; + if (config->titlebar_position == TITLEBAR_BOTTOM) { + titlebar_y += con->current.height - container_titlebar_height(); + } render_titlebar(ctx, con, floor(con->current.x), - floor(con->current.y), con->current.width, colors, + floor(titlebar_y), con->current.width, colors, title_texture, marks_texture); } else if (con->current.border == B_PIXEL) { render_top_border(ctx, con, colors); diff --git a/sway/tree/container.c b/sway/tree/container.c index d2c4ffc44..5329a8015 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -924,14 +924,19 @@ void container_set_geometry_from_content(struct sway_container *con) { if (con->pending.border != B_CSD && !con->pending.fullscreen_mode) { border_width = con->pending.border_thickness * (con->pending.border != B_NONE); - top = con->pending.border == B_NORMAL ? - container_titlebar_height() : border_width; + top = con->pending.border == B_NORMAL + && (config->titlebar_position != TITLEBAR_BOTTOM) + ? container_titlebar_height() + : border_width; } con->pending.x = con->pending.content_x - border_width; con->pending.y = con->pending.content_y - top; con->pending.width = con->pending.content_width + border_width * 2; con->pending.height = top + con->pending.content_height + border_width; + if (config->titlebar_position == TITLEBAR_BOTTOM) { + con->pending.height += container_titlebar_height() - border_width; + } node_set_dirty(&con->node); } diff --git a/sway/tree/view.c b/sway/tree/view.c index ec54fed81..45f92aa46 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -266,6 +266,16 @@ void view_autoconfigure(struct sway_view *view) { con->pending.border_top = con->pending.border_bottom = true; con->pending.border_left = con->pending.border_right = true; double y_offset = 0; + double height_offset = 0; + bool titlebar_visible = con->pending.border == B_NORMAL; + bool titlebar_is_on_top = config->titlebar_position == TITLEBAR_TOP; + bool titlebar_is_visible_on_top = titlebar_is_on_top && titlebar_visible; + bool titlebar_is_visible_on_bottom = !titlebar_is_on_top && titlebar_visible; + if (titlebar_is_visible_on_top) { + con->pending.border_top = false; + } else if (titlebar_is_visible_on_bottom) { + con->pending.border_bottom = false; + } if (!container_is_floating_or_child(con) && ws) { if (config->hide_edge_borders == E_BOTH @@ -277,9 +287,9 @@ void view_autoconfigure(struct sway_view *view) { if (config->hide_edge_borders == E_BOTH || config->hide_edge_borders == E_HORIZONTAL) { - con->pending.border_top = con->pending.y != ws->y; + con->pending.border_top &= con->pending.y != ws->y; int bottom_y = con->pending.y + con->pending.height; - con->pending.border_bottom = bottom_y != ws->y + ws->height; + con->pending.border_bottom &= bottom_y != ws->y + ws->height; } bool smart = config->hide_edge_borders_smart == ESMART_ON || @@ -304,15 +314,27 @@ void view_autoconfigure(struct sway_view *view) { if (show_titlebar) { enum sway_container_layout layout = container_parent_layout(con); if (layout == L_TABBED) { - y_offset = container_titlebar_height(); - con->pending.border_top = false; + height_offset = container_titlebar_height(); + if (titlebar_is_on_top) { + con->pending.border_top = false; + } else { + con->pending.border_bottom = false; + } } else if (layout == L_STACKED) { - y_offset = container_titlebar_height() * siblings->length; - con->pending.border_top = false; + height_offset = container_titlebar_height() * siblings->length; + if (titlebar_is_on_top) { + con->pending.border_top = false; + } else { + con->pending.border_bottom = false; + } } } } + if (titlebar_visible && titlebar_is_visible_on_top) { + y_offset = height_offset; + } + double x, y, width, height; switch (con->pending.border) { default: @@ -321,7 +343,7 @@ void view_autoconfigure(struct sway_view *view) { x = con->pending.x; y = con->pending.y + y_offset; width = con->pending.width; - height = con->pending.height - y_offset; + height = con->pending.height - height_offset; break; case B_PIXEL: x = con->pending.x + con->pending.border_thickness * con->pending.border_left; @@ -329,7 +351,7 @@ void view_autoconfigure(struct sway_view *view) { width = con->pending.width - con->pending.border_thickness * con->pending.border_left - con->pending.border_thickness * con->pending.border_right; - height = con->pending.height - y_offset + height = con->pending.height - height_offset - con->pending.border_thickness * con->pending.border_top - con->pending.border_thickness * con->pending.border_bottom; break; @@ -339,14 +361,17 @@ void view_autoconfigure(struct sway_view *view) { width = con->pending.width - con->pending.border_thickness * con->pending.border_left - con->pending.border_thickness * con->pending.border_right; - if (y_offset) { + if (y_offset || height_offset) { y = con->pending.y + y_offset; - height = con->pending.height - y_offset + height = con->pending.height - height_offset - con->pending.border_thickness * con->pending.border_bottom; } else { - y = con->pending.y + container_titlebar_height(); + y = con->pending.y; + if (titlebar_is_visible_on_top) { + y += container_titlebar_height(); + } height = con->pending.height - container_titlebar_height() - - con->pending.border_thickness * con->pending.border_bottom; + - con->pending.border_thickness * (con->pending.border_bottom || con->pending.border_top); } break; }