diff --git a/include/sway/commands.h b/include/sway/commands.h index 5210d3ba7..12c081a10 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -124,6 +124,8 @@ sway_cmd cmd_commands; sway_cmd cmd_create_output; sway_cmd cmd_default_border; sway_cmd cmd_default_floating_border; +sway_cmd cmd_default_stacking_titlebar; +sway_cmd cmd_default_tabbed_titlebar; sway_cmd cmd_default_orientation; sway_cmd cmd_exec; sway_cmd cmd_exec_always; @@ -181,10 +183,12 @@ sway_cmd cmd_split; sway_cmd cmd_splith; sway_cmd cmd_splitt; sway_cmd cmd_splitv; +sway_cmd cmd_stacking_titlebar; sway_cmd cmd_sticky; sway_cmd cmd_swaybg_command; sway_cmd cmd_swaynag_command; sway_cmd cmd_swap; +sway_cmd cmd_tabbed_titlebar; sway_cmd cmd_tiling_drag; sway_cmd cmd_tiling_drag_threshold; sway_cmd cmd_title_align; diff --git a/include/sway/config.h b/include/sway/config.h index d9f561571..2f9acce2d 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -583,6 +583,9 @@ struct sway_config { bool has_focused_tab_title; + bool stacking_titlebar_follows_border; + bool tabbed_titlebar_follows_border; + // floating view int32_t floating_maximum_width; int32_t floating_maximum_height; diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 8bf1955d7..a2b778667 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -60,6 +60,9 @@ struct sway_container_state { bool border_left; bool border_right; + bool stacking_titlebar_follows_border; + bool tabbed_titlebar_follows_border; + // These are in layout coordinates. double content_x, content_y; double content_width, content_height; @@ -217,6 +220,13 @@ void container_set_geometry_from_content(struct sway_container *con); */ bool container_is_floating(struct sway_container *container); +/** + * Determine if the given container should have a titlebar. + * + * Uses pending container state. + */ +bool container_has_titlebar(struct sway_container *container); + /** * Get a container's box in layout coordinates. */ diff --git a/sway/commands.c b/sway/commands.c index c2c12ee65..39fbe48aa 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -57,6 +57,8 @@ static const struct cmd_handler handlers[] = { { "client.urgent", cmd_client_urgent }, { "default_border", cmd_default_border }, { "default_floating_border", cmd_default_floating_border }, + { "default_stacking_titlebar", cmd_default_stacking_titlebar }, + { "default_tabbed_titlebar", cmd_default_tabbed_titlebar }, { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "floating_maximum_size", cmd_floating_maximum_size }, @@ -135,8 +137,10 @@ static const struct cmd_handler command_handlers[] = { { "splith", cmd_splith }, { "splitt", cmd_splitt }, { "splitv", cmd_splitv }, + { "stacking_titlebar", cmd_stacking_titlebar }, { "sticky", cmd_sticky }, { "swap", cmd_swap }, + { "tabbed_titlebar", cmd_tabbed_titlebar }, { "title_format", cmd_title_format }, { "unmark", cmd_unmark }, { "urgent", cmd_urgent }, diff --git a/sway/commands/default_stacking_titlebar.c b/sway/commands/default_stacking_titlebar.c new file mode 100644 index 000000000..f3df196b0 --- /dev/null +++ b/sway/commands/default_stacking_titlebar.c @@ -0,0 +1,40 @@ +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/tree/container.h" + +struct cmd_results *cmd_default_stacking_titlebar(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "default_stacking_titlebar", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (strcmp(argv[0], "always_visible") == 0) { + config->stacking_titlebar_follows_border = false; + } else if (strcmp(argv[0], "follows_border") == 0) { + config->stacking_titlebar_follows_border = true; + } else { + return cmd_results_new(CMD_INVALID, + "Expected 'default_stacking_titlebar "); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} + +struct cmd_results *cmd_default_tabbed_titlebar(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "default_tabbed_titlebar", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (strcmp(argv[0], "always_visible") == 0) { + config->tabbed_titlebar_follows_border = false; + } else if (strcmp(argv[0], "follows_border") == 0) { + config->tabbed_titlebar_follows_border = true; + } else { + return cmd_results_new(CMD_INVALID, + "Expected 'default_tabbed_titlebar "); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/commands/stacking_titlebar.c b/sway/commands/stacking_titlebar.c new file mode 100644 index 000000000..68f32529b --- /dev/null +++ b/sway/commands/stacking_titlebar.c @@ -0,0 +1,64 @@ +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/tree/arrange.h" +#include "sway/tree/container.h" +#include "sway/tree/view.h" + +struct cmd_results *cmd_stacking_titlebar(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "border", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + struct sway_container *container = config->handler_context.container; + if (!container) { + return cmd_results_new(CMD_INVALID, "No container to set"); + } + + if (strcmp(argv[0], "always_visible") == 0) { + container->pending.stacking_titlebar_follows_border = false; + } else if (strcmp(argv[0], "follows_border") == 0) { + container->pending.stacking_titlebar_follows_border = true; + } else { + return cmd_results_new(CMD_INVALID, + "Expected 'stacking_titlebar "); + } + + if (container_is_floating(container)) { + container_set_geometry_from_content(container); + } + + arrange_container(container); + + return cmd_results_new(CMD_SUCCESS, NULL); +} + +struct cmd_results *cmd_tabbed_titlebar(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "border", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + struct sway_container *container = config->handler_context.container; + if (!container) { + return cmd_results_new(CMD_INVALID, "No container to set"); + } + + if (strcmp(argv[0], "always_visible") == 0) { + container->pending.tabbed_titlebar_follows_border = false; + } else if (strcmp(argv[0], "follows_border") == 0) { + container->pending.tabbed_titlebar_follows_border = true; + } else { + return cmd_results_new(CMD_INVALID, + "Expected 'tabbed_titlebar "); + } + + if (container_is_floating(container)) { + container_set_geometry_from_content(container); + } + + arrange_container(container); + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 2ee5a5dff..11333ffcd 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -299,6 +299,11 @@ static void arrange_children(enum sway_container_layout layout, list_t *children title_bar_height = 0; } + if (active && active->current.tabbed_titlebar_follows_border && + active->current.border != B_NORMAL) { + title_bar_height = 0; + } + double w = (double) width / children->length; int title_offset = 0; for (int i = 0; i < children->length; i++) { @@ -329,6 +334,11 @@ static void arrange_children(enum sway_container_layout layout, list_t *children title_bar_height = 0; } + if (active && active->current.stacking_titlebar_follows_border && + active->current.border != B_NORMAL) { + title_bar_height = 0; + } + int title_height = title_bar_height * children->length; int y = 0; diff --git a/sway/meson.build b/sway/meson.build index 8042c89be..7844848c2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -51,6 +51,7 @@ sway_sources = files( 'commands/create_output.c', 'commands/default_border.c', 'commands/default_floating_border.c', + 'commands/default_stacking_titlebar.c', 'commands/default_orientation.c', 'commands/exit.c', 'commands/exec.c', @@ -69,6 +70,7 @@ sway_sources = files( 'commands/fullscreen.c', 'commands/gaps.c', 'commands/gesture.c', + 'commands/stacking_titlebar.c', 'commands/hide_edge_borders.c', 'commands/inhibit_idle.c', 'commands/kill.c', diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 0b36a7572..bc9f676f2 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -111,6 +111,16 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). *border* toggle Cycles through the available border styles. +*stacking_titlebar* always_visible|follows_border + Set whether the titlebar for contains with stacking layouts should always + be visible (the default) or if it should respect the border setting like + other layouts. + +*tabbed_titlebar* always_visible|follows_border + Set whether the titlebar for contains with tabbed layouts should always + be visible (the default) or if it should respect the border setting like + other layouts. + *exit* Exit sway and end your Wayland session. @@ -677,6 +687,14 @@ The default colors are: windows that are spawned in floating mode, not windows that become floating afterwards. +*default_stacking_titlebar* always_visible|follows_border + Set the default stacking titlebar setting for new windows. Config reload + won't affect existing windows, only newly created ones after the reload. + +*default_tabbed_titlebar* always_visible|follows_border + Set the default tabbed titlebar setting for new windows. Config reload + won't affect existing windows, only newly created ones after the reload. + *exec* Executes _shell command_ with sh. diff --git a/sway/tree/container.c b/sway/tree/container.c index 80ef34fe9..e0a70fd68 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1002,6 +1002,24 @@ bool container_is_floating(struct sway_container *container) { return false; } +bool container_has_titlebar(struct sway_container *container) { + switch (container->pending.layout) { + case L_NONE: + return false; + case L_HORIZ: + case L_VERT: + return container->pending.border == B_NORMAL; + case L_STACKED: + return container->pending.border == B_NORMAL || + !container->pending.stacking_titlebar_follows_border; + case L_TABBED: + return container->pending.border == B_NORMAL || + !container->pending.tabbed_titlebar_follows_border; + default: + abort(); + } +} + void container_get_box(struct sway_container *container, struct wlr_box *box) { box->x = container->pending.x; box->y = container->pending.y; diff --git a/sway/tree/view.c b/sway/tree/view.c index d25a09c2a..6fb4934b5 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -308,7 +308,7 @@ void view_autoconfigure(struct sway_view *view) { } } - if (!container_is_floating(con)) { + if (!container_is_floating(con) && container_has_titlebar(con)) { // In a tabbed or stacked container, the container'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. @@ -819,6 +819,10 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, view->container->pending.border_thickness = config->border_thickness; view_set_tiled(view, true); } + view->container->pending.stacking_titlebar_follows_border = + config->stacking_titlebar_follows_border; + view->container->pending.tabbed_titlebar_follows_border = + config->tabbed_titlebar_follows_border; if (config->popup_during_fullscreen == POPUP_LEAVE && container->pending.workspace &&