]> git.sur5r.net Git - i3/i3/blobdiff - src/ipc.c
ipc: add active flag
[i3/i3] / src / ipc.c
index 0bef2ea244714f0b544c474d7ccd4f01e12f95bc..0df379b4889cc7887a8f910af47a88280707ef5b 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -3,7 +3,7 @@
  *
  * 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;
@@ -59,6 +66,86 @@ void broadcast(EV_P_ struct ev_timer *t, int revents) {
 }
 #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.
  *
@@ -69,12 +156,12 @@ void broadcast(EV_P_ struct ev_timer *t, int revents) {
  * 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: {
@@ -87,8 +174,11 @@ static void ipc_handle_message(uint8_t *message, int size,
 
                         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;
         }
 }
@@ -135,7 +225,7 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
 
                 ev_io_stop(EV_A_ w);
 
-                LOG("IPC: client disconnected\n");
+                DLOG("IPC: client disconnected\n");
                 return;
         }
 
@@ -144,18 +234,18 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
 
         /* 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);
 
@@ -165,7 +255,7 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
                 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;
                 }
 
@@ -174,7 +264,7 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
                 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;
         }
@@ -200,13 +290,13 @@ void ipc_new_client(EV_P_ struct ev_io *w, int revents) {
 
         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);
@@ -228,6 +318,8 @@ int ipc_create_socket(const char *filename) {
                 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;