diff --git a/include/bar/bar.h b/include/bar/bar.h index 89496da6..c20efc55 100644 --- a/include/bar/bar.h +++ b/include/bar/bar.h @@ -8,8 +8,7 @@ struct bar { struct config *config; struct status_line *status; - struct output *output; - /* list_t *outputs; */ + list_t *outputs; int ipc_event_socketfd; int ipc_socketfd; @@ -22,6 +21,7 @@ struct output { struct registry *registry; list_t *workspaces; char *name; + int idx; }; struct workspace { @@ -35,7 +35,12 @@ struct workspace { /** * Setup bar. */ -void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id, int desired_output); +void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id); + +/** + * Create new output struct from name. + */ +struct output *new_output(const char *name); /** * Bar mainloop. diff --git a/include/bar/config.h b/include/bar/config.h index 508b9c42..fc938c38 100644 --- a/include/bar/config.h +++ b/include/bar/config.h @@ -4,6 +4,8 @@ #include #include +#include "list.h" + /** * Colors for a box with background, border and text colors. */ @@ -25,6 +27,8 @@ struct config { bool strip_workspace_numbers; bool binding_mode_indicator; bool workspace_buttons; + bool all_outputs; + list_t *outputs; int height; diff --git a/include/bar/ipc.h b/include/bar/ipc.h index c3f661f8..741c067b 100644 --- a/include/bar/ipc.h +++ b/include/bar/ipc.h @@ -6,7 +6,7 @@ /** * Initialize ipc connection to sway and get sway state, outputs, bar_config. */ -void ipc_bar_init(struct bar *bar, int outputi, const char *bar_id); +void ipc_bar_init(struct bar *bar, const char *bar_id); /** * Handle ipc event from sway. diff --git a/include/config.h b/include/config.h index 655d0a9c..d77872ee 100644 --- a/include/config.h +++ b/include/config.h @@ -125,6 +125,7 @@ struct bar_config { bool strip_workspace_numbers; bool binding_mode_indicator; bool verbose; + pid_t pid; struct { char background[10]; char statusline[10]; @@ -191,6 +192,10 @@ bool load_config(const char *file); /** Reads the config from the given FILE. */ bool read_config(FILE *file, bool is_active); +/** + * Free config struct + */ +void free_config(struct sway_config *config); /** * Does variable replacement for a string based on the config's currently loaded variables. */ @@ -226,8 +231,7 @@ int sway_mouse_binding_cmp_qsort(const void *a, const void *b); int sway_mouse_binding_cmp_buttons(const void *a, const void *b); void free_sway_mouse_binding(struct sway_mouse_binding *smb); -void load_swaybars(swayc_t *output, int output_idx); -void terminate_swaybars(list_t *pids); +void load_swaybars(); void terminate_swaybg(pid_t pid); /** diff --git a/include/container.h b/include/container.h index d5126e74..a96beab9 100644 --- a/include/container.h +++ b/include/container.h @@ -82,9 +82,7 @@ struct sway_container { char *class; char *app_id; - // Used by output containers to keep track of swaybar/swaybg child - // processes. - list_t *bar_pids; + // Used by output containers to keep track of swaybg child processes. pid_t bg_pid; int gaps; diff --git a/sway/commands.c b/sway/commands.c index c4b7f6ab..3b8556ca 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -1526,14 +1526,7 @@ static struct cmd_results *cmd_reload(int argc, char **argv) { } if (!load_config(NULL)) return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); - int i; - swayc_t *cont = NULL; - for (i = 0; i < root_container.children->length; ++i) { - cont = root_container.children->items[i]; - if (cont->type == C_OUTPUT) { - load_swaybars(cont, i); - } - } + load_swaybars(); arrange_windows(&root_container, -1, -1); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/config.c b/sway/config.c index 65dba365..296e164c 100644 --- a/sway/config.c +++ b/sway/config.c @@ -23,6 +23,8 @@ struct sway_config *config = NULL; +static void terminate_swaybar(pid_t pid); + static void free_variable(struct sway_variable *var) { free(var->name); free(var->value); @@ -60,6 +62,11 @@ static void free_bar(struct bar_config *bar) { if (bar->outputs) { free_flat_list(bar->outputs); } + + if (bar->pid != 0) { + terminate_swaybar(bar->pid); + } + free(bar); } @@ -79,7 +86,7 @@ static void free_workspace_output(struct workspace_output *wo) { free(wo); } -static void free_config(struct sway_config *config) { +void free_config(struct sway_config *config) { int i; for (i = 0; i < config->symbols->length; ++i) { free_variable(config->symbols->items[i]); @@ -471,32 +478,23 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { } } -static void invoke_swaybar(swayc_t *output, struct bar_config *bar, int output_i) { - sway_log(L_DEBUG, "Invoking swaybar for output %s[%d] and bar %s", output->name, output_i, bar->id); - - size_t bufsize = 4; - char output_id[bufsize]; - snprintf(output_id, bufsize, "%d", output_i); - output_id[bufsize-1] = 0; - - pid_t *pid = malloc(sizeof(pid_t)); - *pid = fork(); - if (*pid == 0) { +static void invoke_swaybar(struct bar_config *bar) { + bar->pid = fork(); + if (bar->pid == 0) { if (!bar->swaybar_command) { char *const cmd[] = { "swaybar", "-b", bar->id, - output_id, NULL, }; execvp(cmd[0], cmd); } else { // run custom swaybar - int len = strlen(bar->swaybar_command) + strlen(bar->id) + strlen(output_id) + 6; + int len = strlen(bar->swaybar_command) + strlen(bar->id) + 5; char *command = malloc(len * sizeof(char)); - snprintf(command, len, "%s -b %s %s", bar->swaybar_command, bar->id, output_id); + snprintf(command, len, "%s -b %s", bar->swaybar_command, bar->id); char *const cmd[] = { "sh", @@ -509,30 +507,15 @@ static void invoke_swaybar(swayc_t *output, struct bar_config *bar, int output_i free(command); } } - - // add swaybar pid to output - list_add(output->bar_pids, pid); } -void terminate_swaybars(list_t *pids) { - int i, ret; - pid_t *pid; - for (i = 0; i < pids->length; ++i) { - pid = pids->items[i]; - ret = kill(*pid, SIGTERM); - if (ret != 0) { - sway_log(L_ERROR, "Unable to terminate swaybar [pid: %d]", *pid); - } else { - int status; - waitpid(*pid, &status, 0); - } - } - - // empty pids list - for (i = 0; i < pids->length; ++i) { - pid = pids->items[i]; - list_del(pids, i); - free(pid); +static void terminate_swaybar(pid_t pid) { + int ret = kill(pid, SIGTERM); + if (ret != 0) { + sway_log(L_ERROR, "Unable to terminate swaybar [pid: %d]", pid); + } else { + int status; + waitpid(pid, &status, 0); } } @@ -546,7 +529,20 @@ void terminate_swaybg(pid_t pid) { } } -void load_swaybars(swayc_t *output, int output_idx) { +static bool active_output(const char *name) { + int i; + swayc_t *cont = NULL; + for (i = 0; i < root_container.children->length; ++i) { + cont = root_container.children->items[i]; + if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) { + return true; + } + } + + return false; +} + +void load_swaybars() { // Check for bars list_t *bars = create_list(); struct bar_config *bar = NULL; @@ -558,7 +554,7 @@ void load_swaybars(swayc_t *output, int output_idx) { int j; for (j = 0; j < bar->outputs->length; ++j) { char *o = bar->outputs->items[j]; - if (!strcmp(o, "*") || !strcasecmp(o, output->name)) { + if (!strcmp(o, "*") || active_output(o)) { apply = true; break; } @@ -571,13 +567,13 @@ void load_swaybars(swayc_t *output, int output_idx) { } } - // terminate swaybar processes previously spawned for this - // output. - terminate_swaybars(output->bar_pids); - for (i = 0; i < bars->length; ++i) { bar = bars->items[i]; - invoke_swaybar(output, bar, output_idx); + if (bar->pid != 0) { + terminate_swaybar(bar->pid); + } + sway_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); + invoke_swaybar(bar); } list_free(bars); @@ -700,8 +696,8 @@ void apply_output_config(struct output_config *oc, swayc_t *output) { } } - // load swaybars for output - load_swaybars(output, output_i); + // reload swaybars + load_swaybars(); } char *do_var_replacement(char *str) { @@ -889,6 +885,7 @@ struct bar_config *default_bar_config(void) { bar->strip_workspace_numbers = false; bar->binding_mode_indicator = true; bar->tray_padding = 2; + bar->pid = 0; // set default colors strcpy(bar->colors.background, "#000000ff"); strcpy(bar->colors.statusline, "#ffffffff"); diff --git a/sway/container.c b/sway/container.c index 746890c9..2db7b218 100644 --- a/sway/container.c +++ b/sway/container.c @@ -61,10 +61,6 @@ static void free_swayc(swayc_t *cont) { if (cont->app_id) { free(cont->app_id); } - if (cont->bar_pids) { - terminate_swaybars(cont->bar_pids); - free_flat_list(cont->bar_pids); - } if (cont->bg_pid != 0) { terminate_swaybg(cont->bg_pid); } @@ -123,7 +119,6 @@ swayc_t *new_output(wlc_handle handle) { output->width = size->w; output->height = size->h; output->unmanaged = create_list(); - output->bar_pids = create_list(); output->bg_pid = 0; apply_output_config(oc, output); diff --git a/sway/ipc-server.c b/sway/ipc-server.c index a63026c6..9ea034d1 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -628,6 +628,17 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { json_object_object_add(json, "colors", colors); + // Add outputs if defined + if (bar->outputs && bar->outputs->length > 0) { + json_object *outputs = json_object_new_array(); + int i; + for (i = 0; i < bar->outputs->length; ++i) { + const char *name = bar->outputs->items[i]; + json_object_array_add(outputs, json_object_new_string(name)); + } + json_object_object_add(json, "outputs", outputs); + } + return json; } diff --git a/sway/main.c b/sway/main.c index 7ea392b6..7c712281 100644 --- a/sway/main.c +++ b/sway/main.c @@ -228,6 +228,10 @@ int main(int argc, char **argv) { ipc_terminate(); + if (config) { + free_config(config); + } + return exit_value; } 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 @@ #include #include +#include #include #include -#include #include +#include #include "ipc-client.h" #include "list.h" @@ -17,11 +18,7 @@ static void bar_init(struct bar *bar) { bar->config = init_config(); bar->status = init_status_line(); - bar->output = malloc(sizeof(struct output)); - bar->output->window = NULL; - bar->output->registry = NULL; - bar->output->workspaces = create_list(); - bar->output->name = NULL; + bar->outputs = create_list(); } static void spawn_status_cmd_proc(struct bar *bar) { @@ -49,78 +46,109 @@ static void spawn_status_cmd_proc(struct bar *bar) { } } +struct output *new_output(const char *name) { + struct output *output = malloc(sizeof(struct output)); + output->name = strdup(name); + output->window = NULL; + output->registry = NULL; + output->workspaces = create_list(); + return output; +} -void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id, int desired_output) { +void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { /* initialize bar with default values */ bar_init(bar); - bar->output->registry = registry_poll(); - - if (!bar->output->registry->desktop_shell) { - sway_abort("swaybar requires the compositor to support the desktop-shell extension."); - } - /* connect to sway ipc */ bar->ipc_socketfd = ipc_open_socket(socket_path); bar->ipc_event_socketfd = ipc_open_socket(socket_path); - ipc_bar_init(bar, desired_output, bar_id); + ipc_bar_init(bar, bar_id); - struct output_state *output = bar->output->registry->outputs->items[desired_output]; + int i; + for (i = 0; i < bar->outputs->length; ++i) { + struct output *bar_output = bar->outputs->items[i]; - bar->output->window = window_setup(bar->output->registry, output->width, 30, false); - if (!bar->output->window) { - sway_abort("Failed to create window."); - } - desktop_shell_set_panel(bar->output->registry->desktop_shell, output->output, bar->output->window->surface); - desktop_shell_set_panel_position(bar->output->registry->desktop_shell, bar->config->position); + bar_output->registry = registry_poll(); - /* set font */ - bar->output->window->font = bar->config->font; + if (!bar_output->registry->desktop_shell) { + sway_abort("swaybar requires the compositor to support the desktop-shell extension."); + } - /* set window height */ - set_window_height(bar->output->window, bar->config->height); + struct output_state *output = bar_output->registry->outputs->items[bar_output->idx]; + bar_output->window = window_setup(bar_output->registry, output->width, 30, false); + if (!bar_output->window) { + sway_abort("Failed to create window."); + } + desktop_shell_set_panel(bar_output->registry->desktop_shell, output->output, bar_output->window->surface); + desktop_shell_set_panel_position(bar_output->registry->desktop_shell, bar->config->position); + + /* set font */ + bar_output->window->font = bar->config->font; + + /* set window height */ + set_window_height(bar_output->window, bar->config->height); + } /* spawn status command */ spawn_status_cmd_proc(bar); } void bar_run(struct bar *bar) { - fd_set readfds; - int activity; + int pfds = bar->outputs->length + 2; + struct pollfd *pfd = malloc(pfds * sizeof(struct pollfd)); bool dirty = true; + pfd[0].fd = bar->ipc_event_socketfd; + pfd[0].events = POLLIN; + pfd[1].fd = bar->status_read_fd; + pfd[1].events = POLLIN; + + int i; + for (i = 0; i < bar->outputs->length; ++i) { + struct output *output = bar->outputs->items[i]; + pfd[i+2].fd = wl_display_get_fd(output->registry->display); + pfd[i+2].events = POLLIN; + } + while (1) { if (dirty) { - struct output *output = bar->output; - if (window_prerender(output->window) && output->window->cairo) { - render(output, bar->config, bar->status); - window_render(output->window); - if (wl_display_dispatch(output->registry->display) == -1) { - break; + int i; + for (i = 0; i < bar->outputs->length; ++i) { + struct output *output = bar->outputs->items[i]; + if (window_prerender(output->window) && output->window->cairo) { + render(output, bar->config, bar->status); + window_render(output->window); + wl_display_flush(output->registry->display); } } } dirty = false; - FD_ZERO(&readfds); - FD_SET(bar->ipc_event_socketfd, &readfds); - FD_SET(bar->status_read_fd, &readfds); - activity = select(FD_SETSIZE, &readfds, NULL, NULL, NULL); - if (activity < 0) { - sway_log(L_ERROR, "polling failed: %d", errno); - } + poll(pfd, pfds, -1); - if (FD_ISSET(bar->ipc_event_socketfd, &readfds)) { + if (pfd[0].revents & POLLIN) { sway_log(L_DEBUG, "Got IPC event."); dirty = handle_ipc_event(bar); } - if (bar->config->status_command && FD_ISSET(bar->status_read_fd, &readfds)) { + if (bar->config->status_command && pfd[1].revents & POLLIN) { sway_log(L_DEBUG, "Got update from status command."); dirty = handle_status_line(bar); } + + // dispatch wl_display events + for (i = 0; i < bar->outputs->length; ++i) { + struct output *output = bar->outputs->items[i]; + if (pfd[i+2].revents & POLLIN) { + if (wl_display_dispatch(output->registry->display) == -1) { + sway_log(L_ERROR, "failed to dispatch wl: %d", errno); + } + } else { + wl_display_dispatch_pending(output->registry->display); + } + } } } @@ -149,6 +177,14 @@ static void free_output(struct output *output) { free(output); } +static void free_outputs(list_t *outputs) { + int i; + for (i = 0; i < outputs->length; ++i) { + free_output(outputs->items[i]); + } + list_free(outputs); +} + static void terminate_status_command(pid_t pid) { if (pid) { // terminate status_command process @@ -164,7 +200,7 @@ static void terminate_status_command(pid_t pid) { void bar_teardown(struct bar *bar) { free_config(bar->config); - free_output(bar->output); + free_outputs(bar->outputs); free_status_line(bar->status); /* 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() { config->strip_workspace_numbers = false; config->binding_mode_indicator = true; config->workspace_buttons = true; + config->all_outputs = false; + config->outputs = create_list(); /* height */ 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) { json_object *bar_config = json_tokener_parse(payload); json_object *tray_output, *mode, *hidden_bar, *position, *status_command; json_object *font, *bar_height, *workspace_buttons, *strip_workspace_numbers; - json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol; + json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; json_object_object_get_ex(bar_config, "tray_output", &tray_output); json_object_object_get_ex(bar_config, "mode", &mode); 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) { json_object_object_get_ex(bar_config, "verbose", &verbose); json_object_object_get_ex(bar_config, "separator_symbol", &sep_symbol); json_object_object_get_ex(bar_config, "colors", &colors); + json_object_object_get_ex(bar_config, "outputs", &outputs); if (status_command) { free(config->status_command); @@ -61,6 +62,31 @@ static void ipc_parse_config(struct config *config, const char *payload) { config->height = json_object_get_int(bar_height); } + // free previous outputs list + int i; + for (i = 0; i < config->outputs->length; ++i) { + free(config->outputs->items[i]); + } + list_free(config->outputs); + config->outputs = create_list(); + + if (outputs) { + int length = json_object_array_length(outputs); + json_object *output; + const char *output_str; + for (i = 0; i < length; ++i) { + output = json_object_array_get_idx(outputs, i); + output_str = json_object_get_string(output); + if (strcmp("*", output_str) == 0) { + config->all_outputs = true; + break; + } + list_add(config->outputs, strdup(output_str)); + } + } else { + config->all_outputs = true; + } + if (colors) { json_object *background, *statusline, *separator; 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) { } static void ipc_update_workspaces(struct bar *bar) { - if (bar->output->workspaces) { - free_workspaces(bar->output->workspaces); + int i; + for (i = 0; i < bar->outputs->length; ++i) { + struct output *output = bar->outputs->items[i]; + if (output->workspaces) { + free_workspaces(output->workspaces); + } + output->workspaces = create_list(); } - bar->output->workspaces = create_list(); uint32_t len = 0; 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) { return; } - int i; int length = json_object_array_length(results); json_object *ws_json; json_object *num, *name, *visible, *focused, *out, *urgent; @@ -178,14 +207,18 @@ static void ipc_update_workspaces(struct bar *bar) { json_object_object_get_ex(ws_json, "output", &out); json_object_object_get_ex(ws_json, "urgent", &urgent); - if (strcmp(json_object_get_string(out), bar->output->name) == 0) { - struct workspace *ws = malloc(sizeof(struct workspace)); - ws->num = json_object_get_int(num); - ws->name = strdup(json_object_get_string(name)); - ws->visible = json_object_get_boolean(visible); - ws->focused = json_object_get_boolean(focused); - ws->urgent = json_object_get_boolean(urgent); - list_add(bar->output->workspaces, ws); + int j; + for (j = 0; j < bar->outputs->length; ++j) { + struct output *output = bar->outputs->items[j]; + if (strcmp(json_object_get_string(out), output->name) == 0) { + struct workspace *ws = malloc(sizeof(struct workspace)); + ws->num = json_object_get_int(num); + ws->name = strdup(json_object_get_string(name)); + ws->visible = json_object_get_boolean(visible); + ws->focused = json_object_get_boolean(focused); + ws->urgent = json_object_get_boolean(urgent); + list_add(output->workspaces, ws); + } } } @@ -193,22 +226,58 @@ static void ipc_update_workspaces(struct bar *bar) { free(res); } -void ipc_bar_init(struct bar *bar, int outputi, const char *bar_id) { - uint32_t len = 0; - char *res = ipc_single_command(bar->ipc_socketfd, IPC_GET_OUTPUTS, NULL, &len); - json_object *outputs = json_tokener_parse(res); - json_object *info = json_object_array_get_idx(outputs, outputi); - json_object *name; - json_object_object_get_ex(info, "name", &name); - bar->output->name = strdup(json_object_get_string(name)); +void ipc_bar_init(struct bar *bar, const char *bar_id) { + // Get bar config + uint32_t len = strlen(bar_id); + char *res = ipc_single_command(bar->ipc_socketfd, IPC_GET_BAR_CONFIG, bar_id, &len); + + ipc_parse_config(bar->config, res); free(res); - json_object_put(outputs); - len = strlen(bar_id); - res = ipc_single_command(bar->ipc_socketfd, IPC_GET_BAR_CONFIG, bar_id, &len); + // Get outputs + len = 0; + res = ipc_single_command(bar->ipc_socketfd, IPC_GET_OUTPUTS, NULL, &len); + json_object *outputs = json_tokener_parse(res); + int i; + int length = json_object_array_length(outputs); + json_object *output, *output_name, *output_active; + const char *name; + bool active; + for (i = 0; i < length; ++i) { + output = json_object_array_get_idx(outputs, i); + json_object_object_get_ex(output, "name", &output_name); + json_object_object_get_ex(output, "active", &output_active); + name = json_object_get_string(output_name); + active = json_object_get_boolean(output_active); + if (!active) { + continue; + } - ipc_parse_config(bar->config, res); + bool use_output = false; + if (bar->config->all_outputs) { + use_output = true; + } else { + int j = 0; + for (j = 0; j < bar->config->outputs->length; ++j) { + const char *conf_name = bar->config->outputs->items[i]; + if (strcasecmp(name, conf_name) == 0) { + use_output = true; + break; + } + } + } + + if (!use_output) { + continue; + } + + // add bar to the output + struct output *bar_output = new_output(name); + bar_output->idx = i; + list_add(bar->outputs, bar_output); + } free(res); + json_object_put(outputs); const char *subscribe_json = "[ \"workspace\", \"mode\" ]"; 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) { }; const char *usage = - "Usage: swaybar [options...] \n" + "Usage: swaybar [options...]\n" "\n" " -h, --help Show help message and quit.\n" " -v, --version Show the version number and quit.\n" @@ -95,15 +95,9 @@ int main(int argc, char **argv) { } } - if (argc == optind) { - sway_abort("No output index provided"); - } - - int desired_output = atoi(argv[optind]); - signal(SIGTERM, sig_handler); - bar_setup(&swaybar, socket_path, bar_id, desired_output); + bar_setup(&swaybar, socket_path, bar_id); free(socket_path); free(bar_id);