ipc: implement GET_VERSION to find out the i3 version

This is useful for third-party scripts which require certain features
and want to error out cleanly when they are run with an old i3 version.

Additionally, i3 --version might be different from what’s actually
running (an old version of the binary), so i3-msg -t get_version will be
the best way to figure out the i3 version you are actually running from
this commit on.
next
Michael Stapelberg 2012-08-05 14:29:19 +02:00
parent f80b877c6b
commit 78f5f2204d
7 changed files with 122 additions and 6 deletions

View File

@ -23,6 +23,12 @@ else
VERSION := ${I3_VERSION} VERSION := ${I3_VERSION}
endif endif
MAJOR_VERSION := $(shell echo ${VERSION} | cut -d '.' -f 1)
MINOR_VERSION := $(shell echo ${VERSION} | cut -d '.' -f 2)
PATCH_VERSION := $(shell echo ${VERSION} | cut -d '.' -f 3)
ifeq (${PATCH_VERSION},)
PATCH_VERSION := 0
endif
## Generic flags ## Generic flags
@ -46,6 +52,9 @@ I3_CFLAGS += -Wunused-value
I3_CFLAGS += -Iinclude I3_CFLAGS += -Iinclude
I3_CPPFLAGS = -DI3_VERSION=\"${I3_VERSION}\" I3_CPPFLAGS = -DI3_VERSION=\"${I3_VERSION}\"
I3_CPPFLAGS += -DMAJOR_VERSION=${MAJOR_VERSION}
I3_CPPFLAGS += -DMINOR_VERSION=${MINOR_VERSION}
I3_CPPFLAGS += -DPATCH_VERSION=${PATCH_VERSION}
I3_CPPFLAGS += -DSYSCONFDIR=\"${SYSCONFDIR}\" I3_CPPFLAGS += -DSYSCONFDIR=\"${SYSCONFDIR}\"

View File

@ -70,6 +70,9 @@ GET_BAR_CONFIG (6)::
Gets the configuration (as JSON map) of the workspace bar with the Gets the configuration (as JSON map) of the workspace bar with the
given ID. If no ID is provided, an array with all configured bar IDs is given ID. If no ID is provided, an array with all configured bar IDs is
returned instead. returned instead.
GET_VERSION (7)::
Gets the version of i3. The reply will be a JSON-encoded dictionary
with the major, minor, patch and human-readable version.
So, a typical message could look like this: So, a typical message could look like this:
-------------------------------------------------- --------------------------------------------------
@ -125,6 +128,8 @@ MARKS (5)::
Reply to the GET_MARKS message. Reply to the GET_MARKS message.
BAR_CONFIG (6):: BAR_CONFIG (6)::
Reply to the GET_BAR_CONFIG message. Reply to the GET_BAR_CONFIG message.
VERSION (7)::
Reply to the GET_VERSION message.
=== COMMAND reply === COMMAND reply
@ -534,6 +539,35 @@ urgent_workspace_text/urgent_workspace_bar::
} }
-------------- --------------
=== Version reply
The reply consists of a single JSON dictionary with the following keys:
major (integer)::
The major version of i3, such as +4+.
minor (integer)::
The minor version of i3, such as +2+. Changes in the IPC interface (new
features) will only occur with new minor (or major) releases. However,
bugfixes might be introduced in patch releases, too.
patch (integer)::
The patch version of i3, such as +1+ (when the complete version is
+4.2.1+).
human_readable (string)::
A human-readable version of i3 containing the precise git version,
build date and branch name. When you need to display the i3 version to
your users, use the human-readable version whenever possible (since
this is what +i3 --version+ displays, too).
*Example:*
-------------------
{
"human_readable" : "4.2-169-gf80b877 (2012-08-05, branch \"next\")",
"minor" : 2,
"patch" : 0,
"major" : 4
}
-------------------
== Events == Events
[[events]] [[events]]

View File

@ -2,7 +2,7 @@
* vim:ts=4:sw=4:expandtab * vim:ts=4:sw=4:expandtab
* *
* i3 - an improved dynamic tiling window manager * i3 - an improved dynamic tiling window manager
* © 2009-2010 Michael Stapelberg and contributors (see also: LICENSE) * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
* *
* i3-msg/main.c: Utility which sends messages to a running i3-instance using * i3-msg/main.c: Utility which sends messages to a running i3-instance using
* IPC via UNIX domain sockets. * IPC via UNIX domain sockets.
@ -73,9 +73,11 @@ int main(int argc, char *argv[]) {
message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS; message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS;
else if (strcasecmp(optarg, "get_bar_config") == 0) else if (strcasecmp(optarg, "get_bar_config") == 0)
message_type = I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG; message_type = I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG;
else if (strcasecmp(optarg, "get_version") == 0)
message_type = I3_IPC_MESSAGE_TYPE_GET_VERSION;
else { else {
printf("Unknown message type\n"); printf("Unknown message type\n");
printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config\n"); printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config, get_version\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} else if (o == 'q') { } else if (o == 'q') {

View File

@ -2,7 +2,7 @@
* vim:ts=4:sw=4:expandtab * vim:ts=4:sw=4:expandtab
* *
* i3 - an improved dynamic tiling window manager * i3 - an improved dynamic tiling window manager
* © 2009-2010 Michael Stapelberg and contributors (see also: LICENSE) * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
* *
* This public header defines the different constants and message types to use * This public header defines the different constants and message types to use
* for the IPC interface to i3 (see docs/ipc for more information). * for the IPC interface to i3 (see docs/ipc for more information).
@ -40,6 +40,9 @@
/** Request the configuration for a specific 'bar' */ /** Request the configuration for a specific 'bar' */
#define I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG 6 #define I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG 6
/** Request the i3 version */
#define I3_IPC_MESSAGE_TYPE_GET_VERSION 7
/* /*
* Messages from i3 to clients * Messages from i3 to clients
* *
@ -66,6 +69,9 @@
/** Bar config reply type */ /** Bar config reply type */
#define I3_IPC_REPLY_TYPE_BAR_CONFIG 6 #define I3_IPC_REPLY_TYPE_BAR_CONFIG 6
/** i3 version reply type */
#define I3_IPC_REPLY_TYPE_VERSION 7
/* /*
* 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

@ -1,7 +1,7 @@
i3-msg(1) i3-msg(1)
========= =========
Michael Stapelberg <michael+i3@stapelberg.de> Michael Stapelberg <michael@i3wm.org>
v4.2, January 2012 v4.2, August 2012
== NAME == NAME
@ -38,6 +38,9 @@ get_bar_config::
Gets the configuration (as JSON map) of the workspace bar with the given ID. If Gets the configuration (as JSON map) of the workspace bar with the given ID. If
no ID is provided, an array with all configured bar IDs is returned instead. no ID is provided, an array with all configured bar IDs is returned instead.
get_version::
Gets the version of i3. The reply will be a JSON-encoded dictionary with the
major, minor, patch and human-readable version.
== DESCRIPTION == DESCRIPTION

View File

@ -536,6 +536,44 @@ IPC_HANDLER(get_marks) {
y(free); y(free);
} }
/*
* Returns the version of i3
*
*/
IPC_HANDLER(get_version) {
#if YAJL_MAJOR >= 2
yajl_gen gen = yajl_gen_alloc(NULL);
#else
yajl_gen gen = yajl_gen_alloc(NULL, NULL);
#endif
y(map_open);
ystr("major");
y(integer, MAJOR_VERSION);
ystr("minor");
y(integer, MINOR_VERSION);
ystr("patch");
y(integer, PATCH_VERSION);
ystr("human_readable");
ystr(I3_VERSION);
y(map_close);
const unsigned char *payload;
#if YAJL_MAJOR >= 2
size_t length;
#else
unsigned int length;
#endif
y(get_buf, &payload, &length);
ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_VERSION, payload);
y(free);
}
/* /*
* Formats the reply message for a GET_BAR_CONFIG request and sends it to the * Formats the reply message for a GET_BAR_CONFIG request and sends it to the
* client. * client.
@ -792,7 +830,7 @@ 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[7] = { handler_t handlers[8] = {
handle_command, handle_command,
handle_get_workspaces, handle_get_workspaces,
handle_subscribe, handle_subscribe,
@ -800,6 +838,7 @@ handler_t handlers[7] = {
handle_tree, handle_tree,
handle_get_marks, handle_get_marks,
handle_get_bar_config, handle_get_bar_config,
handle_get_version,
}; };
/* /*

View File

@ -0,0 +1,23 @@
#!perl
# vim:ts=4:sw=4:expandtab
# Verifies that we can get the version number of i3 via IPC.
use i3test;
my $i3 = i3(get_socket_path());
$i3->connect->recv;
# We explicitly send the version message because AnyEvent::I3s 'version' sugar
# method has a fallback which tries to parse the version number from i3
# --version for older versions, and we want to avoid using that.
my $version = $i3->message(7, "")->recv;
# We need to change this when the major version changes (but we need to touch a
# lot of changes then anyways).
is($version->{major}, 4, 'major version is 4');
cmp_ok($version->{minor}, '>', 0, 'minor version > 0');
is(int($version->{minor}), $version->{minor}, 'minor version is an integer');
is(int($version->{patch}), $version->{patch}, 'patch version is an integer');
like($version->{human_readable}, qr/branch/, 'human readable version contains branch name');
done_testing;