From 6d57f03028b4b32b4377d869be8de9a7e6aa55ee Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Mon, 22 Feb 2016 17:27:17 +0100 Subject: [PATCH] Make single bar handle multiple outputs --- include/bar/bar.h | 11 ++-- include/bar/config.h | 3 ++ include/bar/ipc.h | 2 +- swaybar/bar.c | 82 ++++++++++++++++++------------ swaybar/config.c | 1 + swaybar/ipc.c | 116 +++++++++++++++++++++++++++++++++---------- swaybar/main.c | 10 +--- 7 files changed, 157 insertions(+), 68 deletions(-) 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..dfad0ba4 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,7 @@ struct config { bool strip_workspace_numbers; bool binding_mode_indicator; bool workspace_buttons; + 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/swaybar/bar.c b/swaybar/bar.c index d80c9af3..6d2872c3 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -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,38 +46,50 @@ 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); } @@ -92,12 +101,15 @@ void bar_run(struct bar *bar) { 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); + if (wl_display_dispatch(output->registry->display) == -1) { + break; + } } } } @@ -149,6 +161,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 +184,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..5609f85f 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -51,6 +51,7 @@ struct config *init_config() { config->strip_workspace_numbers = false; config->binding_mode_indicator = true; config->workspace_buttons = true; + config->outputs = create_list(); /* height */ config->height = 0; diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 4104103d..b5ae6747 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,28 @@ 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) { + break; + } + list_add(config->outputs, strdup(output_str)); + } + } + if (colors) { json_object *background, *statusline, *separator; json_object *focused_workspace_border, *focused_workspace_bg, *focused_workspace_text; @@ -151,10 +174,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 +191,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 +204,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 +223,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->outputs->length == 0) { + 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);