From f57149deddedf63203d2a470d7ab4519aae91e77 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 9 Jun 2023 20:15:00 +0200 Subject: [PATCH 1/7] Implement `workspace persistent yes|no` --- include/sway/tree/workspace.h | 1 + sway/commands/workspace.c | 27 +++++++++++++++++++++++++++ sway/tree/workspace.c | 5 +++++ 3 files changed, 33 insertions(+) diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index b0fef4ca7..55412c37c 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -42,6 +42,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/sway/commands/workspace.c b/sway/commands/workspace.c index 03e488ba9..01da27fcc 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -10,6 +10,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); @@ -130,6 +131,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) { @@ -143,6 +145,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 '"); @@ -165,6 +174,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/tree/workspace.c b/sway/tree/workspace.c index 18218768b..b32f15aab 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -77,6 +77,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; @@ -154,6 +155,10 @@ void workspace_begin_destroy(struct sway_workspace *workspace) { } void workspace_consider_destroy(struct sway_workspace *ws) { + if (ws->persistent) { + return; + } + if (ws->tiling->length || ws->floating->length) { return; } From d3ac8566882a77ccc407e120df841cc22d9589bc Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 9 Jun 2023 20:15:58 +0200 Subject: [PATCH 2/7] Implement `empty` flag for workspaces in ipc --- sway/ipc-json.c | 2 ++ swaybar/ipc.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sway/ipc-json.c b/sway/ipc-json.c index c7cbea013..f770e9844 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -506,6 +506,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); diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 33ae65448..18dfd7ad1 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -355,7 +355,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 +365,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 +400,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); } } From 173c918e43609ac332028a8f3f4f308af167c861 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 9 Jun 2023 20:16:39 +0200 Subject: [PATCH 3/7] Implement `empty` workspaces in swaybar --- include/sway/commands.h | 1 + include/sway/config.h | 3 +++ include/swaybar/bar.h | 1 + include/swaybar/config.h | 1 + sway/commands/bar/colors.c | 10 ++++++++++ sway/config/bar.c | 12 ++++++++++++ sway/ipc-json.c | 7 +++++++ swaybar/config.c | 4 ++++ swaybar/ipc.c | 3 +++ swaybar/render.c | 2 ++ 10 files changed, 44 insertions(+) diff --git a/include/sway/commands.h b/include/sway/commands.h index 3212c2cf4..ceea16389 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -244,6 +244,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 aa58da531..8a104b16b 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -387,6 +387,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/swaybar/bar.h b/include/swaybar/bar.h index 3ad0bdf3c..95b60a8f0 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -86,6 +86,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/config/bar.c b/sway/config/bar.c index a8389244f..04e2190df 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 f770e9844..fb3d40854 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -1307,6 +1307,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/swaybar/config.c b/swaybar/config.c index 5e8287734..572501e87 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -73,6 +73,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 18dfd7ad1..10a136d04 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 }, diff --git a/swaybar/render.c b/swaybar/render.c index 1113ca44a..b814621f0 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -623,6 +623,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; } From f1f503b2798be3675bf8611b518021dbeb6da926 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 9 Jun 2023 20:56:08 +0200 Subject: [PATCH 4/7] Add docs for `workspace persistent yes|no` --- sway/sway.5.scd | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 78d7d2316..baf568c8a 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -920,6 +920,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, From 71f9f2d9d82b7290dcb4e4f6364a5abcf402b8d8 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 9 Jun 2023 20:56:37 +0200 Subject: [PATCH 5/7] Add docs for `empty` flag for workspaces in ipc --- sway/sway-ipc.7.scd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index 42aaaab67..e49c97a04 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_ @@ -1562,6 +1565,7 @@ The following change types are currently available: "num": 2, "output": "eDP-1", "type": "workspace", + "empty": true, "representation": null, "nodes": [ ] From 409bc681ff41f25327045b380221a78cbb942ff5 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 9 Jun 2023 20:56:54 +0200 Subject: [PATCH 6/7] Add docs for `empty` workspaces in swaybar --- sway/sway-bar.5.scd | 4 ++++ sway/sway-ipc.7.scd | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index 42e59d57d..27709d071 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd @@ -222,6 +222,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 e49c97a04..b62991a39 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -918,6 +918,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 @@ -967,6 +976,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" From 5438d6631f0fd93f07f0d4f44e8639c10558eb04 Mon Sep 17 00:00:00 2001 From: Marko Date: Sat, 10 Jun 2023 03:10:05 +0200 Subject: [PATCH 7/7] Make sure to send the `empty` event --- sway/tree/workspace.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index b32f15aab..921e8f6bd 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -155,10 +155,6 @@ void workspace_begin_destroy(struct sway_workspace *workspace) { } void workspace_consider_destroy(struct sway_workspace *ws) { - if (ws->persistent) { - return; - } - if (ws->tiling->length || ws->floating->length) { return; } @@ -175,6 +171,11 @@ void workspace_consider_destroy(struct sway_workspace *ws) { } } + if (ws->persistent) { + ipc_event_workspace(NULL, ws, "empty"); + return; + } + workspace_begin_destroy(ws); }