diff options
-rw-r--r-- | include/ipc-server.h | 4 | ||||
-rw-r--r-- | sway/commands.c | 154 | ||||
-rw-r--r-- | sway/config.c | 2 | ||||
-rw-r--r-- | sway/focus.c | 15 | ||||
-rw-r--r-- | sway/ipc-server.c | 171 | ||||
-rw-r--r-- | sway/layout.c | 7 | ||||
-rw-r--r-- | swaybar/main.c | 30 |
7 files changed, 273 insertions, 110 deletions
diff --git a/include/ipc-server.h b/include/ipc-server.h index 5ac255cf..ab9807ef 100644 --- a/include/ipc-server.h +++ b/include/ipc-server.h @@ -2,13 +2,15 @@ #define _SWAY_IPC_SERVER_H #include "container.h" +#include "config.h" #include "ipc.h" void ipc_init(void); void ipc_terminate(void); struct sockaddr_un *ipc_user_sockaddr(void); -void ipc_event_workspace(swayc_t *old, swayc_t *new); +void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change); +void ipc_event_barconfig_update(struct bar_config *bar); const char *swayc_type_string(enum swayc_types type); #endif diff --git a/sway/commands.c b/sway/commands.c index f6d9b947..b1b1c5b6 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -25,6 +25,7 @@ #include "resize.h" #include "input_state.h" #include "criteria.h" +#include "ipc-server.h" typedef struct cmd_results *sway_cmd(int argc, char **argv); @@ -1147,16 +1148,26 @@ static struct cmd_results *cmd_resize(int argc, char **argv) { static struct cmd_results *cmd_bar(int argc, char **argv) { struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bar", EXPECTED_EQUAL_TO, 1))) { + if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) { return error; } - if (strcmp("{", argv[0]) != 0) { + if (config->reading && strcmp("{", argv[0]) != 0) { return cmd_results_new(CMD_INVALID, "bar", "Expected '{' at start of bar config definition."); } if (!config->reading) { + if (argc > 1) { + if (strcasecmp("mode", argv[0]) == 0) { + return bar_cmd_mode(argc-1, argv + 1); + } + + if (strcasecmp("hidden_state", argv[0]) == 0) { + return bar_cmd_hidden_state(argc-1, argv + 1); + } + } + return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file."); } @@ -1679,53 +1690,144 @@ static struct cmd_results *bar_cmd_height(int argc, char **argv) { return cmd_results_new(CMD_SUCCESS, NULL, NULL); } +static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, const char *hidden_state) { + char *old_state = bar->hidden_state; + if (strcasecmp("toggle", hidden_state) == 0 && !config->reading) { + if (strcasecmp("hide", bar->hidden_state) == 0) { + bar->hidden_state = strdup("show"); + } else if (strcasecmp("show", bar->hidden_state) == 0) { + bar->hidden_state = strdup("hide"); + } + } else if (strcasecmp("hide", hidden_state) == 0) { + bar->hidden_state = strdup("hide"); + } else if (strcasecmp("show", hidden_state) == 0) { + bar->hidden_state = strdup("show"); + } else { + return cmd_results_new(CMD_INVALID, "hidden_state", "Invalid value %s", hidden_state); + } + + if (strcmp(old_state, bar->hidden_state) != 0) { + if (!config->reading) { + ipc_event_barconfig_update(bar); + } + sway_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", bar->hidden_state, bar->id); + } + + // free old mode + free(old_state); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + + static struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { struct cmd_results *error = NULL; - if ((error = checkarg(argc, "hidden_state", EXPECTED_EQUAL_TO, 1))) { + if ((error = checkarg(argc, "hidden_state", EXPECTED_AT_LEAST, 1))) { + return error; + } + if ((error = checkarg(argc, "hidden_state", EXPECTED_LESS_THAN, 3))) { return error; } + if (config->reading && argc > 1) { + return cmd_results_new(CMD_INVALID, "hidden_state", "Unexpected value %s in config mode", argv[1]); + } + const char *state = argv[0]; - char *old_state = config->current_bar->hidden_state; - if (strcasecmp("hide", state) == 0) { - config->current_bar->hidden_state = strdup(state); - } else if(strcmp("show", state) == 0) { - config->current_bar->hidden_state = strdup(state); + if (config->reading) { + return bar_set_hidden_state(config->current_bar, state); + } + + const char *id; + if (argc == 2) { + id = argv[1]; + } + + int i; + struct bar_config *bar; + for (i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + if (id && strcmp(id, bar->id) == 0) { + return bar_set_hidden_state(bar, state); + } + + error = bar_set_hidden_state(bar, state); + if (error) { + return error; + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode) { + char *old_mode = bar->mode; + if (strcasecmp("toggle", mode) == 0 && !config->reading) { + if (strcasecmp("dock", bar->mode) == 0) { + bar->mode = strdup("hide"); + } else if (strcasecmp("hide", bar->mode) == 0) { + bar->mode = strdup("dock"); + } + } else if (strcasecmp("dock", mode) == 0) { + bar->mode = strdup("dock"); + } else if (strcasecmp("hide", mode) == 0) { + bar->mode = strdup("hide"); + } else if (strcasecmp("invisible", mode) == 0) { + bar->mode = strdup("invisible"); } else { - return cmd_results_new(CMD_INVALID, "hidden_state", "Invalid value %s", state); + return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode); } - sway_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", state, config->current_bar->id); + if (strcmp(old_mode, bar->mode) != 0) { + if (!config->reading) { + ipc_event_barconfig_update(bar); + } + sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); + } - // free old state - free(old_state); + // free old mode + free(old_mode); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } static struct cmd_results *bar_cmd_mode(int argc, char **argv) { struct cmd_results *error = NULL; - if ((error = checkarg(argc, "mode", EXPECTED_EQUAL_TO, 1))) { + if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) { + return error; + } + if ((error = checkarg(argc, "mode", EXPECTED_LESS_THAN, 3))) { return error; } + if (config->reading && argc > 1) { + return cmd_results_new(CMD_INVALID, "mode", "Unexpected value %s in config mode", argv[1]); + } + const char *mode = argv[0]; - char *old_mode = config->current_bar->mode; - - if (strcasecmp("dock", mode) == 0) { - config->current_bar->mode = strdup(mode); - } else if(strcmp("hide", mode) == 0) { - config->current_bar->mode = strdup(mode); - } else if(strcmp("invisible", mode) == 0) { - config->current_bar->mode = strdup(mode); - } else { - return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode); + + if (config->reading) { + return bar_set_mode(config->current_bar, mode); } - sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", mode, config->current_bar->id); + const char *id; + if (argc == 2) { + id = argv[1]; + } + + int i; + struct bar_config *bar; + for (i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + if (id && strcmp(id, bar->id) == 0) { + return bar_set_mode(bar, mode); + } + + error = bar_set_mode(bar, mode); + if (error) { + return error; + } + } - // free old mode - free(old_mode); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/config.c b/sway/config.c index e86eda53..853a7111 100644 --- a/sway/config.c +++ b/sway/config.c @@ -701,7 +701,7 @@ struct bar_config *default_bar_config(void) { bar->bindings = create_list(); bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p' && sleep 1; done"); bar->swaybar_command = NULL; - bar->font = strdup("monospace 10"); + bar->font = strdup("pango:monospace 10"); bar->height = -1; bar->workspace_buttons = true; bar->separator_symbol = NULL; diff --git a/sway/focus.c b/sway/focus.c index c1170ca4..cf0ee7f6 100644 --- a/sway/focus.c +++ b/sway/focus.c @@ -34,7 +34,7 @@ static void update_focus(swayc_t *c) { // Case where workspace changes case C_WORKSPACE: if (prev) { - ipc_event_workspace(prev, c); + ipc_event_workspace(prev, c, "focus"); // update visibility of old workspace update_visibility(prev); @@ -122,11 +122,6 @@ bool set_focused_container(swayc_t *c) { p = p->parent; p->is_focused = false; } - // active_ws might have been destroyed by now - // (focus swap away from empty ws = destroy ws) - if (active_ws_child_count == 0) { - active_ws = NULL; - } // get new focused view and set focus to it. p = get_focused_view(c); @@ -146,7 +141,13 @@ bool set_focused_container(swayc_t *c) { } if (active_ws != workspace) { - ipc_event_workspace(active_ws, workspace); + // active_ws might have been destroyed by now + // (focus swap away from empty ws = destroy ws) + if (active_ws_child_count == 0) { + active_ws = NULL; + } + + ipc_event_workspace(active_ws, workspace, "focus"); } return true; } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 9dd3e1a5..e161c756 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -43,6 +43,7 @@ void ipc_client_handle_command(struct ipc_client *client); bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); void ipc_get_workspaces_callback(swayc_t *workspace, void *data); void ipc_get_outputs_callback(swayc_t *container, void *data); +json_object *ipc_json_describe_bar_config(struct bar_config *bar); void ipc_init(void) { ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); @@ -290,8 +291,9 @@ void ipc_client_handle_command(struct ipc_client *client) { const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); if (strcmp(event_type, "workspace") == 0) { client->subscribed_events |= IPC_GET_WORKSPACES; - } - else { + } else if (strcmp(event_type, "barconfig_update") == 0) { + client->subscribed_events |= IPC_GET_BAR_CONFIG; + } else { ipc_send_reply(client, "{\"success\": false}", 18); ipc_client_disconnect(client); json_object_put(request); @@ -397,64 +399,7 @@ void ipc_client_handle_command(struct ipc_client *client) { ipc_send_reply(client, error, (uint32_t)strlen(error)); break; } - json_object *json = json_object_new_object(); - json_object_object_add(json, "id", json_object_new_string(bar->id)); - json_object_object_add(json, "tray_output", NULL); - json_object_object_add(json, "mode", json_object_new_string(bar->mode)); - json_object_object_add(json, "hidden_state", json_object_new_string(bar->hidden_state)); - //json_object_object_add(json, "modifier", json_object_new_string(bar->modifier)); // TODO: Fix modifier - switch (bar->position) { - case DESKTOP_SHELL_PANEL_POSITION_TOP: - json_object_object_add(json, "position", json_object_new_string("top")); - break; - case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: - json_object_object_add(json, "position", json_object_new_string("bottom")); - break; - case DESKTOP_SHELL_PANEL_POSITION_LEFT: - json_object_object_add(json, "position", json_object_new_string("left")); - break; - case DESKTOP_SHELL_PANEL_POSITION_RIGHT: - json_object_object_add(json, "position", json_object_new_string("right")); - break; - } - json_object_object_add(json, "status_command", json_object_new_string(bar->status_command)); - json_object_object_add(json, "font", json_object_new_string(bar->font)); - if (bar->separator_symbol) { - json_object_object_add(json, "separator_symbol", json_object_new_string(bar->separator_symbol)); - } - json_object_object_add(json, "bar_height", json_object_new_int(bar->height)); - json_object_object_add(json, "workspace_buttons", json_object_new_boolean(bar->workspace_buttons)); - json_object_object_add(json, "strip_workspace_numbers", json_object_new_boolean(bar->strip_workspace_numbers)); - json_object_object_add(json, "binding_mode_indicator", json_object_new_boolean(bar->binding_mode_indicator)); - json_object_object_add(json, "verbose", json_object_new_boolean(bar->verbose)); - - json_object *colors = json_object_new_object(); - json_object_object_add(colors, "background", json_object_new_string(bar->colors.background)); - json_object_object_add(colors, "statusline", json_object_new_string(bar->colors.statusline)); - json_object_object_add(colors, "separator", json_object_new_string(bar->colors.separator)); - - json_object_object_add(colors, "focused_workspace_border", json_object_new_string(bar->colors.focused_workspace_border)); - json_object_object_add(colors, "focused_workspace_bg", json_object_new_string(bar->colors.focused_workspace_bg)); - json_object_object_add(colors, "focused_workspace_text", json_object_new_string(bar->colors.focused_workspace_text)); - - json_object_object_add(colors, "inactive_workspace_border", json_object_new_string(bar->colors.inactive_workspace_border)); - json_object_object_add(colors, "inactive_workspace_bg", json_object_new_string(bar->colors.inactive_workspace_bg)); - json_object_object_add(colors, "inactive_workspace_text", json_object_new_string(bar->colors.inactive_workspace_text)); - - json_object_object_add(colors, "active_workspace_border", json_object_new_string(bar->colors.active_workspace_border)); - json_object_object_add(colors, "active_workspace_bg", json_object_new_string(bar->colors.active_workspace_bg)); - json_object_object_add(colors, "active_workspace_text", json_object_new_string(bar->colors.active_workspace_text)); - - json_object_object_add(colors, "urgent_workspace_border", json_object_new_string(bar->colors.urgent_workspace_border)); - json_object_object_add(colors, "urgent_workspace_bg", json_object_new_string(bar->colors.urgent_workspace_bg)); - json_object_object_add(colors, "urgent_workspace_text", json_object_new_string(bar->colors.urgent_workspace_text)); - - json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.binding_mode_border)); - json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.binding_mode_bg)); - json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.binding_mode_text)); - - json_object_object_add(json, "colors", colors); - + json_object *json = ipc_json_describe_bar_config(bar); const char *json_string = json_object_to_json_string(json); ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); json_object_put(json); // free @@ -551,22 +496,114 @@ void ipc_get_outputs_callback(swayc_t *container, void *data) { } } -void ipc_event_workspace(swayc_t *old, swayc_t *new) { +json_object *ipc_json_describe_bar_config(struct bar_config *bar) { + if (!sway_assert(bar, "Bar must not be NULL")) { + return NULL; + } + + json_object *json = json_object_new_object(); + json_object_object_add(json, "id", json_object_new_string(bar->id)); + json_object_object_add(json, "tray_output", NULL); + json_object_object_add(json, "mode", json_object_new_string(bar->mode)); + json_object_object_add(json, "hidden_state", json_object_new_string(bar->hidden_state)); + //json_object_object_add(json, "modifier", json_object_new_string(bar->modifier)); // TODO: Fix modifier + switch (bar->position) { + case DESKTOP_SHELL_PANEL_POSITION_TOP: + json_object_object_add(json, "position", json_object_new_string("top")); + break; + case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: + json_object_object_add(json, "position", json_object_new_string("bottom")); + break; + case DESKTOP_SHELL_PANEL_POSITION_LEFT: + json_object_object_add(json, "position", json_object_new_string("left")); + break; + case DESKTOP_SHELL_PANEL_POSITION_RIGHT: + json_object_object_add(json, "position", json_object_new_string("right")); + break; + } + json_object_object_add(json, "status_command", json_object_new_string(bar->status_command)); + json_object_object_add(json, "font", json_object_new_string(bar->font)); + if (bar->separator_symbol) { + json_object_object_add(json, "separator_symbol", json_object_new_string(bar->separator_symbol)); + } + json_object_object_add(json, "bar_height", json_object_new_int(bar->height)); + json_object_object_add(json, "workspace_buttons", json_object_new_boolean(bar->workspace_buttons)); + json_object_object_add(json, "strip_workspace_numbers", json_object_new_boolean(bar->strip_workspace_numbers)); + json_object_object_add(json, "binding_mode_indicator", json_object_new_boolean(bar->binding_mode_indicator)); + json_object_object_add(json, "verbose", json_object_new_boolean(bar->verbose)); + + json_object *colors = json_object_new_object(); + json_object_object_add(colors, "background", json_object_new_string(bar->colors.background)); + json_object_object_add(colors, "statusline", json_object_new_string(bar->colors.statusline)); + json_object_object_add(colors, "separator", json_object_new_string(bar->colors.separator)); + + json_object_object_add(colors, "focused_workspace_border", json_object_new_string(bar->colors.focused_workspace_border)); + json_object_object_add(colors, "focused_workspace_bg", json_object_new_string(bar->colors.focused_workspace_bg)); + json_object_object_add(colors, "focused_workspace_text", json_object_new_string(bar->colors.focused_workspace_text)); + + json_object_object_add(colors, "inactive_workspace_border", json_object_new_string(bar->colors.inactive_workspace_border)); + json_object_object_add(colors, "inactive_workspace_bg", json_object_new_string(bar->colors.inactive_workspace_bg)); + json_object_object_add(colors, "inactive_workspace_text", json_object_new_string(bar->colors.inactive_workspace_text)); + + json_object_object_add(colors, "active_workspace_border", json_object_new_string(bar->colors.active_workspace_border)); + json_object_object_add(colors, "active_workspace_bg", json_object_new_string(bar->colors.active_workspace_bg)); + json_object_object_add(colors, "active_workspace_text", json_object_new_string(bar->colors.active_workspace_text)); + + json_object_object_add(colors, "urgent_workspace_border", json_object_new_string(bar->colors.urgent_workspace_border)); + json_object_object_add(colors, "urgent_workspace_bg", json_object_new_string(bar->colors.urgent_workspace_bg)); + json_object_object_add(colors, "urgent_workspace_text", json_object_new_string(bar->colors.urgent_workspace_text)); + + json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.binding_mode_border)); + json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.binding_mode_bg)); + json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.binding_mode_text)); + + json_object_object_add(json, "colors", colors); + + return json; +} + +void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { json_object *obj = json_object_new_object(); - json_object_object_add(obj, "change", json_object_new_string("focus")); - if (old) { - json_object_object_add(obj, "old", ipc_json_describe_workspace(old)); + json_object_object_add(obj, "change", json_object_new_string(change)); + if (strcmp("focus", change) == 0) { + if (old) { + json_object_object_add(obj, "old", ipc_json_describe_workspace(old)); + } else { + json_object_object_add(obj, "old", NULL); + } + } + + if (new) { + json_object_object_add(obj, "current", ipc_json_describe_workspace(new)); } else { - json_object_object_add(obj, "old", NULL); + json_object_object_add(obj, "current", NULL); } - json_object_object_add(obj, "current", ipc_json_describe_workspace(new)); + const char *json_string = json_object_to_json_string(obj); for (int i = 0; i < ipc_client_list->length; i++) { struct ipc_client *client = ipc_client_list->items[i]; - if ((client->subscribed_events & IPC_GET_WORKSPACES) == 0) break; + if ((client->subscribed_events & IPC_GET_WORKSPACES) == 0) { + continue; + } ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); } json_object_put(obj); // free } + +void ipc_event_barconfig_update(struct bar_config *bar) { + json_object *json = ipc_json_describe_bar_config(bar); + const char *json_string = json_object_to_json_string(json); + int i; + struct ipc_client *client; + for (i = 0; i < ipc_client_list->length; ++i) { + client = ipc_client_list->items[i]; + if ((client->subscribed_events & IPC_GET_BAR_CONFIG) == 0) { + continue; + } + ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); + } + + json_object_put(json); // free +} diff --git a/sway/layout.c b/sway/layout.c index a9e7c7f1..563e9d11 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -10,6 +10,7 @@ #include "workspace.h" #include "focus.h" #include "output.h" +#include "ipc-server.h" swayc_t root_container; list_t *scratchpad; @@ -312,6 +313,12 @@ void move_container_to(swayc_t* container, swayc_t* destination) { // reset container geometry container->width = container->height = 0; add_child(destination, container); + + // If the workspace only has one child after adding one, it + // means that the workspace was just initialized. + if (destination->children->length + destination->floating->length == 1) { + ipc_event_workspace(NULL, destination, "init"); + } } else { // reset container geometry container->width = container->height = 0; diff --git a/swaybar/main.c b/swaybar/main.c index 88cd1dbe..4323d370 100644 --- a/swaybar/main.c +++ b/swaybar/main.c @@ -5,6 +5,7 @@ #include <stdbool.h> #include <unistd.h> #include <sys/select.h> +#include <sys/wait.h> #include <errno.h> #include <json-c/json.h> #include <sys/un.h> @@ -87,7 +88,7 @@ struct colors colors = { }, }; -void sway_terminate(void) { +void swaybar_teardown() { window_teardown(window); if (registry) { registry_teardown(registry); @@ -99,16 +100,31 @@ void sway_terminate(void) { if (pid) { // terminate status_command process - kill(pid, SIGTERM); + int ret = kill(pid, SIGTERM); + if (ret != 0) { + sway_log(L_ERROR, "Unable to terminate status_command [pid: %d]", pid); + } else { + int status; + waitpid(pid, &status, 0); + } } if (pipefd[0]) { close(pipefd[0]); } +} + +void sway_terminate(void) { + swaybar_teardown(); exit(EXIT_FAILURE); } +void sig_handler(int signal) { + swaybar_teardown(); + exit(0); +} + void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { cairo_set_source_rgba(cairo, ((color & 0xFF000000) >> 24) / 256.0, @@ -525,14 +541,12 @@ int main(int argc, char **argv) { line[0] = '\0'; } + signal(SIGTERM, sig_handler); + poll_for_update(); - window_teardown(window); - registry_teardown(registry); - fclose(command); - // terminate status_command process - kill(pid, SIGTERM); - close(pipefd[0]); + // gracefully shutdown swaybar and status_command + swaybar_teardown(); return 0; } |