From b7553976878797fb6038308f08603028f9c1268f Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 2 Oct 2011 19:20:43 +0100 Subject: [PATCH] Make i3 send arguments as command to a running i3 instance (like i3-msg) From i3 --help: If you pass plain text arguments, i3 will interpret them as a command to send to a currently running i3 (like i3-msg). This allows you to use nice and logical commands, such as: i3 border none i3 floating toggle i3 kill window --- src/main.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/main.c b/src/main.c index ac05f26e..3ebfb5f4 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,9 @@ */ #include #include +#include +#include +#include #include "all.h" #include "sd-daemon.h" @@ -281,10 +284,77 @@ int main(int argc, char *argv[]) { fprintf(stderr, "\n"); fprintf(stderr, "\t--get-socketpath\n" "\tRetrieve the i3 IPC socket path from X11, print it, then exit.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "If you pass plain text arguments, i3 will interpret them as a command\n" + "to send to a currently running i3 (like i3-msg). This allows you to\n" + "use nice and logical commands, such as:\n" + "\n" + "\ti3 border none\n" + "\ti3 floating toggle\n" + "\ti3 kill window\n" + "\n"); exit(EXIT_FAILURE); } } + /* If the user passes more arguments, we act like i3-msg would: Just send + * the arguments as an IPC message to i3. This allows for nice semantic + * commands such as 'i3 border none'. */ + if (optind < argc) { + /* We enable verbose mode so that the user knows what’s going on. + * This should make it easier to find mistakes when the user passes + * arguments by mistake. */ + set_verbosity(true); + + LOG("Additional arguments passed. Sending them as a command to i3.\n"); + char *payload = NULL; + while (optind < argc) { + if (!payload) { + payload = sstrdup(argv[optind]); + } else { + char *both; + if (asprintf(&both, "%s %s", payload, argv[optind]) == -1) + err(EXIT_FAILURE, "asprintf"); + free(payload); + payload = both; + } + optind++; + } + LOG("Command is: %s (%d bytes)\n", payload, strlen(payload)); + char *socket_path = socket_path_from_x11(); + if (!socket_path) { + ELOG("Could not get i3 IPC socket path\n"); + return 1; + } + + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sockfd == -1) + err(EXIT_FAILURE, "Could not create socket"); + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_LOCAL; + strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); + if (connect(sockfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) + err(EXIT_FAILURE, "Could not connect to i3"); + + if (ipc_send_message(sockfd, strlen(payload), I3_IPC_MESSAGE_TYPE_COMMAND, + (uint8_t*)payload) == -1) + err(EXIT_FAILURE, "IPC: write()"); + + uint32_t reply_length; + uint8_t *reply; + int ret; + if ((ret = ipc_recv_message(sockfd, I3_IPC_MESSAGE_TYPE_COMMAND, + &reply_length, &reply)) != 0) { + if (ret == -1) + err(EXIT_FAILURE, "IPC: read()"); + return 1; + } + printf("%.*s\n", reply_length, reply); + return 0; + } + LOG("i3 (tree) version " I3_VERSION " starting\n"); conn = xcb_connect(NULL, &screens);