Include workspace con in workspace event

Send the affected workspace in the "current" property for each workspace
event for any type of workspace event that affects a particular
workspace.

fixes #1411
next
Tony Crisci 2014-12-19 23:43:47 -05:00 committed by Michael Stapelberg
parent 04fa40d3e5
commit 823b46a544
9 changed files with 90 additions and 41 deletions

View File

@ -668,15 +668,16 @@ if ($is_event) {
This event consists of a single serialized map containing a property
+change (string)+ which indicates the type of the change ("focus", "init",
"empty", "urgent").
"empty", "urgent"). A +current (object)+ property will be present with the
affected workspace whenever the type of event affects a workspace (otherwise,
it will be +null).
Moreover, when the change is "focus", an +old (object)+ and a +current
(object)+ properties will be present with the previous and current
workspace respectively. When the first switch occurs (when i3 focuses
the workspace visible at the beginning) there is no previous
workspace, and the +old+ property will be set to +null+. Also note
that if the previous is empty it will get destroyed when switching,
but will still be present in the "old" property.
When the change is "focus", an +old (object)+ property will be present with the
previous workspace. When the first switch occurs (when i3 focuses the
workspace visible at the beginning) there is no previous workspace, and the
+old+ property will be set to +null+. Also note that if the previous is empty
it will get destroyed when switching, but will still be present in the "old"
property.
*Example:*
---------------------

View File

@ -89,11 +89,17 @@ void ipc_shutdown(void);
void dump_node(yajl_gen gen, Con *con, bool inplace_restart);
/**
* For the workspace "focus" event we send, along the usual "change" field,
* also the current and previous workspace, in "current" and "old"
* respectively.
* Generates a json workspace event. Returns a dynamically allocated yajl
* generator. Free with yajl_gen_free().
*/
void ipc_send_workspace_focus_event(Con *current, Con *old);
yajl_gen ipc_marshal_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 in "current". For focus events, we send the
* previously focused workspace in "old".
*/
void ipc_send_workspace_event(const char *change, Con *current, Con *old);
/**
* For the window events we send, along the usual "change" field,

View File

@ -944,7 +944,7 @@ void cmd_append_layout(I3_CMD, char *path) {
restore_open_placeholder_windows(parent);
if (content == JSON_CONTENT_WORKSPACE)
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"restored\"}");
ipc_send_workspace_event("restored", parent, NULL);
cmd_output->needs_tree_render = true;
}
@ -1313,7 +1313,7 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) {
create_workspace_on_output(current_output, ws->parent);
/* notify the IPC listeners */
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
ipc_send_workspace_event("init", ws, NULL);
}
DLOG("Detaching\n");
@ -1334,7 +1334,7 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) {
TAILQ_FOREACH(floating_con, &(ws->floating_head), floating_windows)
floating_fix_coordinates(floating_con, &(old_content->rect), &(content->rect));
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"move\"}");
ipc_send_workspace_event("move", ws, NULL);
if (workspace_was_visible) {
/* Focus the moved workspace on the destination output. */
workspace_show(ws);
@ -1761,7 +1761,7 @@ void cmd_reload(I3_CMD) {
load_configuration(conn, NULL, true);
x_set_i3_atoms();
/* Send an IPC event just in case the ws names have changed */
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"reload\"}");
ipc_send_workspace_event("reload", NULL, NULL);
/* Send an update event for the barconfig just in case it has changed */
update_barconfig();
@ -2040,7 +2040,7 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
cmd_output->needs_tree_render = true;
ysuccess(true);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"rename\"}");
ipc_send_workspace_event("rename", workspace, NULL);
ewmh_update_desktop_names();
ewmh_update_desktop_viewport();
ewmh_update_current_desktop();

View File

@ -12,6 +12,7 @@
*
*/
#include "all.h"
#include "yajl_utils.h"
static void con_on_remove_child(Con *con);
@ -1435,8 +1436,15 @@ static void con_on_remove_child(Con *con) {
if (con->type == CT_WORKSPACE) {
if (TAILQ_EMPTY(&(con->focus_head)) && !workspace_is_visible(con)) {
LOG("Closing old workspace (%p / %s), it is empty\n", con, con->name);
yajl_gen gen = ipc_marshal_workspace_event("empty", con, NULL);
tree_close(con, DONT_KILL_WINDOW, false, false);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}");
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
y(free);
}
return;
}

View File

@ -1120,21 +1120,23 @@ int ipc_create_socket(const char *filename) {
}
/*
* For the workspace "focus" event we send, along the usual "change" field,
* also the current and previous workspace, in "current" and "old"
* respectively.
* Generates a json workspace event. Returns a dynamically allocated yajl
* generator. Free with yajl_gen_free().
*/
void ipc_send_workspace_focus_event(Con *current, Con *old) {
yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old) {
setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc();
y(map_open);
ystr("change");
ystr("focus");
ystr(change);
ystr("current");
dump_node(gen, current, false);
if (current == NULL)
y(null);
else
dump_node(gen, current, false);
ystr("old");
if (old == NULL)
@ -1144,13 +1146,26 @@ void ipc_send_workspace_focus_event(Con *current, Con *old) {
y(map_close);
setlocale(LC_NUMERIC, "");
return gen;
}
/*
* For the workspace events we send, along with the usual "change" field, also
* the workspace container in "current". For focus events, we send the
* previously focused workspace in "old".
*/
void ipc_send_workspace_event(const char *change, Con *current, Con *old) {
yajl_gen gen = ipc_marshal_workspace_event(change, current, old);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
y(free);
setlocale(LC_NUMERIC, "");
}
/**

View File

@ -128,7 +128,7 @@ static void move_to_output_directed(Con *con, direction_t direction) {
tree_flatten(croot);
ipc_send_workspace_focus_event(ws, old_ws);
ipc_send_workspace_event("focus", ws, old_ws);
}
/*

View File

@ -11,6 +11,7 @@
*
*/
#include "all.h"
#include "yajl_utils.h"
/* Stores a copy of the name of the last used workspace for the workspace
* back-and-forth switching. */
@ -91,7 +92,7 @@ Con *workspace_get(const char *num, bool *created) {
con_attach(workspace, content, false);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
ipc_send_workspace_event("init", workspace, NULL);
ewmh_update_number_of_desktops();
ewmh_update_desktop_names();
ewmh_update_desktop_viewport();
@ -409,7 +410,7 @@ static void _workspace_show(Con *workspace) {
} else
con_focus(next);
ipc_send_workspace_focus_event(workspace, current);
ipc_send_workspace_event("focus", workspace, current);
DLOG("old = %p / %s\n", old, (old ? old->name : "(null)"));
/* Close old workspace if necessary. This must be done *after* doing
@ -421,8 +422,16 @@ static void _workspace_show(Con *workspace) {
/* check if this workspace is currently visible */
if (!workspace_is_visible(old)) {
LOG("Closing old workspace (%p / %s), it is empty\n", old, old->name);
yajl_gen gen = ipc_marshal_workspace_event("empty", old, NULL);
tree_close(old, DONT_KILL_WINDOW, false, false);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}");
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
y(free);
ewmh_update_number_of_desktops();
ewmh_update_desktop_names();
ewmh_update_desktop_viewport();
@ -766,7 +775,7 @@ void workspace_update_urgent_flag(Con *ws) {
DLOG("Workspace urgency flag changed from %d to %d\n", old_flag, ws->urgent);
if (old_flag != ws->urgent)
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"urgent\"}");
ipc_send_workspace_event("urgent", ws, NULL);
}
/*

View File

@ -23,7 +23,7 @@ $i3->connect()->recv;
# Workspaces requests and events
################################
my $focused = get_ws(focused_ws());
my $old_ws = get_ws(focused_ws());
# Events
@ -36,15 +36,11 @@ $i3->subscribe({
workspace => sub {
my ($event) = @_;
if ($event->{change} eq 'init') {
$init->send(1);
$init->send($event);
} elsif ($event->{change} eq 'focus') {
# Check that we have the old and new workspace
$focus->send(
$event->{current}->{name} == '2' &&
$event->{old}->{name} == $focused->{name}
);
$focus->send($event);
} elsif ($event->{change} eq 'empty') {
$empty->send(1);
$empty->send($event);
}
}
})->recv;
@ -61,8 +57,20 @@ $t = AnyEvent->timer(
}
);
ok($init->recv, 'Workspace "init" event received');
ok($focus->recv, 'Workspace "focus" event received');
ok($empty->recv, 'Workspace "empty" event received');
my $init_event = $init->recv;
my $focus_event = $focus->recv;
my $empty_event = $empty->recv;
my $current_ws = get_ws(focused_ws());
ok($init_event, 'workspace "init" event received');
is($init_event->{current}->{id}, $current_ws->{id}, 'the "current" property should contain the initted workspace con');
ok($focus_event, 'workspace "focus" event received');
is($focus_event->{current}->{id}, $current_ws->{id}, 'the "current" property should contain the focused workspace con');
is($focus_event->{old}->{id}, $old_ws->{id}, 'the "old" property should contain the workspace con that was focused last');
ok($empty_event, 'workspace "empty" event received');
is($empty_event->{current}->{id}, $old_ws->{id}, 'the "current" property should contain the emptied workspace con');
done_testing;

View File

@ -50,6 +50,7 @@ subtest 'Workspace empty event upon switch', sub {
my $event = $cond->recv;
is($event->{change}, 'empty', '"Empty" event received upon workspace switch');
is($event->{current}->{name}, $ws1, '"current" property should be set to the workspace con');
};
################################################################################
@ -116,6 +117,7 @@ subtest 'Workspace empty event upon window close', sub {
my $event = $cond->recv;
is($event->{change}, 'empty', '"Empty" event received upon window close');
is($event->{current}->{name}, $ws1, '"current" property should be set to the workspace con');
};
}