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