*
* i3 - an improved dynamic tiling window manager
*
- * © 2009 Michael Stapelberg and contributors
+ * © 2009-2010 Michael Stapelberg and contributors
*
* See file LICENSE for license information.
*
#include <stdint.h>
#include <stdio.h>
#include <ev.h>
+#include <yajl/yajl_gen.h>
#include "queue.h"
#include "i3/ipc.h"
#include "i3.h"
#include "util.h"
#include "commands.h"
+#include "log.h"
+#include "table.h"
+
+/* Shorter names for all those yajl_gen_* functions */
+#define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__)
+#define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str))
typedef struct ipc_client {
int fd;
}
#endif
+static void ipc_send_message(int fd, const unsigned char *payload,
+ int message_type, int message_size) {
+ int buffer_size = strlen("i3-ipc") + sizeof(uint32_t) +
+ sizeof(uint32_t) + message_size;
+ char msg[buffer_size];
+ char *walk = msg;
+
+ strcpy(walk, "i3-ipc");
+ walk += strlen("i3-ipc");
+ memcpy(walk, &message_size, sizeof(uint32_t));
+ walk += sizeof(uint32_t);
+ memcpy(walk, &message_type, sizeof(uint32_t));
+ walk += sizeof(uint32_t);
+ memcpy(walk, payload, message_size);
+
+ int sent_bytes = 0;
+ int bytes_to_go = buffer_size;
+ while (sent_bytes < bytes_to_go) {
+ int n = write(fd, msg + sent_bytes, bytes_to_go);
+ if (n == -1)
+ err(EXIT_FAILURE, "write() failed");
+
+ sent_bytes += n;
+ bytes_to_go -= n;
+ }
+}
+
+/*
+ * Formats the reply message for a GET_WORKSPACES request and sends it to the
+ * client
+ *
+ */
+static void ipc_send_workspaces(int fd) {
+ Workspace *ws;
+
+ yajl_gen gen = yajl_gen_alloc(NULL, NULL);
+ y(array_open);
+
+ TAILQ_FOREACH(ws, workspaces, workspaces) {
+ if (ws->output == NULL)
+ continue;
+
+ y(map_open);
+ ystr("num");
+ y(integer, ws->num);
+
+ ystr("name");
+ ystr(ws->utf8_name);
+
+ ystr("active");
+ y(bool, ws->output->current_workspace == ws);
+
+ ystr("rect");
+ y(map_open);
+ ystr("x");
+ y(integer, ws->rect.x);
+ ystr("y");
+ y(integer, ws->rect.y);
+ ystr("width");
+ y(integer, ws->rect.width);
+ ystr("height");
+ y(integer, ws->rect.height);
+ y(map_close);
+
+ ystr("output");
+ ystr(ws->output->name);
+
+ y(map_close);
+ }
+
+ y(array_close);
+
+ const unsigned char *payload;
+ unsigned int length;
+ y(get_buf, &payload, &length);
+
+ ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_WORKSPACES, length);
+ y(free);
+}
+
/*
* Decides what to do with the received message.
*
* message_type is the type of the message as the sender specified it.
*
*/
-static void ipc_handle_message(uint8_t *message, int size,
- uint32_t message_size, uint32_t message_type) {
- LOG("handling message of size %d\n", size);
- LOG("sender specified size %d\n", message_size);
- LOG("sender specified type %d\n", message_type);
- LOG("payload as a string = %s\n", message);
+static void ipc_handle_message(int fd, uint8_t *message, int size,
+ uint32_t message_size, uint32_t message_type) {
+ DLOG("handling message of size %d\n", size);
+ DLOG("sender specified size %d\n", message_size);
+ DLOG("sender specified type %d\n", message_type);
+ DLOG("payload as a string = %s\n", message);
switch (message_type) {
case I3_IPC_MESSAGE_TYPE_COMMAND: {
break;
}
+ case I3_IPC_MESSAGE_TYPE_GET_WORKSPACES:
+ ipc_send_workspaces(fd);
+ break;
default:
- LOG("unhandled ipc message\n");
+ DLOG("unhandled ipc message\n");
break;
}
}
ev_io_stop(EV_A_ w);
- LOG("IPC: client disconnected\n");
+ DLOG("IPC: client disconnected\n");
return;
}
/* Check if the message starts with the i3 IPC magic code */
if (n < strlen(I3_IPC_MAGIC)) {
- LOG("IPC: message too short, ignoring\n");
+ DLOG("IPC: message too short, ignoring\n");
return;
}
if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) {
- LOG("IPC: message does not start with the IPC magic\n");
+ DLOG("IPC: message does not start with the IPC magic\n");
return;
}
uint8_t *message = (uint8_t*)buf;
while (n > 0) {
- LOG("IPC: n = %d\n", n);
+ DLOG("IPC: n = %d\n", n);
message += strlen(I3_IPC_MAGIC);
n -= strlen(I3_IPC_MAGIC);
n -= sizeof(uint32_t);
if (message_size > n) {
- LOG("IPC: Either the message size was wrong or the message was not read completely, dropping\n");
+ DLOG("IPC: Either the message size was wrong or the message was not read completely, dropping\n");
return;
}
message += sizeof(uint32_t);
n -= sizeof(uint32_t);
- ipc_handle_message(message, n, message_size, message_type);
+ ipc_handle_message(w->fd, message, n, message_size, message_type);
n -= message_size;
message += message_size;
}
set_nonblock(client);
- struct ev_io *package = calloc(sizeof(struct ev_io), 1);
+ struct ev_io *package = scalloc(sizeof(struct ev_io));
ev_io_init(package, ipc_receive_message, client, EV_READ);
ev_io_start(EV_A_ package);
- LOG("IPC: new client connected\n");
+ DLOG("IPC: new client connected\n");
- struct ipc_client *new = calloc(sizeof(struct ipc_client), 1);
+ struct ipc_client *new = scalloc(sizeof(struct ipc_client));
new->fd = client;
TAILQ_INSERT_TAIL(&all_clients, new, clients);
return -1;
}
+ (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
+
struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_LOCAL;