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