aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/swaybar/bar.h5
-rw-r--r--include/swaybar/config.h5
-rw-r--r--sway/commands/bar.c93
-rw-r--r--sway/commands/bar/hidden_state.c8
-rw-r--r--sway/commands/bar/mode.c8
-rw-r--r--sway/commands/bar/output.c15
-rw-r--r--sway/commands/bar/status_command.c5
-rw-r--r--sway/commands/bar/tray_output.c12
-rw-r--r--sway/config/bar.c1
-rw-r--r--sway/sway-bar.5.scd146
-rw-r--r--sway/sway.5.scd12
-rw-r--r--swaybar/bar.c35
-rw-r--r--swaybar/config.c4
-rw-r--r--swaybar/ipc.c367
-rw-r--r--swaybar/status_line.c3
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) {