diff options
author | Brian Ashworth <bosrsf04@gmail.com> | 2019-09-02 21:41:11 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-09-04 16:48:50 -1000 |
commit | 1fd2c6ba498e61f4fe823bf552f9d2fce8612de4 (patch) | |
tree | 8e2d9adab3451f1f05c76340d466a442c840e558 | |
parent | 187306640ba8f2ab2f246a5030617ee985cf9223 (diff) |
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
-rw-r--r-- | include/swaybar/bar.h | 5 | ||||
-rw-r--r-- | include/swaybar/config.h | 5 | ||||
-rw-r--r-- | sway/commands/bar.c | 93 | ||||
-rw-r--r-- | sway/commands/bar/hidden_state.c | 8 | ||||
-rw-r--r-- | sway/commands/bar/mode.c | 8 | ||||
-rw-r--r-- | sway/commands/bar/output.c | 15 | ||||
-rw-r--r-- | sway/commands/bar/status_command.c | 5 | ||||
-rw-r--r-- | sway/commands/bar/tray_output.c | 12 | ||||
-rw-r--r-- | sway/config/bar.c | 1 | ||||
-rw-r--r-- | sway/sway-bar.5.scd | 146 | ||||
-rw-r--r-- | sway/sway.5.scd | 12 | ||||
-rw-r--r-- | swaybar/bar.c | 35 | ||||
-rw-r--r-- | swaybar/config.c | 4 | ||||
-rw-r--r-- | swaybar/ipc.c | 367 | ||||
-rw-r--r-- | 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 <strings.h> #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* <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* <bar_id> Sets the ID of the bar. -*position* top|bottom - Sets position of the bar. Default is _bottom_. - -*output* <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* <command> Executes custom bar command. Default is _swaybar_. -*font* <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* <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] <event-code> <command> + 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]|<event-name> <command> + 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* <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* <all> | <horizontal> <vertical> | <top> <right> <bottom> <left> 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* <height> Sets the height of the bar. Default height (0) will match the font size. -*bindcode* [--release] <event-code> <command> - 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 [<bar-id>] + 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]|<event-name> <command> - 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 [<bar-id>]_ is + supported along with the sway only _bar <bar-id> 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 <bar-id1> + hidden_state hide|show <bar-id2>_ will result in an error due to + conflicting bar ids. -*mode* dock|hide|invisible|overlay +*mode* dock|hide|invisible|overlay [<bar-id>] 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 <mode> [<bar-id>]_ syntax is supported + along with the sway only _bar <bar-id> mode <mode>_ syntax. When using the + i3 syntax, if _bar-id_ is omitted, the mode will be changed for all bars. + Attempting to use _bar <bar-id1> mode <mode> <bar-id2>_ will result in an + error due to conflicting bar ids. *modifier* <Modifier>|none Specifies the modifier key that shows a hidden bar. Default is _Mod4_. -*status_padding* <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* <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* <symbol> + Specifies the separator symbol to separate blocks on the bar. + +*status_command* <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* <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* <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] <event-code> Removes the binding with the given <event-code>. *unbindsym* [--release] button[1-9]|<event-name> Removes the binding with the given <button> or <event-name>. +*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_. + ## TRAY Swaybar provides a system tray where third-party applications may place icons. @@ -142,10 +161,11 @@ ContextMenu|Activate|SecondaryActivate|ScrollDown|ScrollLeft|ScrollRight|ScrollU Sets the pixel padding of the system tray. This padding will surround the tray on all sides and between each item. The default value for _px_ is 2. -*tray_output* none|<output> +*tray_output* none|<output>|\* Restrict the tray to a certain output, can be specified multiple times. If omitted, the tray will be displayed on all outputs. Unlike i3bar, swaybar - can show icons on any number of bars and outputs without races. + can show icons on any number of bars and outputs without races. _\*_ can be + given at any point to reset it to display on all outputs. *icon_theme* <name> Sets the icon theme that sway will look for item icons in. This option has diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 280b6176..d6ba2e11 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -755,18 +755,6 @@ The default colors are: *workspace_layout* default|stacking|tabbed Specifies the initial layout for new workspaces. -# BAR CONTROL - -*bar hidden_state* hide|show|toggle [<bar_id>] - Sets the hidden state of the bar (see *sway-bar*(5)), either individually, - by specifying a bar id, or if none is given, for all bar instances. - _toggle_ switches between _hide_ and _show_. - -*bar mode* dock|hide|invisible|toggle [<bar_id>] - Sets the mode of the bar (see *sway-bar*(5)), either individually, - by specifying a bar id, or if none is given, for all bar instances. - _toggle_ switches between _dock_ and _hide_. - # CRITERIA A criteria is a string in the form of, for example: diff --git a/swaybar/bar.c b/swaybar/bar.c index 35e1662b..efd0da4b 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -126,7 +126,7 @@ static void add_layer_surface(struct swaybar_output *output) { } } -static void destroy_layer_surface(struct swaybar_output *output) { +void destroy_layer_surface(struct swaybar_output *output) { if (!output->layer_surface) { return; } @@ -181,7 +181,7 @@ bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) { } static bool bar_uses_output(struct swaybar_output *output) { - if (output->bar->config->all_outputs) { + if (wl_list_empty(&output->bar->config->outputs)) { return true; } char *identifier = output->identifier; @@ -256,20 +256,27 @@ static void xdg_output_handle_done(void *data, struct swaybar_output *output = data; struct swaybar *bar = output->bar; + if (!wl_list_empty(&output->link)) { + return; + } + assert(output->name != NULL); if (!bar_uses_output(output)) { - swaybar_output_free(output); + wl_list_remove(&output->link); + wl_list_insert(&bar->unused_outputs, &output->link); return; } - if (wl_list_empty(&output->link)) { - wl_list_remove(&output->link); - wl_list_insert(&bar->outputs, &output->link); + wl_list_remove(&output->link); + wl_list_insert(&bar->outputs, &output->link); - output->surface = wl_compositor_create_surface(bar->compositor); - assert(output->surface); + output->surface = wl_compositor_create_surface(bar->compositor); + assert(output->surface); - determine_bar_visibility(bar, false); + determine_bar_visibility(bar, false); + + if (bar->running && bar->config->workspace_buttons) { + ipc_get_workspaces(bar); } } @@ -373,6 +380,12 @@ static void handle_global_remove(void *data, struct wl_registry *registry, return; } } + wl_list_for_each_safe(output, tmp, &bar->unused_outputs, link) { + if (output->wl_name == name) { + swaybar_output_free(output); + return; + } + } struct swaybar_seat *seat, *tmp_seat; wl_list_for_each_safe(seat, tmp_seat, &bar->seats, link) { if (seat->wl_name == name) { @@ -391,6 +404,7 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) { bar->visible = true; bar->config = init_config(); wl_list_init(&bar->outputs); + wl_list_init(&bar->unused_outputs); wl_list_init(&bar->seats); bar->eventloop = loop_create(); @@ -458,7 +472,7 @@ static void ipc_in(int fd, short mask, void *data) { } } -static void status_in(int fd, short mask, void *data) { +void status_in(int fd, short mask, void *data) { struct swaybar *bar = data; if (mask & (POLLHUP | POLLERR)) { status_error(bar->status, "[error reading from status command]"); @@ -510,6 +524,7 @@ void bar_teardown(struct swaybar *bar) { destroy_tray(bar->tray); #endif free_outputs(&bar->outputs); + free_outputs(&bar->unused_outputs); free_seats(&bar->seats); if (bar->config) { free_config(bar->config); diff --git a/swaybar/config.c b/swaybar/config.c index 6e36573c..52297310 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -84,7 +84,7 @@ struct swaybar_config *init_config(void) { return config; } -static void free_binding(struct swaybar_binding *binding) { +void free_binding(struct swaybar_binding *binding) { if (!binding) { return; } @@ -93,7 +93,7 @@ static void free_binding(struct swaybar_binding *binding) { } #if HAVE_TRAY -static void free_tray_binding(struct tray_binding *binding) { +void free_tray_binding(struct tray_binding *binding) { if (!binding) { return; } diff --git a/swaybar/ipc.c b/swaybar/ipc.c index a096f01a..afaffb04 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -1,15 +1,21 @@ #define _POSIX_C_SOURCE 200809 #include <limits.h> +#include <poll.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <json.h> #include "swaybar/config.h" #include "swaybar/ipc.h" +#include "swaybar/status_line.h" +#if HAVE_TRAY +#include "swaybar/tray/tray.h" +#endif #include "config.h" #include "ipc-client.h" #include "list.h" #include "log.h" +#include "loop.h" #include "util.h" void ipc_send_workspace_command(struct swaybar *bar, const char *ws) { @@ -169,75 +175,58 @@ static bool ipc_parse_config( json_object *success; if (json_object_object_get_ex(bar_config, "success", &success) && !json_object_get_boolean(success)) { - sway_log(SWAY_ERROR, "No bar with that ID. Use 'swaymsg -t get_bar_config to get the available bar configs."); + sway_log(SWAY_ERROR, "No bar with that ID. Use 'swaymsg -t " + "get_bar_config' to get the available bar configs."); json_object_put(bar_config); return false; } - json_object *markup, *mode, *hidden_state, *position, *status_command; - json_object *font, *gaps, *bar_height, *wrap_scroll, *workspace_buttons; - json_object *strip_workspace_numbers, *strip_workspace_name; - json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol; - json_object *outputs, *bindings, *status_padding, *status_edge_padding; - json_object_object_get_ex(bar_config, "mode", &mode); - json_object_object_get_ex(bar_config, "hidden_state", &hidden_state); - json_object_object_get_ex(bar_config, "position", &position); - json_object_object_get_ex(bar_config, "status_command", &status_command); - json_object_object_get_ex(bar_config, "font", &font); - json_object_object_get_ex(bar_config, "gaps", &gaps); - json_object_object_get_ex(bar_config, "bar_height", &bar_height); - json_object_object_get_ex(bar_config, "wrap_scroll", &wrap_scroll); - json_object_object_get_ex(bar_config, "workspace_buttons", &workspace_buttons); - json_object_object_get_ex(bar_config, "strip_workspace_numbers", &strip_workspace_numbers); - json_object_object_get_ex(bar_config, "strip_workspace_name", &strip_workspace_name); - json_object_object_get_ex(bar_config, "binding_mode_indicator", &binding_mode_indicator); - json_object_object_get_ex(bar_config, "verbose", &verbose); - json_object_object_get_ex(bar_config, "separator_symbol", &sep_symbol); - json_object_object_get_ex(bar_config, "colors", &colors); - json_object_object_get_ex(bar_config, "outputs", &outputs); - json_object_object_get_ex(bar_config, "pango_markup", &markup); - json_object_object_get_ex(bar_config, "bindings", &bindings); - json_object_object_get_ex(bar_config, "status_padding", &status_padding); - json_object_object_get_ex(bar_config, "status_edge_padding", - &status_edge_padding); - if (status_command) { - free(config->status_command); - config->status_command = strdup(json_object_get_string(status_command)); - } - if (position) { - config->position = parse_position(json_object_get_string(position)); - } - if (font) { - free(config->font); - config->font = parse_font(json_object_get_string(font)); - } - if (sep_symbol) { - free(config->sep_symbol); - config->sep_symbol = strdup(json_object_get_string(sep_symbol)); - } - if (strip_workspace_numbers) { - config->strip_workspace_numbers = json_object_get_boolean(strip_workspace_numbers); - } - if (strip_workspace_name) { - config->strip_workspace_name = json_object_get_boolean(strip_workspace_name); + + json_object *bar_height = json_object_object_get(bar_config, "bar_height"); + if (bar_height) { + config->height = json_object_get_int(bar_height); } + + json_object *binding_mode_indicator = + json_object_object_get(bar_config, "binding_mode_indicator"); if (binding_mode_indicator) { - config->binding_mode_indicator = json_object_get_boolean(binding_mode_indicator); + config->binding_mode_indicator = + json_object_get_boolean(binding_mode_indicator); } - if (wrap_scroll) { - config->wrap_scroll = json_object_get_boolean(wrap_scroll); - } - if (workspace_buttons) { - config->workspace_buttons = json_object_get_boolean(workspace_buttons); + + json_object *bindings = json_object_object_get(bar_config, "bindings"); + while (config->bindings->length) { + struct swaybar_binding *binding = config->bindings->items[0]; + list_del(config->bindings, 0); + free_binding(binding); } - if (bar_height) { - config->height = json_object_get_int(bar_height); + if (bindings) { + int length = json_object_array_length(bindings); + for (int i = 0; i < length; ++i) { + json_object *bindobj = json_object_array_get_idx(bindings, i); + struct swaybar_binding *binding = + calloc(1, sizeof(struct swaybar_binding)); + binding->button = json_object_get_int( + json_object_object_get(bindobj, "event_code")); + binding->command = strdup(json_object_get_string( + json_object_object_get(bindobj, "command"))); + binding->release = json_object_get_boolean( + json_object_object_get(bindobj, "release")); + list_add(config->bindings, binding); + } } - if (status_padding) { - config->status_padding = json_object_get_int(status_padding); + + json_object *colors = json_object_object_get(bar_config, "colors"); + if (colors) { + ipc_parse_colors(config, colors); } - if (status_edge_padding) { - config->status_edge_padding = json_object_get_int(status_edge_padding); + + json_object *font = json_object_object_get(bar_config, "font"); + if (font) { + free(config->font); + config->font = parse_font(json_object_get_string(font)); } + + json_object *gaps = json_object_object_get(bar_config, "gaps"); if (gaps) { json_object *top = json_object_object_get(gaps, "top"); if (top) { @@ -256,33 +245,21 @@ static bool ipc_parse_config( config->gaps.left = json_object_get_int(left); } } - if (markup) { - config->pango_markup = json_object_get_boolean(markup); - } - if (bindings) { - int length = json_object_array_length(bindings); - for (int i = 0; i < length; ++i) { - json_object *bindobj = json_object_array_get_idx(bindings, i); - struct swaybar_binding *binding = - calloc(1, sizeof(struct swaybar_binding)); - binding->button = json_object_get_int( - json_object_object_get(bindobj, "event_code")); - binding->command = strdup(json_object_get_string( - json_object_object_get(bindobj, "command"))); - binding->release = json_object_get_boolean( - json_object_object_get(bindobj, "release")); - list_add(config->bindings, binding); - } - } + + json_object *hidden_state = + json_object_object_get(bar_config, "hidden_state"); if (hidden_state) { free(config->hidden_state); config->hidden_state = strdup(json_object_get_string(hidden_state)); } + + json_object *mode = json_object_object_get(bar_config, "mode"); if (mode) { free(config->mode); config->mode = strdup(json_object_get_string(mode)); } + json_object *outputs = json_object_object_get(bar_config, "outputs"); struct config_output *output, *tmp; wl_list_for_each_safe(output, tmp, &config->outputs, link) { wl_list_remove(&output->link); @@ -295,40 +272,115 @@ static bool ipc_parse_config( json_object *output = json_object_array_get_idx(outputs, i); const char *name = json_object_get_string(output); if (strcmp("*", name) == 0) { - config->all_outputs = true; + struct config_output *coutput, *tmp; + wl_list_for_each_safe(coutput, tmp, &config->outputs, link) { + wl_list_remove(&coutput->link); + free(coutput->name); + free(coutput); + } break; } struct config_output *coutput = calloc( 1, sizeof(struct config_output)); coutput->name = strdup(name); - coutput->index = SIZE_MAX; wl_list_insert(&config->outputs, &coutput->link); } - } else { - config->all_outputs = true; } - if (colors) { - ipc_parse_colors(config, colors); + json_object *pango_markup = + json_object_object_get(bar_config, "pango_markup"); + if (pango_markup) { + config->pango_markup = json_object_get_boolean(pango_markup); + } + + json_object *position = json_object_object_get(bar_config, "position"); + if (position) { + config->position = parse_position(json_object_get_string(position)); + } + + json_object *separator_symbol = + json_object_object_get(bar_config, "separator_symbol"); + if (separator_symbol) { + free(config->sep_symbol); + config->sep_symbol = strdup(json_object_get_string(separator_symbol)); + } + + json_object *status_command = + json_object_object_get(bar_config, "status_command"); + if (status_command) { + const char *command = json_object_get_string(status_command); + free(config->status_command); + config->status_command = strdup(command); + } + + json_object *status_edge_padding = + json_object_object_get(bar_config, "status_edge_padding"); + if (status_edge_padding) { + config->status_edge_padding = json_object_get_int(status_edge_padding); + } + + json_object *status_padding = + json_object_object_get(bar_config, "status_padding"); + if (status_padding) { + config->status_padding = json_object_get_int(status_padding); + } + + json_object *strip_workspace_name = + json_object_object_get(bar_config, "strip_workspace_name"); + if (strip_workspace_name) { + config->strip_workspace_name = + json_object_get_boolean(strip_workspace_name); } + json_object *strip_workspace_numbers = + json_object_object_get(bar_config, "strip_workspace_numbers"); + if (strip_workspace_numbers) { + config->strip_workspace_numbers = + json_object_get_boolean(strip_workspace_numbers); + } + + json_object *workspace_buttons = + json_object_object_get(bar_config, "workspace_buttons"); + if (workspace_buttons) { + config->workspace_buttons = json_object_get_boolean(workspace_buttons); + } + + json_object *wrap_scroll = json_object_object_get(bar_config, "wrap_scroll"); + if (wrap_scroll) { + config->wrap_scroll = json_object_get_boolean(wrap_scroll); + } #if HAVE_TRAY json_object *tray_outputs, *tray_padding, *tray_bindings, *icon_theme; + if (config->tray_outputs && config->tray_outputs->length) { + list_free_items_and_destroy(config->tray_outputs); + } if ((json_object_object_get_ex(bar_config, "tray_outputs", &tray_outputs))) { config->tray_outputs = create_list(); int length = json_object_array_length(tray_outputs); for (int i = 0; i < length; ++i) { - json_object *o = json_object_array_get_idx(tray_outputs, i); - list_add(config->tray_outputs, strdup(json_object_get_string(o))); + json_object *output= json_object_array_get_idx(tray_outputs, i); + const char *name = json_object_get_string(output); + if (strcmp(name, "none") == 0) { + config->tray_hidden = true; + list_free_items_and_destroy(config->tray_outputs); + config->tray_outputs = create_list(); + break; + } + list_add(config->tray_outputs, strdup(name)); } - config->tray_hidden = strcmp(config->tray_outputs->items[0], "none") == 0; } if ((json_object_object_get_ex(bar_config, "tray_padding", &tray_padding))) { config->tray_padding = json_object_get_int(tray_padding); } + struct tray_binding *tray_bind = NULL, *tmp_tray_bind = NULL; + wl_list_for_each_safe(tray_bind, tmp_tray_bind, &config->tray_bindings, + link) { + wl_list_remove(&tray_bind->link); + free_tray_binding(tray_bind); + } if ((json_object_object_get_ex(bar_config, "tray_bindings", &tray_bindings))) { int length = json_object_array_length(tray_bindings); for (int i = 0; i < length; ++i) { @@ -423,41 +475,6 @@ bool ipc_get_workspaces(struct swaybar *bar) { return determine_bar_visibility(bar, false); } -static void ipc_get_outputs(struct swaybar *bar) { - uint32_t len = 0; - char *res = ipc_single_command(bar->ipc_socketfd, - IPC_GET_OUTPUTS, NULL, &len); - json_object *outputs = json_tokener_parse(res); - for (size_t i = 0; i < json_object_array_length(outputs); ++i) { - json_object *output = json_object_array_get_idx(outputs, i); - json_object *output_name, *output_active; - json_object_object_get_ex(output, "name", &output_name); - json_object_object_get_ex(output, "active", &output_active); - const char *name = json_object_get_string(output_name); - bool active = json_object_get_boolean(output_active); - if (!active) { - continue; - } - if (bar->config->all_outputs) { - struct config_output *coutput = - calloc(1, sizeof(struct config_output)); - coutput->name = strdup(name); - coutput->index = i; - wl_list_insert(&bar->config->outputs, &coutput->link); - } else { - struct config_output *coutput; - wl_list_for_each(coutput, &bar->config->outputs, link) { - if (strcmp(name, coutput->name) == 0) { - coutput->index = i; - break; - } - } - } - } - json_object_put(outputs); - free(res); -} - void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) { sway_log(SWAY_DEBUG, "Executing binding for button %u (release=%d): `%s`", bind->button, bind->release, bind->command); @@ -475,7 +492,6 @@ bool ipc_initialize(struct swaybar *bar) { return false; } free(res); - ipc_get_outputs(bar); struct swaybar_config *config = bar->config; char subscribe[128]; // suitably large buffer @@ -509,56 +525,87 @@ static bool handle_bar_state_update(struct swaybar *bar, json_object *event) { return determine_bar_visibility(bar, false); } -static bool handle_barconfig_update(struct swaybar *bar, +static bool handle_barconfig_update(struct swaybar *bar, const char *payload, json_object *json_config) { - json_object *json_id; - json_object_object_get_ex(json_config, "id", &json_id); + json_object *json_id = json_object_object_get(json_config, "id"); const char *id = json_object_get_string(json_id); if (strcmp(id, bar->id) != 0) { return false; } - struct swaybar_config *config = bar->config; + struct swaybar_config *newcfg = init_config(); + ipc_parse_config(newcfg, payload); - json_object *json_state; - json_object_object_get_ex(json_config, "hidden_state", &json_state); - const char *new_state = json_object_get_string(json_state); - char *old_state = config->hidden_state; - if (strcmp(new_state, old_state) != 0) { - sway_log(SWAY_DEBUG, "Changing bar hidden state to %s", new_state); - free(old_state); - config->hidden_state = strdup(new_state); - return determine_bar_visibility(bar, false); - } - - free(config->mode); - json_object *json_mode; - json_object_object_get_ex(json_config, "mode", &json_mode); - config->mode = strdup(json_object_get_string(json_mode)); - sway_log(SWAY_DEBUG, "Changing bar mode to %s", config->mode); - - json_object *gaps; - json_object_object_get_ex(json_config, "gaps", &gaps); - if (gaps) { - json_object *top = json_object_object_get(gaps, "top"); - if (top) { - config->gaps.top = json_object_get_int(top); + struct swaybar_config *oldcfg = bar->config; + bar->config = newcfg; + + struct swaybar_output *output, *tmp_output; + wl_list_for_each_safe(output, tmp_output, &bar->outputs, link) { + bool found = wl_list_empty(&newcfg->outputs); + struct config_output *coutput; + wl_list_for_each(coutput, &newcfg->outputs, link) { + if (strcmp(coutput->name, output->name) == 0 || + strcmp(coutput->name, output->identifier) == 0) { + found = true; + break; + } } - json_object *right = json_object_object_get(gaps, "right"); - if (right) { - config->gaps.right = json_object_get_int(right); + if (!found) { + destroy_layer_surface(output); + wl_list_remove(&output->link); + wl_list_insert(&bar->unused_outputs, &output->link); + } else if (!oldcfg->font || !newcfg->font || + strcmp(oldcfg->font, newcfg->font) != 0) { + output->height = 0; // force update height } - json_object *bottom = json_object_object_get(gaps, "bottom"); - if (bottom) { - config->gaps.bottom = json_object_get_int(bottom); + } + wl_list_for_each_safe(output, tmp_output, &bar->unused_outputs, link) { + bool found = wl_list_empty(&newcfg->outputs); + struct config_output *coutput; + wl_list_for_each(coutput, &newcfg->outputs, link) { + if (strcmp(coutput->name, output->name) == 0 || + strcmp(coutput->name, output->identifier) == 0) { + found = true; + break; + } } - json_object *left = json_object_object_get(gaps, "left"); - if (left) { - config->gaps.left = json_object_get_int(left); + if (found) { + wl_list_remove(&output->link); + wl_list_insert(&bar->outputs, &output->link); } } - return determine_bar_visibility(bar, true); + if (bar->status && (!newcfg->status_command || + strcmp(newcfg->status_command, oldcfg->status_command) != 0)) { + status_line_free(bar->status); + bar->status = NULL; + } + if (!bar->status && newcfg->status_command) { + bar->status = status_line_init(newcfg->status_command); + bar->status->bar = bar; + loop_add_fd(bar->eventloop, bar->status->read_fd, POLLIN, + status_in, bar); + } + +#if HAVE_TRAY + if (oldcfg->tray_hidden && !newcfg->tray_hidden) { + bar->tray = create_tray(bar); + loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, + bar->tray->bus); + } else if (bar->tray && newcfg->tray_hidden) { + loop_remove_fd(bar->eventloop, bar->tray->fd); + destroy_tray(bar->tray); + bar->tray = NULL; + } +#endif + + if (newcfg->workspace_buttons) { + ipc_get_workspaces(bar); + } + + free_config(oldcfg); + determine_bar_visibility(bar, true); + return true; } bool handle_ipc_readable(struct swaybar *bar) { @@ -599,7 +646,7 @@ bool handle_ipc_readable(struct swaybar *bar) { break; } case IPC_EVENT_BARCONFIG_UPDATE: - bar_is_dirty = handle_barconfig_update(bar, result); + bar_is_dirty = handle_barconfig_update(bar, resp->payload, result); break; case IPC_EVENT_BAR_STATE_UPDATE: bar_is_dirty = handle_bar_state_update(bar, result); diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 342f981e..2a9e1da8 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -5,6 +5,8 @@ #include <stdlib.h> #include <string.h> #include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> #include <unistd.h> #include "log.h" #include "loop.h" @@ -174,6 +176,7 @@ struct status_line *status_line_init(char *cmd) { void status_line_free(struct status_line *status) { status_line_close_fds(status); kill(status->pid, SIGTERM); + waitpid(status->pid, NULL, 0); if (status->protocol == PROTOCOL_I3BAR) { struct i3bar_block *block, *tmp; wl_list_for_each_safe(block, tmp, &status->blocks, link) { |