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
This commit is contained in:
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 This event consists of a single serialized map containing a property
+change (string)+ which indicates the type of the change ("focus", "init", +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 When the change is "focus", an +old (object)+ property will be present with the
(object)+ properties will be present with the previous and current previous workspace. When the first switch occurs (when i3 focuses the
workspace respectively. When the first switch occurs (when i3 focuses workspace visible at the beginning) there is no previous workspace, and the
the workspace visible at the beginning) there is no previous +old+ property will be set to +null+. Also note that if the previous is empty
workspace, and the +old+ property will be set to +null+. Also note it will get destroyed when switching, but will still be present in the "old"
that if the previous is empty it will get destroyed when switching, property.
but will still be present in the "old" property.
*Example:* *Example:*
--------------------- ---------------------

View File

@ -89,11 +89,17 @@ void ipc_shutdown(void);
void dump_node(yajl_gen gen, Con *con, bool inplace_restart); void dump_node(yajl_gen gen, Con *con, bool inplace_restart);
/** /**
* For the workspace "focus" event we send, along the usual "change" field, * Generates a json workspace event. Returns a dynamically allocated yajl
* also the current and previous workspace, in "current" and "old" * generator. Free with yajl_gen_free().
* respectively.
*/ */
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, * 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); restore_open_placeholder_windows(parent);
if (content == JSON_CONTENT_WORKSPACE) 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; 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); create_workspace_on_output(current_output, ws->parent);
/* notify the IPC listeners */ /* notify the IPC listeners */
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}"); ipc_send_workspace_event("init", ws, NULL);
} }
DLOG("Detaching\n"); 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) TAILQ_FOREACH(floating_con, &(ws->floating_head), floating_windows)
floating_fix_coordinates(floating_con, &(old_content->rect), &(content->rect)); 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) { if (workspace_was_visible) {
/* Focus the moved workspace on the destination output. */ /* Focus the moved workspace on the destination output. */
workspace_show(ws); workspace_show(ws);
@ -1761,7 +1761,7 @@ void cmd_reload(I3_CMD) {
load_configuration(conn, NULL, true); load_configuration(conn, NULL, true);
x_set_i3_atoms(); x_set_i3_atoms();
/* Send an IPC event just in case the ws names have changed */ /* 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 */ /* Send an update event for the barconfig just in case it has changed */
update_barconfig(); update_barconfig();
@ -2040,7 +2040,7 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
cmd_output->needs_tree_render = true; cmd_output->needs_tree_render = true;
ysuccess(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_names();
ewmh_update_desktop_viewport(); ewmh_update_desktop_viewport();
ewmh_update_current_desktop(); ewmh_update_current_desktop();

View File

@ -12,6 +12,7 @@
* *
*/ */
#include "all.h" #include "all.h"
#include "yajl_utils.h"
static void con_on_remove_child(Con *con); 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 (con->type == CT_WORKSPACE) {
if (TAILQ_EMPTY(&(con->focus_head)) && !workspace_is_visible(con)) { if (TAILQ_EMPTY(&(con->focus_head)) && !workspace_is_visible(con)) {
LOG("Closing old workspace (%p / %s), it is empty\n", con, con->name); 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); 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; 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, * Generates a json workspace event. Returns a dynamically allocated yajl
* also the current and previous workspace, in "current" and "old" * generator. Free with yajl_gen_free().
* respectively.
*/ */
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"); setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc(); yajl_gen gen = ygenalloc();
y(map_open); y(map_open);
ystr("change"); ystr("change");
ystr("focus"); ystr(change);
ystr("current"); ystr("current");
dump_node(gen, current, false); if (current == NULL)
y(null);
else
dump_node(gen, current, false);
ystr("old"); ystr("old");
if (old == NULL) if (old == NULL)
@ -1144,13 +1146,26 @@ void ipc_send_workspace_focus_event(Con *current, Con *old) {
y(map_close); 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; const unsigned char *payload;
ylength length; ylength length;
y(get_buf, &payload, &length); y(get_buf, &payload, &length);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload); ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
y(free); 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); 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 "all.h"
#include "yajl_utils.h"
/* Stores a copy of the name of the last used workspace for the workspace /* Stores a copy of the name of the last used workspace for the workspace
* back-and-forth switching. */ * back-and-forth switching. */
@ -91,7 +92,7 @@ Con *workspace_get(const char *num, bool *created) {
con_attach(workspace, content, false); 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_number_of_desktops();
ewmh_update_desktop_names(); ewmh_update_desktop_names();
ewmh_update_desktop_viewport(); ewmh_update_desktop_viewport();
@ -409,7 +410,7 @@ static void _workspace_show(Con *workspace) {
} else } else
con_focus(next); 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)")); DLOG("old = %p / %s\n", old, (old ? old->name : "(null)"));
/* Close old workspace if necessary. This must be done *after* doing /* 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 */ /* check if this workspace is currently visible */
if (!workspace_is_visible(old)) { if (!workspace_is_visible(old)) {
LOG("Closing old workspace (%p / %s), it is empty\n", old, old->name); 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); 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_number_of_desktops();
ewmh_update_desktop_names(); ewmh_update_desktop_names();
ewmh_update_desktop_viewport(); 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); DLOG("Workspace urgency flag changed from %d to %d\n", old_flag, ws->urgent);
if (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 # Workspaces requests and events
################################ ################################
my $focused = get_ws(focused_ws()); my $old_ws = get_ws(focused_ws());
# Events # Events
@ -36,15 +36,11 @@ $i3->subscribe({
workspace => sub { workspace => sub {
my ($event) = @_; my ($event) = @_;
if ($event->{change} eq 'init') { if ($event->{change} eq 'init') {
$init->send(1); $init->send($event);
} elsif ($event->{change} eq 'focus') { } elsif ($event->{change} eq 'focus') {
# Check that we have the old and new workspace $focus->send($event);
$focus->send(
$event->{current}->{name} == '2' &&
$event->{old}->{name} == $focused->{name}
);
} elsif ($event->{change} eq 'empty') { } elsif ($event->{change} eq 'empty') {
$empty->send(1); $empty->send($event);
} }
} }
})->recv; })->recv;
@ -61,8 +57,20 @@ $t = AnyEvent->timer(
} }
); );
ok($init->recv, 'Workspace "init" event received'); my $init_event = $init->recv;
ok($focus->recv, 'Workspace "focus" event received'); my $focus_event = $focus->recv;
ok($empty->recv, 'Workspace "empty" event received'); 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; done_testing;

View File

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