]> git.sur5r.net Git - i3/i3/blobdiff - src/ipc.c
ipc: dump window properties when not restarting inplace
[i3/i3] / src / ipc.c
index 84ef2c36289adc63736c74583d4b0bd49e6cbcaf..ab12dcb0a88befa7bffbec21d79b9425e3121fec 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -10,6 +10,7 @@
  *
  */
 #include "all.h"
+#include "yajl_utils.h"
 
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <ev.h>
 #include <yajl/yajl_gen.h>
 #include <yajl/yajl_parse.h>
-#include <yajl/yajl_version.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))
-
 TAILQ_HEAD(ipc_client_head, ipc_client) all_clients = TAILQ_HEAD_INITIALIZER(all_clients);
 
 /*
@@ -128,11 +124,7 @@ IPC_HANDLER(command) {
         tree_render();
 
     const unsigned char *reply;
-#if YAJL_MAJOR >= 2
-    size_t length;
-#else
-    unsigned int length;
-#endif
+    ylength length;
     yajl_gen_get_buf(command_output->json_gen, &reply, &length);
 
     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_COMMAND,
@@ -161,11 +153,34 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     y(integer, (long int)con);
 
     ystr("type");
-    y(integer, con->type);
+    switch (con->type) {
+        case CT_ROOT:
+            ystr("root");
+            break;
+        case CT_OUTPUT:
+            ystr("output");
+            break;
+        case CT_CON:
+            ystr("con");
+            break;
+        case CT_FLOATING_CON:
+            ystr("floating_con");
+            break;
+        case CT_WORKSPACE:
+            ystr("workspace");
+            break;
+        case CT_DOCKAREA:
+            ystr("dockarea");
+            break;
+        default:
+            DLOG("About to dump unknown container type=%d. This is a bug.\n", con->type);
+            assert(false);
+            break;
+    }
 
     /* provided for backwards compatibility only. */
     ystr("orientation");
-    if (!con->split)
+    if (!con_is_split(con))
         ystr("none");
     else {
         if (con_orientation(con) == HORIZ)
@@ -202,9 +217,6 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     ystr("focused");
     y(bool, (con == focused));
 
-    ystr("split");
-    y(bool, con->split);
-
     ystr("layout");
     switch (con->layout) {
         case L_DEFAULT:
@@ -294,6 +306,32 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
         y(integer, con->window->id);
     else y(null);
 
+    if (con->window && !inplace_restart) {
+        /* Window properties are useless to preserve when restarting because
+         * they will be queried again anyway. However, for i3-save-tree(1),
+         * they are very useful and save i3-save-tree dealing with X11. */
+        ystr("window_properties");
+        y(map_open);
+
+#define DUMP_PROPERTY(key, prop_name) do { \
+    if (con->window->prop_name != NULL) { \
+        ystr(key); \
+        ystr(con->window->prop_name); \
+    } \
+} while (0)
+
+        DUMP_PROPERTY("class", class_class);
+        DUMP_PROPERTY("instance", class_instance);
+        DUMP_PROPERTY("window_role", role);
+
+        if (con->window->name != NULL) {
+            ystr("title");
+            ystr(i3string_as_utf8(con->window->name));
+        }
+
+        y(map_close);
+    }
+
     ystr("nodes");
     y(array_open);
     Con *node;
@@ -365,25 +403,22 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     }
     y(array_close);
 
+    if (inplace_restart && con->window != NULL) {
+        ystr("depth");
+        y(integer, con->depth);
+    }
+
     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
+    yajl_gen gen = ygenalloc();
     dump_node(gen, croot, false);
     setlocale(LC_NUMERIC, "");
 
     const unsigned char *payload;
-#if YAJL_MAJOR >= 2
-    size_t length;
-#else
-    unsigned int length;
-#endif
+    ylength length;
     y(get_buf, &payload, &length);
 
     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_TREE, payload);
@@ -397,11 +432,7 @@ IPC_HANDLER(tree) {
  *
  */
 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
+    yajl_gen gen = ygenalloc();
     y(array_open);
 
     Con *focused_ws = con_get_workspace(focused);
@@ -454,11 +485,7 @@ IPC_HANDLER(get_workspaces) {
     y(array_close);
 
     const unsigned char *payload;
-#if YAJL_MAJOR >= 2
-    size_t length;
-#else
-    unsigned int length;
-#endif
+    ylength length;
     y(get_buf, &payload, &length);
 
     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload);
@@ -471,11 +498,7 @@ 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
+    yajl_gen gen = ygenalloc();
     y(array_open);
 
     Output *output;
@@ -515,11 +538,7 @@ IPC_HANDLER(get_outputs) {
     y(array_close);
 
     const unsigned char *payload;
-#if YAJL_MAJOR >= 2
-    size_t length;
-#else
-    unsigned int length;
-#endif
+    ylength length;
     y(get_buf, &payload, &length);
 
     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload);
@@ -532,11 +551,7 @@ IPC_HANDLER(get_outputs) {
  *
  */
 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
+    yajl_gen gen = ygenalloc();
     y(array_open);
 
     Con *con;
@@ -547,11 +562,7 @@ IPC_HANDLER(get_marks) {
     y(array_close);
 
     const unsigned char *payload;
-#if YAJL_MAJOR >= 2
-    size_t length;
-#else
-    unsigned int length;
-#endif
+    ylength length;
     y(get_buf, &payload, &length);
 
     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_MARKS, payload);
@@ -563,11 +574,7 @@ IPC_HANDLER(get_marks) {
  *
  */
 IPC_HANDLER(get_version) {
-#if YAJL_MAJOR >= 2
-    yajl_gen gen = yajl_gen_alloc(NULL);
-#else
-    yajl_gen gen = yajl_gen_alloc(NULL, NULL);
-#endif
+    yajl_gen gen = ygenalloc();
     y(map_open);
 
     ystr("major");
@@ -585,11 +592,7 @@ IPC_HANDLER(get_version) {
     y(map_close);
 
     const unsigned char *payload;
-#if YAJL_MAJOR >= 2
-    size_t length;
-#else
-    unsigned int length;
-#endif
+    ylength length;
     y(get_buf, &payload, &length);
 
     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_VERSION, payload);
@@ -602,11 +605,7 @@ IPC_HANDLER(get_version) {
  *
  */
 IPC_HANDLER(get_bar_config) {
-#if YAJL_MAJOR >= 2
-    yajl_gen gen = yajl_gen_alloc(NULL);
-#else
-    yajl_gen gen = yajl_gen_alloc(NULL, NULL);
-#endif
+    yajl_gen gen = ygenalloc();
 
     /* If no ID was passed, we return a JSON array with all IDs */
     if (message_size == 0) {
@@ -618,11 +617,7 @@ IPC_HANDLER(get_bar_config) {
         y(array_close);
 
         const unsigned char *payload;
-#if YAJL_MAJOR >= 2
-        size_t length;
-#else
-        unsigned int length;
-#endif
+        ylength length;
         y(get_buf, &payload, &length);
 
         ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
@@ -675,9 +670,29 @@ IPC_HANDLER(get_bar_config) {
         YSTR_IF_SET(socket_path);
 
         ystr("mode");
-        if (config->mode == M_HIDE)
-            ystr("hide");
-        else ystr("dock");
+        switch (config->mode) {
+            case M_HIDE:
+                ystr("hide");
+                break;
+            case M_INVISIBLE:
+                ystr("invisible");
+                break;
+            case M_DOCK:
+            default:
+                ystr("dock");
+                break;
+        }
+
+        ystr("hidden_state");
+        switch (config->hidden_state) {
+            case S_SHOW:
+                ystr("show");
+                break;
+            case S_HIDE:
+            default:
+                ystr("hide");
+                break;
+        }
 
         ystr("modifier");
         switch (config->modifier) {
@@ -720,6 +735,9 @@ IPC_HANDLER(get_bar_config) {
         ystr("workspace_buttons");
         y(bool, !config->hide_workspace_buttons);
 
+        ystr("binding_mode_indicator");
+        y(bool, !config->hide_binding_mode_indicator);
+
         ystr("verbose");
         y(bool, config->verbose);
 
@@ -736,6 +754,7 @@ IPC_HANDLER(get_bar_config) {
         y(map_open);
         YSTR_IF_SET(background);
         YSTR_IF_SET(statusline);
+        YSTR_IF_SET(separator);
         YSTR_IF_SET(focused_workspace_border);
         YSTR_IF_SET(focused_workspace_bg);
         YSTR_IF_SET(focused_workspace_text);
@@ -756,11 +775,7 @@ IPC_HANDLER(get_bar_config) {
     y(map_close);
 
     const unsigned char *payload;
-#if YAJL_MAJOR >= 2
-    size_t length;
-#else
-    unsigned int length;
-#endif
+    ylength length;
     y(get_buf, &payload, &length);
 
     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
@@ -771,13 +786,8 @@ IPC_HANDLER(get_bar_config) {
  * 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
+                            ylength len) {
     ipc_client *client = extra;
 
     DLOG("should add subscription to extra %p, sub %.*s\n", client, (int)len, s);
@@ -827,11 +837,7 @@ 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
+    p = yalloc(&callbacks, (void*)client);
     stat = yajl_parse(p, (const unsigned char*)message, message_size);
     if (stat != yajl_status_ok) {
         unsigned char *err;
@@ -874,18 +880,16 @@ handler_t handlers[8] = {
  *
  */
 static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
-    char buf[2048];
-    int n = read(w->fd, buf, sizeof(buf));
-
-    /* On error or an empty message, we close the connection */
-    if (n <= 0) {
-#if 0
-        /* FIXME: I get these when closing a client socket,
-         * therefore we just treat them as an error. Is this
-         * correct? */
-        if (errno == EAGAIN || errno == EWOULDBLOCK)
-                return;
-#endif
+    uint32_t message_type;
+    uint32_t message_length;
+    uint8_t *message;
+
+    int ret = ipc_recv_message(w->fd, &message_type, &message_length, &message);
+    /* EOF or other error */
+    if (ret < 0) {
+        /* Was this a spurious read? See ev(3) */
+        if (ret == -1 && errno == EAGAIN)
+            return;
 
         /* If not, there was some kind of error. We don’t bother
          * and close the connection */
@@ -913,51 +917,11 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
         return;
     }
 
-    /* Terminate the message correctly */
-    buf[n] = '\0';
-
-    /* Check if the message starts with the i3 IPC magic code */
-    if (n < strlen(I3_IPC_MAGIC)) {
-        DLOG("IPC: message too short, ignoring\n");
-        return;
-    }
-
-    if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) {
-        DLOG("IPC: message does not start with the IPC magic\n");
-        return;
-    }
-
-    uint8_t *message = (uint8_t*)buf;
-    while (n > 0) {
-        DLOG("IPC: n = %d\n", n);
-        message += strlen(I3_IPC_MAGIC);
-        n -= strlen(I3_IPC_MAGIC);
-
-        /* The next 32 bit after the magic are the message size */
-        uint32_t message_size;
-        memcpy(&message_size, (uint32_t*)message, sizeof(uint32_t));
-        message += sizeof(uint32_t);
-        n -= sizeof(uint32_t);
-
-        if (message_size > n) {
-            DLOG("IPC: Either the message size was wrong or the message was not read completely, dropping\n");
-            return;
-        }
-
-        /* The last 32 bits of the header are the message type */
-        uint32_t message_type;
-        memcpy(&message_type, (uint32_t*)message, sizeof(uint32_t));
-        message += sizeof(uint32_t);
-        n -= sizeof(uint32_t);
-
-        if (message_type >= (sizeof(handlers) / sizeof(handler_t)))
-            DLOG("Unhandled message type: %d\n", message_type);
-        else {
-            handler_t h = handlers[message_type];
-            h(w->fd, message, n, message_size, message_type);
-        }
-        n -= message_size;
-        message += message_size;
+    if (message_type >= (sizeof(handlers) / sizeof(handler_t)))
+        DLOG("Unhandled message type: %d\n", message_type);
+    else {
+        handler_t h = handlers[message_type];
+        h(w->fd, message, 0, message_length, message_type);
     }
 }