aboutsummaryrefslogtreecommitdiffstats
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 {
41 int ipc_socketfd; 41 int ipc_socketfd;
42 42
43 struct wl_list outputs; // swaybar_output::link 43 struct wl_list outputs; // swaybar_output::link
44 struct wl_list unused_outputs; // swaybar_output::link
44 struct wl_list seats; // swaybar_seat::link 45 struct wl_list seats; // swaybar_seat::link
45 46
46#if HAVE_TRAY 47#if HAVE_TRAY
@@ -109,4 +110,8 @@ void set_bar_dirty(struct swaybar *bar);
109bool determine_bar_visibility(struct swaybar *bar, bool moving_layer); 110bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
110void free_workspaces(struct wl_list *list); 111void free_workspaces(struct wl_list *list);
111 112
113void status_in(int fd, short mask, void *data);
114
115void destroy_layer_surface(struct swaybar_output *output);
116
112#endif 117#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 {
16struct config_output { 16struct config_output {
17 struct wl_list link; // swaybar_config::outputs 17 struct wl_list link; // swaybar_config::outputs
18 char *name; 18 char *name;
19 size_t index;
20}; 19};
21 20
22struct swaybar_binding { 21struct swaybar_binding {
@@ -41,7 +40,6 @@ struct swaybar_config {
41 bool workspace_buttons; 40 bool workspace_buttons;
42 list_t *bindings; 41 list_t *bindings;
43 struct wl_list outputs; // config_output::link 42 struct wl_list outputs; // config_output::link
44 bool all_outputs;
45 int height; 43 int height;
46 int status_padding; 44 int status_padding;
47 int status_edge_padding; 45 int status_edge_padding;
@@ -83,10 +81,13 @@ struct tray_binding {
83 char *command; 81 char *command;
84 struct wl_list link; // struct tray_binding::link 82 struct wl_list link; // struct tray_binding::link
85}; 83};
84
85void free_tray_binding(struct tray_binding *binding);
86#endif 86#endif
87 87
88struct swaybar_config *init_config(void); 88struct swaybar_config *init_config(void);
89void free_config(struct swaybar_config *config); 89void free_config(struct swaybar_config *config);
90uint32_t parse_position(const char *position); 90uint32_t parse_position(const char *position);
91void free_binding(struct swaybar_binding *binding);
91 92
92#endif 93#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 @@
4#include <strings.h> 4#include <strings.h>
5#include "sway/commands.h" 5#include "sway/commands.h"
6#include "sway/config.h" 6#include "sway/config.h"
7#include "sway/ipc-server.h"
7#include "log.h" 8#include "log.h"
8 9
9// Must be in alphabetical order for bsearch 10// Must be in alphabetical order for bsearch
@@ -56,30 +57,27 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
56 return error; 57 return error;
57 } 58 }
58 59
59 bool spawn = false; 60 char *id = NULL;
60 struct bar_config *bar = NULL;
61 if (strcmp(argv[0], "id") != 0 && is_subcommand(argv[1])) { 61 if (strcmp(argv[0], "id") != 0 && is_subcommand(argv[1])) {
62 for (int i = 0; i < config->bars->length; ++i) { 62 for (int i = 0; i < config->bars->length; ++i) {
63 struct bar_config *item = config->bars->items[i]; 63 struct bar_config *item = config->bars->items[i];
64 if (strcmp(item->id, argv[0]) == 0) { 64 if (strcmp(item->id, argv[0]) == 0) {
65 sway_log(SWAY_DEBUG, "Selecting bar: %s", argv[0]); 65 sway_log(SWAY_DEBUG, "Selecting bar: %s", argv[0]);
66 bar = item; 66 config->current_bar = item;
67 break; 67 break;
68 } 68 }
69 } 69 }
70 if (!bar) { 70 if (!config->current_bar) {
71 spawn = !config->reading; 71 id = strdup(argv[0]);
72 sway_log(SWAY_DEBUG, "Creating bar: %s", argv[0]);
73 bar = default_bar_config();
74 if (!bar) {
75 return cmd_results_new(CMD_FAILURE,
76 "Unable to allocate bar state");
77 }
78
79 bar->id = strdup(argv[0]);
80 } 72 }
81 config->current_bar = bar;
82 ++argv; --argc; 73 ++argv; --argc;
74 } else if (config->reading && !config->current_bar) {
75 int len = snprintf(NULL, 0, "bar-%d", config->bars->length) + 1;
76 id = malloc(len * sizeof(char));
77 if (!id) {
78 return cmd_results_new(CMD_FAILURE, "Unable to allocate bar id");
79 }
80 snprintf(id, len, "bar-%d", config->bars->length);
83 } else if (!config->reading && strcmp(argv[0], "mode") != 0 && 81 } else if (!config->reading && strcmp(argv[0], "mode") != 0 &&
84 strcmp(argv[0], "hidden_state") != 0) { 82 strcmp(argv[0], "hidden_state") != 0) {
85 if (is_subcommand(argv[0])) { 83 if (is_subcommand(argv[0])) {
@@ -90,56 +88,49 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
90 } 88 }
91 } 89 }
92 90
93 if (!config->current_bar) { 91 if (id) {
94 if (config->reading) { 92 sway_log(SWAY_DEBUG, "Creating bar: %s", id);
95 // Create new bar with default values 93 config->current_bar = default_bar_config();
96 struct bar_config *bar = default_bar_config(); 94 if (!config->current_bar) {
97 if (!bar) { 95 free(id);
98 return cmd_results_new(CMD_FAILURE, 96 return cmd_results_new(CMD_FAILURE, "Unable to allocate bar config");
99 "Unable to allocate bar state");
100 }
101
102 // set bar id
103 int len = snprintf(NULL, 0, "bar-%d", config->bars->length - 1) + 1;
104 bar->id = malloc(len * sizeof(char));
105 if (bar->id) {
106 snprintf(bar->id, len, "bar-%d", config->bars->length - 1);
107 } else {
108 return cmd_results_new(CMD_FAILURE, "Unable to allocate bar ID");
109 }
110
111 // Set current bar
112 config->current_bar = bar;
113 sway_log(SWAY_DEBUG, "Creating bar %s", bar->id);
114 } 97 }
98 config->current_bar->id = id;
115 } 99 }
116 100
101 struct cmd_results *res = NULL;
117 if (find_handler(argv[0], bar_config_handlers, 102 if (find_handler(argv[0], bar_config_handlers,
118 sizeof(bar_config_handlers))) { 103 sizeof(bar_config_handlers))) {
119 if (config->reading) { 104 if (config->reading) {
120 return config_subcommand(argv, argc, bar_config_handlers, 105 res = config_subcommand(argv, argc, bar_config_handlers,
121 sizeof(bar_config_handlers)); 106 sizeof(bar_config_handlers));
122 } else if (spawn) { 107 } else {
123 for (int i = config->bars->length - 1; i >= 0; i--) { 108 res = cmd_results_new(CMD_INVALID,
124 struct bar_config *bar = config->bars->items[i]; 109 "Can only be used in the config file");
125 if (bar == config->current_bar) { 110 }
126 list_del(config->bars, i); 111 } else {
127 free_bar_config(bar); 112 res = config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers));
128 break; 113 }
129 } 114
130 } 115 if (res && res->status != CMD_SUCCESS) {
116 if (id) {
117 free_bar_config(config->current_bar);
118 id = NULL;
131 } 119 }
132 return cmd_results_new(CMD_INVALID, 120 return res;
133 "Can only be used in the config file."); 121 }
122
123 if (id) {
124 list_add(config->bars, config->current_bar);
134 } 125 }
135 126
136 struct cmd_results *res = 127 if (!config->reading && config->current_bar) {
137 config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers)); 128 ipc_event_barconfig_update(config->current_bar);
138 if (!config->reading) { 129 if (id) {
139 if (spawn) {
140 load_swaybar(config->current_bar); 130 load_swaybar(config->current_bar);
141 } 131 }
142 config->current_bar = NULL; 132 config->current_bar = NULL;
143 } 133 }
134
144 return res; 135 return res;
145} 136}
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,
23 return cmd_results_new(CMD_INVALID, "Invalid value %s", hidden_state); 23 return cmd_results_new(CMD_INVALID, "Invalid value %s", hidden_state);
24 } 24 }
25 if (strcmp(old_state, bar->hidden_state) != 0) { 25 if (strcmp(old_state, bar->hidden_state) != 0) {
26 if (!config->reading) { 26 if (!config->current_bar) {
27 ipc_event_barconfig_update(bar); 27 ipc_event_barconfig_update(bar);
28 } 28 }
29 sway_log(SWAY_DEBUG, "Setting hidden_state: '%s' for bar: %s", 29 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) {
47 "Unexpected value %s in config mode", argv[1]); 47 "Unexpected value %s in config mode", argv[1]);
48 } 48 }
49 49
50 if (config->current_bar && argc == 2 &&
51 strcmp(config->current_bar->id, argv[1]) != 0) {
52 return cmd_results_new(CMD_INVALID, "Conflicting bar ids: %s and %s",
53 config->current_bar->id, argv[1]);
54 }
55
50 const char *state = argv[0]; 56 const char *state = argv[0];
51 if (config->reading) { 57 if (config->reading) {
52 error = bar_set_hidden_state(config->current_bar, state); 58 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
27 } 27 }
28 28
29 if (strcmp(old_mode, bar->mode) != 0) { 29 if (strcmp(old_mode, bar->mode) != 0) {
30 if (!config->reading) { 30 if (!config->current_bar) {
31 ipc_event_barconfig_update(bar); 31 ipc_event_barconfig_update(bar);
32 } 32 }
33 sway_log(SWAY_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); 33 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) {
51 "Unexpected value %s in config mode", argv[1]); 51 "Unexpected value %s in config mode", argv[1]);
52 } 52 }
53 53
54 if (config->current_bar && argc == 2 &&
55 strcmp(config->current_bar->id, argv[1]) != 0) {
56 return cmd_results_new(CMD_INVALID, "Conflicting bar ids: %s and %s",
57 config->current_bar->id, argv[1]);
58 }
59
54 const char *mode = argv[0]; 60 const char *mode = argv[0];
55 if (config->reading) { 61 if (config->reading) {
56 error = bar_set_mode(config->current_bar, mode); 62 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) {
21 bool add_output = true; 21 bool add_output = true;
22 if (strcmp("*", output) == 0) { 22 if (strcmp("*", output) == 0) {
23 // remove all previous defined outputs and replace with '*' 23 // remove all previous defined outputs and replace with '*'
24 for (int i = 0; i < outputs->length; ++i) { 24 while (outputs->length) {
25 free(outputs->items[i]); 25 free(outputs->items[0]);
26 list_del(outputs, i); 26 list_del(outputs, 0);
27 } 27 }
28 } else { 28 } else {
29 // only add output if not already defined with either the same 29 // only add output if not already defined, if the list has '*', remove
30 // name or as '*' 30 // it, in favor of a manual list
31 for (int i = 0; i < outputs->length; ++i) { 31 for (int i = 0; i < outputs->length; ++i) {
32 const char *find = outputs->items[i]; 32 const char *find = outputs->items[i];
33 if (strcmp("*", find) == 0 || strcmp(output, find) == 0) { 33 if (strcmp("*", find) == 0) {
34 free(outputs->items[i]);
35 list_del(outputs, i);
36 } else if (strcmp(output, find) == 0) {
34 add_output = false; 37 add_output = false;
35 break; 38 break;
36 } 39 }
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) {
19 } else { 19 } else {
20 free(new_command); 20 free(new_command);
21 } 21 }
22
23 if (config->active && !config->validating) {
24 load_swaybar(config->current_bar);
25 }
26
27 return cmd_results_new(CMD_SUCCESS, NULL); 22 return cmd_results_new(CMD_SUCCESS, NULL);
28} 23}
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) {
24 free(outputs->items[i]); 24 free(outputs->items[i]);
25 } 25 }
26 outputs->length = 0; 26 outputs->length = 0;
27 } else if (strcmp(argv[0], "*") == 0) {
28 sway_log(SWAY_DEBUG, "Showing tray on all outputs for bar: %s",
29 config->current_bar->id);
30 while (outputs->length) {
31 free(outputs->items[0]);
32 list_del(outputs, 0);
33 }
34 return cmd_results_new(CMD_SUCCESS, NULL);
27 } else { 35 } else {
28 sway_log(SWAY_DEBUG, "Showing tray on output '%s' for bar: %s", argv[0], 36 sway_log(SWAY_DEBUG, "Showing tray on output '%s' for bar: %s", argv[0],
29 config->current_bar->id); 37 config->current_bar->id);
38 if (outputs->length == 1 && strcmp(outputs->items[0], "none") == 0) {
39 free(outputs->items[0]);
40 list_del(outputs, 0);
41 }
30 } 42 }
31 list_add(outputs, strdup(argv[0])); 43 list_add(outputs, strdup(argv[0]));
32 44
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) {
172 wl_list_init(&bar->tray_bindings); 172 wl_list_init(&bar->tray_bindings);
173#endif 173#endif
174 174
175 list_add(config->bars, bar);
176 return bar; 175 return bar;
177cleanup: 176cleanup:
178 free_bar_config(bar); 177 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.
10 10
11# COMMANDS 11# COMMANDS
12 12
13*status_command* <status command> 13The following commands may only be used in the configuration file.
14 Executes the bar _status command_ with _sh -c_. Each line of text printed
15 to stdout from this command will be displayed in the status area of the
16 bar. You may also use swaybar's JSON status line protocol. See
17 *swaybar-protocol*(7) for more information on the protocol
18
19 If running this command via IPC, you can disable a running status command by
20 setting the command to a single dash: _swaybar bar bar-0 status\_command -_
21
22*pango_markup* enabled|disabled
23 Enables or disables pango markup for status lines. This has no effect on
24 status lines using the i3bar JSON protocol.
25 14
26*id* <bar_id> 15*id* <bar_id>
27 Sets the ID of the bar. 16 Sets the ID of the bar.
28 17
29*position* top|bottom
30 Sets position of the bar. Default is _bottom_.
31
32*output* <output>
33 Restrict the bar to a certain output, can be specified multiple times. If
34 the output command is omitted, the bar will be displayed on all outputs.
35
36*swaybar_command* <command> 18*swaybar_command* <command>
37 Executes custom bar command. Default is _swaybar_. 19 Executes custom bar command. Default is _swaybar_.
38 20
39*font* <font> 21The following commands may be used either in the configuration file or at
40 Specifies the font to be used in the bar. _font_ should be specified as a 22runtime.
41 pango font description. For more information on pango font descriptions,
42 see https://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string
43 23
44*separator_symbol* <symbol> 24*bindcode* [--release] <event-code> <command>
45 Specifies the separator symbol to separate blocks on the bar. 25 Executes _command_ when the mouse button has been pressed (or if _released_
46 26 is given, when the button has been released). The buttons can be given as
47*wrap_scroll* yes|no 27 an event code, which can be obtaining from *libinput debug-events*. To
48 Enables or disables wrapping when scrolling through workspaces with the 28 disable the default behavior for a button, use the command _nop_.
49 scroll wheel. Default is _no_.
50
51*workspace_buttons* yes|no
52 Enables or disables workspace buttons on the bar. Default is _yes_.
53
54*strip_workspace_name* yes|no
55 If set to _yes_, then workspace names will be omitted from the workspace
56 button and only the custom number will be shown. Default is _no_.
57 29
58*strip_workspace_numbers* yes|no 30*bindsym* [--release] button[1-9]|<event-name> <command>
59 If set to _yes_, then workspace numbers will be omitted from the workspace 31 Executes _command_ when the mouse button has been pressed (or if _released_
60 button and only the custom name will be shown. Default is _no_. 32 is given, when the button has been released). The buttons can be given as a
33 x11 button number or an event name, which can be obtained from *libinput
34 debug-events*. To disable the default behavior for a button, use the
35 command _nop_.
61 36
62*binding_mode_indicator* yes|no 37*binding_mode_indicator* yes|no
63 Enable or disable binding mode indicator. Default is _yes_. 38 Enable or disable binding mode indicator. Default is _yes_.
64 39
40*font* <font>
41 Specifies the font to be used in the bar. _font_ should be specified as a
42 pango font description. For more information on pango font descriptions,
43 see https://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string
44
65*gaps* <all> | <horizontal> <vertical> | <top> <right> <bottom> <left> 45*gaps* <all> | <horizontal> <vertical> | <top> <right> <bottom> <left>
66 Sets the gaps from the edge of the screen for the bar. Gaps can either be 46 Sets the gaps from the edge of the screen for the bar. Gaps can either be
67 set all at once, per direction, or per side. Note that only sides that 47 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.
72*height* <height> 52*height* <height>
73 Sets the height of the bar. Default height (0) will match the font size. 53 Sets the height of the bar. Default height (0) will match the font size.
74 54
75*bindcode* [--release] <event-code> <command> 55*hidden_state* hide|show [<bar-id>]
76 Executes _command_ when the mouse button has been pressed (or if _released_ 56 Specifies the behaviour of the bar when it is in _hide_ mode. When the
77 is given, when the button has been released). The buttons can be given as 57 hidden state is _hide_, then it is normally hidden, and only unhidden by
78 an event code, which can be obtaining from *libinput debug-events*. To 58 pressing the modifier key or in case of urgency hints. When the hidden
79 disable the default behavior for a button, use the command _nop_. 59 state is _show_, then it is permanently visible, drawn on top of the
60 currently visible workspace. Default is _hide_.
80 61
81*bindsym* [--release] button[1-9]|<event-name> <command> 62 For compatibility with i3, _bar hidden_state hide|show [<bar-id>]_ is
82 Executes _command_ when the mouse button has been pressed (or if _released_ 63 supported along with the sway only _bar <bar-id> hidden_state hide|show_
83 is given, when the button has been released). The buttons can be given as a 64 syntax. When using the i3 syntax, if _bar-id_ is omitted, the hidden_state
84 x11 button number or an event name, which can be obtained from *libinput 65 will be changed for all bars. Attempting to use _bar <bar-id1>
85 debug-events*. To disable the default behavior for a button, use the 66 hidden_state hide|show <bar-id2>_ will result in an error due to
86 command _nop_. 67 conflicting bar ids.
87 68
88*mode* dock|hide|invisible|overlay 69*mode* dock|hide|invisible|overlay [<bar-id>]
89 Specifies the visibility of the bar. In _dock_ mode, it is permanently 70 Specifies the visibility of the bar. In _dock_ mode, it is permanently
90 visible at one edge of the screen. In _hide_ mode, it is hidden unless the 71 visible at one edge of the screen. In _hide_ mode, it is hidden unless the
91 modifier key is pressed, though this behaviour depends on the hidden state. 72 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.
93 permanently visible on top of other windows. (In _overlay_ mode the bar is 74 permanently visible on top of other windows. (In _overlay_ mode the bar is
94 transparent to input events.) Default is _dock_. 75 transparent to input events.) Default is _dock_.
95 76
96*hidden_state* hide|show 77 For compatibility with i3, _bar mode <mode> [<bar-id>]_ syntax is supported
97 Specifies the behaviour of the bar when it is in _hide_ mode. When the 78 along with the sway only _bar <bar-id> mode <mode>_ syntax. When using the
98 hidden state is _hide_, then it is normally hidden, and only unhidden by 79 i3 syntax, if _bar-id_ is omitted, the mode will be changed for all bars.
99 pressing the modifier key or in case of urgency hints. When the hidden 80 Attempting to use _bar <bar-id1> mode <mode> <bar-id2>_ will result in an
100 state is _show_, then it is permanently visible, drawn on top of the 81 error due to conflicting bar ids.
101 currently visible workspace. Default is _hide_.
102 82
103*modifier* <Modifier>|none 83*modifier* <Modifier>|none
104 Specifies the modifier key that shows a hidden bar. Default is _Mod4_. 84 Specifies the modifier key that shows a hidden bar. Default is _Mod4_.
105 85
106*status_padding* <padding> 86*output* <output>|\*
107 Sets the vertical padding that is used for the status line. The default is 87 Restrict the bar to a certain output, can be specified multiple times. If
108 _1_. If _padding_ is _0_, blocks will be able to take up the full height of 88 the output command is omitted, the bar will be displayed on all outputs. _\*_
109 the bar. This value will be multiplied by the output scale. 89 can be given at any point to reset it back to all outputs.
90
91*pango_markup* enabled|disabled
92 Enables or disables pango markup for status lines. This has no effect on
93 status lines using the i3bar JSON protocol.
94
95*position* top|bottom
96 Sets position of the bar. Default is _bottom_.
97
98*separator_symbol* <symbol>
99 Specifies the separator symbol to separate blocks on the bar.
100
101*status_command* <status command>
102 Executes the bar _status command_ with _sh -c_. Each line of text printed
103 to stdout from this command will be displayed in the status area of the
104 bar. You may also use swaybar's JSON status line protocol. See
105 *swaybar-protocol*(7) for more information on the protocol
106
107 If running this command via IPC, you can disable a running status command by
108 setting the command to a single dash: _swaybar bar bar-0 status\_command -_
110 109
111*status_edge_padding* <padding> 110*status_edge_padding* <padding>
112 Sets the padding that is used when the status line is at the right edge of 111 Sets the padding that is used when the status line is at the right edge of
113 the bar. This value will be multiplied by the output scale. The default is 112 the bar. This value will be multiplied by the output scale. The default is
114 _3_. 113 _3_.
115 114
115*status_padding* <padding>
116 Sets the vertical padding that is used for the status line. The default is
117 _1_. If _padding_ is _0_, blocks will be able to take up the full height of
118 the bar. This value will be multiplied by the output scale.
119
120*strip_workspace_name* yes|no
121 If set to _yes_, then workspace names will be omitted from the workspace
122 button and only the custom number will be shown. Default is _no_.
123
124*strip_workspace_numbers* yes|no
125 If set to _yes_, then workspace numbers will be omitted from the workspace
126 button and only the custom name will be shown. Default is _no_.
127
116*unbindcode* [--release] <event-code> 128*unbindcode* [--release] <event-code>
117 Removes the binding with the given <event-code>. 129 Removes the binding with the given <event-code>.
118 130
119*unbindsym* [--release] button[1-9]|<event-name> 131*unbindsym* [--release] button[1-9]|<event-name>
120 Removes the binding with the given <button> or <event-name>. 132 Removes the binding with the given <button> or <event-name>.
121 133
134*wrap_scroll* yes|no
135 Enables or disables wrapping when scrolling through workspaces with the
136 scroll wheel. Default is _no_.
137
138*workspace_buttons* yes|no
139 Enables or disables workspace buttons on the bar. Default is _yes_.
140
122## TRAY 141## TRAY
123 142
124Swaybar provides a system tray where third-party applications may place icons. 143Swaybar provides a system tray where third-party applications may place icons.
@@ -142,10 +161,11 @@ ContextMenu|Activate|SecondaryActivate|ScrollDown|ScrollLeft|ScrollRight|ScrollU
142 Sets the pixel padding of the system tray. This padding will surround the 161 Sets the pixel padding of the system tray. This padding will surround the
143 tray on all sides and between each item. The default value for _px_ is 2. 162 tray on all sides and between each item. The default value for _px_ is 2.
144 163
145*tray_output* none|<output> 164*tray_output* none|<output>|\*
146 Restrict the tray to a certain output, can be specified multiple times. If 165 Restrict the tray to a certain output, can be specified multiple times. If
147 omitted, the tray will be displayed on all outputs. Unlike i3bar, swaybar 166 omitted, the tray will be displayed on all outputs. Unlike i3bar, swaybar
148 can show icons on any number of bars and outputs without races. 167 can show icons on any number of bars and outputs without races. _\*_ can be
168 given at any point to reset it to display on all outputs.
149 169
150*icon_theme* <name> 170*icon_theme* <name>
151 Sets the icon theme that sway will look for item icons in. This option has 171 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:
755*workspace_layout* default|stacking|tabbed 755*workspace_layout* default|stacking|tabbed
756 Specifies the initial layout for new workspaces. 756 Specifies the initial layout for new workspaces.
757 757
758# BAR CONTROL
759
760*bar hidden_state* hide|show|toggle [<bar_id>]
761 Sets the hidden state of the bar (see *sway-bar*(5)), either individually,
762 by specifying a bar id, or if none is given, for all bar instances.
763 _toggle_ switches between _hide_ and _show_.
764
765*bar mode* dock|hide|invisible|toggle [<bar_id>]
766 Sets the mode of the bar (see *sway-bar*(5)), either individually,
767 by specifying a bar id, or if none is given, for all bar instances.
768 _toggle_ switches between _dock_ and _hide_.
769
770# CRITERIA 758# CRITERIA
771 759
772A criteria is a string in the form of, for example: 760A 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) {
126 } 126 }
127} 127}
128 128
129static void destroy_layer_surface(struct swaybar_output *output) { 129void destroy_layer_surface(struct swaybar_output *output) {
130 if (!output->layer_surface) { 130 if (!output->layer_surface) {
131 return; 131 return;
132 } 132 }
@@ -181,7 +181,7 @@ bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) {
181} 181}
182 182
183static bool bar_uses_output(struct swaybar_output *output) { 183static bool bar_uses_output(struct swaybar_output *output) {
184 if (output->bar->config->all_outputs) { 184 if (wl_list_empty(&output->bar->config->outputs)) {
185 return true; 185 return true;
186 } 186 }
187 char *identifier = output->identifier; 187 char *identifier = output->identifier;
@@ -256,20 +256,27 @@ static void xdg_output_handle_done(void *data,
256 struct swaybar_output *output = data; 256 struct swaybar_output *output = data;
257 struct swaybar *bar = output->bar; 257 struct swaybar *bar = output->bar;
258 258
259 if (!wl_list_empty(&output->link)) {
260 return;
261 }
262
259 assert(output->name != NULL); 263 assert(output->name != NULL);
260 if (!bar_uses_output(output)) { 264 if (!bar_uses_output(output)) {
261 swaybar_output_free(output); 265 wl_list_remove(&output->link);
266 wl_list_insert(&bar->unused_outputs, &output->link);
262 return; 267 return;
263 } 268 }
264 269
265 if (wl_list_empty(&output->link)) { 270 wl_list_remove(&output->link);
266 wl_list_remove(&output->link); 271 wl_list_insert(&bar->outputs, &output->link);
267 wl_list_insert(&bar->outputs, &output->link);
268 272
269 output->surface = wl_compositor_create_surface(bar->compositor); 273 output->surface = wl_compositor_create_surface(bar->compositor);
270 assert(output->surface); 274 assert(output->surface);
271 275
272 determine_bar_visibility(bar, false); 276 determine_bar_visibility(bar, false);
277
278 if (bar->running && bar->config->workspace_buttons) {
279 ipc_get_workspaces(bar);
273 } 280 }
274} 281}
275 282
@@ -373,6 +380,12 @@ static void handle_global_remove(void *data, struct wl_registry *registry,
373 return; 380 return;
374 } 381 }
375 } 382 }
383 wl_list_for_each_safe(output, tmp, &bar->unused_outputs, link) {
384 if (output->wl_name == name) {
385 swaybar_output_free(output);
386 return;
387 }
388 }
376 struct swaybar_seat *seat, *tmp_seat; 389 struct swaybar_seat *seat, *tmp_seat;
377 wl_list_for_each_safe(seat, tmp_seat, &bar->seats, link) { 390 wl_list_for_each_safe(seat, tmp_seat, &bar->seats, link) {
378 if (seat->wl_name == name) { 391 if (seat->wl_name == name) {
@@ -391,6 +404,7 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) {
391 bar->visible = true; 404 bar->visible = true;
392 bar->config = init_config(); 405 bar->config = init_config();
393 wl_list_init(&bar->outputs); 406 wl_list_init(&bar->outputs);
407 wl_list_init(&bar->unused_outputs);
394 wl_list_init(&bar->seats); 408 wl_list_init(&bar->seats);
395 bar->eventloop = loop_create(); 409 bar->eventloop = loop_create();
396 410
@@ -458,7 +472,7 @@ static void ipc_in(int fd, short mask, void *data) {
458 } 472 }
459} 473}
460 474
461static void status_in(int fd, short mask, void *data) { 475void status_in(int fd, short mask, void *data) {
462 struct swaybar *bar = data; 476 struct swaybar *bar = data;
463 if (mask & (POLLHUP | POLLERR)) { 477 if (mask & (POLLHUP | POLLERR)) {
464 status_error(bar->status, "[error reading from status command]"); 478 status_error(bar->status, "[error reading from status command]");
@@ -510,6 +524,7 @@ void bar_teardown(struct swaybar *bar) {
510 destroy_tray(bar->tray); 524 destroy_tray(bar->tray);
511#endif 525#endif
512 free_outputs(&bar->outputs); 526 free_outputs(&bar->outputs);
527 free_outputs(&bar->unused_outputs);
513 free_seats(&bar->seats); 528 free_seats(&bar->seats);
514 if (bar->config) { 529 if (bar->config) {
515 free_config(bar->config); 530 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) {
84 return config; 84 return config;
85} 85}
86 86
87static void free_binding(struct swaybar_binding *binding) { 87void free_binding(struct swaybar_binding *binding) {
88 if (!binding) { 88 if (!binding) {
89 return; 89 return;
90 } 90 }
@@ -93,7 +93,7 @@ static void free_binding(struct swaybar_binding *binding) {
93} 93}
94 94
95#if HAVE_TRAY 95#if HAVE_TRAY
96static void free_tray_binding(struct tray_binding *binding) { 96void free_tray_binding(struct tray_binding *binding) {
97 if (!binding) { 97 if (!binding) {
98 return; 98 return;
99 } 99 }
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 @@
1#define _POSIX_C_SOURCE 200809 1#define _POSIX_C_SOURCE 200809
2#include <limits.h> 2#include <limits.h>
3#include <poll.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <string.h> 5#include <string.h>
5#include <strings.h> 6#include <strings.h>
6#include <json.h> 7#include <json.h>
7#include "swaybar/config.h" 8#include "swaybar/config.h"
8#include "swaybar/ipc.h" 9#include "swaybar/ipc.h"
10#include "swaybar/status_line.h"
11#if HAVE_TRAY
12#include "swaybar/tray/tray.h"
13#endif
9#include "config.h" 14#include "config.h"
10#include "ipc-client.h" 15#include "ipc-client.h"
11#include "list.h" 16#include "list.h"
12#include "log.h" 17#include "log.h"
18#include "loop.h"
13#include "util.h" 19#include "util.h"
14 20
15void ipc_send_workspace_command(struct swaybar *bar, const char *ws) { 21void ipc_send_workspace_command(struct swaybar *bar, const char *ws) {
@@ -169,75 +175,58 @@ static bool ipc_parse_config(
169 json_object *success; 175 json_object *success;
170 if (json_object_object_get_ex(bar_config, "success", &success) 176 if (json_object_object_get_ex(bar_config, "success", &success)
171 && !json_object_get_boolean(success)) { 177 && !json_object_get_boolean(success)) {
172 sway_log(SWAY_ERROR, "No bar with that ID. Use 'swaymsg -t get_bar_config to get the available bar configs."); 178 sway_log(SWAY_ERROR, "No bar with that ID. Use 'swaymsg -t "
179 "get_bar_config' to get the available bar configs.");
173 json_object_put(bar_config); 180 json_object_put(bar_config);
174 return false; 181 return false;
175 } 182 }
176 json_object *markup, *mode, *hidden_state, *position, *status_command; 183
177 json_object *font, *gaps, *bar_height, *wrap_scroll, *workspace_buttons; 184 json_object *bar_height = json_object_object_get(bar_config, "bar_height");
178 json_object *strip_workspace_numbers, *strip_workspace_name; 185 if (bar_height) {
179 json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol; 186 config->height = json_object_get_int(bar_height);
180 json_object *outputs, *bindings, *status_padding, *status_edge_padding;
181 json_object_object_get_ex(bar_config, "mode", &mode);
182 json_object_object_get_ex(bar_config, "hidden_state", &hidden_state);
183 json_object_object_get_ex(bar_config, "position", &position);
184 json_object_object_get_ex(bar_config, "status_command", &status_command);
185 json_object_object_get_ex(bar_config, "font", &font);
186 json_object_object_get_ex(bar_config, "gaps", &gaps);
187 json_object_object_get_ex(bar_config, "bar_height", &bar_height);
188 json_object_object_get_ex(bar_config, "wrap_scroll", &wrap_scroll);
189 json_object_object_get_ex(bar_config, "workspace_buttons", &workspace_buttons);
190 json_object_object_get_ex(bar_config, "strip_workspace_numbers", &strip_workspace_numbers);
191 json_object_object_get_ex(bar_config, "strip_workspace_name", &strip_workspace_name);
192 json_object_object_get_ex(bar_config, "binding_mode_indicator", &binding_mode_indicator);
193 json_object_object_get_ex(bar_config, "verbose", &verbose);
194 json_object_object_get_ex(bar_config, "separator_symbol", &sep_symbol);
195 json_object_object_get_ex(bar_config, "colors", &colors);
196 json_object_object_get_ex(bar_config, "outputs", &outputs);
197 json_object_object_get_ex(bar_config, "pango_markup", &markup);
198 json_object_object_get_ex(bar_config, "bindings", &bindings);
199 json_object_object_get_ex(bar_config, "status_padding", &status_padding);
200 json_object_object_get_ex(bar_config, "status_edge_padding",
201 &status_edge_padding);
202 if (status_command) {
203 free(config->status_command);
204 config->status_command = strdup(json_object_get_string(status_command));
205 }
206 if (position) {
207 config->position = parse_position(json_object_get_string(position));
208 }
209 if (font) {
210 free(config->font);
211 config->font = parse_font(json_object_get_string(font));
212 }
213 if (sep_symbol) {
214 free(config->sep_symbol);
215 config->sep_symbol = strdup(json_object_get_string(sep_symbol));
216 }
217 if (strip_workspace_numbers) {
218 config->strip_workspace_numbers = json_object_get_boolean(strip_workspace_numbers);
219 }
220 if (strip_workspace_name) {
221 config->strip_workspace_name = json_object_get_boolean(strip_workspace_name);
222 } 187 }
188
189 json_object *binding_mode_indicator =
190 json_object_object_get(bar_config, "binding_mode_indicator");
223 if (binding_mode_indicator) { 191 if (binding_mode_indicator) {
224 config->binding_mode_indicator = json_object_get_boolean(binding_mode_indicator); 192 config->binding_mode_indicator =
193 json_object_get_boolean(binding_mode_indicator);
225 } 194 }
226 if (wrap_scroll) { 195
227 config->wrap_scroll = json_object_get_boolean(wrap_scroll); 196 json_object *bindings = json_object_object_get(bar_config, "bindings");
228 } 197 while (config->bindings->length) {
229 if (workspace_buttons) { 198 struct swaybar_binding *binding = config->bindings->items[0];
230 config->workspace_buttons = json_object_get_boolean(workspace_buttons); 199 list_del(config->bindings, 0);
200 free_binding(binding);
231 } 201 }
232 if (bar_height) { 202 if (bindings) {
233 config->height = json_object_get_int(bar_height); 203 int length = json_object_array_length(bindings);
204 for (int i = 0; i < length; ++i) {
205 json_object *bindobj = json_object_array_get_idx(bindings, i);
206 struct swaybar_binding *binding =
207 calloc(1, sizeof(struct swaybar_binding));
208 binding->button = json_object_get_int(
209 json_object_object_get(bindobj, "event_code"));
210 binding->command = strdup(json_object_get_string(
211 json_object_object_get(bindobj, "command")));
212 binding->release = json_object_get_boolean(
213 json_object_object_get(bindobj, "release"));
214 list_add(config->bindings, binding);
215 }
234 } 216 }
235 if (status_padding) { 217
236 config->status_padding = json_object_get_int(status_padding); 218 json_object *colors = json_object_object_get(bar_config, "colors");
219 if (colors) {
220 ipc_parse_colors(config, colors);
237 } 221 }
238 if (status_edge_padding) { 222
239 config->status_edge_padding = json_object_get_int(status_edge_padding); 223 json_object *font = json_object_object_get(bar_config, "font");
224 if (font) {
225 free(config->font);
226 config->font = parse_font(json_object_get_string(font));
240 } 227 }
228
229 json_object *gaps = json_object_object_get(bar_config, "gaps");
241 if (gaps) { 230 if (gaps) {
242 json_object *top = json_object_object_get(gaps, "top"); 231 json_object *top = json_object_object_get(gaps, "top");
243 if (top) { 232 if (top) {
@@ -256,33 +245,21 @@ static bool ipc_parse_config(
256 config->gaps.left = json_object_get_int(left); 245 config->gaps.left = json_object_get_int(left);
257 } 246 }
258 } 247 }
259 if (markup) { 248
260 config->pango_markup = json_object_get_boolean(markup); 249 json_object *hidden_state =
261 } 250 json_object_object_get(bar_config, "hidden_state");
262 if (bindings) {
263 int length = json_object_array_length(bindings);
264 for (int i = 0; i < length; ++i) {
265 json_object *bindobj = json_object_array_get_idx(bindings, i);
266 struct swaybar_binding *binding =
267 calloc(1, sizeof(struct swaybar_binding));
268 binding->button = json_object_get_int(
269 json_object_object_get(bindobj, "event_code"));
270 binding->command = strdup(json_object_get_string(
271 json_object_object_get(bindobj, "command")));
272 binding->release = json_object_get_boolean(
273 json_object_object_get(bindobj, "release"));
274 list_add(config->bindings, binding);
275 }
276 }
277 if (hidden_state) { 251 if (hidden_state) {
278 free(config->hidden_state); 252 free(config->hidden_state);
279 config->hidden_state = strdup(json_object_get_string(hidden_state)); 253 config->hidden_state = strdup(json_object_get_string(hidden_state));
280 } 254 }
255
256 json_object *mode = json_object_object_get(bar_config, "mode");
281 if (mode) { 257 if (mode) {
282 free(config->mode); 258 free(config->mode);
283 config->mode = strdup(json_object_get_string(mode)); 259 config->mode = strdup(json_object_get_string(mode));
284 } 260 }
285 261
262 json_object *outputs = json_object_object_get(bar_config, "outputs");
286 struct config_output *output, *tmp; 263 struct config_output *output, *tmp;
287 wl_list_for_each_safe(output, tmp, &config->outputs, link) { 264 wl_list_for_each_safe(output, tmp, &config->outputs, link) {
288 wl_list_remove(&output->link); 265 wl_list_remove(&output->link);
@@ -295,40 +272,115 @@ static bool ipc_parse_config(
295 json_object *output = json_object_array_get_idx(outputs, i); 272 json_object *output = json_object_array_get_idx(outputs, i);
296 const char *name = json_object_get_string(output); 273 const char *name = json_object_get_string(output);
297 if (strcmp("*", name) == 0) { 274 if (strcmp("*", name) == 0) {
298 config->all_outputs = true; 275 struct config_output *coutput, *tmp;
276 wl_list_for_each_safe(coutput, tmp, &config->outputs, link) {
277 wl_list_remove(&coutput->link);
278 free(coutput->name);
279 free(coutput);
280 }
299 break; 281 break;
300 } 282 }
301 struct config_output *coutput = calloc( 283 struct config_output *coutput = calloc(
302 1, sizeof(struct config_output)); 284 1, sizeof(struct config_output));
303 coutput->name = strdup(name); 285 coutput->name = strdup(name);
304 coutput->index = SIZE_MAX;
305 wl_list_insert(&config->outputs, &coutput->link); 286 wl_list_insert(&config->outputs, &coutput->link);
306 } 287 }
307 } else {
308 config->all_outputs = true;
309 } 288 }
310 289
311 if (colors) { 290 json_object *pango_markup =
312 ipc_parse_colors(config, colors); 291 json_object_object_get(bar_config, "pango_markup");
292 if (pango_markup) {
293 config->pango_markup = json_object_get_boolean(pango_markup);
294 }
295
296 json_object *position = json_object_object_get(bar_config, "position");
297 if (position) {
298 config->position = parse_position(json_object_get_string(position));
299 }
300
301 json_object *separator_symbol =
302 json_object_object_get(bar_config, "separator_symbol");
303 if (separator_symbol) {
304 free(config->sep_symbol);
305 config->sep_symbol = strdup(json_object_get_string(separator_symbol));
306 }
307
308 json_object *status_command =
309 json_object_object_get(bar_config, "status_command");
310 if (status_command) {
311 const char *command = json_object_get_string(status_command);
312 free(config->status_command);
313 config->status_command = strdup(command);
314 }
315
316 json_object *status_edge_padding =
317 json_object_object_get(bar_config, "status_edge_padding");
318 if (status_edge_padding) {
319 config->status_edge_padding = json_object_get_int(status_edge_padding);
320 }
321
322 json_object *status_padding =
323 json_object_object_get(bar_config, "status_padding");
324 if (status_padding) {
325 config->status_padding = json_object_get_int(status_padding);
326 }
327
328 json_object *strip_workspace_name =
329 json_object_object_get(bar_config, "strip_workspace_name");
330 if (strip_workspace_name) {
331 config->strip_workspace_name =
332 json_object_get_boolean(strip_workspace_name);
313 } 333 }
314 334
335 json_object *strip_workspace_numbers =
336 json_object_object_get(bar_config, "strip_workspace_numbers");
337 if (strip_workspace_numbers) {
338 config->strip_workspace_numbers =
339 json_object_get_boolean(strip_workspace_numbers);
340 }
341
342 json_object *workspace_buttons =
343 json_object_object_get(bar_config, "workspace_buttons");
344 if (workspace_buttons) {
345 config->workspace_buttons = json_object_get_boolean(workspace_buttons);
346 }
347
348 json_object *wrap_scroll = json_object_object_get(bar_config, "wrap_scroll");
349 if (wrap_scroll) {
350 config->wrap_scroll = json_object_get_boolean(wrap_scroll);
351 }
315#if HAVE_TRAY 352#if HAVE_TRAY
316 json_object *tray_outputs, *tray_padding, *tray_bindings, *icon_theme; 353 json_object *tray_outputs, *tray_padding, *tray_bindings, *icon_theme;
317 354
355 if (config->tray_outputs && config->tray_outputs->length) {
356 list_free_items_and_destroy(config->tray_outputs);
357 }
318 if ((json_object_object_get_ex(bar_config, "tray_outputs", &tray_outputs))) { 358 if ((json_object_object_get_ex(bar_config, "tray_outputs", &tray_outputs))) {
319 config->tray_outputs = create_list(); 359 config->tray_outputs = create_list();
320 int length = json_object_array_length(tray_outputs); 360 int length = json_object_array_length(tray_outputs);
321 for (int i = 0; i < length; ++i) { 361 for (int i = 0; i < length; ++i) {
322 json_object *o = json_object_array_get_idx(tray_outputs, i); 362 json_object *output= json_object_array_get_idx(tray_outputs, i);
323 list_add(config->tray_outputs, strdup(json_object_get_string(o))); 363 const char *name = json_object_get_string(output);
364 if (strcmp(name, "none") == 0) {
365 config->tray_hidden = true;
366 list_free_items_and_destroy(config->tray_outputs);
367 config->tray_outputs = create_list();
368 break;
369 }
370 list_add(config->tray_outputs, strdup(name));
324 } 371 }
325 config->tray_hidden = strcmp(config->tray_outputs->items[0], "none") == 0;
326 } 372 }
327 373
328 if ((json_object_object_get_ex(bar_config, "tray_padding", &tray_padding))) { 374 if ((json_object_object_get_ex(bar_config, "tray_padding", &tray_padding))) {
329 config->tray_padding = json_object_get_int(tray_padding); 375 config->tray_padding = json_object_get_int(tray_padding);
330 } 376 }
331 377
378 struct tray_binding *tray_bind = NULL, *tmp_tray_bind = NULL;
379 wl_list_for_each_safe(tray_bind, tmp_tray_bind, &config->tray_bindings,
380 link) {
381 wl_list_remove(&tray_bind->link);
382 free_tray_binding(tray_bind);
383 }
332 if ((json_object_object_get_ex(bar_config, "tray_bindings", &tray_bindings))) { 384 if ((json_object_object_get_ex(bar_config, "tray_bindings", &tray_bindings))) {
333 int length = json_object_array_length(tray_bindings); 385 int length = json_object_array_length(tray_bindings);
334 for (int i = 0; i < length; ++i) { 386 for (int i = 0; i < length; ++i) {
@@ -423,41 +475,6 @@ bool ipc_get_workspaces(struct swaybar *bar) {
423 return determine_bar_visibility(bar, false); 475 return determine_bar_visibility(bar, false);
424} 476}
425 477
426static void ipc_get_outputs(struct swaybar *bar) {
427 uint32_t len = 0;
428 char *res = ipc_single_command(bar->ipc_socketfd,
429 IPC_GET_OUTPUTS, NULL, &len);
430 json_object *outputs = json_tokener_parse(res);
431 for (size_t i = 0; i < json_object_array_length(outputs); ++i) {
432 json_object *output = json_object_array_get_idx(outputs, i);
433 json_object *output_name, *output_active;
434 json_object_object_get_ex(output, "name", &output_name);
435 json_object_object_get_ex(output, "active", &output_active);
436 const char *name = json_object_get_string(output_name);
437 bool active = json_object_get_boolean(output_active);
438 if (!active) {
439 continue;
440 }
441 if (bar->config->all_outputs) {
442 struct config_output *coutput =
443 calloc(1, sizeof(struct config_output));
444 coutput->name = strdup(name);
445 coutput->index = i;
446 wl_list_insert(&bar->config->outputs, &coutput->link);
447 } else {
448 struct config_output *coutput;
449 wl_list_for_each(coutput, &bar->config->outputs, link) {
450 if (strcmp(name, coutput->name) == 0) {
451 coutput->index = i;
452 break;
453 }
454 }
455 }
456 }
457 json_object_put(outputs);
458 free(res);
459}
460
461void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) { 478void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) {
462 sway_log(SWAY_DEBUG, "Executing binding for button %u (release=%d): `%s`", 479 sway_log(SWAY_DEBUG, "Executing binding for button %u (release=%d): `%s`",
463 bind->button, bind->release, bind->command); 480 bind->button, bind->release, bind->command);
@@ -475,7 +492,6 @@ bool ipc_initialize(struct swaybar *bar) {
475 return false; 492 return false;
476 } 493 }
477 free(res); 494 free(res);
478 ipc_get_outputs(bar);
479 495
480 struct swaybar_config *config = bar->config; 496 struct swaybar_config *config = bar->config;
481 char subscribe[128]; // suitably large buffer 497 char subscribe[128]; // suitably large buffer
@@ -509,56 +525,87 @@ static bool handle_bar_state_update(struct swaybar *bar, json_object *event) {
509 return determine_bar_visibility(bar, false); 525 return determine_bar_visibility(bar, false);
510} 526}
511 527
512static bool handle_barconfig_update(struct swaybar *bar, 528static bool handle_barconfig_update(struct swaybar *bar, const char *payload,
513 json_object *json_config) { 529 json_object *json_config) {
514 json_object *json_id; 530 json_object *json_id = json_object_object_get(json_config, "id");
515 json_object_object_get_ex(json_config, "id", &json_id);
516 const char *id = json_object_get_string(json_id); 531 const char *id = json_object_get_string(json_id);
517 if (strcmp(id, bar->id) != 0) { 532 if (strcmp(id, bar->id) != 0) {
518 return false; 533 return false;
519 } 534 }
520 535
521 struct swaybar_config *config = bar->config; 536 struct swaybar_config *newcfg = init_config();
537 ipc_parse_config(newcfg, payload);
522 538
523 json_object *json_state; 539 struct swaybar_config *oldcfg = bar->config;
524 json_object_object_get_ex(json_config, "hidden_state", &json_state); 540 bar->config = newcfg;
525 const char *new_state = json_object_get_string(json_state); 541
526 char *old_state = config->hidden_state; 542 struct swaybar_output *output, *tmp_output;
527 if (strcmp(new_state, old_state) != 0) { 543 wl_list_for_each_safe(output, tmp_output, &bar->outputs, link) {
528 sway_log(SWAY_DEBUG, "Changing bar hidden state to %s", new_state); 544 bool found = wl_list_empty(&newcfg->outputs);
529 free(old_state); 545 struct config_output *coutput;
530 config->hidden_state = strdup(new_state); 546 wl_list_for_each(coutput, &newcfg->outputs, link) {
531 return determine_bar_visibility(bar, false); 547 if (strcmp(coutput->name, output->name) == 0 ||
532 } 548 strcmp(coutput->name, output->identifier) == 0) {
533 549 found = true;
534 free(config->mode); 550 break;
535 json_object *json_mode; 551 }
536 json_object_object_get_ex(json_config, "mode", &json_mode);
537 config->mode = strdup(json_object_get_string(json_mode));
538 sway_log(SWAY_DEBUG, "Changing bar mode to %s", config->mode);
539
540 json_object *gaps;
541 json_object_object_get_ex(json_config, "gaps", &gaps);
542 if (gaps) {
543 json_object *top = json_object_object_get(gaps, "top");
544 if (top) {
545 config->gaps.top = json_object_get_int(top);
546 } 552 }
547 json_object *right = json_object_object_get(gaps, "right"); 553 if (!found) {
548 if (right) { 554 destroy_layer_surface(output);
549 config->gaps.right = json_object_get_int(right); 555 wl_list_remove(&output->link);
556 wl_list_insert(&bar->unused_outputs, &output->link);
557 } else if (!oldcfg->font || !newcfg->font ||
558 strcmp(oldcfg->font, newcfg->font) != 0) {
559 output->height = 0; // force update height
550 } 560 }
551 json_object *bottom = json_object_object_get(gaps, "bottom"); 561 }
552 if (bottom) { 562 wl_list_for_each_safe(output, tmp_output, &bar->unused_outputs, link) {
553 config->gaps.bottom = json_object_get_int(bottom); 563 bool found = wl_list_empty(&newcfg->outputs);
564 struct config_output *coutput;
565 wl_list_for_each(coutput, &newcfg->outputs, link) {
566 if (strcmp(coutput->name, output->name) == 0 ||
567 strcmp(coutput->name, output->identifier) == 0) {
568 found = true;
569 break;
570 }
554 } 571 }
555 json_object *left = json_object_object_get(gaps, "left"); 572 if (found) {
556 if (left) { 573 wl_list_remove(&output->link);
557 config->gaps.left = json_object_get_int(left); 574 wl_list_insert(&bar->outputs, &output->link);
558 } 575 }
559 } 576 }
560 577
561 return determine_bar_visibility(bar, true); 578 if (bar->status && (!newcfg->status_command ||
579 strcmp(newcfg->status_command, oldcfg->status_command) != 0)) {
580 status_line_free(bar->status);
581 bar->status = NULL;
582 }
583 if (!bar->status && newcfg->status_command) {
584 bar->status = status_line_init(newcfg->status_command);
585 bar->status->bar = bar;
586 loop_add_fd(bar->eventloop, bar->status->read_fd, POLLIN,
587 status_in, bar);
588 }
589
590#if HAVE_TRAY
591 if (oldcfg->tray_hidden && !newcfg->tray_hidden) {
592 bar->tray = create_tray(bar);
593 loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in,
594 bar->tray->bus);
595 } else if (bar->tray && newcfg->tray_hidden) {
596 loop_remove_fd(bar->eventloop, bar->tray->fd);
597 destroy_tray(bar->tray);
598 bar->tray = NULL;
599 }
600#endif
601
602 if (newcfg->workspace_buttons) {
603 ipc_get_workspaces(bar);
604 }
605
606 free_config(oldcfg);
607 determine_bar_visibility(bar, true);
608 return true;
562} 609}
563 610
564bool handle_ipc_readable(struct swaybar *bar) { 611bool handle_ipc_readable(struct swaybar *bar) {
@@ -599,7 +646,7 @@ bool handle_ipc_readable(struct swaybar *bar) {
599 break; 646 break;
600 } 647 }
601 case IPC_EVENT_BARCONFIG_UPDATE: 648 case IPC_EVENT_BARCONFIG_UPDATE:
602 bar_is_dirty = handle_barconfig_update(bar, result); 649 bar_is_dirty = handle_barconfig_update(bar, resp->payload, result);
603 break; 650 break;
604 case IPC_EVENT_BAR_STATE_UPDATE: 651 case IPC_EVENT_BAR_STATE_UPDATE:
605 bar_is_dirty = handle_bar_state_update(bar, result); 652 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 @@
5#include <stdlib.h> 5#include <stdlib.h>
6#include <string.h> 6#include <string.h>
7#include <stdio.h> 7#include <stdio.h>
8#include <sys/types.h>
9#include <sys/wait.h>
8#include <unistd.h> 10#include <unistd.h>
9#include "log.h" 11#include "log.h"
10#include "loop.h" 12#include "loop.h"
@@ -174,6 +176,7 @@ struct status_line *status_line_init(char *cmd) {
174void status_line_free(struct status_line *status) { 176void status_line_free(struct status_line *status) {
175 status_line_close_fds(status); 177 status_line_close_fds(status);
176 kill(status->pid, SIGTERM); 178 kill(status->pid, SIGTERM);
179 waitpid(status->pid, NULL, 0);
177 if (status->protocol == PROTOCOL_I3BAR) { 180 if (status->protocol == PROTOCOL_I3BAR) {
178 struct i3bar_block *block, *tmp; 181 struct i3bar_block *block, *tmp;
179 wl_list_for_each_safe(block, tmp, &status->blocks, link) { 182 wl_list_for_each_safe(block, tmp, &status->blocks, link) {