15 #include <sys/socket.h> 20 #include <yajl/yajl_gen.h> 21 #include <yajl/yajl_parse.h> 35 int flags = fcntl(sockfd, F_GETFL, 0);
37 if (fcntl(sockfd, F_SETFL, flags) < 0)
38 err(-1,
"Could not set O_NONBLOCK");
46 void ipc_send_event(
const char *event, uint32_t message_type,
const char *payload) {
50 bool interested =
false;
51 for (
int i = 0; i < current->
num_events; i++) {
52 if (strcasecmp(current->
events[i], event) != 0)
60 ipc_send_message(current->
fd, strlen(payload), message_type, (
const uint8_t *)payload);
81 const unsigned char *payload;
84 y(get_buf, &payload, &length);
85 ipc_send_event(
"shutdown", I3_IPC_EVENT_SHUTDOWN, (
const char *)payload);
101 shutdown(current->
fd, SHUT_RDWR);
119 char *command =
scalloc(message_size + 1, 1);
120 strncpy(command, (
const char *)message, message_size);
121 LOG(
"IPC: received: *%s*\n", command);
122 yajl_gen gen = yajl_gen_alloc(NULL);
132 const unsigned char *reply;
134 yajl_gen_get_buf(gen, &reply, &length);
137 (
const uint8_t *)reply);
158 for (
int i = 0; i < 20; i++) {
161 case XCB_KEY_BUT_MASK_SHIFT:
164 case XCB_KEY_BUT_MASK_LOCK:
167 case XCB_KEY_BUT_MASK_CONTROL:
170 case XCB_KEY_BUT_MASK_MOD_1:
173 case XCB_KEY_BUT_MASK_MOD_2:
176 case XCB_KEY_BUT_MASK_MOD_3:
179 case XCB_KEY_BUT_MASK_MOD_4:
182 case XCB_KEY_BUT_MASK_MOD_5:
185 case XCB_KEY_BUT_MASK_BUTTON_1:
188 case XCB_KEY_BUT_MASK_BUTTON_2:
191 case XCB_KEY_BUT_MASK_BUTTON_3:
194 case XCB_KEY_BUT_MASK_BUTTON_4:
197 case XCB_KEY_BUT_MASK_BUTTON_5:
240 ystr(
"event_state_mask");
249 y(integer, (uintptr_t)con);
262 case CT_FLOATING_CON:
263 ystr(
"floating_con");
272 DLOG(
"About to dump unknown container type=%d. This is a bug.\n", con->type);
288 ystr(
"scratchpad_state");
289 switch (con->scratchpad_state) {
290 case SCRATCHPAD_NONE:
293 case SCRATCHPAD_FRESH:
296 case SCRATCHPAD_CHANGED:
302 if (con->percent == 0.0)
305 y(
double, con->percent);
308 y(
bool, con->urgent);
325 if (con->type != CT_ROOT && con->type != CT_OUTPUT) {
331 switch (con->layout) {
333 DLOG(
"About to dump layout=default, this is a bug in the code.\n");
356 ystr(
"workspace_layout");
357 switch (con->workspace_layout) {
368 DLOG(
"About to dump workspace_layout=%d (none of default/stacked/tabbed), this is a bug.\n", con->workspace_layout);
373 ystr(
"last_split_layout");
374 switch (con->layout) {
384 switch (con->border_style) {
396 ystr(
"current_border_width");
397 y(integer, con->current_border_width);
400 dump_rect(gen,
"deco_rect", con->deco_rect);
401 dump_rect(gen,
"window_rect", con->window_rect);
402 dump_rect(gen,
"geometry", con->geometry);
405 if (con->window && con->window->name)
407 else if (con->name != NULL)
412 if (con->title_format != NULL) {
413 ystr(
"title_format");
414 ystr(con->title_format);
417 if (con->type == CT_WORKSPACE) {
419 y(integer, con->num);
424 y(integer, con->window->id);
428 if (con->window && !inplace_restart) {
432 ystr(
"window_properties");
435 #define DUMP_PROPERTY(key, prop_name) \ 437 if (con->window->prop_name != NULL) { \ 439 ystr(con->window->prop_name); \ 447 if (con->window->name != NULL) {
452 ystr(
"transient_for");
453 if (con->window->transient_for == XCB_NONE)
456 y(integer, con->window->transient_for);
464 if (con->type != CT_DOCKAREA || !inplace_restart) {
471 ystr(
"floating_nodes");
473 TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
481 y(integer, (uintptr_t)node);
485 ystr(
"fullscreen_mode");
486 y(integer, con->fullscreen_mode);
489 y(
bool, con->sticky);
492 switch (con->floating) {
493 case FLOATING_AUTO_OFF:
496 case FLOATING_AUTO_ON:
499 case FLOATING_USER_OFF:
502 case FLOATING_USER_ON:
516 if (match->
dock != M_DONTCHECK) {
518 y(integer, match->
dock);
519 ystr(
"insert_where");
523 #define DUMP_REGEX(re_name) \ 525 if (match->re_name != NULL) { \ 527 ystr(match->re_name->pattern); \ 540 if (inplace_restart) {
541 if (con->window != NULL) {
544 y(integer, con->window->id);
545 ystr(
"restart_mode");
552 if (inplace_restart && con->window != NULL) {
554 y(integer, con->depth);
576 y(
bool, current->
release == B_UPON_KEYRELEASE);
586 if (strcasecmp(name,
"primary") == 0) {
613 ystr(
"tray_outputs");
624 #define YSTR_IF_SET(name) \ 626 if (config->name) { \ 628 ystr(config->name); \ 632 ystr(
"tray_padding");
638 switch (config->
mode) {
651 ystr(
"hidden_state");
702 ystr(
"separator_symbol");
706 ystr(
"workspace_buttons");
709 ystr(
"strip_workspace_numbers");
712 ystr(
"binding_mode_indicator");
719 #define YSTR_IF_SET(name) \ 721 if (config->colors.name) { \ 723 ystr(config->colors.name); \ 757 setlocale(LC_NUMERIC,
"C");
760 setlocale(LC_NUMERIC,
"");
762 const unsigned char *payload;
764 y(get_buf, &payload, &length);
787 assert(ws->
type == CT_WORKSPACE);
800 y(
bool, ws == focused_ws);
826 const unsigned char *payload;
828 y(get_buf, &payload, &length);
859 y(integer, output->
rect.
x);
861 y(integer, output->
rect.
y);
868 ystr(
"current_workspace");
880 const unsigned char *payload;
882 y(get_buf, &payload, &length);
907 const unsigned char *payload;
909 y(get_buf, &payload, &length);
924 y(integer, MAJOR_VERSION);
927 y(integer, MINOR_VERSION);
930 y(integer, PATCH_VERSION);
932 ystr(
"human_readable");
935 ystr(
"loaded_config_file_name");
940 const unsigned char *payload;
942 y(get_buf, &payload, &length);
957 if (message_size == 0) {
965 const unsigned char *payload;
967 y(get_buf, &payload, &length);
977 sasprintf(&bar_id,
"%.*s", message_size, message);
978 LOG(
"IPC: looking for config for bar ID \"%s\"\n", bar_id);
981 if (strcmp(current->
id, bar_id) != 0)
1002 const unsigned char *payload;
1004 y(get_buf, &payload, &length);
1024 const unsigned char *payload;
1026 y(get_buf, &payload, &length);
1040 DLOG(
"should add subscription to extra %p, sub %.*s\n", client, (
int)len, s);
1048 memcpy(client->
events[event], s, len);
1050 DLOG(
"client is now subscribed to:\n");
1051 for (
int i = 0; i < client->
num_events; i++) {
1071 if (current->
fd != fd)
1078 if (client == NULL) {
1079 ELOG(
"Could not find ipc_client data structure for fd %d\n", fd);
1084 static yajl_callbacks callbacks = {
1088 p =
yalloc(&callbacks, (
void *)client);
1089 stat = yajl_parse(p, (
const unsigned char *)message, message_size);
1090 if (stat != yajl_status_ok) {
1092 err = yajl_get_error(p,
true, (
const unsigned char *)message,
1094 ELOG(
"YAJL parse error: %s\n", err);
1095 yajl_free_error(p, err);
1097 const char *reply =
"{\"success\":false}";
1098 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t *)reply);
1103 const char *reply =
"{\"success\":true}";
1104 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (
const uint8_t *)reply);
1106 if (client->first_tick_sent) {
1110 bool is_tick =
false;
1111 for (
int i = 0; i < client->num_events; i++) {
1112 if (strcmp(client->events[i],
"tick") == 0) {
1121 client->first_tick_sent =
true;
1122 const char *payload =
"{\"first\":true,\"payload\":\"\"}";
1123 ipc_send_message(client->fd, strlen(payload), I3_IPC_EVENT_TICK, (
const uint8_t *)payload);
1139 const unsigned char *payload;
1141 y(get_buf, &payload, &length);
1157 yajl_gen_string(gen, (
unsigned char *)message, message_size);
1161 const unsigned char *payload;
1163 y(get_buf, &payload, &length);
1165 ipc_send_event(
"tick", I3_IPC_EVENT_TICK, (
const char *)payload);
1168 const char *reply =
"{\"success\":true}";
1169 ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_TICK, (
const uint8_t *)reply);
1170 DLOG(
"Sent tick event\n");
1177 handle_get_workspaces,
1182 handle_get_bar_config,
1184 handle_get_binding_modes,
1200 uint32_t message_type;
1201 uint32_t message_length;
1202 uint8_t *message = NULL;
1204 int ret =
ipc_recv_message(w->fd, &message_type, &message_length, &message);
1208 if (ret == -1 && errno == EAGAIN) {
1220 if (current->
fd != w->fd)
1223 for (
int i = 0; i < current->
num_events; i++)
1224 free(current->
events[i]);
1233 ev_io_stop(EV_A_ w);
1237 DLOG(
"IPC: client disconnected\n");
1242 DLOG(
"Unhandled message type: %d\n", message_type);
1245 h(w->fd, message, 0, message_length, message_type);
1259 struct sockaddr_un peer;
1260 socklen_t len =
sizeof(
struct sockaddr_un);
1262 if ((client = accept(w->fd, (
struct sockaddr *)&peer, &len)) < 0) {
1271 (void)fcntl(client, F_SETFD, FD_CLOEXEC);
1275 struct ev_io *
package = scalloc(1, sizeof(struct ev_io));
1277 ev_io_start(EV_A_ package);
1279 DLOG(
"IPC: new client connected on fd %d\n", w->fd);
1298 DLOG(
"Creating IPC-socket at %s\n", resolved);
1299 char *copy =
sstrdup(resolved);
1300 const char *dir = dirname(copy);
1308 if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
1314 (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
1316 struct sockaddr_un addr;
1317 memset(&addr, 0,
sizeof(
struct sockaddr_un));
1318 addr.sun_family = AF_LOCAL;
1319 strncpy(addr.sun_path, resolved,
sizeof(addr.sun_path) - 1);
1320 if (bind(sockfd, (
struct sockaddr *)&addr,
sizeof(
struct sockaddr_un)) < 0) {
1328 if (listen(sockfd, 5) < 0) {
1343 setlocale(LC_NUMERIC,
"C");
1352 if (current == NULL)
1365 setlocale(LC_NUMERIC,
"");
1378 const unsigned char *payload;
1380 y(get_buf, &payload, &length);
1382 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE, (
const char *)payload);
1392 DLOG(
"Issue IPC window %s event (con = %p, window = 0x%08x)\n",
1393 property, con, (con->
window ? con->
window->
id : XCB_WINDOW_NONE));
1395 setlocale(LC_NUMERIC,
"C");
1408 const unsigned char *payload;
1410 y(get_buf, &payload, &length);
1412 ipc_send_event(
"window", I3_IPC_EVENT_WINDOW, (
const char *)payload);
1414 setlocale(LC_NUMERIC,
"");
1421 DLOG(
"Issue barconfig_update event for id = %s\n", barconfig->
id);
1422 setlocale(LC_NUMERIC,
"C");
1427 const unsigned char *payload;
1429 y(get_buf, &payload, &length);
1431 ipc_send_event(
"barconfig_update", I3_IPC_EVENT_BARCONFIG_UPDATE, (
const char *)payload);
1433 setlocale(LC_NUMERIC,
"");
1440 DLOG(
"Issue IPC binding %s event (sym = %s, code = %d)\n", event_type, bind->
symbol, bind->
keycode);
1442 setlocale(LC_NUMERIC,
"C");
1456 const unsigned char *payload;
1458 y(get_buf, &payload, &length);
1460 ipc_send_event(
"binding", I3_IPC_EVENT_BINDING, (
const char *)payload);
1463 setlocale(LC_NUMERIC,
"");
int sasprintf(char **strp, const char *fmt,...)
Safe-wrapper around asprintf which exits if it returns -1 (meaning that there is no more memory avail...
struct outputs_head outputs
#define TAILQ_HEAD_INITIALIZER(head)
bool hide_workspace_buttons
Hide workspace buttons? Configuration option is 'workspace_buttons no' but we invert the bool to get ...
#define YSTR_IF_SET(name)
char * current_socketpath
bool verbose
Enable verbose mode? Useful for debugging purposes.
#define TAILQ_HEAD(name, type)
struct barconfig_head barconfigs
const char * i3string_as_utf8(i3String *str)
Returns the UTF-8 encoded version of the i3String.
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
#define TAILQ_EMPTY(head)
Holds the status bar configuration (i3bar).
char * separator_symbol
A custom separator to use instead of a vertical line.
A 'Con' represents everything from the X11 root window down to a single X11 window.
static void dump_bar_config(yajl_gen gen, Barconfig *config)
char * command
Command, like in command mode.
void ipc_send_binding_event(const char *event_type, Binding *bind)
For the binding events, we send the serialized binding struct.
static void dump_event_state_mask(yajl_gen gen, Binding *bind)
static void dump_bar_bindings(yajl_gen gen, Barconfig *config)
#define TAILQ_INSERT_TAIL(head, elm, field)
shutdown_reason_t
Calls to ipc_shutdown() should provide a reason for the shutdown.
static void ipc_receive_message(EV_P_ struct ev_io *w, int revents)
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...
Defines a mouse command to be executed instead of the default behavior when clicking on the non-statu...
struct bindings_head * bindings
bool strip_workspace_numbers
Strip workspace numbers? Configuration option is 'strip_workspace_numbers yes'.
void ipc_send_window_event(const char *property, Con *con)
For the window events we send, along the usual "change" field, also the window container, in "container".
char * command
The command which is to be executed for this button.
const char * i3_version
Git commit identifier, from version.c.
uint32_t keycode
Keycode to bind.
int num_outputs
Number of outputs in the outputs array.
enum Barconfig::@9 hidden_state
Output * get_output_by_name(const char *name, const bool require_active)
Returns the output with the given name or NULL.
void ipc_send_barconfig_update_event(Barconfig *barconfig)
For the barconfig update events, we send the serialized barconfig.
char * resolve_tilde(const char *path)
This function resolves ~ in pathnames.
static void set_nonblock(int sockfd)
bool path_exists(const char *path)
Checks if the given path exists by calling stat().
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
Con * con_get_output(Con *con)
Gets the output container (first container with CT_OUTPUT in hierarchy) this node is on...
static int add_subscription(void *extra, const unsigned char *s, ylength len)
#define TAILQ_FOREACH(var, head, field)
void command_result_free(CommandResult *result)
Frees a CommandResult.
#define TAILQ_FIRST(head)
orientation_t con_orientation(Con *con)
Returns the orientation of the given container (for stacked containers, vertical orientation is used ...
#define TAILQ_REMOVE(head, elm, field)
#define DUMP_PROPERTY(key, prop_name)
char * current_configpath
static void dump_binding(yajl_gen gen, Binding *bind)
#define DUMP_REGEX(re_name)
bool con_is_split(Con *con)
Returns true if a container should be considered split.
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
void(* handler_t)(int, uint8_t *, int, uint32_t, uint32_t)
struct all_cons_head all_cons
enum Barconfig::@11 position
Bar position (bottom by default).
Con * output_get_content(Con *output)
Returns the output container below the given output container.
void * scalloc(size_t num, size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
void ipc_shutdown(shutdown_reason_t reason)
Calls shutdown() on each socket and closes it.
char * id
Automatically generated ID for this bar config.
static void ipc_send_shutdown_event(shutdown_reason_t reason)
An Output is a physical output on your graphics driver.
A struct that contains useful information about the result of a command as a whole (e...
void * srealloc(void *ptr, size_t size)
Safe-wrapper around realloc which exits if realloc returns NULL (meaning that there is no more memory...
bool release
If true, the command will be executed after the button is released.
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...
enum Match::@17 insert_where
CommandResult * parse_command(const char *input, yajl_gen gen)
Parses and executes the given command.
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...
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...
yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old)
Generates a json workspace event.
i3_event_state_mask_t event_state_mask
Bitmask which is applied against event->state for KeyPress and KeyRelease events to determine whether...
int input_code
The button to be used (e.g., 1 for "button1").
enum Barconfig::@8 mode
Bar display mode (hide unless modifier is pressed or show in dock mode or always hide in invisible mo...
static void dump_rect(yajl_gen gen, const char *name, Rect r)
char ** outputs
Outputs on which this bar should show up on.
#define SLIST_FOREACH(var, head, field)
The configuration file can contain multiple sets of bindings.
static char * canonicalize_output_name(char *name)
A "match" is a data structure which acts like a mask or expression to match certain windows or not...
Con * con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode)
Returns the first fullscreen node below this node.
Con * con
Pointer to the Con which represents this output.
char * symbol
Symbol the user specified in configfile, if any.
int mkdirp(const char *path, mode_t mode)
Emulates mkdir -p (creates any missing folders)
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
enum Barconfig::@10 modifier
Bar modifier (to show bar when in hide mode).
bool hide_binding_mode_indicator
Hide mode button? Configuration option is 'binding_mode_indicator no' but we invert the bool for the ...
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart)
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
Rect rect
x, y, width, height
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...
void ipc_send_workspace_event(const char *change, Con *current, Con *old)
For the workspace events we send, along with the usual "change" field, also the workspace container i...
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 * output_primary_name(Output *output)
Retrieves the primary name of an output.
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.
bool active
Whether the output is currently active (has a CRTC attached with a valid mode)
#define yalloc(callbacks, client)