+
+ y(map_close);
+}
+
+IPC_HANDLER(tree) {
+ printf("tree\n");
+ yajl_gen gen = yajl_gen_alloc(NULL, NULL);
+ dump_node(gen, croot, false);
+
+ const unsigned char *payload;
+ unsigned int length;
+ y(get_buf, &payload, &length);
+
+ ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_TREE, length);
+ y(free);
+
+}
+
+#if 0
+/*
+ * Formats the reply message for a GET_WORKSPACES request and sends it to the
+ * client
+ *
+ */
+IPC_HANDLER(get_workspaces) {
+ Workspace *ws;
+
+ Client *last_focused = SLIST_FIRST(&(c_ws->focus_stack));
+ if (last_focused == SLIST_END(&(c_ws->focus_stack)))
+ last_focused = NULL;
+
+ 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 + 1);
+
+ ystr("name");
+ ystr(ws->utf8_name);
+
+ ystr("visible");
+ y(bool, ws->output->current_workspace == ws);
+
+ ystr("focused");
+ y(bool, c_ws == 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);
+
+ ystr("urgent");
+ y(bool, ws->urgent);
+
+ 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);
+}
+
+/*
+ * Formats the reply message for a GET_OUTPUTS request and sends it to the
+ * client
+ *
+ */
+IPC_HANDLER(get_outputs) {
+ Output *output;
+
+ yajl_gen gen = yajl_gen_alloc(NULL, NULL);
+ y(array_open);
+
+ TAILQ_FOREACH(output, &outputs, outputs) {
+ y(map_open);
+
+ ystr("name");
+ ystr(output->name);
+
+ ystr("active");
+ y(bool, output->active);
+
+ ystr("rect");
+ y(map_open);
+ ystr("x");
+ y(integer, output->rect.x);
+ ystr("y");
+ y(integer, output->rect.y);
+ ystr("width");
+ y(integer, output->rect.width);
+ ystr("height");
+ y(integer, output->rect.height);
+ y(map_close);
+
+ ystr("current_workspace");
+ if (output->current_workspace == NULL)
+ y(null);
+ else y(integer, output->current_workspace->num + 1);
+
+ 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_OUTPUTS, length);
+ y(free);
+}
+
+/*
+ * Callback for the YAJL parser (will be called when a string is parsed).
+ *
+ */
+static int add_subscription(void *extra, const unsigned char *s,
+ unsigned int len) {
+ ipc_client *client = extra;
+
+ DLOG("should add subscription to extra %p, sub %.*s\n", client, len, s);
+ int event = client->num_events;
+
+ client->num_events++;
+ client->events = realloc(client->events, client->num_events * sizeof(char*));
+ /* We copy the string because it is not null-terminated and strndup()
+ * is missing on some BSD systems */
+ client->events[event] = scalloc(len+1);
+ memcpy(client->events[event], s, len);
+
+ DLOG("client is now subscribed to:\n");
+ for (int i = 0; i < client->num_events; i++)
+ DLOG("event %s\n", client->events[i]);
+ DLOG("(done)\n");
+
+ return 1;
+}
+
+/*
+ * Subscribes this connection to the event types which were given as a JSON
+ * serialized array in the payload field of the message.
+ *
+ */
+IPC_HANDLER(subscribe) {
+ yajl_handle p;
+ yajl_callbacks callbacks;
+ yajl_status stat;
+ ipc_client *current, *client = NULL;
+
+ /* Search the ipc_client structure for this connection */
+ TAILQ_FOREACH(current, &all_clients, clients) {
+ if (current->fd != fd)
+ continue;
+
+ client = current;
+ break;
+ }
+
+ if (client == NULL) {
+ ELOG("Could not find ipc_client data structure for fd %d\n", fd);
+ return;
+ }
+
+ /* Setup the JSON parser */
+ memset(&callbacks, 0, sizeof(yajl_callbacks));
+ callbacks.yajl_string = add_subscription;
+
+ p = yajl_alloc(&callbacks, NULL, NULL, (void*)client);
+ stat = yajl_parse(p, (const unsigned char*)message, message_size);
+ if (stat != yajl_status_ok) {
+ unsigned char *err;
+ err = yajl_get_error(p, true, (const unsigned char*)message,
+ message_size);
+ ELOG("YAJL parse error: %s\n", err);
+ yajl_free_error(p, err);
+
+ const char *reply = "{\"success\":false}";
+ ipc_send_message(fd, (const unsigned char*)reply,
+ I3_IPC_REPLY_TYPE_SUBSCRIBE, strlen(reply));
+ yajl_free(p);
+ return;
+ }
+ yajl_free(p);
+ const char *reply = "{\"success\":true}";
+ ipc_send_message(fd, (const unsigned char*)reply,
+ I3_IPC_REPLY_TYPE_SUBSCRIBE, strlen(reply));