diff --git a/i3.config b/i3.config index 56cb2704..11bd9066 100644 --- a/i3.config +++ b/i3.config @@ -116,6 +116,10 @@ bind Mod1+Shift+26 exit # Mod1+Shift+r restarts i3 inplace bind Mod1+Shift+27 restart +# The IPC interface allows programs like an external workspace bar +# (i3-wsbar) or i3-msg (can be used to "remote-control" i3) to work. +ipc-socket ~/.i3/ipc.sock + ############################################################# # DELETE THE FOLLOWING LINES TO DISABLE THE WELCOME MESSAGE # ############################################################# diff --git a/include/config.h b/include/config.h index 0b671b7a..0c790bf2 100644 --- a/include/config.h +++ b/include/config.h @@ -124,6 +124,18 @@ struct Config { } bar; }; +/** + * This function resolves ~ in pathnames. + * + */ +char *glob_path(const char *path); + +/** + * Checks if the given path exists by calling stat(). + * + */ +bool path_exists(const char *path); + /** * Reads the configuration from ~/.i3/config or /etc/i3/config if not found. * diff --git a/src/config.c b/src/config.c index c7ef0af9..972e376c 100644 --- a/src/config.c +++ b/src/config.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /* We need Xlib for XStringToKeysym */ @@ -40,12 +41,25 @@ struct modes_head modes; * This function resolves ~ in pathnames. * */ -static char *glob_path(const char *path) { +char *glob_path(const char *path) { static glob_t globbuf; if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) die("glob() failed"); char *result = sstrdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); globfree(&globbuf); + + /* If the file does not exist yet, we still may need to resolve tilde, + * so call wordexp */ + if (strcmp(result, path) == 0) { + wordexp_t we; + wordexp(path, &we, WRDE_NOCMD); + if (we.we_wordc > 0) { + free(result); + result = sstrdup(we.we_wordv[0]); + } + wordfree(&we); + } + return result; } @@ -53,7 +67,7 @@ static char *glob_path(const char *path) { * Checks if the given path exists by calling stat(). * */ -static bool path_exists(const char *path) { +bool path_exists(const char *path) { struct stat buf; return (stat(path, &buf) == 0); } diff --git a/src/ipc.c b/src/ipc.c index 8ed455dd..dbd0a697 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +35,7 @@ #include "log.h" #include "table.h" #include "randr.h" +#include "config.h" /* Shorter names for all those yajl_gen_* functions */ #define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__) @@ -53,6 +56,34 @@ static void set_nonblock(int sockfd) { err(-1, "Could not set O_NONBLOCK"); } +/* + * Emulates mkdir -p (creates any missing folders) + * + */ +static bool mkdirp(const char *path) { + if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0) + return true; + if (errno != ENOENT) { + ELOG("mkdir(%s) failed: %s\n", path, strerror(errno)); + return false; + } + char *copy = strdup(path); + /* strip trailing slashes, if any */ + while (copy[strlen(copy)-1] == '/') + copy[strlen(copy)-1] = '\0'; + + char *sep = strrchr(copy, '/'); + if (sep == NULL) + return false; + *sep = '\0'; + bool result = false; + if (mkdirp(copy)) + result = mkdirp(path); + free(copy); + + return result; +} + 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) + @@ -471,11 +502,20 @@ void ipc_new_client(EV_P_ struct ev_io *w, int revents) { int ipc_create_socket(const char *filename) { int sockfd; + char *globbed = glob_path(filename); + DLOG("Creating IPC-socket at %s\n", globbed); + char *copy = sstrdup(globbed); + const char *dir = dirname(copy); + if (!path_exists(dir)) + mkdirp(dir); + free(copy); + /* Unlink the unix domain socket before */ unlink(filename); if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { perror("socket()"); + free(globbed); return -1; } @@ -484,12 +524,14 @@ int ipc_create_socket(const char *filename) { struct sockaddr_un addr; memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_LOCAL; - strcpy(addr.sun_path, filename); + strcpy(addr.sun_path, globbed); if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) { perror("bind()"); + free(globbed); return -1; } + free(globbed); set_nonblock(sockfd); if (listen(sockfd, 5) < 0) {