diff --git a/common/ipc-client.c b/common/ipc-client.c index e92a09fee..813489135 100644 --- a/common/ipc-client.c +++ b/common/ipc-client.c @@ -10,6 +10,7 @@ #include "stringop.h" #include "ipc.h" #include "readline.h" +#include "ipc-client.h" static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; static const size_t ipc_header_size = sizeof(ipc_magic)+8; @@ -39,7 +40,7 @@ int ipc_open_socket(const char *socket_path) { return socketfd; } -char *ipc_recv_response(int socketfd, uint32_t *len) { +struct ipc_response *ipc_recv_response(int socketfd) { char data[ipc_header_size]; uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); @@ -52,21 +53,29 @@ char *ipc_recv_response(int socketfd, uint32_t *len) { total += received; } + struct ipc_response *response = malloc(sizeof(struct ipc_response)); total = 0; - *len = data32[0]; - char *response = malloc(*len + 1); - while (total < *len) { - ssize_t received = recv(socketfd, response + total, *len - total, 0); + response->size = data32[0]; + response->type = data32[1]; + char *payload = malloc(response->size + 1); + while (total < response->size) { + ssize_t received = recv(socketfd, payload + total, response->size - total, 0); if (received < 0) { sway_abort("Unable to receive IPC response"); } total += received; } - response[*len] = '\0'; + payload[response->size] = '\0'; + response->payload = payload; return response; } +void free_ipc_response(struct ipc_response *response) { + free(response->payload); + free(response); +} + char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len) { char data[ipc_header_size]; uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); @@ -82,5 +91,10 @@ char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint3 sway_abort("Unable to send IPC payload"); } - return ipc_recv_response(socketfd, len); + struct ipc_response *resp = ipc_recv_response(socketfd); + char *response = resp->payload; + *len = resp->size; + free(resp); + + return response; } diff --git a/include/ipc-client.h b/include/ipc-client.h index a4cfd87f6..030c80b67 100644 --- a/include/ipc-client.h +++ b/include/ipc-client.h @@ -3,6 +3,16 @@ #include "ipc.h" +/** + * IPC response including type of IPC response, size of payload and the json + * encoded payload string. + */ +struct ipc_response { + uint32_t size; + uint32_t type; + char *payload; +}; + /** * Gets the path to the IPC socket from sway. */ @@ -17,9 +27,12 @@ int ipc_open_socket(const char *socket_path); */ char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len); /** - * Receives a single IPC resposne and returns the buffer. len will be updated - * with the length of the buffer returned from sway. + * Receives a single IPC response and returns an ipc_response. */ -char *ipc_recv_response(int socketfd, uint32_t *len); +struct ipc_response *ipc_recv_response(int socketfd); +/** + * Free ipc_response struct + */ +void free_ipc_response(struct ipc_response *response); #endif diff --git a/include/ipc.h b/include/ipc.h index 75be58a62..e0b3b7364 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -10,6 +10,13 @@ enum ipc_command_type { IPC_GET_MARKS = 5, IPC_GET_BAR_CONFIG = 6, IPC_GET_VERSION = 7, + // Events send from sway to clients. Events have the higest bit set. + IPC_EVENT_WORKSPACE = (1 << 31 | 0), + IPC_EVENT_OUTPUT = (1 << 31 | 1), + IPC_EVENT_MODE = (1 << 31 | 2), + IPC_EVENT_WINDOW = (1 << 31 | 3), + IPC_EVENT_BARCONFIG_UPDATE = (1 << 31 | 4), + IPC_EVENT_BINDING = (1 << 31 | 5), IPC_SWAY_GET_PIXELS = 0x81 }; diff --git a/sway/ipc-server.c b/sway/ipc-server.c index e161c7567..2bb25202c 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -290,9 +290,9 @@ void ipc_client_handle_command(struct ipc_client *client) { for (int i = 0; i < json_object_array_length(request); i++) { 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; + client->subscribed_events |= IPC_EVENT_WORKSPACE; } else if (strcmp(event_type, "barconfig_update") == 0) { - client->subscribed_events |= IPC_GET_BAR_CONFIG; + client->subscribed_events |= IPC_EVENT_BARCONFIG_UPDATE; } else { ipc_send_reply(client, "{\"success\": false}", 18); ipc_client_disconnect(client); @@ -562,6 +562,19 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { return json; } +void ipc_send_event(const char *json_string, enum ipc_command_type event) { + 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 & event) == 0) { + continue; + } + client->current_command = event; + ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); + } +} + 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(change)); @@ -580,14 +593,7 @@ void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { } 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) { - continue; - } - ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); - } + ipc_send_event(json_string, IPC_EVENT_WORKSPACE); json_object_put(obj); // free } @@ -595,15 +601,7 @@ void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { 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)); - } + ipc_send_event(json_string, IPC_EVENT_BARCONFIG_UPDATE); json_object_put(json); // free } diff --git a/swaybar/main.c b/swaybar/main.c index 3ac337d12..2ee25589f 100644 --- a/swaybar/main.c +++ b/swaybar/main.c @@ -66,7 +66,7 @@ struct status_block { list_t *status_line = NULL; list_t *workspaces = NULL; -int ipc_socketfd, ipc_listen_socketfd; +int ipc_socketfd, ipc_event_socketfd; pid_t pid; int status_read_fd; char line[1024]; @@ -156,8 +156,8 @@ void swaybar_teardown() { close(ipc_socketfd); } - if (ipc_listen_socketfd) { - close(ipc_listen_socketfd); + if (ipc_event_socketfd) { + close(ipc_event_socketfd); } } @@ -408,9 +408,9 @@ void bar_ipc_init(int outputi, const char *bar_id) { json_object_put(bar_config); free(res); - const char *subscribe_json = "[ \"workspace\" ]"; + const char *subscribe_json = "[ \"workspace\", \"mode\" ]"; len = strlen(subscribe_json); - res = ipc_single_command(ipc_listen_socketfd, IPC_SUBSCRIBE, subscribe_json, &len); + res = ipc_single_command(ipc_event_socketfd, IPC_SUBSCRIBE, subscribe_json, &len); free(res); ipc_update_workspaces(); @@ -1049,7 +1049,7 @@ void poll_for_update() { dirty = false; FD_ZERO(&readfds); - FD_SET(ipc_listen_socketfd, &readfds); + FD_SET(ipc_event_socketfd, &readfds); FD_SET(status_read_fd, &readfds); activity = select(FD_SETSIZE, &readfds, NULL, NULL, NULL); @@ -1057,11 +1057,10 @@ void poll_for_update() { sway_log(L_ERROR, "polling failed: %d", errno); } - if (FD_ISSET(ipc_listen_socketfd, &readfds)) { + if (FD_ISSET(ipc_event_socketfd, &readfds)) { sway_log(L_DEBUG, "Got workspace update."); - uint32_t len; - char *buf = ipc_recv_response(ipc_listen_socketfd, &len); - free(buf); + struct ipc_response *resp = ipc_recv_response(ipc_event_socketfd); + free_ipc_response(resp); ipc_update_workspaces(); dirty = true; } @@ -1165,7 +1164,7 @@ int main(int argc, char **argv) { } } ipc_socketfd = ipc_open_socket(socket_path); - ipc_listen_socketfd = ipc_open_socket(socket_path); + ipc_event_socketfd = ipc_open_socket(socket_path); if (argc == optind) {