*
* i3 - an improved dynamic tiling window manager
*
- * © 2009-2010 Michael Stapelberg and contributors
+ * © 2009-2011 Michael Stapelberg and contributors
*
* See file LICENSE for license information.
*
#include <ev.h>
#include <yajl/yajl_gen.h>
#include <yajl/yajl_parse.h>
+#include <yajl/yajl_version.h>
#include "all.h"
+char *current_socketpath = NULL;
+
/* 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))
char msg[buffer_size];
char *walk = msg;
- strcpy(walk, "i3-ipc");
+ strncpy(walk, "i3-ipc", buffer_size - 1);
walk += strlen("i3-ipc");
memcpy(walk, &message_size, sizeof(uint32_t));
walk += sizeof(uint32_t);
char *command = scalloc(message_size + 1);
strncpy(command, (const char*)message, message_size);
LOG("IPC: received: *%s*\n", command);
- const char *reply = parse_cmd((const char*)command);
- tree_render();
+ char *reply = parse_cmd((const char*)command);
+ char *save_reply = reply;
free(command);
/* If no reply was provided, we just use the default success message */
reply = "{\"success\":true}";
ipc_send_message(fd, (const unsigned char*)reply,
I3_IPC_REPLY_TYPE_COMMAND, strlen(reply));
+
+ FREE(save_reply);
+}
+
+static void dump_rect(yajl_gen gen, const char *name, Rect r) {
+ ystr(name);
+ y(map_open);
+ ystr("x");
+ y(integer, r.x);
+ ystr("y");
+ y(integer, r.y);
+ ystr("width");
+ y(integer, r.width);
+ ystr("height");
+ y(integer, r.height);
+ y(map_close);
}
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
y(integer, con->type);
ystr("orientation");
- y(integer, con->orientation);
+ switch (con->orientation) {
+ case NO_ORIENTATION:
+ ystr("none");
+ break;
+ case HORIZ:
+ ystr("horizontal");
+ break;
+ case VERT:
+ ystr("vertical");
+ break;
+ }
+
+ ystr("percent");
+ if (con->percent == 0.0)
+ y(null);
+ else y(double, con->percent);
ystr("urgent");
- y(integer, con->urgent);
+ y(bool, con->urgent);
+
+ if (con->mark != NULL) {
+ ystr("mark");
+ ystr(con->mark);
+ }
ystr("focused");
- y(integer, (con == focused));
+ y(bool, (con == focused));
ystr("layout");
- y(integer, con->layout);
+ switch (con->layout) {
+ case L_DEFAULT:
+ ystr("default");
+ break;
+ case L_STACKED:
+ ystr("stacked");
+ break;
+ case L_TABBED:
+ ystr("tabbed");
+ break;
+ case L_DOCKAREA:
+ ystr("dockarea");
+ break;
+ case L_OUTPUT:
+ ystr("output");
+ break;
+ }
ystr("border");
- y(integer, con->border_style);
+ switch (con->border_style) {
+ case BS_NORMAL:
+ ystr("normal");
+ break;
+ case BS_NONE:
+ ystr("none");
+ break;
+ case BS_1PIXEL:
+ ystr("1pixel");
+ break;
+ }
- ystr("rect");
- y(map_open);
- ystr("x");
- y(integer, con->rect.x);
- ystr("y");
- y(integer, con->rect.y);
- ystr("width");
- y(integer, con->rect.width);
- ystr("height");
- y(integer, con->rect.height);
- y(map_close);
+ dump_rect(gen, "rect", con->rect);
+ dump_rect(gen, "window_rect", con->window_rect);
+ dump_rect(gen, "geometry", con->geometry);
ystr("name");
ystr(con->name);
+ if (con->type == CT_WORKSPACE) {
+ ystr("num");
+ y(integer, con->num);
+ }
+
ystr("window");
if (con->window)
y(integer, con->window->id);
ystr("nodes");
y(array_open);
Con *node;
- TAILQ_FOREACH(node, &(con->nodes_head), nodes) {
- dump_node(gen, node, inplace_restart);
+ if (con->type != CT_DOCKAREA || !inplace_restart) {
+ TAILQ_FOREACH(node, &(con->nodes_head), nodes) {
+ dump_node(gen, node, inplace_restart);
+ }
}
y(array_close);
ystr("fullscreen_mode");
y(integer, con->fullscreen_mode);
+ ystr("swallows");
+ y(array_open);
+ Match *match;
+ TAILQ_FOREACH(match, &(con->swallow_head), matches) {
+ if (match->dock != -1) {
+ y(map_open);
+ ystr("dock");
+ y(integer, match->dock);
+ ystr("insert_where");
+ y(integer, match->insert_where);
+ y(map_close);
+ }
+
+ /* TODO: the other swallow keys */
+ }
+
if (inplace_restart) {
if (con->window != NULL) {
- ystr("swallows");
- y(array_open);
y(map_open);
ystr("id");
y(integer, con->window->id);
y(map_close);
- y(array_close);
}
}
+ y(array_close);
y(map_close);
}
IPC_HANDLER(tree) {
+ setlocale(LC_NUMERIC, "C");
+#if YAJL_MAJOR >= 2
+ yajl_gen gen = yajl_gen_alloc(NULL);
+#else
yajl_gen gen = yajl_gen_alloc(NULL, NULL);
+#endif
dump_node(gen, croot, false);
+ setlocale(LC_NUMERIC, "");
const unsigned char *payload;
+#if YAJL_MAJOR >= 2
+ size_t length;
+#else
unsigned int length;
+#endif
y(get_buf, &payload, &length);
ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_TREE, length);
y(free);
}
+
/*
* Formats the reply message for a GET_WORKSPACES request and sends it to the
* client
*
*/
IPC_HANDLER(get_workspaces) {
+#if YAJL_MAJOR >= 2
+ yajl_gen gen = yajl_gen_alloc(NULL);
+#else
yajl_gen gen = yajl_gen_alloc(NULL, NULL);
+#endif
y(array_open);
Con *focused_ws = con_get_workspace(focused);
Con *output;
TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
Con *ws;
- TAILQ_FOREACH(ws, &(output->nodes_head), nodes) {
+ TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
assert(ws->type == CT_WORKSPACE);
y(map_open);
y(array_close);
const unsigned char *payload;
+#if YAJL_MAJOR >= 2
+ size_t length;
+#else
unsigned int length;
+#endif
y(get_buf, &payload, &length);
ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_WORKSPACES, length);
*
*/
IPC_HANDLER(get_outputs) {
+#if YAJL_MAJOR >= 2
+ yajl_gen gen = yajl_gen_alloc(NULL);
+#else
yajl_gen gen = yajl_gen_alloc(NULL, NULL);
+#endif
y(array_open);
Output *output;
ystr("current_workspace");
Con *ws = NULL;
- if (output->con && (ws = con_get_fullscreen_con(output->con)))
+ if (output->con && (ws = con_get_fullscreen_con(output->con, CF_OUTPUT)))
ystr(ws->name);
else y(null);
y(array_close);
const unsigned char *payload;
+#if YAJL_MAJOR >= 2
+ size_t length;
+#else
unsigned int length;
+#endif
y(get_buf, &payload, &length);
ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_OUTPUTS, length);
y(free);
}
+/*
+ * Formats the reply message for a GET_MARKS request and sends it to the
+ * client
+ *
+ */
+IPC_HANDLER(get_marks) {
+#if YAJL_MAJOR >= 2
+ yajl_gen gen = yajl_gen_alloc(NULL);
+#else
+ yajl_gen gen = yajl_gen_alloc(NULL, NULL);
+#endif
+ y(array_open);
+
+ Con *con;
+ TAILQ_FOREACH(con, &all_cons, all_cons)
+ if (con->mark != NULL)
+ ystr(con->mark);
+
+ y(array_close);
+
+ const unsigned char *payload;
+#if YAJL_MAJOR >= 2
+ size_t length;
+#else
+ unsigned int length;
+#endif
+ y(get_buf, &payload, &length);
+
+ ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_MARKS, length);
+ y(free);
+}
+
/*
* Callback for the YAJL parser (will be called when a string is parsed).
*
*/
+#if YAJL_MAJOR < 2
static int add_subscription(void *extra, const unsigned char *s,
unsigned int len) {
+#else
+static int add_subscription(void *extra, const unsigned char *s,
+ size_t len) {
+#endif
ipc_client *client = extra;
DLOG("should add subscription to extra %p, sub %.*s\n", client, len, s);
memset(&callbacks, 0, sizeof(yajl_callbacks));
callbacks.yajl_string = add_subscription;
+#if YAJL_MAJOR >= 2
+ p = yajl_alloc(&callbacks, NULL, (void*)client);
+#else
p = yajl_alloc(&callbacks, NULL, NULL, (void*)client);
+#endif
stat = yajl_parse(p, (const unsigned char*)message, message_size);
if (stat != yajl_status_ok) {
unsigned char *err;
/* The index of each callback function corresponds to the numeric
* value of the message type (see include/i3/ipc.h) */
-handler_t handlers[5] = {
+handler_t handlers[6] = {
handle_command,
handle_get_workspaces,
handle_subscribe,
handle_get_outputs,
- handle_tree
+ handle_tree,
+ handle_get_marks
};
/*
n -= strlen(I3_IPC_MAGIC);
/* The next 32 bit after the magic are the message size */
- uint32_t message_size = *((uint32_t*)message);
+ uint32_t message_size;
+ memcpy(&message_size, (uint32_t*)message, sizeof(uint32_t));
message += sizeof(uint32_t);
n -= sizeof(uint32_t);
}
/* The last 32 bits of the header are the message type */
- uint32_t message_type = *((uint32_t*)message);
+ uint32_t message_type;
+ memcpy(&message_type, (uint32_t*)message, sizeof(uint32_t));
message += sizeof(uint32_t);
n -= sizeof(uint32_t);
ev_io_init(package, ipc_receive_message, client, EV_READ);
ev_io_start(EV_A_ package);
- DLOG("IPC: new client connected\n");
+ DLOG("IPC: new client connected on fd %d\n", w->fd);
ipc_client *new = scalloc(sizeof(ipc_client));
new->fd = client;
int ipc_create_socket(const char *filename) {
int sockfd;
+ FREE(current_socketpath);
+
char *resolved = resolve_tilde(filename);
DLOG("Creating IPC-socket at %s\n", resolved);
char *copy = sstrdup(resolved);
return -1;
}
- free(resolved);
set_nonblock(sockfd);
if (listen(sockfd, 5) < 0) {
perror("listen()");
+ free(resolved);
return -1;
}
+ current_socketpath = resolved;
return sockfd;
}