From fb2afacce3fb5b805ce8e32e91edfd29ec3c84ca Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 23 Jul 2010 04:43:43 +0200 Subject: [PATCH] Rework the IPC-Code --- i3bar/include/ipc.h | 11 +- i3bar/include/outputs.h | 2 +- i3bar/include/workspaces.h | 2 +- i3bar/src/ipc.c | 354 +++++++++++++------------------------ i3bar/src/main.c | 15 +- i3bar/src/outputs.c | 39 ++-- i3bar/src/workspaces.c | 33 ++-- 7 files changed, 158 insertions(+), 298 deletions(-) diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index 45565618..278077e0 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -2,13 +2,10 @@ #define IPC_H_ #include +#include -ev_io* i3_events; -ev_io* outputs_watcher; -ev_io* workspaces_watcher; - -void init_i3(const char* socket_path); -void get_outputs_json(void (*callback)(char*, void*), void* params); -void get_workspaces_json(void (*callback)(char*, void*), void* params); +int init_connection(const char *socket_path); +int i3_send_msg(uint32_t type, const char* payload); +void subscribe_events(); #endif diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 83364c2f..0c241527 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -8,7 +8,7 @@ typedef struct i3_output_t i3_output; i3_output* outputs; -void refresh_outputs(); +void parse_outputs_json(char* json); void free_outputs(); i3_output* get_output_by_name(char* name); diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index ad6ac787..339b8890 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -8,7 +8,7 @@ typedef struct i3_ws_t i3_ws; i3_ws* workspaces; -void refresh_workspaces(); +void parse_workspaces_json(); void free_workspaces(); struct i3_ws_t { diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 35d3d5be..b753c088 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -1,24 +1,19 @@ +#include #include -#include +#include +#include #include #include -#include -#include -#include -#include #include #include "common.h" +#include "outputs.h" +#include "workspaces.h" #include "ipc.h" -struct callback_t { - void (*callback)(char*, void*); - void* params; - struct callback_t* next; -}; +ev_io* i3_connection; -struct callback_t* outputs_cb_queue; -struct callback_t* workspaces_cb_queue; +typedef void(*handler_t)(char*); int get_ipc_fd(const char* socket_path) { int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); @@ -38,271 +33,164 @@ int get_ipc_fd(const char* socket_path) { return sockfd; } -void get_outputs_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - +void got_command_reply(char *reply) { } -void init_i3(const char* socket_path) { - int sockfd = get_ipc_fd(socket_path); - - struct get_outputs_callback* cb = malloc(sizeof(struct get_outputs_callback)); - cb->callback = callback; - cb->params = params; - - ev_io* get_outputs_write = malloc(sizeof(ev_io)); - - ev_io_init(get_outputs_write, &get_outputs_write_cb, sockfd, EV_WRITE); - get_outputs_write->data = (void*) cb; - ev_io_start(main_loop, get_outputs_write); - - ev_io* get_outputs_read = malloc(sizeof(ev_io)); - ev_io_init(get_outputs_read, &get_outputs_read_cb, sockfd, EV_READ); - get_outputs_read->data = (void*) cb; - ev_io_start(main_loop, get_outputs_read); +void got_workspace_reply(char *reply) { + printf("Got Workspace-Data!\n"); + parse_workspaces_json(reply); } - -void get_outputs_write_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - ev_io_stop(loop, watcher); - - int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[buffer_size]; - char *walk = msg; - uint32_t msg_size = 0; - uint32_t msg_type = I3_IPC_MESSAGE_TYPE_GET_OUTPUTS; - int sockfd = watcher->fd; - - strcpy(walk, I3_IPC_MAGIC); - walk += strlen(I3_IPC_MAGIC); - memcpy(walk, &msg_size, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, &msg_type, sizeof(uint32_t)); - - int sent_bytes = 0; - int bytes_to_go = buffer_size; - while (sent_bytes < bytes_to_go) { - int n = write(sockfd, msg + sent_bytes, bytes_to_go); - if (n == -1) { - printf("ERROR: write() failed!\n"); - exit(EXIT_FAILURE); - } - - sent_bytes += n; - bytes_to_go -= n; - } - FREE(watcher); +void got_subscribe_reply(char *reply) { + printf("Got Subscribe Reply: %s\n", reply); } -void get_outputs_read_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - ev_io_stop(loop, watcher); - - int to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[to_read]; - char *walk = msg; - int sockfd = watcher->fd; - uint8_t *reply; - struct get_outputs_callback* cb = watcher->data; - - uint32_t reply_length; - - uint32_t read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, msg + read_bytes, to_read); - if (n == -1) { - printf("ERROR: read() failed!\n"); - exit(EXIT_FAILURE); - } - if (n == 0) { - printf("ERROR: No reply!\n"); - exit(EXIT_FAILURE); - } - - read_bytes += n; - to_read -= n; - } - - if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { - printf("ERROR: Wrong magic!\n"); - exit(EXIT_FAILURE); - } - - walk += strlen(I3_IPC_MAGIC); - reply_length = *((uint32_t*) walk); - walk += sizeof(uint32_t); - if (*((uint32_t*) walk) != I3_IPC_MESSAGE_TYPE_GET_OUTPUTS) { - printf("ERROR: Wrong reply type (%d) expected %d!\n", - *((uint32_t*) walk), - I3_IPC_MESSAGE_TYPE_GET_OUTPUTS); - exit(EXIT_FAILURE); - } - walk += sizeof(uint32_t); - - reply = malloc(reply_length); - if (reply == NULL) { - printf("ERROR: malloc() failed!\n"); - exit(EXIT_FAILURE); - } - - to_read = reply_length; - read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, reply + read_bytes, to_read); - if (n == -1) { - printf("ERROR: read() failed!\n"); - exit(EXIT_FAILURE); - } - - read_bytes += n; - to_read -= n; - } - - cb->callback((char*) reply, cb->params); - FREE(cb); - FREE(watcher); +void got_output_reply(char *reply) { + parse_outputs_json(reply); + printf("Got Outputs-Data!\n"); } -void get_outputs_json(void (*callback)(char*, void*), void* params) { -} - - - -struct get_workspaces_callback { - void (*callback)(char*, void*); - void* params; +handler_t reply_handlers[] = { + &got_command_reply, + &got_workspace_reply, + &got_subscribe_reply, + &got_output_reply, }; -void get_workspaces_write_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - ev_io_stop(loop, watcher); - //FREE(watcher); - - int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[buffer_size]; - char *walk = msg; - uint32_t msg_size = 0; - uint32_t msg_type = I3_IPC_MESSAGE_TYPE_GET_WORKSPACES; - int sockfd = watcher->fd; - - strcpy(walk, I3_IPC_MAGIC); - walk += strlen(I3_IPC_MAGIC); - memcpy(walk, &msg_size, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, &msg_type, sizeof(uint32_t)); - - int sent_bytes = 0; - int bytes_to_go = buffer_size; - while (sent_bytes < bytes_to_go) { - int n = write(sockfd, msg + sent_bytes, bytes_to_go); - if (n == -1) { - printf("ERROR: write() failed!\n"); - exit(EXIT_FAILURE); - } - - sent_bytes += n; - bytes_to_go -= n; - } - FREE(watcher); +void got_workspace_event(char *event) { + printf("Got Workspace Event!\n"); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } -void get_workspaces_read_cb(struct ev_loop* loop, ev_io *watcher, int revents) { - ev_io_stop(loop, watcher); - //FREE(watcher); +void got_output_event(char *event) { + printf("Got Output Event!\n"); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); +} - int to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[to_read]; - char *walk = msg; - int sockfd = watcher->fd; - uint8_t *reply; - struct get_workspaces_callback* cb = watcher->data; +handler_t event_handlers[] = { + &got_workspace_event, + &got_output_event +}; - uint32_t reply_length; +void got_data(struct ev_loop *loop, ev_io *watcher, int events) { + printf("Got data!\n"); + int fd = watcher->fd; + uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; + char *header = malloc(header_len); + if (header == NULL) { + printf("ERROR: Could not allocate memory!\n"); + exit(EXIT_FAILURE); + } - uint32_t read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, msg + read_bytes, to_read); + uint32_t rec = 0; + while (rec < header_len) { + int n = read(fd, header + rec, header_len - rec); if (n == -1) { printf("ERROR: read() failed!\n"); exit(EXIT_FAILURE); } if (n == 0) { - printf("ERROR: No reply!\n"); + printf("ERROR: Nothing to read!\n"); exit(EXIT_FAILURE); } - - read_bytes += n; - to_read -= n; + rec += n; } - - if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { - printf("ERROR: Wrong magic!\n"); + + if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) { + printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n", + (int) strlen(I3_IPC_MAGIC), + header, + I3_IPC_MAGIC); exit(EXIT_FAILURE); } - walk += strlen(I3_IPC_MAGIC); - reply_length = *((uint32_t*) walk); + char *walk = header + strlen(I3_IPC_MAGIC); + uint32_t size = *((uint32_t*) walk); walk += sizeof(uint32_t); - if (*((uint32_t*) walk) != I3_IPC_MESSAGE_TYPE_GET_WORKSPACES) { - printf("ERROR: Wrong reply type (%d) expected %d!\n", - *((uint32_t*) walk), - I3_IPC_MESSAGE_TYPE_GET_WORKSPACES); + uint32_t type = *((uint32_t*) walk); + char *buffer = malloc(size + 1); + if (buffer == NULL) { + printf("ERROR: Could not allocate memory!\n"); exit(EXIT_FAILURE); } - walk += sizeof(uint32_t); + rec = 0; - reply = malloc(reply_length); - if (reply == NULL) { - printf("ERROR: malloc() failed!\n"); - exit(EXIT_FAILURE); - } - - to_read = reply_length; - read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, reply + read_bytes, to_read); + while (rec < size) { + int n = read(fd, buffer + rec, size - rec); if (n == -1) { printf("ERROR: read() failed!\n"); exit(EXIT_FAILURE); } - - read_bytes += n; - to_read -= n; + if (n == 0) { + printf("ERROR: Nothing to read!\n"); + exit(EXIT_FAILURE); + } + rec += n; } + buffer[size] = '\0'; - cb->callback((char*) reply, cb->params); - FREE(cb); + if (type & (1 << 31)) { + type ^= 1 << 31; + event_handlers[type](buffer); + } else { + reply_handlers[type](buffer); + } - FREE(watcher); + FREE(buffer); } -void get_workspaces_json(void (*callback)(char*, void*), void* params) { - socket_path = "/home/mero/.i3/ipc.sock"; +int i3_send_msg(uint32_t type, const char* payload) { + uint32_t len = 0; + if (payload != NULL) { + len = strlen(payload); + } - int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (sockfd == -1) { - printf("ERROR: Could not create Socket!\n"); + uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len; + char *buffer = malloc(to_write); + if (buffer == NULL) { + printf("ERROR: Could not allocate memory\n"); exit(EXIT_FAILURE); } - struct sockaddr_un addr; - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_LOCAL; - strcpy(addr.sun_path, socket_path); - if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - printf("ERROR: Could not connct to i3\n"); - exit(EXIT_FAILURE); + char *walk = buffer; + + strncpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)); + walk += strlen(I3_IPC_MAGIC); + memcpy(walk, &len, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, &type, sizeof(uint32_t)); + walk += sizeof(uint32_t); + + strncpy(walk, payload, len); + + uint32_t written = 0; + + while (to_write > 0) { + int n = write(i3_connection->fd, buffer + written, to_write); + if (n == -1) { + printf("ERROR: write() failed!\n"); + exit(EXIT_FAILURE); + } + + to_write -= n; + written += n; } - struct get_workspaces_callback* cb = malloc(sizeof(struct get_workspaces_callback)); - cb->callback = callback; - cb->params = params; + FREE(buffer); - ev_io* get_workspaces_write = malloc(sizeof(ev_io)); - - ev_io_init(get_workspaces_write, &get_workspaces_write_cb, sockfd, EV_WRITE); - get_workspaces_write->data = (void*) cb; - ev_io_start(main_loop, get_workspaces_write); - - ev_io* get_workspaces_read = malloc(sizeof(ev_io)); - ev_io_init(get_workspaces_read, &get_workspaces_read_cb, sockfd, EV_READ); - get_workspaces_read->data = (void*) cb; - ev_io_start(main_loop, get_workspaces_read); + return 1; +} + +int init_connection(const char *socket_path) { + int sockfd = get_ipc_fd(socket_path); + + i3_connection = malloc(sizeof(ev_io)); + ev_io_init(i3_connection, &got_data, sockfd, EV_READ); + ev_io_start(main_loop, i3_connection); + + return 1; +} + +void subscribe_events() { + i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]"); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 90a48ee2..dbb6104c 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -1,21 +1,21 @@ +#include +#include +#include +#include + #include "ipc.h" #include "outputs.h" #include "workspaces.h" #include "common.h" #include "xcb.h" -#include -#include -#include -#include - int main(int argc, char **argv) { main_loop = ev_default_loop(0); init_xcb(); + init_connection("/home/mero/.i3/ipc.sock"); - refresh_outputs(&create_windows, NULL); - refresh_workspaces(NULL, NULL); + subscribe_events(); ev_loop(main_loop, 0); @@ -24,6 +24,5 @@ int main(int argc, char **argv) { free_outputs(); free_workspaces(); - //sleep(5); return 0; } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 2b2600b5..6ddfa8c9 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -13,8 +14,6 @@ struct outputs_json_params { i3_output* outputs_walk; char* cur_key; char* json; - void (*callback)(void*); - void* cb_params; }; static int outputs_null_cb(void* params_) { @@ -144,18 +143,20 @@ yajl_callbacks outputs_callbacks = { NULL }; -void got_outputs_json_cb(char* json, void* params_) { +void parse_outputs_json(char* json) { /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret * JSON in chunks */ - struct outputs_json_params* params = (struct outputs_json_params*) params_; + struct outputs_json_params params; + params.outputs = NULL; + params.outputs_walk = NULL; + params.cur_key = NULL; + params.json = json; yajl_handle handle; yajl_parser_config parse_conf = { 0, 0 }; yajl_status state; - params->json = json; - - handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) params); + handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) ¶ms); state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); @@ -174,27 +175,7 @@ void got_outputs_json_cb(char* json, void* params_) { yajl_free(handle); free_outputs(); - outputs = params->outputs; - - if (params->callback != NULL) { - params->callback(params->cb_params); - } - - FREE(params->json); - FREE(params); -} - -void refresh_outputs(void (*callback)(void*), void* cb_params) { - struct outputs_json_params* params = malloc(sizeof(struct outputs_json_params)); - - params->outputs = NULL; - params->outputs_walk = NULL; - params->cur_key = NULL; - params->json = NULL; - params->callback = callback; - params->cb_params = cb_params; - - get_outputs_json(&got_outputs_json_cb, params); + outputs = params.outputs; } void free_outputs() { @@ -209,7 +190,7 @@ void free_outputs() { i3_output* get_output_by_name(char* name) { if (outputs == NULL) { - refresh_outputs(NULL, NULL); + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); return NULL; } diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 15927631..aa97bccc 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -91,6 +91,7 @@ static int workspaces_integer_cb(void* params_, long val) { } static int workspaces_string_cb(void* params_, const unsigned char* val, unsigned int len) { + struct workspaces_json_params* params = (struct workspaces_json_params*) params_; char* output_name; @@ -151,6 +152,10 @@ static int workspaces_map_key_cb(void* params_, const unsigned char* keyVal, uns FREE(params->cur_key); params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + if (params->cur_key == NULL) { + printf("ERROR: Could not allocate memory!\n"); + exit(EXIT_FAILURE); + } strncpy(params->cur_key, (const char*) keyVal, keyLen); params->cur_key[keyLen] = '\0'; @@ -171,18 +176,20 @@ yajl_callbacks workspaces_callbacks = { NULL }; -void got_workspaces_json_cb(char* json, void* params_) { +void parse_workspaces_json(char* json) { /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret * JSON in chunks */ - struct workspaces_json_params* params = (struct workspaces_json_params*) params_; + struct workspaces_json_params params; + params.workspaces = NULL; + params.workspaces_walk = NULL; + params.cur_key = NULL; + params.json = json; yajl_handle handle; yajl_parser_config parse_conf = { 0, 0 }; yajl_status state; - params->json = json; - - handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) params); + handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) ¶ms); state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); @@ -201,21 +208,9 @@ void got_workspaces_json_cb(char* json, void* params_) { yajl_free(handle); free_workspaces(); - workspaces = params->workspaces; + workspaces = params.workspaces; - FREE(params->json); - FREE(params); -} - -void refresh_workspaces() { - struct workspaces_json_params* params = malloc(sizeof(struct workspaces_json_params)); - - params->workspaces = NULL; - params->workspaces_walk = NULL; - params->cur_key = NULL; - params->json = NULL; - - get_workspaces_json(&got_workspaces_json_cb, params); + FREE(params.cur_key); } void free_workspaces() {