diff options
author | Drew DeVault <sir@cmpwn.com> | 2016-02-27 16:18:50 -0500 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2016-02-27 16:18:50 -0500 |
commit | 3453910c3e887be900c69394b738e34d9d8ba095 (patch) | |
tree | 28e0d8d72557ac57a2f9aed5c94818c8ba20e97f /swaybar | |
parent | Set pointer pos before focusing view under it (diff) | |
parent | Free config before exiting sway. (diff) | |
download | sway-3453910c3e887be900c69394b738e34d9d8ba095.tar.gz sway-3453910c3e887be900c69394b738e34d9d8ba095.tar.zst sway-3453910c3e887be900c69394b738e34d9d8ba095.zip |
Merge pull request #492 from mikkeloscar/swaybar-multi-output
Display single swaybar on multiple outputs
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/bar.c | 122 | ||||
-rw-r--r-- | swaybar/config.c | 2 | ||||
-rw-r--r-- | swaybar/ipc.c | 119 | ||||
-rw-r--r-- | swaybar/main.c | 10 |
4 files changed, 177 insertions, 76 deletions
diff --git a/swaybar/bar.c b/swaybar/bar.c index d80c9af3..b6329123 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -1,9 +1,10 @@ | |||
1 | #include <stdlib.h> | 1 | #include <stdlib.h> |
2 | #include <unistd.h> | 2 | #include <unistd.h> |
3 | #include <string.h> | ||
3 | #include <fcntl.h> | 4 | #include <fcntl.h> |
4 | #include <errno.h> | 5 | #include <errno.h> |
5 | #include <sys/types.h> | ||
6 | #include <sys/wait.h> | 6 | #include <sys/wait.h> |
7 | #include <poll.h> | ||
7 | 8 | ||
8 | #include "ipc-client.h" | 9 | #include "ipc-client.h" |
9 | #include "list.h" | 10 | #include "list.h" |
@@ -17,11 +18,7 @@ | |||
17 | static void bar_init(struct bar *bar) { | 18 | static void bar_init(struct bar *bar) { |
18 | bar->config = init_config(); | 19 | bar->config = init_config(); |
19 | bar->status = init_status_line(); | 20 | bar->status = init_status_line(); |
20 | bar->output = malloc(sizeof(struct output)); | 21 | bar->outputs = create_list(); |
21 | bar->output->window = NULL; | ||
22 | bar->output->registry = NULL; | ||
23 | bar->output->workspaces = create_list(); | ||
24 | bar->output->name = NULL; | ||
25 | } | 22 | } |
26 | 23 | ||
27 | static void spawn_status_cmd_proc(struct bar *bar) { | 24 | static void spawn_status_cmd_proc(struct bar *bar) { |
@@ -49,78 +46,109 @@ static void spawn_status_cmd_proc(struct bar *bar) { | |||
49 | } | 46 | } |
50 | } | 47 | } |
51 | 48 | ||
49 | struct output *new_output(const char *name) { | ||
50 | struct output *output = malloc(sizeof(struct output)); | ||
51 | output->name = strdup(name); | ||
52 | output->window = NULL; | ||
53 | output->registry = NULL; | ||
54 | output->workspaces = create_list(); | ||
55 | return output; | ||
56 | } | ||
52 | 57 | ||
53 | void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id, int desired_output) { | 58 | void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { |
54 | /* initialize bar with default values */ | 59 | /* initialize bar with default values */ |
55 | bar_init(bar); | 60 | bar_init(bar); |
56 | 61 | ||
57 | bar->output->registry = registry_poll(); | ||
58 | |||
59 | if (!bar->output->registry->desktop_shell) { | ||
60 | sway_abort("swaybar requires the compositor to support the desktop-shell extension."); | ||
61 | } | ||
62 | |||
63 | /* connect to sway ipc */ | 62 | /* connect to sway ipc */ |
64 | bar->ipc_socketfd = ipc_open_socket(socket_path); | 63 | bar->ipc_socketfd = ipc_open_socket(socket_path); |
65 | bar->ipc_event_socketfd = ipc_open_socket(socket_path); | 64 | bar->ipc_event_socketfd = ipc_open_socket(socket_path); |
66 | 65 | ||
67 | ipc_bar_init(bar, desired_output, bar_id); | 66 | ipc_bar_init(bar, bar_id); |
68 | 67 | ||
69 | struct output_state *output = bar->output->registry->outputs->items[desired_output]; | 68 | int i; |
69 | for (i = 0; i < bar->outputs->length; ++i) { | ||
70 | struct output *bar_output = bar->outputs->items[i]; | ||
70 | 71 | ||
71 | bar->output->window = window_setup(bar->output->registry, output->width, 30, false); | 72 | bar_output->registry = registry_poll(); |
72 | if (!bar->output->window) { | ||
73 | sway_abort("Failed to create window."); | ||
74 | } | ||
75 | desktop_shell_set_panel(bar->output->registry->desktop_shell, output->output, bar->output->window->surface); | ||
76 | desktop_shell_set_panel_position(bar->output->registry->desktop_shell, bar->config->position); | ||
77 | 73 | ||
78 | /* set font */ | 74 | if (!bar_output->registry->desktop_shell) { |
79 | bar->output->window->font = bar->config->font; | 75 | sway_abort("swaybar requires the compositor to support the desktop-shell extension."); |
76 | } | ||
80 | 77 | ||
81 | /* set window height */ | 78 | struct output_state *output = bar_output->registry->outputs->items[bar_output->idx]; |
82 | set_window_height(bar->output->window, bar->config->height); | ||
83 | 79 | ||
80 | bar_output->window = window_setup(bar_output->registry, output->width, 30, false); | ||
81 | if (!bar_output->window) { | ||
82 | sway_abort("Failed to create window."); | ||
83 | } | ||
84 | desktop_shell_set_panel(bar_output->registry->desktop_shell, output->output, bar_output->window->surface); | ||
85 | desktop_shell_set_panel_position(bar_output->registry->desktop_shell, bar->config->position); | ||
86 | |||
87 | /* set font */ | ||
88 | bar_output->window->font = bar->config->font; | ||
89 | |||
90 | /* set window height */ | ||
91 | set_window_height(bar_output->window, bar->config->height); | ||
92 | } | ||
84 | /* spawn status command */ | 93 | /* spawn status command */ |
85 | spawn_status_cmd_proc(bar); | 94 | spawn_status_cmd_proc(bar); |
86 | } | 95 | } |
87 | 96 | ||
88 | void bar_run(struct bar *bar) { | 97 | void bar_run(struct bar *bar) { |
89 | fd_set readfds; | 98 | int pfds = bar->outputs->length + 2; |
90 | int activity; | 99 | struct pollfd *pfd = malloc(pfds * sizeof(struct pollfd)); |
91 | bool dirty = true; | 100 | bool dirty = true; |
92 | 101 | ||
102 | pfd[0].fd = bar->ipc_event_socketfd; | ||
103 | pfd[0].events = POLLIN; | ||
104 | pfd[1].fd = bar->status_read_fd; | ||
105 | pfd[1].events = POLLIN; | ||
106 | |||
107 | int i; | ||
108 | for (i = 0; i < bar->outputs->length; ++i) { | ||
109 | struct output *output = bar->outputs->items[i]; | ||
110 | pfd[i+2].fd = wl_display_get_fd(output->registry->display); | ||
111 | pfd[i+2].events = POLLIN; | ||
112 | } | ||
113 | |||
93 | while (1) { | 114 | while (1) { |
94 | if (dirty) { | 115 | if (dirty) { |
95 | struct output *output = bar->output; | 116 | int i; |
96 | if (window_prerender(output->window) && output->window->cairo) { | 117 | for (i = 0; i < bar->outputs->length; ++i) { |
97 | render(output, bar->config, bar->status); | 118 | struct output *output = bar->outputs->items[i]; |
98 | window_render(output->window); | 119 | if (window_prerender(output->window) && output->window->cairo) { |
99 | if (wl_display_dispatch(output->registry->display) == -1) { | 120 | render(output, bar->config, bar->status); |
100 | break; | 121 | window_render(output->window); |
122 | wl_display_flush(output->registry->display); | ||
101 | } | 123 | } |
102 | } | 124 | } |
103 | } | 125 | } |
104 | 126 | ||
105 | dirty = false; | 127 | dirty = false; |
106 | FD_ZERO(&readfds); | ||
107 | FD_SET(bar->ipc_event_socketfd, &readfds); | ||
108 | FD_SET(bar->status_read_fd, &readfds); | ||
109 | 128 | ||
110 | activity = select(FD_SETSIZE, &readfds, NULL, NULL, NULL); | 129 | poll(pfd, pfds, -1); |
111 | if (activity < 0) { | ||
112 | sway_log(L_ERROR, "polling failed: %d", errno); | ||
113 | } | ||
114 | 130 | ||
115 | if (FD_ISSET(bar->ipc_event_socketfd, &readfds)) { | 131 | if (pfd[0].revents & POLLIN) { |
116 | sway_log(L_DEBUG, "Got IPC event."); | 132 | sway_log(L_DEBUG, "Got IPC event."); |
117 | dirty = handle_ipc_event(bar); | 133 | dirty = handle_ipc_event(bar); |
118 | } | 134 | } |
119 | 135 | ||
120 | if (bar->config->status_command && FD_ISSET(bar->status_read_fd, &readfds)) { | 136 | if (bar->config->status_command && pfd[1].revents & POLLIN) { |
121 | sway_log(L_DEBUG, "Got update from status command."); | 137 | sway_log(L_DEBUG, "Got update from status command."); |
122 | dirty = handle_status_line(bar); | 138 | dirty = handle_status_line(bar); |
123 | } | 139 | } |
140 | |||
141 | // dispatch wl_display events | ||
142 | for (i = 0; i < bar->outputs->length; ++i) { | ||
143 | struct output *output = bar->outputs->items[i]; | ||
144 | if (pfd[i+2].revents & POLLIN) { | ||
145 | if (wl_display_dispatch(output->registry->display) == -1) { | ||
146 | sway_log(L_ERROR, "failed to dispatch wl: %d", errno); | ||
147 | } | ||
148 | } else { | ||
149 | wl_display_dispatch_pending(output->registry->display); | ||
150 | } | ||
151 | } | ||
124 | } | 152 | } |
125 | } | 153 | } |
126 | 154 | ||
@@ -149,6 +177,14 @@ static void free_output(struct output *output) { | |||
149 | free(output); | 177 | free(output); |
150 | } | 178 | } |
151 | 179 | ||
180 | static void free_outputs(list_t *outputs) { | ||
181 | int i; | ||
182 | for (i = 0; i < outputs->length; ++i) { | ||
183 | free_output(outputs->items[i]); | ||
184 | } | ||
185 | list_free(outputs); | ||
186 | } | ||
187 | |||
152 | static void terminate_status_command(pid_t pid) { | 188 | static void terminate_status_command(pid_t pid) { |
153 | if (pid) { | 189 | if (pid) { |
154 | // terminate status_command process | 190 | // terminate status_command process |
@@ -164,7 +200,7 @@ static void terminate_status_command(pid_t pid) { | |||
164 | 200 | ||
165 | void bar_teardown(struct bar *bar) { | 201 | void bar_teardown(struct bar *bar) { |
166 | free_config(bar->config); | 202 | free_config(bar->config); |
167 | free_output(bar->output); | 203 | free_outputs(bar->outputs); |
168 | free_status_line(bar->status); | 204 | free_status_line(bar->status); |
169 | 205 | ||
170 | /* close sockets/pipes */ | 206 | /* close sockets/pipes */ |
diff --git a/swaybar/config.c b/swaybar/config.c index 92251831..fddea791 100644 --- a/swaybar/config.c +++ b/swaybar/config.c | |||
@@ -51,6 +51,8 @@ struct config *init_config() { | |||
51 | config->strip_workspace_numbers = false; | 51 | config->strip_workspace_numbers = false; |
52 | config->binding_mode_indicator = true; | 52 | config->binding_mode_indicator = true; |
53 | config->workspace_buttons = true; | 53 | config->workspace_buttons = true; |
54 | config->all_outputs = false; | ||
55 | config->outputs = create_list(); | ||
54 | 56 | ||
55 | /* height */ | 57 | /* height */ |
56 | config->height = 0; | 58 | config->height = 0; |
diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 4104103d..312c79b9 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c | |||
@@ -11,7 +11,7 @@ static void ipc_parse_config(struct config *config, const char *payload) { | |||
11 | json_object *bar_config = json_tokener_parse(payload); | 11 | json_object *bar_config = json_tokener_parse(payload); |
12 | json_object *tray_output, *mode, *hidden_bar, *position, *status_command; | 12 | json_object *tray_output, *mode, *hidden_bar, *position, *status_command; |
13 | json_object *font, *bar_height, *workspace_buttons, *strip_workspace_numbers; | 13 | json_object *font, *bar_height, *workspace_buttons, *strip_workspace_numbers; |
14 | json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol; | 14 | json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; |
15 | json_object_object_get_ex(bar_config, "tray_output", &tray_output); | 15 | json_object_object_get_ex(bar_config, "tray_output", &tray_output); |
16 | json_object_object_get_ex(bar_config, "mode", &mode); | 16 | json_object_object_get_ex(bar_config, "mode", &mode); |
17 | json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar); | 17 | json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar); |
@@ -25,6 +25,7 @@ static void ipc_parse_config(struct config *config, const char *payload) { | |||
25 | json_object_object_get_ex(bar_config, "verbose", &verbose); | 25 | json_object_object_get_ex(bar_config, "verbose", &verbose); |
26 | json_object_object_get_ex(bar_config, "separator_symbol", &sep_symbol); | 26 | json_object_object_get_ex(bar_config, "separator_symbol", &sep_symbol); |
27 | json_object_object_get_ex(bar_config, "colors", &colors); | 27 | json_object_object_get_ex(bar_config, "colors", &colors); |
28 | json_object_object_get_ex(bar_config, "outputs", &outputs); | ||
28 | 29 | ||
29 | if (status_command) { | 30 | if (status_command) { |
30 | free(config->status_command); | 31 | free(config->status_command); |
@@ -61,6 +62,31 @@ static void ipc_parse_config(struct config *config, const char *payload) { | |||
61 | config->height = json_object_get_int(bar_height); | 62 | config->height = json_object_get_int(bar_height); |
62 | } | 63 | } |
63 | 64 | ||
65 | // free previous outputs list | ||
66 | int i; | ||
67 | for (i = 0; i < config->outputs->length; ++i) { | ||
68 | free(config->outputs->items[i]); | ||
69 | } | ||
70 | list_free(config->outputs); | ||
71 | config->outputs = create_list(); | ||
72 | |||
73 | if (outputs) { | ||
74 | int length = json_object_array_length(outputs); | ||
75 | json_object *output; | ||
76 | const char *output_str; | ||
77 | for (i = 0; i < length; ++i) { | ||
78 | output = json_object_array_get_idx(outputs, i); | ||
79 | output_str = json_object_get_string(output); | ||
80 | if (strcmp("*", output_str) == 0) { | ||
81 | config->all_outputs = true; | ||
82 | break; | ||
83 | } | ||
84 | list_add(config->outputs, strdup(output_str)); | ||
85 | } | ||
86 | } else { | ||
87 | config->all_outputs = true; | ||
88 | } | ||
89 | |||
64 | if (colors) { | 90 | if (colors) { |
65 | json_object *background, *statusline, *separator; | 91 | json_object *background, *statusline, *separator; |
66 | json_object *focused_workspace_border, *focused_workspace_bg, *focused_workspace_text; | 92 | json_object *focused_workspace_border, *focused_workspace_bg, *focused_workspace_text; |
@@ -151,10 +177,14 @@ static void ipc_parse_config(struct config *config, const char *payload) { | |||
151 | } | 177 | } |
152 | 178 | ||
153 | static void ipc_update_workspaces(struct bar *bar) { | 179 | static void ipc_update_workspaces(struct bar *bar) { |
154 | if (bar->output->workspaces) { | 180 | int i; |
155 | free_workspaces(bar->output->workspaces); | 181 | for (i = 0; i < bar->outputs->length; ++i) { |
182 | struct output *output = bar->outputs->items[i]; | ||
183 | if (output->workspaces) { | ||
184 | free_workspaces(output->workspaces); | ||
185 | } | ||
186 | output->workspaces = create_list(); | ||
156 | } | 187 | } |
157 | bar->output->workspaces = create_list(); | ||
158 | 188 | ||
159 | uint32_t len = 0; | 189 | uint32_t len = 0; |
160 | char *res = ipc_single_command(bar->ipc_socketfd, IPC_GET_WORKSPACES, NULL, &len); | 190 | char *res = ipc_single_command(bar->ipc_socketfd, IPC_GET_WORKSPACES, NULL, &len); |
@@ -164,7 +194,6 @@ static void ipc_update_workspaces(struct bar *bar) { | |||
164 | return; | 194 | return; |
165 | } | 195 | } |
166 | 196 | ||
167 | int i; | ||
168 | int length = json_object_array_length(results); | 197 | int length = json_object_array_length(results); |
169 | json_object *ws_json; | 198 | json_object *ws_json; |
170 | json_object *num, *name, *visible, *focused, *out, *urgent; | 199 | json_object *num, *name, *visible, *focused, *out, *urgent; |
@@ -178,14 +207,18 @@ static void ipc_update_workspaces(struct bar *bar) { | |||
178 | json_object_object_get_ex(ws_json, "output", &out); | 207 | json_object_object_get_ex(ws_json, "output", &out); |
179 | json_object_object_get_ex(ws_json, "urgent", &urgent); | 208 | json_object_object_get_ex(ws_json, "urgent", &urgent); |
180 | 209 | ||
181 | if (strcmp(json_object_get_string(out), bar->output->name) == 0) { | 210 | int j; |
182 | struct workspace *ws = malloc(sizeof(struct workspace)); | 211 | for (j = 0; j < bar->outputs->length; ++j) { |
183 | ws->num = json_object_get_int(num); | 212 | struct output *output = bar->outputs->items[j]; |
184 | ws->name = strdup(json_object_get_string(name)); | 213 | if (strcmp(json_object_get_string(out), output->name) == 0) { |
185 | ws->visible = json_object_get_boolean(visible); | 214 | struct workspace *ws = malloc(sizeof(struct workspace)); |
186 | ws->focused = json_object_get_boolean(focused); | 215 | ws->num = json_object_get_int(num); |
187 | ws->urgent = json_object_get_boolean(urgent); | 216 | ws->name = strdup(json_object_get_string(name)); |
188 | list_add(bar->output->workspaces, ws); | 217 | ws->visible = json_object_get_boolean(visible); |
218 | ws->focused = json_object_get_boolean(focused); | ||
219 | ws->urgent = json_object_get_boolean(urgent); | ||
220 | list_add(output->workspaces, ws); | ||
221 | } | ||
189 | } | 222 | } |
190 | } | 223 | } |
191 | 224 | ||
@@ -193,22 +226,58 @@ static void ipc_update_workspaces(struct bar *bar) { | |||
193 | free(res); | 226 | free(res); |
194 | } | 227 | } |
195 | 228 | ||
196 | void ipc_bar_init(struct bar *bar, int outputi, const char *bar_id) { | 229 | void ipc_bar_init(struct bar *bar, const char *bar_id) { |
197 | uint32_t len = 0; | 230 | // Get bar config |
198 | char *res = ipc_single_command(bar->ipc_socketfd, IPC_GET_OUTPUTS, NULL, &len); | 231 | uint32_t len = strlen(bar_id); |
199 | json_object *outputs = json_tokener_parse(res); | 232 | char *res = ipc_single_command(bar->ipc_socketfd, IPC_GET_BAR_CONFIG, bar_id, &len); |
200 | json_object *info = json_object_array_get_idx(outputs, outputi); | 233 | |
201 | json_object *name; | 234 | ipc_parse_config(bar->config, res); |
202 | json_object_object_get_ex(info, "name", &name); | ||
203 | bar->output->name = strdup(json_object_get_string(name)); | ||
204 | free(res); | 235 | free(res); |
205 | json_object_put(outputs); | ||
206 | 236 | ||
207 | len = strlen(bar_id); | 237 | // Get outputs |
208 | res = ipc_single_command(bar->ipc_socketfd, IPC_GET_BAR_CONFIG, bar_id, &len); | 238 | len = 0; |
239 | res = ipc_single_command(bar->ipc_socketfd, IPC_GET_OUTPUTS, NULL, &len); | ||
240 | json_object *outputs = json_tokener_parse(res); | ||
241 | int i; | ||
242 | int length = json_object_array_length(outputs); | ||
243 | json_object *output, *output_name, *output_active; | ||
244 | const char *name; | ||
245 | bool active; | ||
246 | for (i = 0; i < length; ++i) { | ||
247 | output = json_object_array_get_idx(outputs, i); | ||
248 | json_object_object_get_ex(output, "name", &output_name); | ||
249 | json_object_object_get_ex(output, "active", &output_active); | ||
250 | name = json_object_get_string(output_name); | ||
251 | active = json_object_get_boolean(output_active); | ||
252 | if (!active) { | ||
253 | continue; | ||
254 | } | ||
209 | 255 | ||
210 | ipc_parse_config(bar->config, res); | 256 | bool use_output = false; |
257 | if (bar->config->all_outputs) { | ||
258 | use_output = true; | ||
259 | } else { | ||
260 | int j = 0; | ||
261 | for (j = 0; j < bar->config->outputs->length; ++j) { | ||
262 | const char *conf_name = bar->config->outputs->items[i]; | ||
263 | if (strcasecmp(name, conf_name) == 0) { | ||
264 | use_output = true; | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | |||
270 | if (!use_output) { | ||
271 | continue; | ||
272 | } | ||
273 | |||
274 | // add bar to the output | ||
275 | struct output *bar_output = new_output(name); | ||
276 | bar_output->idx = i; | ||
277 | list_add(bar->outputs, bar_output); | ||
278 | } | ||
211 | free(res); | 279 | free(res); |
280 | json_object_put(outputs); | ||
212 | 281 | ||
213 | const char *subscribe_json = "[ \"workspace\", \"mode\" ]"; | 282 | const char *subscribe_json = "[ \"workspace\", \"mode\" ]"; |
214 | len = strlen(subscribe_json); | 283 | len = strlen(subscribe_json); |
diff --git a/swaybar/main.c b/swaybar/main.c index c6bbc7a5..d7534f5d 100644 --- a/swaybar/main.c +++ b/swaybar/main.c | |||
@@ -35,7 +35,7 @@ int main(int argc, char **argv) { | |||
35 | }; | 35 | }; |
36 | 36 | ||
37 | const char *usage = | 37 | const char *usage = |
38 | "Usage: swaybar [options...] <output>\n" | 38 | "Usage: swaybar [options...]\n" |
39 | "\n" | 39 | "\n" |
40 | " -h, --help Show help message and quit.\n" | 40 | " -h, --help Show help message and quit.\n" |
41 | " -v, --version Show the version number and quit.\n" | 41 | " -v, --version Show the version number and quit.\n" |
@@ -95,15 +95,9 @@ int main(int argc, char **argv) { | |||
95 | } | 95 | } |
96 | } | 96 | } |
97 | 97 | ||
98 | if (argc == optind) { | ||
99 | sway_abort("No output index provided"); | ||
100 | } | ||
101 | |||
102 | int desired_output = atoi(argv[optind]); | ||
103 | |||
104 | signal(SIGTERM, sig_handler); | 98 | signal(SIGTERM, sig_handler); |
105 | 99 | ||
106 | bar_setup(&swaybar, socket_path, bar_id, desired_output); | 100 | bar_setup(&swaybar, socket_path, bar_id); |
107 | 101 | ||
108 | free(socket_path); | 102 | free(socket_path); |
109 | free(bar_id); | 103 | free(bar_id); |