diff options
-rw-r--r-- | include/swaybar/bar.h | 5 | ||||
-rw-r--r-- | include/swaybar/config.h | 5 | ||||
-rw-r--r-- | sway/commands/bar.c | 93 | ||||
-rw-r--r-- | sway/commands/bar/hidden_state.c | 8 | ||||
-rw-r--r-- | sway/commands/bar/mode.c | 8 | ||||
-rw-r--r-- | sway/commands/bar/output.c | 15 | ||||
-rw-r--r-- | sway/commands/bar/status_command.c | 5 | ||||
-rw-r--r-- | sway/commands/bar/tray_output.c | 12 | ||||
-rw-r--r-- | sway/config/bar.c | 1 | ||||
-rw-r--r-- | sway/sway-bar.5.scd | 146 | ||||
-rw-r--r-- | sway/sway.5.scd | 12 | ||||
-rw-r--r-- | swaybar/bar.c | 35 | ||||
-rw-r--r-- | swaybar/config.c | 4 | ||||
-rw-r--r-- | swaybar/ipc.c | 367 | ||||
-rw-r--r-- | swaybar/status_line.c | 3 |
15 files changed, 405 insertions, 314 deletions
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 10984ab0..545a66a8 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h | |||
@@ -41,6 +41,7 @@ struct swaybar { | |||
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); | |||
109 | bool determine_bar_visibility(struct swaybar *bar, bool moving_layer); | 110 | bool determine_bar_visibility(struct swaybar *bar, bool moving_layer); |
110 | void free_workspaces(struct wl_list *list); | 111 | void free_workspaces(struct wl_list *list); |
111 | 112 | ||
113 | void status_in(int fd, short mask, void *data); | ||
114 | |||
115 | void 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 { | |||
16 | struct config_output { | 16 | struct 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 | ||
22 | struct swaybar_binding { | 21 | struct 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 | |||
85 | void free_tray_binding(struct tray_binding *binding); | ||
86 | #endif | 86 | #endif |
87 | 87 | ||
88 | struct swaybar_config *init_config(void); | 88 | struct swaybar_config *init_config(void); |
89 | void free_config(struct swaybar_config *config); | 89 | void free_config(struct swaybar_config *config); |
90 | uint32_t parse_position(const char *position); | 90 | uint32_t parse_position(const char *position); |
91 | void 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; |
177 | cleanup: | 176 | cleanup: |
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> | 13 | The 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> | 21 | The 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 | 22 | runtime. |
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 | ||
124 | Swaybar provides a system tray where third-party applications may place icons. | 143 | Swaybar 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 | ||
772 | A criteria is a string in the form of, for example: | 760 | 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) { | |||
126 | } | 126 | } |
127 | } | 127 | } |
128 | 128 | ||
129 | static void destroy_layer_surface(struct swaybar_output *output) { | 129 | void 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 | ||
183 | static bool bar_uses_output(struct swaybar_output *output) { | 183 | static 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 | ||
461 | static void status_in(int fd, short mask, void *data) { | 475 | void 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 | ||
87 | static void free_binding(struct swaybar_binding *binding) { | 87 | void 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 |
96 | static void free_tray_binding(struct tray_binding *binding) { | 96 | void 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 | ||
15 | void ipc_send_workspace_command(struct swaybar *bar, const char *ws) { | 21 | void 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 | ||
426 | static 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 | |||
461 | void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) { | 478 | void 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 | ||
512 | static bool handle_barconfig_update(struct swaybar *bar, | 528 | static 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 | ||
564 | bool handle_ipc_readable(struct swaybar *bar) { | 611 | bool 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) { | |||
174 | void status_line_free(struct status_line *status) { | 176 | void 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) { |