2 #define I3__FILE__ "ipc.c"
15 #include <sys/socket.h>
20 #include <yajl/yajl_gen.h>
21 #include <yajl/yajl_parse.h>
33 static
void set_nonblock(
int sockfd) {
34 int flags = fcntl(sockfd, F_GETFL, 0);
36 if (fcntl(sockfd, F_SETFL, flags) < 0)
37 err(-1,
"Could not set O_NONBLOCK");
44 static bool mkdirp(
const char *path) {
45 if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
47 if (errno != ENOENT) {
48 ELOG(
"mkdir(%s) failed: %s\n", path, strerror(errno));
53 while (copy[strlen(copy)-1] ==
'/')
54 copy[strlen(copy)-1] =
'\0';
56 char *sep = strrchr(copy,
'/');
75 void ipc_send_event(
const char *event, uint32_t message_type,
const char *payload) {
79 bool interested =
false;
80 for (
int i = 0; i < current->
num_events; i++) {
81 if (strcasecmp(current->
events[i], event) != 0)
102 shutdown(current->
fd, SHUT_RDWR);
117 char *command =
scalloc(message_size + 1);
118 strncpy(command, (
const char*)message, message_size);
119 LOG(
"IPC: received: *%s*\n", command);
126 const unsigned char *reply;
128 yajl_gen_get_buf(command_output->
json_gen, &reply, &length);
131 (
const uint8_t*)reply);
133 yajl_gen_free(command_output->
json_gen);
153 y(integer, (
long int)con);
156 y(integer, con->type);
165 else ystr(
"vertical");
168 ystr(
"scratchpad_state");
169 switch (con->scratchpad_state) {
170 case SCRATCHPAD_NONE:
173 case SCRATCHPAD_FRESH:
176 case SCRATCHPAD_CHANGED:
182 if (con->percent == 0.0)
184 else y(
double, con->percent);
187 y(
bool, con->urgent);
189 if (con->mark != NULL) {
198 switch (con->layout) {
200 DLOG(
"About to dump layout=default, this is a bug in the code.\n");
223 ystr(
"workspace_layout");
224 switch (con->workspace_layout) {
235 DLOG(
"About to dump workspace_layout=%d (none of default/stacked/tabbed), this is a bug.\n", con->workspace_layout);
240 ystr(
"last_split_layout");
241 switch (con->layout) {
251 switch (con->border_style) {
263 ystr(
"current_border_width");
264 y(integer, con->current_border_width);
267 dump_rect(gen,
"window_rect", con->window_rect);
268 dump_rect(gen,
"geometry", con->geometry);
271 if (con->window && con->window->name)
276 if (con->type == CT_WORKSPACE) {
278 y(integer, con->num);
283 y(integer, con->window->id);
289 if (con->type != CT_DOCKAREA || !inplace_restart) {
296 ystr(
"floating_nodes");
298 TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
306 y(integer, (
long int)node);
310 ystr(
"fullscreen_mode");
311 y(integer, con->fullscreen_mode);
314 switch (con->floating) {
315 case FLOATING_AUTO_OFF:
318 case FLOATING_AUTO_ON:
321 case FLOATING_USER_OFF:
324 case FLOATING_USER_ON:
333 if (match->
dock != -1) {
336 y(integer, match->
dock);
337 ystr(
"insert_where");
345 if (inplace_restart) {
346 if (con->window != NULL) {
349 y(integer, con->window->id);
350 ystr(
"restart_mode");
357 if (inplace_restart && con->window != NULL) {
359 y(integer, con->depth);
366 setlocale(LC_NUMERIC,
"C");
369 setlocale(LC_NUMERIC,
"");
371 const unsigned char *payload;
373 y(get_buf, &payload, &length);
397 assert(ws->
type == CT_WORKSPACE);
403 else y(integer, ws->
num);
412 y(
bool, ws == focused_ws);
438 const unsigned char *payload;
440 y(get_buf, &payload, &length);
471 y(integer, output->
rect.
x);
473 y(integer, output->
rect.
y);
480 ystr(
"current_workspace");
491 const unsigned char *payload;
493 y(get_buf, &payload, &length);
510 if (con->
mark != NULL)
515 const unsigned char *payload;
517 y(get_buf, &payload, &length);
532 y(integer, MAJOR_VERSION);
535 y(integer, MINOR_VERSION);
538 y(integer, PATCH_VERSION);
540 ystr(
"human_readable");
545 const unsigned char *payload;
547 y(get_buf, &payload, &length);
562 if (message_size == 0) {
570 const unsigned char *payload;
572 y(get_buf, &payload, &length);
581 char *bar_id =
scalloc(message_size + 1);
582 strncpy(bar_id, (
const char*)message, message_size);
583 LOG(
"IPC: looking for config for bar ID \"%s\"\n", bar_id);
586 if (strcmp(current->
id, bar_id) != 0)
612 #define YSTR_IF_SET(name) \
614 if (config->name) { \
616 ystr(config->name); \
624 switch (config->
mode) {
637 ystr(
"hidden_state");
686 ystr(
"workspace_buttons");
693 #define YSTR_IF_SET(name) \
695 if (config->colors.name) { \
697 ystr(config->colors.name); \
725 const unsigned char *payload;
727 y(get_buf, &payload, &length);
741 DLOG(
"should add subscription to extra %p, sub %.*s\n", client, (
int)len, s);
749 memcpy(client->
events[event], s, len);
751 DLOG(
"client is now subscribed to:\n");
766 yajl_callbacks callbacks;
772 if (current->
fd != fd)
779 if (client == NULL) {
780 ELOG(
"Could not find ipc_client data structure for fd %d\n", fd);
785 memset(&callbacks, 0,
sizeof(yajl_callbacks));
788 p =
yalloc(&callbacks, (
void*)client);
789 stat = yajl_parse(p, (
const unsigned char*)message, message_size);
790 if (stat != yajl_status_ok) {
792 err = yajl_get_error(p,
true, (
const unsigned char*)message,
794 ELOG(
"YAJL parse error: %s\n", err);
795 yajl_free_error(p, err);
797 const char *reply =
"{\"success\":false}";
798 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
803 const char *reply =
"{\"success\":true}";
804 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t*)reply);
811 handle_get_workspaces,
816 handle_get_bar_config,
831 uint32_t message_type;
832 uint32_t message_length;
835 int ret =
ipc_recv_message(w->fd, &message_type, &message_length, &message);
839 if (ret == -1 && errno == EAGAIN)
849 if (current->
fd != w->fd)
864 DLOG(
"IPC: client disconnected\n");
869 DLOG(
"Unhandled message type: %d\n", message_type);
872 h(w->fd, message, 0, message_length, message_type);
884 struct sockaddr_un peer;
885 socklen_t len =
sizeof(
struct sockaddr_un);
887 if ((client = accept(w->fd, (
struct sockaddr*)&peer, &len)) < 0) {
890 else perror(
"accept()");
895 (void)fcntl(client, F_SETFD, FD_CLOEXEC);
897 set_nonblock(client);
899 struct ev_io *
package = scalloc(sizeof(struct ev_io));
901 ev_io_start(EV_A_ package);
903 DLOG(
"IPC: new client connected on fd %d\n", w->fd);
922 DLOG(
"Creating IPC-socket at %s\n", resolved);
923 char *copy =
sstrdup(resolved);
924 const char *dir = dirname(copy);
932 if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
938 (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
940 struct sockaddr_un addr;
941 memset(&addr, 0,
sizeof(
struct sockaddr_un));
942 addr.sun_family = AF_LOCAL;
943 strncpy(addr.sun_path, resolved,
sizeof(addr.sun_path) - 1);
944 if (bind(sockfd, (
struct sockaddr*)&addr,
sizeof(
struct sockaddr_un)) < 0) {
950 set_nonblock(sockfd);
952 if (listen(sockfd, 5) < 0) {
char * name
Name of the output.
static int add_subscription(void *extra, const unsigned char *s, ylength len)
A 'Con' represents everything from the X11 root window down to a single X11 window.
int ipc_send_message(int sockfd, const uint32_t message_size, const uint32_t message_type, const uint8_t *payload)
Formats a message (payload) of the given size and type and sends it to i3 via the given socket file d...
struct all_cons_head all_cons
#define TAILQ_INSERT_TAIL(head, elm, field)
void(* handler_t)(int, uint8_t *, int, uint32_t, uint32_t)
Stores a rectangle, for example the size of a window, the child window etc.
bool workspace_is_visible(Con *ws)
Returns true if the workspace is currently visible.
struct barconfig_head barconfigs
enum Barconfig::@5 mode
Bar display mode (hide unless modifier is pressed or show in dock mode or always hide in invisible mo...
enum Barconfig::@8 position
Bar position (bottom by default).
#define TAILQ_EMPTY(head)
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
A "match" is a data structure which acts like a mask or expression to match certain windows or not...
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
bool verbose
Enable verbose mode? Useful for debugging purposes.
static struct CommandResult command_output
void * scalloc(size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
const char * i3string_as_utf8(i3String *str)
Returns the UTF-8 encoded version of the i3String.
char * resolve_tilde(const char *path)
This function resolves ~ in pathnames.
static void ipc_receive_message(EV_P_ struct ev_io *w, int revents)
static bool mkdirp(const char *path)
#define TAILQ_REMOVE(head, elm, field)
struct CommandResult * parse_command(const char *input)
#define yalloc(callbacks, client)
#define TAILQ_HEAD(name, type)
#define TAILQ_HEAD_INITIALIZER(head)
struct outputs_head outputs
void ipc_send_event(const char *event, uint32_t message_type, const char *payload)
Sends the specified event to all IPC clients which are currently connected and subscribed to this kin...
Rect rect
x, y, width, height
int ipc_create_socket(const char *filename)
Creates the UNIX domain socket at the given path, sets it to non-blocking mode, bind()s and listen()s...
char * id
Automatically generated ID for this bar config.
enum Barconfig::@7 modifier
Bar modifier (to show bar when in hide mode).
int ipc_recv_message(int sockfd, uint32_t *message_type, uint32_t *reply_length, uint8_t **reply)
Reads a message from the given socket file descriptor and stores its length (reply_length) as well as...
bool con_is_split(Con *con)
enum Match::@15 insert_where
static void dump_rect(yajl_gen gen, const char *name, Rect r)
#define TAILQ_FIRST(head)
char * current_socketpath
bool active
Whether the output is currently active (has a CRTC attached with a valid mode)
An Output is a physical output on your graphics driver.
enum Barconfig::@6 hidden_state
#define TAILQ_FOREACH(var, head, field)
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
#define IPC_HANDLER(name)
Con * output_get_content(Con *output)
Returns the output container below the given output container.
bool hide_workspace_buttons
Hide workspace buttons? Configuration option is 'workspace_buttons no' but we invert the bool to get ...
char ** outputs
Outputs on which this bar should show up on.
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
Con * con
Pointer to the Con which represents this output.
#define YSTR_IF_SET(name)
void ipc_shutdown(void)
Calls shutdown() on each socket and closes it.
Con * con_get_fullscreen_con(Con *con, int fullscreen_mode)
Returns the first fullscreen node below this node.
bool path_exists(const char *path)
Checks if the given path exists by calling stat().
Holds the status bar configuration (i3bar).
int con_orientation(Con *con)
Returns the orientation of the given container (for stacked containers, vertical orientation is used ...
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart)
void ipc_new_client(EV_P_ struct ev_io *w, int revents)
Handler for activity on the listening socket, meaning that a new client has just connected and we sho...
int num_outputs
Number of outputs in the outputs array.