From 1fd2c6ba498e61f4fe823bf552f9d2fce8612de4 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Mon, 2 Sep 2019 21:41:11 -0400 Subject: swaybar: complete barconfig_update event handling This adds complete support for the barconfig_update ipc event. This also changes the bar command and subcommand handlers to correctly emit the event. This makes it so all bar subcommands other than id and swaybar_command are dynamically changeable at runtime. sway-bar.5 has been updated accordingly --- include/swaybar/bar.h | 5 + include/swaybar/config.h | 5 +- sway/commands/bar.c | 93 +++++----- sway/commands/bar/hidden_state.c | 8 +- sway/commands/bar/mode.c | 8 +- sway/commands/bar/output.c | 15 +- sway/commands/bar/status_command.c | 5 - sway/commands/bar/tray_output.c | 12 ++ sway/config/bar.c | 1 - sway/sway-bar.5.scd | 146 ++++++++------- sway/sway.5.scd | 12 -- swaybar/bar.c | 35 +++- swaybar/config.c | 4 +- swaybar/ipc.c | 367 +++++++++++++++++++++---------------- swaybar/status_line.c | 3 + 15 files changed, 405 insertions(+), 314 deletions(-) diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 10984ab0..545a66a8 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -41,6 +41,7 @@ struct swaybar { int ipc_socketfd; struct wl_list outputs; // swaybar_output::link + struct wl_list unused_outputs; // swaybar_output::link struct wl_list seats; // swaybar_seat::link #if HAVE_TRAY @@ -109,4 +110,8 @@ void set_bar_dirty(struct swaybar *bar); bool determine_bar_visibility(struct swaybar *bar, bool moving_layer); void free_workspaces(struct wl_list *list); +void status_in(int fd, short mask, void *data); + +void destroy_layer_surface(struct swaybar_output *output); + #endif diff --git a/include/swaybar/config.h b/include/swaybar/config.h index ec042e51..688fa2d7 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h @@ -16,7 +16,6 @@ struct box_colors { struct config_output { struct wl_list link; // swaybar_config::outputs char *name; - size_t index; }; struct swaybar_binding { @@ -41,7 +40,6 @@ struct swaybar_config { bool workspace_buttons; list_t *bindings; struct wl_list outputs; // config_output::link - bool all_outputs; int height; int status_padding; int status_edge_padding; @@ -83,10 +81,13 @@ struct tray_binding { char *command; struct wl_list link; // struct tray_binding::link }; + +void free_tray_binding(struct tray_binding *binding); #endif struct swaybar_config *init_config(void); void free_config(struct swaybar_config *config); uint32_t parse_position(const char *position); +void free_binding(struct swaybar_binding *binding); #endif diff --git a/sway/commands/bar.c b/sway/commands/bar.c index 88580ffb..7370910d 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c @@ -4,6 +4,7 @@ #include #include "sway/commands.h" #include "sway/config.h" +#include "sway/ipc-server.h" #include "log.h" // Must be in alphabetical order for bsearch @@ -56,30 +57,27 @@ struct cmd_results *cmd_bar(int argc, char **argv) { return error; } - bool spawn = false; - struct bar_config *bar = NULL; + char *id = NULL; if (strcmp(argv[0], "id") != 0 && is_subcommand(argv[1])) { for (int i = 0; i < config->bars->length; ++i) { struct bar_config *item = config->bars->items[i]; if (strcmp(item->id, argv[0]) == 0) { sway_log(SWAY_DEBUG, "Selecting bar: %s", argv[0]); - bar = item; + config->current_bar = item; break; } } - if (!bar) { - spawn = !config->reading; - sway_log(SWAY_DEBUG, "Creating bar: %s", argv[0]); - bar = default_bar_config(); - if (!bar) { - return cmd_results_new(CMD_FAILURE, - "Unable to allocate bar state"); - } - - bar->id = strdup(argv[0]); + if (!config->current_bar) { + id = strdup(argv[0]); } - config->current_bar = bar; ++argv; --argc; + } else if (config->reading && !config->current_bar) { + int len = snprintf(NULL, 0, "bar-%d", config->bars->length) + 1; + id = malloc(len * sizeof(char)); + if (!id) { + return cmd_results_new(CMD_FAILURE, "Unable to allocate bar id"); + } + snprintf(id, len, "bar-%d", config->bars->length); } else if (!config->reading && strcmp(argv[0], "mode") != 0 && strcmp(argv[0], "hidden_state") != 0) { if (is_subcommand(argv[0])) { @@ -90,56 +88,49 @@ struct cmd_results *cmd_bar(int argc, char **argv) { } } - if (!config->current_bar) { - if (config->reading) { - // Create new bar with default values - struct bar_config *bar = default_bar_config(); - if (!bar) { - return cmd_results_new(CMD_FAILURE, - "Unable to allocate bar state"); - } - - // set bar id - int len = snprintf(NULL, 0, "bar-%d", config->bars->length - 1) + 1; - bar->id = malloc(len * sizeof(char)); - if (bar->id) { - snprintf(bar->id, len, "bar-%d", config->bars->length - 1); - } else { - return cmd_results_new(CMD_FAILURE, "Unable to allocate bar ID"); - } - - // Set current bar - config->current_bar = bar; - sway_log(SWAY_DEBUG, "Creating bar %s", bar->id); + if (id) { + sway_log(SWAY_DEBUG, "Creating bar: %s", id); + config->current_bar = default_bar_config(); + if (!config->current_bar) { + free(id); + return cmd_results_new(CMD_FAILURE, "Unable to allocate bar config"); } + config->current_bar->id = id; } + struct cmd_results *res = NULL; if (find_handler(argv[0], bar_config_handlers, sizeof(bar_config_handlers))) { if (config->reading) { - return config_subcommand(argv, argc, bar_config_handlers, + res = config_subcommand(argv, argc, bar_config_handlers, sizeof(bar_config_handlers)); - } else if (spawn) { - for (int i = config->bars->length - 1; i >= 0; i--) { - struct bar_config *bar = config->bars->items[i]; - if (bar == config->current_bar) { - list_del(config->bars, i); - free_bar_config(bar); - break; - } - } + } else { + res = cmd_results_new(CMD_INVALID, + "Can only be used in the config file"); + } + } else { + res = config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers)); + } + + if (res && res->status != CMD_SUCCESS) { + if (id) { + free_bar_config(config->current_bar); + id = NULL; } - return cmd_results_new(CMD_INVALID, - "Can only be used in the config file."); + return res; + } + + if (id) { + list_add(config->bars, config->current_bar); } - struct cmd_results *res = - config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers)); - if (!config->reading) { - if (spawn) { + if (!config->reading && config->current_bar) { + ipc_event_barconfig_update(config->current_bar); + if (id) { load_swaybar(config->current_bar); } config->current_bar = NULL; } + return res; } diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c index b2c2d245..1f08a5d2 100644 --- a/sway/commands/bar/hidden_state.c +++ b/sway/commands/bar/hidden_state.c @@ -23,7 +23,7 @@ static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, return cmd_results_new(CMD_INVALID, "Invalid value %s", hidden_state); } if (strcmp(old_state, bar->hidden_state) != 0) { - if (!config->reading) { + if (!config->current_bar) { ipc_event_barconfig_update(bar); } sway_log(SWAY_DEBUG, "Setting hidden_state: '%s' for bar: %s", @@ -47,6 +47,12 @@ struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { "Unexpected value %s in config mode", argv[1]); } + if (config->current_bar && argc == 2 && + strcmp(config->current_bar->id, argv[1]) != 0) { + return cmd_results_new(CMD_INVALID, "Conflicting bar ids: %s and %s", + config->current_bar->id, argv[1]); + } + const char *state = argv[0]; if (config->reading) { error = bar_set_hidden_state(config->current_bar, state); diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c index 1081ad4b..8b3fb275 100644 --- a/sway/commands/bar/mode.c +++ b/sway/commands/bar/mode.c @@ -27,7 +27,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode } if (strcmp(old_mode, bar->mode) != 0) { - if (!config->reading) { + if (!config->current_bar) { ipc_event_barconfig_update(bar); } sway_log(SWAY_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); @@ -51,6 +51,12 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) { "Unexpected value %s in config mode", argv[1]); } + if (config->current_bar && argc == 2 && + strcmp(config->current_bar->id, argv[1]) != 0) { + return cmd_results_new(CMD_INVALID, "Conflicting bar ids: %s and %s", + config->current_bar->id, argv[1]); + } + const char *mode = argv[0]; if (config->reading) { error = bar_set_mode(config->current_bar, mode); diff --git a/sway/commands/bar/output.c b/sway/commands/bar/output.c index 6a78b30d..cac1d056 100644 --- a/sway/commands/bar/output.c +++ b/sway/commands/bar/output.c @@ -21,16 +21,19 @@ struct cmd_results *bar_cmd_output(int argc, char **argv) { bool add_output = true; if (strcmp("*", output) == 0) { // remove all previous defined outputs and replace with '*' - for (int i = 0; i < outputs->length; ++i) { - free(outputs->items[i]); - list_del(outputs, i); + while (outputs->length) { + free(outputs->items[0]); + list_del(outputs, 0); } } else { - // only add output if not already defined with either the same - // name or as '*' + // only add output if not already defined, if the list has '*', remove + // it, in favor of a manual list for (int i = 0; i < outputs->length; ++i) { const char *find = outputs->items[i]; - if (strcmp("*", find) == 0 || strcmp(output, find) == 0) { + if (strcmp("*", find) == 0) { + free(outputs->items[i]); + list_del(outputs, i); + } else if (strcmp(output, find) == 0) { add_output = false; break; } diff --git a/sway/commands/bar/status_command.c b/sway/commands/bar/status_command.c index 77a73ab6..bb92e8e0 100644 --- a/sway/commands/bar/status_command.c +++ b/sway/commands/bar/status_command.c @@ -19,10 +19,5 @@ struct cmd_results *bar_cmd_status_command(int argc, char **argv) { } else { free(new_command); } - - if (config->active && !config->validating) { - load_swaybar(config->current_bar); - } - return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/bar/tray_output.c b/sway/commands/bar/tray_output.c index 8bfdf193..eb3b486e 100644 --- a/sway/commands/bar/tray_output.c +++ b/sway/commands/bar/tray_output.c @@ -24,9 +24,21 @@ struct cmd_results *bar_cmd_tray_output(int argc, char **argv) { free(outputs->items[i]); } outputs->length = 0; + } else if (strcmp(argv[0], "*") == 0) { + sway_log(SWAY_DEBUG, "Showing tray on all outputs for bar: %s", + config->current_bar->id); + while (outputs->length) { + free(outputs->items[0]); + list_del(outputs, 0); + } + return cmd_results_new(CMD_SUCCESS, NULL); } else { sway_log(SWAY_DEBUG, "Showing tray on output '%s' for bar: %s", argv[0], config->current_bar->id); + if (outputs->length == 1 && strcmp(outputs->items[0], "none") == 0) { + free(outputs->items[0]); + list_del(outputs, 0); + } } list_add(outputs, strdup(argv[0])); diff --git a/sway/config/bar.c b/sway/config/bar.c index 4ab98ff1..9c30204e 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -172,7 +172,6 @@ struct bar_config *default_bar_config(void) { wl_list_init(&bar->tray_bindings); #endif - list_add(config->bars, bar); return bar; cleanup: free_bar_config(bar); diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index 36e84496..78124c92 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd @@ -10,58 +10,38 @@ Sway allows configuring swaybar in the sway configuration file. # COMMANDS -*status_command* - Executes the bar _status command_ with _sh -c_. Each line of text printed - to stdout from this command will be displayed in the status area of the - bar. You may also use swaybar's JSON status line protocol. See - *swaybar-protocol*(7) for more information on the protocol - - If running this command via IPC, you can disable a running status command by - setting the command to a single dash: _swaybar bar bar-0 status\_command -_ - -*pango_markup* enabled|disabled - Enables or disables pango markup for status lines. This has no effect on - status lines using the i3bar JSON protocol. +The following commands may only be used in the configuration file. *id* Sets the ID of the bar. -*position* top|bottom - Sets position of the bar. Default is _bottom_. - -*output* - Restrict the bar to a certain output, can be specified multiple times. If - the output command is omitted, the bar will be displayed on all outputs. - *swaybar_command* Executes custom bar command. Default is _swaybar_. -*font* - Specifies the font to be used in the bar. _font_ should be specified as a - pango font description. For more information on pango font descriptions, - see https://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string +The following commands may be used either in the configuration file or at +runtime. -*separator_symbol* - Specifies the separator symbol to separate blocks on the bar. - -*wrap_scroll* yes|no - Enables or disables wrapping when scrolling through workspaces with the - scroll wheel. Default is _no_. - -*workspace_buttons* yes|no - Enables or disables workspace buttons on the bar. Default is _yes_. - -*strip_workspace_name* yes|no - If set to _yes_, then workspace names will be omitted from the workspace - button and only the custom number will be shown. Default is _no_. +*bindcode* [--release] + Executes _command_ when the mouse button has been pressed (or if _released_ + is given, when the button has been released). The buttons can be given as + an event code, which can be obtaining from *libinput debug-events*. To + disable the default behavior for a button, use the command _nop_. -*strip_workspace_numbers* yes|no - If set to _yes_, then workspace numbers will be omitted from the workspace - button and only the custom name will be shown. Default is _no_. +*bindsym* [--release] button[1-9]| + Executes _command_ when the mouse button has been pressed (or if _released_ + is given, when the button has been released). The buttons can be given as a + x11 button number or an event name, which can be obtained from *libinput + debug-events*. To disable the default behavior for a button, use the + command _nop_. *binding_mode_indicator* yes|no Enable or disable binding mode indicator. Default is _yes_. +*font* + Specifies the font to be used in the bar. _font_ should be specified as a + pango font description. For more information on pango font descriptions, + see https://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string + *gaps* | | Sets the gaps from the edge of the screen for the bar. Gaps can either be set all at once, per direction, or per side. Note that only sides that @@ -72,20 +52,21 @@ Sway allows configuring swaybar in the sway configuration file. *height* Sets the height of the bar. Default height (0) will match the font size. -*bindcode* [--release] - Executes _command_ when the mouse button has been pressed (or if _released_ - is given, when the button has been released). The buttons can be given as - an event code, which can be obtaining from *libinput debug-events*. To - disable the default behavior for a button, use the command _nop_. +*hidden_state* hide|show [] + Specifies the behaviour of the bar when it is in _hide_ mode. When the + hidden state is _hide_, then it is normally hidden, and only unhidden by + pressing the modifier key or in case of urgency hints. When the hidden + state is _show_, then it is permanently visible, drawn on top of the + currently visible workspace. Default is _hide_. -*bindsym* [--release] button[1-9]| - Executes _command_ when the mouse button has been pressed (or if _released_ - is given, when the button has been released). The buttons can be given as a - x11 button number or an event name, which can be obtained from *libinput - debug-events*. To disable the default behavior for a button, use the - command _nop_. + For compatibility with i3, _bar hidden_state hide|show []_ is + supported along with the sway only _bar hidden_state hide|show_ + syntax. When using the i3 syntax, if _bar-id_ is omitted, the hidden_state + will be changed for all bars. Attempting to use _bar + hidden_state hide|show _ will result in an error due to + conflicting bar ids. -*mode* dock|hide|invisible|overlay +*mode* dock|hide|invisible|overlay [] Specifies the visibility of the bar. In _dock_ mode, it is permanently visible at one edge of the screen. In _hide_ mode, it is hidden unless the modifier key is pressed, though this behaviour depends on the hidden state. @@ -93,32 +74,70 @@ Sway allows configuring swaybar in the sway configuration file. permanently visible on top of other windows. (In _overlay_ mode the bar is transparent to input events.) Default is _dock_. -*hidden_state* hide|show - Specifies the behaviour of the bar when it is in _hide_ mode. When the - hidden state is _hide_, then it is normally hidden, and only unhidden by - pressing the modifier key or in case of urgency hints. When the hidden - state is _show_, then it is permanently visible, drawn on top of the - currently visible workspace. Default is _hide_. + For compatibility with i3, _bar mode []_ syntax is supported + along with the sway only _bar mode _ syntax. When using the + i3 syntax, if _bar-id_ is omitted, the mode will be changed for all bars. + Attempting to use _bar mode _ will result in an + error due to conflicting bar ids. *modifier* |none Specifies the modifier key that shows a hidden bar. Default is _Mod4_. -*status_padding* - Sets the vertical padding that is used for the status line. The default is - _1_. If _padding_ is _0_, blocks will be able to take up the full height of - the bar. This value will be multiplied by the output scale. +*output* |\* + Restrict the bar to a certain output, can be specified multiple times. If + the output command is omitted, the bar will be displayed on all outputs. _\*_ + can be given at any point to reset it back to all outputs. + +*pango_markup* enabled|disabled + Enables or disables pango markup for status lines. This has no effect on + status lines using the i3bar JSON protocol. + +*position* top|bottom + Sets position of the bar. Default is _bottom_. + +*separator_symbol* + Specifies the separator symbol to separate blocks on the bar. + +*status_command* + Executes the bar _status command_ with _sh -c_. Each line of text printed + to stdout from this command will be displayed in the status area of the + bar. You may also use swaybar's JSON status line protocol. See + *swaybar-protocol*(7) for more information on the protocol + + If running this command via IPC, you can disable a running status command by + setting the command to a single dash: _swaybar bar bar-0 status\_command -_ *status_edge_padding* Sets the padding that is used when the status line is at the right edge of the bar. This value will be multiplied by the output scale. The default is _3_. +*status_padding* + Sets the vertical padding that is used for the status line. The default is + _1_. If _padding_ is _0_, blocks will be able to take up the full height of + the bar. This value will be multiplied by the output scale. + +*strip_workspace_name* yes|no + If set to _yes_, then workspace names will be omitted from the workspace + button and only the custom number will be shown. Default is _no_. + +*strip_workspace_numbers* yes|no + If set to _yes_, then workspace numbers will be omitted from the workspace + button and only the custom name will be shown. Default is _no_. + *unbindcode* [--release] Removes the binding with the given . *unbindsym* [--release] button[1-9]| Removes the binding with the given