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.
This commit is contained in:
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}
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
@ -46,6 +52,9 @@ I3_CFLAGS += -Wunused-value
I3_CFLAGS += -Iinclude
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}\"

View File

@ -70,6 +70,9 @@ GET_BAR_CONFIG (6)::
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.
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:
--------------------------------------------------
@ -125,6 +128,8 @@ MARKS (5)::
Reply to the GET_MARKS message.
BAR_CONFIG (6)::
Reply to the GET_BAR_CONFIG message.
VERSION (7)::
Reply to the GET_VERSION message.
=== 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]]

View File

@ -2,7 +2,7 @@
* vim:ts=4:sw=4:expandtab
*
* 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
* IPC via UNIX domain sockets.
@ -73,9 +73,11 @@ int main(int argc, char *argv[]) {
message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS;
else if (strcasecmp(optarg, "get_bar_config") == 0)
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 {
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);
}
} else if (o == 'q') {

View File

@ -2,7 +2,7 @@
* vim:ts=4:sw=4:expandtab
*
* 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
* for the IPC interface to i3 (see docs/ipc for more information).
@ -40,6 +40,9 @@
/** Request the configuration for a specific 'bar' */
#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
*
@ -66,6 +69,9 @@
/** Bar config reply type */
#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.
*

View File

@ -1,7 +1,7 @@
i3-msg(1)
=========
Michael Stapelberg <michael+i3@stapelberg.de>
v4.2, January 2012
Michael Stapelberg <michael@i3wm.org>
v4.2, August 2012
== NAME
@ -38,6 +38,9 @@ get_bar_config::
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.
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

View File

@ -536,6 +536,44 @@ IPC_HANDLER(get_marks) {
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
* client.
@ -792,7 +830,7 @@ 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[7] = {
handler_t handlers[8] = {
handle_command,
handle_get_workspaces,
handle_subscribe,
@ -800,6 +838,7 @@ handler_t handlers[7] = {
handle_tree,
handle_get_marks,
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;