Merge branch 'get-marks' into next

This commit is contained in:
Michael Stapelberg 2011-08-09 09:28:06 +02:00
commit eb0a56fad1
6 changed files with 127 additions and 3 deletions

View File

@ -59,6 +59,10 @@ GET_TREE (4)::
Gets the layout tree. i3 uses a tree as data structure which includes 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 every container. The reply will be the JSON-encoded tree (see the reply
section). 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: So, a typical message could look like this:
-------------------------------------------------- --------------------------------------------------
@ -110,6 +114,8 @@ GET_OUTPUTS (3)::
Reply to the GET_OUTPUTS message. Reply to the GET_OUTPUTS message.
GET_TREE (4):: GET_TREE (4)::
Reply to the GET_TREE message. Reply to the GET_TREE message.
GET_MARKS (5)::
Reply to the GET_MARKS message.
=== COMMAND reply === 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 [].
------------------------ ------------------------

View File

@ -180,9 +180,11 @@ int main(int argc, char *argv[]) {
message_type = I3_IPC_MESSAGE_TYPE_GET_OUTPUTS; message_type = I3_IPC_MESSAGE_TYPE_GET_OUTPUTS;
else if (strcasecmp(optarg, "get_tree") == 0) else if (strcasecmp(optarg, "get_tree") == 0)
message_type = I3_IPC_MESSAGE_TYPE_GET_TREE; message_type = I3_IPC_MESSAGE_TYPE_GET_TREE;
else if (strcasecmp(optarg, "get_marks") == 0)
message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS;
else { else {
printf("Unknown message type\n"); 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); exit(EXIT_FAILURE);
} }
} else if (o == 'q') { } else if (o == 'q') {

View File

@ -38,6 +38,8 @@
/** Requests the tree layout from i3 */ /** Requests the tree layout from i3 */
#define I3_IPC_MESSAGE_TYPE_GET_TREE 4 #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 * Messages from i3 to clients
@ -59,6 +61,8 @@
/** Tree reply type */ /** Tree reply type */
#define I3_IPC_REPLY_TYPE_TREE 4 #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. * Events from i3 to clients. Events have the first bit set high.

View File

@ -203,6 +203,11 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
ystr("urgent"); ystr("urgent");
y(bool, con->urgent); y(bool, con->urgent);
if (con->mark != NULL) {
ystr("mark");
ystr(con->mark);
}
ystr("focused"); ystr("focused");
y(bool, (con == focused)); y(bool, (con == focused));
@ -333,6 +338,7 @@ IPC_HANDLER(tree) {
y(free); y(free);
} }
/* /*
* Formats the reply message for a GET_WORKSPACES request and sends it to the * Formats the reply message for a GET_WORKSPACES request and sends it to the
* client * client
@ -463,6 +469,34 @@ IPC_HANDLER(get_outputs) {
y(free); 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). * 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 /* The index of each callback function corresponds to the numeric
* value of the message type (see include/i3/ipc.h) */ * value of the message type (see include/i3/ipc.h) */
handler_t handlers[5] = { handler_t handlers[6] = {
handle_command, handle_command,
handle_get_workspaces, handle_get_workspaces,
handle_subscribe, handle_subscribe,
handle_get_outputs, handle_get_outputs,
handle_tree handle_tree,
handle_get_marks
}; };
/* /*

View File

@ -146,6 +146,10 @@ static int json_string(void *ctx, const unsigned char *val, unsigned int len) {
json_node->layout = L_OUTPUT; json_node->layout = L_OUTPUT;
else LOG("Unhandled \"layout\": %s\n", buf); else LOG("Unhandled \"layout\": %s\n", buf);
free(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; return 1;

View File

@ -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;