diff --git a/docs/ipc b/docs/ipc index 7e713260..4093ffce 100644 --- a/docs/ipc +++ b/docs/ipc @@ -59,6 +59,10 @@ GET_TREE (4):: Gets the layout tree. i3 uses a tree as data structure which includes every container. The reply will be the JSON-encoded tree (see the reply section). +GET_MARKS (5):: + Gets a list of marks (identifiers for containers to easily jump to them + later). The reply will be a JSON-encoded list of window marks (see + reply section). So, a typical message could look like this: -------------------------------------------------- @@ -110,6 +114,8 @@ GET_OUTPUTS (3):: Reply to the GET_OUTPUTS message. GET_TREE (4):: Reply to the GET_TREE message. +GET_MARKS (5):: + Reply to the GET_MARKS message. === COMMAND reply @@ -416,6 +422,16 @@ JSON dump: } ] } + + +=== GET_MARKS reply + +The reply consists of a single array of strings for each container that has a +mark. The order of that array is undefined. If more than one container has the +same mark, it will be represented multiple times in the reply (the array +contents are not unique). + +If no window has a mark the response will be the empty array []. ------------------------ diff --git a/i3-msg/main.c b/i3-msg/main.c index 630a345d..d8195e08 100644 --- a/i3-msg/main.c +++ b/i3-msg/main.c @@ -180,9 +180,11 @@ int main(int argc, char *argv[]) { message_type = I3_IPC_MESSAGE_TYPE_GET_OUTPUTS; else if (strcasecmp(optarg, "get_tree") == 0) message_type = I3_IPC_MESSAGE_TYPE_GET_TREE; + else if (strcasecmp(optarg, "get_marks") == 0) + message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS; else { printf("Unknown message type\n"); - printf("Known types: command, get_workspaces, get_outputs, get_tree\n"); + printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks\n"); exit(EXIT_FAILURE); } } else if (o == 'q') { diff --git a/include/i3/ipc.h b/include/i3/ipc.h index e81f9a15..30b2d304 100644 --- a/include/i3/ipc.h +++ b/include/i3/ipc.h @@ -38,6 +38,8 @@ /** Requests the tree layout from i3 */ #define I3_IPC_MESSAGE_TYPE_GET_TREE 4 +/** Request the current defined marks from i3 */ +#define I3_IPC_MESSAGE_TYPE_GET_MARKS 5 /* * Messages from i3 to clients @@ -59,6 +61,8 @@ /** Tree reply type */ #define I3_IPC_REPLY_TYPE_TREE 4 +/** Marks reply type*/ +#define I3_IPC_REPLY_TYPE_MARKS 5 /* * Events from i3 to clients. Events have the first bit set high. diff --git a/src/ipc.c b/src/ipc.c index d798ffa0..d7b5ac70 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -203,6 +203,11 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { ystr("urgent"); y(bool, con->urgent); + if (con->mark != NULL) { + ystr("mark"); + ystr(con->mark); + } + ystr("focused"); y(bool, (con == focused)); @@ -333,6 +338,7 @@ IPC_HANDLER(tree) { y(free); } + /* * Formats the reply message for a GET_WORKSPACES request and sends it to the * client @@ -463,6 +469,34 @@ IPC_HANDLER(get_outputs) { y(free); } +/* + * Formats the reply message for a GET_MARKS request and sends it to the + * client + * + */ +IPC_HANDLER(get_marks) { +#if YAJL_MAJOR >= 2 + yajl_gen gen = yajl_gen_alloc(NULL); +#else + yajl_gen gen = yajl_gen_alloc(NULL, NULL); +#endif + y(array_open); + + Con *con; + TAILQ_FOREACH(con, &all_cons, all_cons) + if (con->mark != NULL) + ystr(con->mark); + + y(array_close); + + const unsigned char *payload; + unsigned int length; + y(get_buf, &payload, &length); + + ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_MARKS, length); + y(free); +} + /* * Callback for the YAJL parser (will be called when a string is parsed). * @@ -550,12 +584,13 @@ IPC_HANDLER(subscribe) { /* The index of each callback function corresponds to the numeric * value of the message type (see include/i3/ipc.h) */ -handler_t handlers[5] = { +handler_t handlers[6] = { handle_command, handle_get_workspaces, handle_subscribe, handle_get_outputs, - handle_tree + handle_tree, + handle_get_marks }; /* diff --git a/src/load_layout.c b/src/load_layout.c index b61a0e5c..37322c4e 100644 --- a/src/load_layout.c +++ b/src/load_layout.c @@ -146,6 +146,10 @@ static int json_string(void *ctx, const unsigned char *val, unsigned int len) { json_node->layout = L_OUTPUT; else LOG("Unhandled \"layout\": %s\n", buf); free(buf); + } else if (strcasecmp(last_key, "mark") == 0) { + char *buf = NULL; + asprintf(&buf, "%.*s", (int)len, val); + json_node->mark = buf; } } return 1; diff --git a/testcases/t/73-get-marks.t b/testcases/t/73-get-marks.t new file mode 100644 index 00000000..86481747 --- /dev/null +++ b/testcases/t/73-get-marks.t @@ -0,0 +1,63 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# checks if the IPC message type get_marks works correctly +# +use i3test; + +# TODO: this will be available in AnyEvent::I3 soon +sub get_marks { + my $i3 = i3(get_socket_path()); + $i3->connect->recv; + my $cv = AnyEvent->condvar; + my $msg = $i3->message(5); + my $t; + $msg->cb(sub { + my ($_cv) = @_; + $cv->send($_cv->recv); + }); + $t = AnyEvent->timer(after => 2, cb => sub { + $cv->croak('timeout while waiting for the marks'); + }); + return $cv->recv; +} + +############################################################## +# 1: check that get_marks returns no marks yet +############################################################## + +my $tmp = fresh_workspace; + +my $marks = get_marks(); +cmp_deeply($marks, [], 'no marks set so far'); + +############################################################## +# 2: check that setting a mark is reflected in the get_marks reply +############################################################## + +cmd 'open'; +cmd 'mark foo'; + +cmp_deeply(get_marks(), [ 'foo' ], 'mark foo set'); + +############################################################## +# 3: check that the mark is gone after killing the container +############################################################## + +cmd 'kill'; + +cmp_deeply(get_marks(), [ ], 'mark gone'); + +############################################################## +# 4: check that duplicate marks are included twice in the get_marks reply +############################################################## + +cmd 'open'; +cmd 'mark bar'; + +cmd 'open'; +cmd 'mark bar'; + +cmp_deeply(get_marks(), [ 'bar', 'bar' ], 'duplicate mark found twice'); + +done_testing;