diff --git a/include/sway/commands.h b/include/sway/commands.h index 5210d3ba7..3a385de30 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -245,6 +245,7 @@ sway_cmd bar_colors_cmd_focused_separator; sway_cmd bar_colors_cmd_statusline; sway_cmd bar_colors_cmd_focused_statusline; sway_cmd bar_colors_cmd_urgent_workspace; +sway_cmd bar_colors_cmd_empty_workspace; sway_cmd input_cmd_seat; sway_cmd input_cmd_accel_profile; diff --git a/include/sway/config.h b/include/sway/config.h index bb770c6f7..e22de0f5b 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -394,6 +394,9 @@ struct bar_config { char *urgent_workspace_border; char *urgent_workspace_bg; char *urgent_workspace_text; + char *empty_workspace_border; + char *empty_workspace_bg; + char *empty_workspace_text; char *binding_mode_border; char *binding_mode_bg; char *binding_mode_text; diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 58bde20cb..a2709858d 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -49,6 +49,7 @@ struct sway_workspace { list_t *tiling; // struct sway_container list_t *output_priority; bool urgent; + bool persistent; struct sway_workspace_state current; }; diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 197d21901..612d4d443 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -88,6 +88,7 @@ struct swaybar_workspace { bool focused; bool visible; bool urgent; + bool empty; }; bool bar_setup(struct swaybar *bar, const char *socket_path); diff --git a/include/swaybar/config.h b/include/swaybar/config.h index 361acd991..b2d74fa3d 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h @@ -65,6 +65,7 @@ struct swaybar_config { struct box_colors active_workspace; struct box_colors inactive_workspace; struct box_colors urgent_workspace; + struct box_colors empty_workspace; struct box_colors binding_mode; } colors; diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c index 275fa3c64..01427f72d 100644 --- a/sway/commands/bar/colors.c +++ b/sway/commands/bar/colors.c @@ -8,6 +8,7 @@ static const struct cmd_handler bar_colors_handlers[] = { { "active_workspace", bar_colors_cmd_active_workspace }, { "background", bar_colors_cmd_background }, { "binding_mode", bar_colors_cmd_binding_mode }, + { "empty_workspace", bar_colors_cmd_empty_workspace }, { "focused_background", bar_colors_cmd_focused_background }, { "focused_separator", bar_colors_cmd_focused_separator }, { "focused_statusline", bar_colors_cmd_focused_statusline }, @@ -150,3 +151,12 @@ struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv) { }; return parse_three_colors(colors, "urgent_workspace", argc, argv); } + +struct cmd_results *bar_colors_cmd_empty_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.empty_workspace_border), + &(config->current_bar->colors.empty_workspace_bg), + &(config->current_bar->colors.empty_workspace_text) + }; + return parse_three_colors(colors, "empty_workspace", argc, argv); +} diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index a14ebb209..62f8e12b6 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -9,6 +9,7 @@ #include "list.h" #include "log.h" #include "stringop.h" +#include "util.h" static struct workspace_config *workspace_config_find_or_create(char *ws_name) { struct workspace_config *wsc = workspace_find_config(ws_name); @@ -129,6 +130,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { int output_location = -1; int gaps_location = -1; + int persistent_location = -1; for (int i = 0; i < argc; ++i) { if (strcasecmp(argv[i], "output") == 0) { @@ -142,6 +144,13 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { break; } } + for (int i = 0; i < argc; ++i) { + if (strcasecmp(argv[i], "persistent") == 0) { + persistent_location = i; + break; + } + } + if (output_location == 0) { return cmd_results_new(CMD_INVALID, "Expected 'workspace output '"); @@ -164,6 +173,24 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { if ((error = cmd_workspace_gaps(argc, argv, gaps_location))) { return error; } + } else if (persistent_location == 0) { + return cmd_results_new(CMD_INVALID, + "Expected 'workspace persistent yes|no'"); + } else if (persistent_location > 0) { + if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, + persistent_location + 2))) { + return error; + } + + struct sway_workspace *ws = NULL; + + char *ws_name = join_args(argv, persistent_location); + if (!(ws = workspace_by_name(ws_name))) { + ws = workspace_create(NULL, ws_name); + } + free(ws_name); + ws->persistent = parse_boolean(argv[persistent_location + 1], ws->persistent); + workspace_consider_destroy(ws); } else { if (config->reading || !config->active) { return cmd_results_new(CMD_DEFER, NULL); diff --git a/sway/config/bar.c b/sway/config/bar.c index ecefb61af..580914475 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -67,6 +67,9 @@ void free_bar_config(struct bar_config *bar) { free(bar->colors.urgent_workspace_border); free(bar->colors.urgent_workspace_bg); free(bar->colors.urgent_workspace_text); + free(bar->colors.empty_workspace_border); + free(bar->colors.empty_workspace_bg); + free(bar->colors.empty_workspace_text); free(bar->colors.binding_mode_border); free(bar->colors.binding_mode_bg); free(bar->colors.binding_mode_text); @@ -161,6 +164,15 @@ struct bar_config *default_bar_config(void) { if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) { goto cleanup; } + if (!(bar->colors.empty_workspace_border = strndup("#000000ff", 9))) { + goto cleanup; + } + if (!(bar->colors.empty_workspace_bg = strndup("#000000ff", 9))) { + goto cleanup; + } + if (!(bar->colors.empty_workspace_text = strndup("#666666FF", 9))) { + goto cleanup; + } // if the following colors stay undefined, they fall back to background, // statusline, separator and urgent_workspace_*. bar->colors.focused_background = NULL; diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 142512eb2..4bfd473c5 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -511,6 +511,8 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace, json_object_new_string(workspace->output->wlr_output->name) : NULL); json_object_object_add(object, "urgent", json_object_new_boolean(workspace->urgent)); + json_object_object_add(object, "empty", + json_object_new_boolean(workspace_is_empty(workspace))); json_object_object_add(object, "representation", workspace->representation ? json_object_new_string(workspace->representation) : NULL); @@ -1364,6 +1366,13 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { json_object_object_add(colors, "urgent_workspace_text", json_object_new_string(bar->colors.urgent_workspace_text)); + json_object_object_add(colors, "empty_workspace_border", + json_object_new_string(bar->colors.empty_workspace_border)); + json_object_object_add(colors, "empty_workspace_bg", + json_object_new_string(bar->colors.empty_workspace_bg)); + json_object_object_add(colors, "empty_workspace_text", + json_object_new_string(bar->colors.empty_workspace_text)); + if (bar->colors.binding_mode_border) { json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.binding_mode_border)); diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index a1733aa2b..6476f4c9a 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd @@ -228,6 +228,10 @@ must be defined in hex: _#RRGGBB_ or _#RRGGBBAA_. Border, background and text color for a workspace button when the workspace contains a window with the urgency hint set. +*empty_workspace* + Border, background and text color for a workspace button when the workspace + contains no windows and is not active. + *binding_mode* Border, background and text color for the binding mode indicator. If not used, the colors will be taken from _urgent_workspace_. diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index f39e35180..4b80447ac 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -139,6 +139,9 @@ has the following properties: |- urgent : boolean : Whether a view on the workspace has the urgent flag set +|- empty +: boolean +: Whether the workspace is empty |- rect : object : The bounds of the workspace. It consists of _x_, _y_, _width_, and _height_ @@ -931,6 +934,15 @@ containing the _#RRGGBBAA_ representation of the color: |- urgent_workspace_border : The color to use for the border of the workspace buttons for workspaces that contain an urgent view +|- empty_workspace_text +: The color to use for the text of the workspace buttons for workspaces that + are empty +|- empty_workspace_bg +: The color to use for the background of the workspace buttons for workspaces + that are empty +|- empty_workspace_border +: The color to use for the border of the workspace buttons for workspaces that + are empty |- binding_mode_text : The color to use for the text of the binding mode indicator |- binding_mode_bg @@ -980,6 +992,9 @@ containing the _#RRGGBBAA_ representation of the color: "urgent_workspace_border": "#2f343aff", "urgent_workspace_bg": "#900000ff", "urgent_workspace_text": "#ffffffff", + "empty_workspace_border": "#000000ff", + "empty_workspace_bg": "#000000ff", + "empty_workspace_text": "#666666ff", "binding_mode_border": "#2f343aff", "binding_mode_bg": "#900000ff", "binding_mode_text": "#ffffffff" @@ -1585,6 +1600,7 @@ The following change types are currently available: "num": 2, "output": "eDP-1", "type": "workspace", + "empty": true, "representation": null, "nodes": [ ] diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 11468d777..872423154 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -961,6 +961,13 @@ The default colors are: criteria (non-empty workspaces only) or _workspace_ command (to switch to the workspace before moving). +*workspace* persistent yes|no + Specifies that workspace _name_ should not be destroyed when it is empty and + inactive. + + This command will apply to an existing workspace or create it if it doesn't + exist. + *workspace_auto_back_and_forth* yes|no When _yes_, repeating a workspace switch command will switch back to the prior workspace. For example, if you are currently on workspace 1, diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index a09dc3a45..035560852 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -89,6 +89,7 @@ struct sway_workspace *workspace_create(struct sway_output *output, ws->floating = create_list(); ws->tiling = create_list(); ws->output_priority = create_list(); + ws->persistent = false; ws->gaps_outer = config->gaps_outer; ws->gaps_inner = config->gaps_inner; @@ -187,6 +188,11 @@ void workspace_consider_destroy(struct sway_workspace *ws) { } } + if (ws->persistent) { + ipc_event_workspace(NULL, ws, "empty"); + return; + } + workspace_begin_destroy(ws); } diff --git a/swaybar/config.c b/swaybar/config.c index 55bfcb722..1da562b91 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -72,6 +72,10 @@ struct swaybar_config *init_config(void) { config->colors.urgent_workspace.background = 0x900000FF; config->colors.urgent_workspace.text = 0xFFFFFFFF; + config->colors.empty_workspace.border = 0x000000FF; + config->colors.empty_workspace.background = 0x000000FF; + config->colors.empty_workspace.text = 0x666666FF; + config->colors.binding_mode.border = 0x2F343AFF; config->colors.binding_mode.background = 0x900000FF; config->colors.binding_mode.text = 0xFFFFFFFF; diff --git a/swaybar/ipc.c b/swaybar/ipc.c index f651f0359..05e0d76ca 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -77,6 +77,9 @@ static void ipc_parse_colors( { "urgent_workspace_border", &config->colors.urgent_workspace.border }, { "urgent_workspace_bg", &config->colors.urgent_workspace.background }, { "urgent_workspace_text", &config->colors.urgent_workspace.text }, + { "empty_workspace_border", &config->colors.empty_workspace.border }, + { "empty_workspace_bg", &config->colors.empty_workspace.background }, + { "empty_workspace_text", &config->colors.empty_workspace.text }, { "binding_mode_border", &config->colors.binding_mode.border }, { "binding_mode_bg", &config->colors.binding_mode.background }, { "binding_mode_text", &config->colors.binding_mode.text }, @@ -355,7 +358,7 @@ bool ipc_get_workspaces(struct swaybar *bar) { bar->visible_by_urgency = false; size_t length = json_object_array_length(results); json_object *ws_json; - json_object *num, *name, *visible, *focused, *out, *urgent; + json_object *num, *name, *visible, *focused, *out, *urgent, *empty; for (size_t i = 0; i < length; ++i) { ws_json = json_object_array_get_idx(results, i); @@ -365,6 +368,7 @@ bool ipc_get_workspaces(struct swaybar *bar) { json_object_object_get_ex(ws_json, "focused", &focused); json_object_object_get_ex(ws_json, "output", &out); json_object_object_get_ex(ws_json, "urgent", &urgent); + json_object_object_get_ex(ws_json, "empty", &empty); wl_list_for_each(output, &bar->outputs, link) { const char *ws_output = json_object_get_string(out); @@ -399,6 +403,7 @@ bool ipc_get_workspaces(struct swaybar *bar) { if (ws->urgent) { bar->visible_by_urgency = true; } + ws->empty = json_object_get_boolean(empty); wl_list_insert(output->workspaces.prev, &ws->link); } } diff --git a/swaybar/render.c b/swaybar/render.c index 45faefa97..1f73196ef 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -625,6 +625,8 @@ static uint32_t render_workspace_button(struct render_context *ctx, box_colors = config->colors.focused_workspace; } else if (ws->visible) { box_colors = config->colors.active_workspace; + } else if (ws->empty) { + box_colors = config->colors.empty_workspace; } else { box_colors = config->colors.inactive_workspace; }