5 #include <sys/socket.h>
14 typedef void(*handler_t)(char*);
17 * Get a connect to the IPC-interface of i3 and return a filedescriptor
20 int get_ipc_fd(const char *socket_path) {
21 int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
23 printf("ERROR: Could not create Socket!\n");
27 struct sockaddr_un addr;
28 memset(&addr, 0, sizeof(struct sockaddr_un));
29 addr.sun_family = AF_LOCAL;
30 strcpy(addr.sun_path, socket_path);
31 if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) {
32 printf("ERROR: Could not connct to i3\n");
39 * Called, when we get a reply to a command from i3.
40 * Since i3 does not give us much feedback on commands, we do not much
43 void got_command_reply(char *reply) {
44 /* FIXME: Error handling for command-replies */
48 * Called, when we get a reply with workspaces-data
51 void got_workspace_reply(char *reply) {
52 printf("Got Workspace-Data!\n");
53 parse_workspaces_json(reply);
58 * Called, when we get a reply for a subscription.
59 * Since i3 does not give us much feedback on commands, we do not much
62 void got_subscribe_reply(char *reply) {
63 printf("Got Subscribe Reply: %s\n", reply);
64 /* FIXME: Error handling for subscribe-commands */
68 * Called, when we get a reply with outputs-data
71 void got_output_reply(char *reply) {
72 printf("Parsing Outputs-JSON...\n");
73 parse_outputs_json(reply);
74 printf("Reconfiguring Windows...\n");
78 /* Data-structure to easily call the reply-handlers later */
79 handler_t reply_handlers[] = {
87 * Called, when a workspace-event arrives (i.e. the user changed the workspace)
90 void got_workspace_event(char *event) {
91 printf("Got Workspace Event!\n");
92 i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
96 * Called, when an output-event arrives (i.e. the screen-configuration changed)
99 void got_output_event(char *event) {
100 printf("Got Output Event!\n");
101 i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL);
102 i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
105 /* Data-structure to easily call the reply-handlers later */
106 handler_t event_handlers[] = {
107 &got_workspace_event,
112 * Called, when we get a message from i3
115 void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
116 printf("Got data!\n");
117 int fd = watcher->fd;
119 /* First we only read the header, because we know it's length */
120 uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2;
121 char *header = malloc(header_len);
122 if (header == NULL) {
123 printf("ERROR: Could not allocate memory!\n");
128 while (rec < header_len) {
129 int n = read(fd, header + rec, header_len - rec);
131 printf("ERROR: read() failed!\n");
135 printf("ERROR: Nothing to read!\n");
141 if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) {
142 printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n",
143 (int) strlen(I3_IPC_MAGIC),
149 /* Know we read the rest of the message */
150 char *walk = header + strlen(I3_IPC_MAGIC);
151 uint32_t size = *((uint32_t*) walk);
152 walk += sizeof(uint32_t);
153 uint32_t type = *((uint32_t*) walk);
154 char *buffer = malloc(size + 1);
155 if (buffer == NULL) {
156 printf("ERROR: Could not allocate memory!\n");
162 int n = read(fd, buffer + rec, size - rec);
164 printf("ERROR: read() failed!\n");
168 printf("ERROR: Nothing to read!\n");
175 /* And call the callback (indexed by the type) */
176 if (type & (1 << 31)) {
178 event_handlers[type](buffer);
180 reply_handlers[type](buffer);
188 * Sends a Message to i3.
189 * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information)
192 int i3_send_msg(uint32_t type, const char *payload) {
194 if (payload != NULL) {
195 len = strlen(payload);
198 uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len;
199 char *buffer = malloc(to_write);
200 if (buffer == NULL) {
201 printf("ERROR: Could not allocate memory\n");
207 strncpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC));
208 walk += strlen(I3_IPC_MAGIC);
209 memcpy(walk, &len, sizeof(uint32_t));
210 walk += sizeof(uint32_t);
211 memcpy(walk, &type, sizeof(uint32_t));
212 walk += sizeof(uint32_t);
214 strncpy(walk, payload, len);
216 uint32_t written = 0;
218 while (to_write > 0) {
219 int n = write(i3_connection->fd, buffer + written, to_write);
221 printf("ERROR: write() failed!\n");
235 * Initiate a connection to i3.
236 * socket-path must be a valid path to the ipc_socket of i3
239 int init_connection(const char *socket_path) {
240 int sockfd = get_ipc_fd(socket_path);
242 i3_connection = malloc(sizeof(ev_io));
243 ev_io_init(i3_connection, &got_data, sockfd, EV_READ);
244 ev_io_start(main_loop, i3_connection);
250 * Subscribe to all the i3-events, we need
253 void subscribe_events() {
254 i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]");