diff --git a/include/ipc-server.h b/include/ipc-server.h index ab9807efa..049750930 100644 --- a/include/ipc-server.h +++ b/include/ipc-server.h @@ -11,6 +11,10 @@ struct sockaddr_un *ipc_user_sockaddr(void); void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change); void ipc_event_barconfig_update(struct bar_config *bar); +/** + * Send IPC mode event to all listening clients + */ +void ipc_event_mode(const char *mode); const char *swayc_type_string(enum swayc_types type); #endif diff --git a/sway/commands.c b/sway/commands.c index 6c24395f7..38019be5f 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -602,6 +602,10 @@ static struct cmd_results *cmd_mode(int argc, char **argv) { free(mode_name); // Set current mode config->current_mode = mode; + if (!mode_make) { + // trigger IPC mode event + ipc_event_mode(config->current_mode->name); + } return cmd_results_new(mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL); } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 2bb25202c..ed3977d51 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -293,6 +293,8 @@ void ipc_client_handle_command(struct ipc_client *client) { client->subscribed_events |= IPC_EVENT_WORKSPACE; } else if (strcmp(event_type, "barconfig_update") == 0) { client->subscribed_events |= IPC_EVENT_BARCONFIG_UPDATE; + } else if (strcmp(event_type, "mode") == 0) { + client->subscribed_events |= IPC_EVENT_MODE; } else { ipc_send_reply(client, "{\"success\": false}", 18); ipc_client_disconnect(client); @@ -605,3 +607,13 @@ void ipc_event_barconfig_update(struct bar_config *bar) { json_object_put(json); // free } + +void ipc_event_mode(const char *mode) { + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string(mode)); + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_MODE); + + json_object_put(obj); // free +} diff --git a/swaybar/main.c b/swaybar/main.c index 2ee25589f..18283afa8 100644 --- a/swaybar/main.c +++ b/swaybar/main.c @@ -76,6 +76,8 @@ struct registry *registry; struct window *window; bool dirty = true; char *separator_symbol = NULL; +char *mode = NULL; +bool binding_mode_indicator = true; bool strip_workspace_numbers = false; typedef enum {UNDEF, TEXT, I3BAR} command_protocol; command_protocol protocol = UNDEF; @@ -291,7 +293,7 @@ void bar_ipc_init(int outputi, const char *bar_id) { json_object *bar_config = json_tokener_parse(res); json_object *tray_output, *mode, *hidden_state, *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; 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_state", &hidden_state); @@ -301,7 +303,7 @@ void bar_ipc_init(int outputi, const char *bar_id) { json_object_object_get_ex(bar_config, "bar_height", &bar_height); json_object_object_get_ex(bar_config, "workspace_buttons", &workspace_buttons); json_object_object_get_ex(bar_config, "strip_workspace_numbers", &_strip_workspace_numbers); - json_object_object_get_ex(bar_config, "binding_mode_indicator", &binding_mode_indicator); + json_object_object_get_ex(bar_config, "binding_mode_indicator", &_binding_mode_indicator); 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); @@ -328,6 +330,10 @@ void bar_ipc_init(int outputi, const char *bar_id) { strip_workspace_numbers = json_object_get_boolean(_strip_workspace_numbers); } + if (_binding_mode_indicator) { + binding_mode_indicator = json_object_get_boolean(_binding_mode_indicator); + } + if (bar_height) { int width, height; get_text_size(window, &width, &height, "Test string for measuring purposes"); @@ -635,6 +641,28 @@ void render_workspace_button(struct workspace *ws, double *x) { free(name); } +void render_binding_mode_indicator(double pos) { + int width, height; + get_text_size(window, &width, &height, "%s", mode); + + // background + cairo_set_source_u32(window->cairo, colors.binding_mode.background); + cairo_rectangle(window->cairo, pos, 1.5, width + ws_hor_padding * 2 - 1, + height + ws_ver_padding * 2); + cairo_fill(window->cairo); + + // border + cairo_set_source_u32(window->cairo, colors.binding_mode.border); + cairo_rectangle(window->cairo, pos, 1.5, width + ws_hor_padding * 2 - 1, + height + ws_ver_padding * 2); + cairo_stroke(window->cairo); + + // text + cairo_set_source_u32(window->cairo, colors.binding_mode.text); + cairo_move_to(window->cairo, (int)pos + ws_hor_padding, margin); + pango_printf(window, "%s", mode); +} + void render() { int i; @@ -675,6 +703,11 @@ void render() { struct workspace *ws = workspaces->items[i]; render_workspace_button(ws, &x); } + + // binding mode indicator + if (mode && binding_mode_indicator) { + render_binding_mode_indicator(x); + } } void free_status_block(void *item) { @@ -1034,6 +1067,45 @@ int i3json_handle_fd(int fd) { return i3json_parse(); } +bool handle_ipc_event() { + struct ipc_response *resp = ipc_recv_response(ipc_event_socketfd); + switch (resp->type) { + case IPC_EVENT_WORKSPACE: + ipc_update_workspaces(); + break; + case IPC_EVENT_MODE: { + json_object *result = json_tokener_parse(resp->payload); + if (!result) { + free_ipc_response(resp); + sway_log(L_ERROR, "failed to parse payload as json"); + return false; + } + json_object *json_change; + if (json_object_object_get_ex(result, "change", &json_change)) { + const char *change = json_object_get_string(json_change); + + free(mode); + if (strcmp(change, "default") == 0) { + mode = NULL; + } else { + mode = strdup(change); + } + } else { + sway_log(L_ERROR, "failed to parse response"); + } + + json_object_put(result); + break; + } + default: + free_ipc_response(resp); + return false; + } + + free_ipc_response(resp); + return true; +} + void poll_for_update() { fd_set readfds; int activity; @@ -1058,11 +1130,8 @@ void poll_for_update() { } if (FD_ISSET(ipc_event_socketfd, &readfds)) { - sway_log(L_DEBUG, "Got workspace update."); - struct ipc_response *resp = ipc_recv_response(ipc_event_socketfd); - free_ipc_response(resp); - ipc_update_workspaces(); - dirty = true; + sway_log(L_DEBUG, "Got IPC event."); + dirty = handle_ipc_event(); } if (status_command && FD_ISSET(status_read_fd, &readfds)) {