]> git.sur5r.net Git - i3/i3/blobdiff - src/ipc.c
Merge branch 'colors-userguide' into next
[i3/i3] / src / ipc.c
index b80eae1262c614f2b92140ef3ddb34ea7df32148..577538c20ddf27af6de40bacffb37158f2477e2c 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -3,7 +3,7 @@
  *
  * 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))
@@ -74,7 +77,7 @@ static void ipc_send_message(int fd, const unsigned char *payload,
     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);
@@ -144,8 +147,8 @@ IPC_HANDLER(command) {
     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 */
@@ -153,6 +156,8 @@ IPC_HANDLER(command) {
         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) {
@@ -191,22 +196,56 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     }
 
     ystr("percent");
-    y(double, con->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;
+    }
 
     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);
@@ -224,8 +263,10 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     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);
 
@@ -246,99 +287,124 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     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 *child;
-        TAILQ_FOREACH(child, &(output->nodes_head), nodes) {
-            if (child->type != CT_CON)
-                continue;
+        Con *ws;
+        TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
+            assert(ws->type == CT_WORKSPACE);
+            y(map_open);
+
+            ystr("num");
+            if (ws->num == -1)
+                y(null);
+            else y(integer, ws->num);
+
+            ystr("name");
+            ystr(ws->name);
+
+            ystr("visible");
+            y(bool, workspace_is_visible(ws));
 
-            Con *ws;
-            TAILQ_FOREACH(ws, &(child->nodes_head), nodes) {
-                assert(ws->type == CT_WORKSPACE);
-                y(map_open);
-
-                ystr("num");
-                if (ws->num == -1)
-                    y(null);
-                else y(integer, ws->num);
-
-                ystr("name");
-                ystr(ws->name);
-
-                ystr("visible");
-                y(bool, workspace_is_visible(ws));
-
-                ystr("focused");
-                y(bool, ws == focused_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(output->name);
-
-                ystr("urgent");
-                y(bool, ws->urgent);
-
-                y(map_close);
-            }
+            ystr("focused");
+            y(bool, ws == focused_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(output->name);
+
+            ystr("urgent");
+            y(bool, ws->urgent);
+
+            y(map_close);
         }
     }
 
     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);
@@ -351,7 +417,11 @@ IPC_HANDLER(get_workspaces) {
  *
  */
 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;
@@ -378,7 +448,7 @@ IPC_HANDLER(get_outputs) {
 
         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);
 
@@ -388,19 +458,60 @@ IPC_HANDLER(get_outputs) {
     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);
@@ -450,7 +561,11 @@ IPC_HANDLER(subscribe) {
     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;
@@ -473,12 +588,13 @@ IPC_HANDLER(subscribe) {
 
 /* 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
 };
 
 /*
@@ -550,7 +666,8 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
         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);
 
@@ -560,7 +677,8 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
         }
 
         /* 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);
 
@@ -599,7 +717,7 @@ void ipc_new_client(EV_P_ struct ev_io *w, int revents) {
     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;
@@ -615,6 +733,8 @@ void ipc_new_client(EV_P_ struct ev_io *w, int revents) {
 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);
@@ -644,13 +764,14 @@ int ipc_create_socket(const char *filename) {
         return -1;
     }
 
-    free(resolved);
     set_nonblock(sockfd);
 
     if (listen(sockfd, 5) < 0) {
         perror("listen()");
+        free(resolved);
         return -1;
     }
 
+    current_socketpath = resolved;
     return sockfd;
 }