diff --git a/include/sway/commands.h b/include/sway/commands.h index e6036e51b..eb446eae5 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -172,6 +172,7 @@ sway_cmd cmd_swaybg_command; sway_cmd cmd_swaynag_command; sway_cmd cmd_swap; sway_cmd cmd_tiling_drag; +sway_cmd cmd_title_align; sway_cmd cmd_title_format; sway_cmd cmd_titlebar_border_thickness; sway_cmd cmd_titlebar_padding; diff --git a/include/sway/config.h b/include/sway/config.h index a69208353..1ff9a104a 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -357,6 +357,12 @@ enum mouse_warping_mode { WARP_CONTAINER }; +enum alignment { + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT +}; + /** * The configuration struct. The result of loading a config file. */ @@ -409,6 +415,7 @@ struct sway_config { bool validating; bool auto_back_and_forth; bool show_marks; + enum alignment title_align; bool tiling_drag; bool smart_gaps; diff --git a/sway/commands.c b/sway/commands.c index d35658d56..bffc18f6f 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -103,6 +103,7 @@ static struct cmd_handler handlers[] = { { "smart_borders", cmd_smart_borders }, { "smart_gaps", cmd_smart_gaps }, { "tiling_drag", cmd_tiling_drag }, + { "title_align", cmd_title_align }, { "titlebar_border_thickness", cmd_titlebar_border_thickness }, { "titlebar_padding", cmd_titlebar_padding }, { "workspace", cmd_workspace }, diff --git a/sway/commands/title_align.c b/sway/commands/title_align.c new file mode 100644 index 000000000..825781862 --- /dev/null +++ b/sway/commands/title_align.c @@ -0,0 +1,30 @@ +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/output.h" +#include "sway/tree/container.h" +#include "sway/tree/root.h" + +struct cmd_results *cmd_title_align(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "title_align", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (strcmp(argv[0], "left") == 0) { + config->title_align = ALIGN_LEFT; + } else if (strcmp(argv[0], "center") == 0) { + config->title_align = ALIGN_CENTER; + } else if (strcmp(argv[0], "right") == 0) { + config->title_align = ALIGN_RIGHT; + } else { + return cmd_results_new(CMD_INVALID, "title_align", + "Expected 'title_align left|center|right'"); + } + + 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, NULL); +} diff --git a/sway/config.c b/sway/config.c index 59edc6d8b..675d20e5d 100644 --- a/sway/config.c +++ b/sway/config.c @@ -234,6 +234,7 @@ static void config_defaults(struct sway_config *config) { config->auto_back_and_forth = false; config->reading = false; config->show_marks = true; + config->title_align = ALIGN_LEFT; config->tiling_drag = true; config->smart_gaps = false; diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 51cb89801..eeda496c3 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -371,6 +371,7 @@ static void render_titlebar(struct sway_output *output, int titlebar_border_thickness = config->titlebar_border_thickness; int titlebar_h_padding = config->titlebar_h_padding; int titlebar_v_padding = config->titlebar_v_padding; + enum alignment title_align = config->title_align; // Single pixel bar above title memcpy(&color, colors->border, sizeof(float) * 4); @@ -420,19 +421,25 @@ static void render_titlebar(struct sway_output *output, render_rect(output->wlr_output, output_damage, &box, color); } - size_t inner_width = width - titlebar_h_padding * 2; + int inner_x = x - output_x + titlebar_h_padding; int bg_y = y + titlebar_border_thickness; + size_t inner_width = width - titlebar_h_padding * 2; + + // output-buffer local + int ob_inner_x = round(inner_x * output_scale); + int ob_inner_width = scale_length(inner_width, inner_x, output_scale); int ob_bg_height = scale_length( (titlebar_v_padding - titlebar_border_thickness) * 2 + config->font_height, bg_y, output_scale); // Marks - int marks_ob_width = 0; // output-buffer-local + int ob_marks_x = 0; // output-buffer-local + int ob_marks_width = 0; // output-buffer-local if (config->show_marks && marks_texture) { struct wlr_box texture_box; wlr_texture_get_size(marks_texture, &texture_box.width, &texture_box.height); - marks_ob_width = texture_box.width; + ob_marks_width = texture_box.width; // The marks texture might be shorter than the config->font_height, in // which case we need to pad it as evenly as possible above and below. @@ -440,9 +447,15 @@ static void render_titlebar(struct sway_output *output, int ob_padding_above = floor(ob_padding_total / 2.0); int ob_padding_below = ceil(ob_padding_total / 2.0); - // Render texture - texture_box.x = round((x - output_x + width - titlebar_h_padding) - * output_scale) - texture_box.width; + // Render texture. If the title is on the right, the marks will be on + // the left. Otherwise, they will be on the right. + if (title_align == ALIGN_RIGHT || texture_box.width > ob_inner_width) { + texture_box.x = ob_inner_x; + } else { + texture_box.x = ob_inner_x + ob_inner_width - texture_box.width; + } + ob_marks_x = texture_box.x; + texture_box.y = round((bg_y - output_y) * output_scale) + ob_padding_above; @@ -451,8 +464,8 @@ static void render_titlebar(struct sway_output *output, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, output->wlr_output->transform_matrix); - if (inner_width * output_scale < texture_box.width) { - texture_box.width = inner_width * output_scale; + if (ob_inner_width < texture_box.width) { + texture_box.width = ob_inner_width; } render_texture(output->wlr_output, output_damage, marks_texture, &texture_box, matrix, con->alpha); @@ -473,12 +486,13 @@ static void render_titlebar(struct sway_output *output, } // Title text - size_t title_ob_width = 0; // output-buffer-local + int ob_title_x = 0; // output-buffer-local + int ob_title_width = 0; // output-buffer-local if (title_texture) { struct wlr_box texture_box; wlr_texture_get_size(title_texture, &texture_box.width, &texture_box.height); - title_ob_width = texture_box.width; + ob_title_width = texture_box.width; // The title texture might be shorter than the config->font_height, // in which case we need to pad it above and below. @@ -489,8 +503,26 @@ static void render_titlebar(struct sway_output *output, texture_box.height; // Render texture - texture_box.x = - round((x - output_x + titlebar_h_padding) * output_scale); + if (texture_box.width > ob_inner_width - ob_marks_width) { + texture_box.x = (title_align == ALIGN_RIGHT && ob_marks_width) + ? ob_marks_x + ob_marks_width : ob_inner_x; + } else if (title_align == ALIGN_LEFT) { + texture_box.x = ob_inner_x; + } else if (title_align == ALIGN_CENTER) { + // If there are marks visible, center between the edge and marks. + // Otherwise, center in the inner area. + if (ob_marks_width) { + texture_box.x = (ob_inner_x + ob_marks_x) / 2 + - texture_box.width / 2; + } else { + texture_box.x = ob_inner_x + ob_inner_width / 2 + - texture_box.width / 2; + } + } else { + texture_box.x = ob_inner_x + ob_inner_width - texture_box.width; + } + ob_title_x = texture_box.x; + texture_box.y = round((bg_y - output_y) * output_scale) + ob_padding_above; @@ -499,11 +531,10 @@ static void render_titlebar(struct sway_output *output, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, output->wlr_output->transform_matrix); - int inner_x = x - output_x + titlebar_h_padding; - int ob_inner_width = scale_length(inner_width, inner_x, output_scale); - if (ob_inner_width - marks_ob_width < texture_box.width) { - texture_box.width = ob_inner_width - marks_ob_width; + if (ob_inner_width - ob_marks_width < texture_box.width) { + texture_box.width = ob_inner_width - ob_marks_width; } + render_texture(output->wlr_output, output_damage, title_texture, &texture_box, matrix, con->alpha); @@ -522,17 +553,36 @@ static void render_titlebar(struct sway_output *output, render_rect(output->wlr_output, output_damage, &box, color); } + // Determine the left + right extends of the textures (output-buffer local) + int ob_left_x, ob_left_width, ob_right_x, ob_right_width; + if (ob_title_x < ob_marks_x) { + ob_left_x = ob_title_x; + ob_left_width = ob_title_width; + ob_right_x = ob_marks_x; + ob_right_width = ob_marks_width; + } else { + ob_left_x = ob_marks_x; + ob_left_width = ob_marks_width; + ob_right_x = ob_title_x; + ob_right_width = ob_title_width; + } + if (ob_left_x < ob_inner_x) { + ob_left_x = ob_inner_x; + } else if (ob_left_x + ob_left_width > ob_right_x + ob_right_width) { + ob_right_x = ob_left_x; + ob_right_width = ob_left_width; + } + // Filler between title and marks - box.width = - round(inner_width * output_scale) - title_ob_width - marks_ob_width; + box.width = ob_right_x - ob_left_x - ob_left_width; if (box.width > 0) { - box.x = round((x + titlebar_h_padding) * output_scale) + title_ob_width; + box.x = ob_left_x + ob_left_width + round(output_x * output_scale); box.y = round(bg_y * output_scale); box.height = ob_bg_height; render_rect(output->wlr_output, output_damage, &box, color); } - // Padding left of title + // Padding on left side left_offset = (layout == L_TABBED) * titlebar_border_thickness; box.x = x + left_offset; box.y = y + titlebar_border_thickness; @@ -540,9 +590,13 @@ static void render_titlebar(struct sway_output *output, box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 + config->font_height; scale_box(&box, output_scale); + int left_x = ob_left_x + round(output_x * output_scale); + if (box.x + box.width < left_x) { + box.width += left_x - box.x - box.width; + } render_rect(output->wlr_output, output_damage, &box, color); - // Padding right of marks + // Padding on right side right_offset = (layout == L_TABBED) * titlebar_border_thickness; box.x = x + width - titlebar_h_padding; box.y = y + titlebar_border_thickness; @@ -550,6 +604,11 @@ static void render_titlebar(struct sway_output *output, box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 + config->font_height; scale_box(&box, output_scale); + int right_rx = ob_right_x + ob_right_width + round(output_x * output_scale); + if (right_rx < box.x) { + box.width += box.x - right_rx; + box.x = right_rx; + } render_rect(output->wlr_output, output_damage, &box, color); if (connects_sides) { diff --git a/sway/meson.build b/sway/meson.build index c8c95a96b..751318918 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -88,6 +88,7 @@ sway_sources = files( 'commands/swaynag_command.c', 'commands/swap.c', 'commands/tiling_drag.c', + 'commands/title_align.c', 'commands/title_format.c', 'commands/titlebar_border_thickness.c', 'commands/titlebar_padding.c', diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 6ccb1acf2..4edd16bf6 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -555,6 +555,11 @@ The default colors are: Set the opacity of the window between 0 (completely transparent) and 1 (completely opaque). +*title\_align* left|center|right + Sets the title alignment. If _right_ is selected and _show\_marks_ is set + to _yes_, the marks will be shown on the _left_ side instead of the + _right_ side. + *unmark* [] *unmark* will remove _identifier_ from the list of current marks on a window. If _identifier_ is omitted, all marks are removed.