]> git.sur5r.net Git - i3/i3/blob - i3bar/src/ipc.c
Refresh the workspace-list on output-events
[i3/i3] / i3bar / src / ipc.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <stdint.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7 #include <i3/ipc.h>
8 #include <ev.h>
9
10 #include "common.h"
11
12 ev_io *i3_connection;
13
14 typedef void(*handler_t)(char*);
15
16 int get_ipc_fd(const char *socket_path) {
17     int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
18     if (sockfd == -1) {
19         printf("ERROR: Could not create Socket!\n");
20         exit(EXIT_FAILURE);
21     }
22
23     struct sockaddr_un addr;
24     memset(&addr, 0, sizeof(struct sockaddr_un));
25     addr.sun_family = AF_LOCAL;
26     strcpy(addr.sun_path, socket_path);
27     if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) {
28         printf("ERROR: Could not connct to i3\n");
29         exit(EXIT_FAILURE);
30     }
31     return sockfd;
32 }
33
34 void got_command_reply(char *reply) {
35     /* FIXME: Error handling for command-replies */
36 }
37
38 void got_workspace_reply(char *reply) {
39     printf("Got Workspace-Data!\n");
40     parse_workspaces_json(reply);
41     draw_bars();
42 }
43
44 void got_subscribe_reply(char *reply) {
45     printf("Got Subscribe Reply: %s\n", reply);
46     /* FIXME: Error handling for subscribe-commands */
47 }
48
49 void got_output_reply(char *reply) {
50     printf("Parsing Outputs-JSON...\n");
51     parse_outputs_json(reply);
52     printf("Reconfiguring Windows...\n");
53     reconfig_windows();
54 }
55
56 handler_t reply_handlers[] = {
57     &got_command_reply,
58     &got_workspace_reply,
59     &got_subscribe_reply,
60     &got_output_reply,
61 };
62
63 void got_workspace_event(char *event) {
64     printf("Got Workspace Event!\n");
65     i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
66 }
67
68 void got_output_event(char *event) {
69     printf("Got Output Event!\n");
70     i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL);
71     i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
72 }
73
74 handler_t event_handlers[] = {
75     &got_workspace_event,
76     &got_output_event
77 };
78
79 void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
80     printf("Got data!\n");
81     int fd = watcher->fd;
82     uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2;
83     char *header = malloc(header_len);
84     if (header == NULL) {
85         printf("ERROR: Could not allocate memory!\n");
86         exit(EXIT_FAILURE);
87     }
88
89     uint32_t rec = 0;
90     while (rec < header_len) {
91         int n = read(fd, header + rec, header_len - rec);
92         if (n == -1) {
93             printf("ERROR: read() failed!\n");
94             exit(EXIT_FAILURE);
95         }
96         if (n == 0) {
97             printf("ERROR: Nothing to read!\n");
98             exit(EXIT_FAILURE);
99         }
100         rec += n;
101     }
102
103     if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) {
104         printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n",
105                (int) strlen(I3_IPC_MAGIC),
106                header,
107                I3_IPC_MAGIC);
108         exit(EXIT_FAILURE);
109     }
110
111     char *walk = header + strlen(I3_IPC_MAGIC);
112     uint32_t size = *((uint32_t*) walk);
113     walk += sizeof(uint32_t);
114     uint32_t type = *((uint32_t*) walk);
115     char *buffer = malloc(size + 1);
116     if (buffer == NULL) {
117         printf("ERROR: Could not allocate memory!\n");
118         exit(EXIT_FAILURE);
119     }
120     rec = 0;
121
122     while (rec < size) {
123         int n = read(fd, buffer + rec, size - rec);
124         if (n == -1) {
125             printf("ERROR: read() failed!\n");
126             exit(EXIT_FAILURE);
127         }
128         if (n == 0) {
129             printf("ERROR: Nothing to read!\n");
130             exit(EXIT_FAILURE);
131         }
132         rec += n;
133     }
134     buffer[size] = '\0';
135
136     if (type & (1 << 31)) {
137         type ^= 1 << 31;
138         event_handlers[type](buffer);
139     } else {
140         reply_handlers[type](buffer);
141     }
142
143     FREE(header);
144     FREE(buffer);
145 }
146
147 int i3_send_msg(uint32_t type, const char *payload) {
148     uint32_t len = 0;
149     if (payload != NULL) {
150         len = strlen(payload);
151     }
152
153     uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len;
154     char *buffer = malloc(to_write);
155     if (buffer == NULL) {
156         printf("ERROR: Could not allocate memory\n");
157         exit(EXIT_FAILURE);
158     }
159
160     char *walk = buffer;
161
162     strncpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC));
163     walk += strlen(I3_IPC_MAGIC);
164     memcpy(walk, &len, sizeof(uint32_t));
165     walk += sizeof(uint32_t);
166     memcpy(walk, &type, sizeof(uint32_t));
167     walk += sizeof(uint32_t);
168
169     strncpy(walk, payload, len);
170
171     uint32_t written = 0;
172
173     while (to_write > 0) {
174         int n = write(i3_connection->fd, buffer + written, to_write);
175         if (n == -1) {
176             printf("ERROR: write() failed!\n");
177             exit(EXIT_FAILURE);
178         }
179
180         to_write -= n;
181         written += n;
182     }
183
184     FREE(buffer);
185
186     return 1;
187 }
188
189 int init_connection(const char *socket_path) {
190     int sockfd = get_ipc_fd(socket_path);
191
192     i3_connection = malloc(sizeof(ev_io));
193     ev_io_init(i3_connection, &got_data, sockfd, EV_READ);
194     ev_io_start(main_loop, i3_connection);
195
196     return 1;
197 }
198
199 void subscribe_events() {
200     i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]");
201 }