]> git.sur5r.net Git - i3/i3/blob - i3bar/src/ipc.c
Get outputs on start. Create dock window for every output.
[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 }
39
40 void got_workspace_reply(char *reply) {
41         printf("Got Workspace-Data!\n");
42         parse_workspaces_json(reply);
43 }
44
45 void got_subscribe_reply(char *reply) {
46         printf("Got Subscribe Reply: %s\n", reply);
47 }
48
49 void got_output_reply(char *reply) {
50         printf("Got Outputs-Data!\nDestroying Windows...\n");
51         destroy_windows();
52         printf("Parsing JSON...\n");
53         parse_outputs_json(reply);
54         printf("Creating_Windows,,,\n");
55         create_windows();
56 }
57
58 handler_t reply_handlers[] = {
59         &got_command_reply,
60         &got_workspace_reply,
61         &got_subscribe_reply,
62         &got_output_reply,
63 };
64
65 void got_workspace_event(char *event) {
66         printf("Got Workspace Event!\n");
67         i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
68 }
69
70 void got_output_event(char *event) {
71         printf("Got Output Event!\n");
72         i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL);
73 }
74
75 handler_t event_handlers[] = {
76         &got_workspace_event,
77         &got_output_event
78 };
79
80 void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
81         printf("Got data!\n");
82         int fd = watcher->fd;
83         uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2;
84         char *header = malloc(header_len);
85         if (header == NULL) {
86                 printf("ERROR: Could not allocate memory!\n");
87                 exit(EXIT_FAILURE);
88         }
89
90         uint32_t rec = 0;
91         while (rec < header_len) {
92                 int n = read(fd, header + rec, header_len - rec);
93                 if (n == -1) {
94                         printf("ERROR: read() failed!\n");
95                         exit(EXIT_FAILURE);
96                 }
97                 if (n == 0) {
98                         printf("ERROR: Nothing to read!\n");
99                         exit(EXIT_FAILURE);
100                 }
101                 rec += n;
102         }
103         
104         if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) {
105                 printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n",
106                        (int) strlen(I3_IPC_MAGIC),
107                        header,
108                        I3_IPC_MAGIC);
109                 exit(EXIT_FAILURE);
110         }
111
112         char *walk = header + strlen(I3_IPC_MAGIC);
113         uint32_t size = *((uint32_t*) walk);
114         walk += sizeof(uint32_t);
115         uint32_t type = *((uint32_t*) walk);
116         char *buffer = malloc(size + 1);
117         if (buffer == NULL) {
118                 printf("ERROR: Could not allocate memory!\n");
119                 exit(EXIT_FAILURE);
120         }
121         rec = 0;
122
123         while (rec < size) {
124                 int n = read(fd, buffer + rec, size - rec);
125                 if (n == -1) {
126                         printf("ERROR: read() failed!\n");
127                         exit(EXIT_FAILURE);
128                 }
129                 if (n == 0) {
130                         printf("ERROR: Nothing to read!\n");
131                         exit(EXIT_FAILURE);
132                 }
133                 rec += n;
134         }
135         buffer[size] = '\0';
136         
137         if (type & (1 << 31)) {
138                 type ^= 1 << 31;
139                 event_handlers[type](buffer);
140         } else {
141                 reply_handlers[type](buffer);
142         }
143
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 }