diff --git a/include/ipc.h b/include/ipc.h index ef50ba86..dfb12b9b 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -82,4 +82,11 @@ 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. + */ +void ipc_send_workspace_focus_event(Con *current, Con *old); + #endif diff --git a/src/ipc.c b/src/ipc.c index a928dba9..4247ca5c 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -961,3 +961,37 @@ int ipc_create_socket(const char *filename) { current_socketpath = resolved; return sockfd; } + +/* + * For the workspace "focus" event we send, along the usual "change" field, + * also the current and previous workspace, in "current" and "old" + * respectively. + */ +void ipc_send_workspace_focus_event(Con *current, Con *old) { + setlocale(LC_NUMERIC, "C"); + yajl_gen gen = ygenalloc(); + + y(map_open); + + ystr("change"); + ystr("focus"); + + ystr("current"); + dump_node(gen, current, false); + + ystr("old"); + if (old == NULL) + y(null); + else + dump_node(gen, old, false); + + y(map_close); + + 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, ""); +} diff --git a/src/move.c b/src/move.c index 0b3ab660..0c67650c 100644 --- a/src/move.c +++ b/src/move.c @@ -99,6 +99,7 @@ static void attach_to_workspace(Con *con, Con *ws, direction_t direction) { * */ static void move_to_output_directed(Con *con, direction_t direction) { + Con *old_ws = con_get_workspace(con); Con *current_output_con = con_get_output(con); Output *current_output = get_output_by_name(current_output_con->name); Output *output = get_output_next(direction, current_output, CLOSEST_OUTPUT); @@ -117,6 +118,16 @@ static void move_to_output_directed(Con *con, direction_t direction) { } attach_to_workspace(con, ws, direction); + + /* fix the focus stack */ + con_focus(con); + + /* force re-painting the indicators */ + FREE(con->deco_render_params); + + tree_flatten(croot); + + ipc_send_workspace_focus_event(ws, old_ws); } /* @@ -137,7 +148,7 @@ void tree_move(int direction) { if (con->parent->type == CT_WORKSPACE && con_num_children(con->parent) == 1) { /* This is the only con on this workspace */ move_to_output_directed(con, direction); - goto end; + return; } orientation_t o = (direction == D_LEFT || direction == D_RIGHT ? HORIZ : VERT); @@ -191,7 +202,7 @@ void tree_move(int direction) { /* If we couldn't find a place to move it on this workspace, * try to move it to a workspace on a different output */ move_to_output_directed(con, direction); - goto end; + return; } /* If there was no con with which we could swap the current one, diff --git a/src/workspace.c b/src/workspace.c index 3f70ced7..670322a9 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -11,9 +11,6 @@ * */ #include "all.h" -#include "yajl_utils.h" - -#include /* Stores a copy of the name of the last used workspace for the workspace * back-and-forth switching. */ @@ -335,39 +332,6 @@ static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents FREE(con->urgency_timer); } -/* - * For the "focus" event we send, along the usual "change" field, also the - * current and previous workspace, in "current" and "old" respectively. - */ -static void ipc_send_workspace_focus_event(Con *current, Con *old) { - setlocale(LC_NUMERIC, "C"); - yajl_gen gen = ygenalloc(); - - y(map_open); - - ystr("change"); - ystr("focus"); - - ystr("current"); - dump_node(gen, current, false); - - ystr("old"); - if (old == NULL) - y(null); - else - dump_node(gen, old, false); - - y(map_close); - - 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, ""); -} - static void _workspace_show(Con *workspace) { Con *current, *old = NULL; diff --git a/testcases/t/517-regress-move-direction-ipc.t b/testcases/t/517-regress-move-direction-ipc.t new file mode 100644 index 00000000..45088c56 --- /dev/null +++ b/testcases/t/517-regress-move-direction-ipc.t @@ -0,0 +1,79 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Make sure the command `move ` properly sends the workspace focus +# ipc event required for i3bar to be properly updated and redrawn. +# +# Bug still in: 4.6-195-g34232b8 +use i3test i3_autostart => 0; + +my $config = <connect()->recv; + +# subscribe to the 'focus' ipc event +my $focus = AnyEvent->condvar; +$i3->subscribe({ + workspace => sub { + my ($event) = @_; + if ($event->{change} eq 'focus') { + $focus->send($event); + } + } +})->recv; + +# give up after 0.5 seconds +my $timer = AnyEvent->timer( + after => 0.5, + cb => sub { + $focus->send(0); + } +); + +# open two windows on the left output +cmd 'workspace ws-left'; +open_window; +open_window; + +# move a window over to the right output +cmd 'move right'; +my $event = $focus->recv; + +ok($event, 'moving from workspace with two windows triggered focus ipc event'); +is($event->{current}->{name}, 'ws-right', 'focus event gave the right workspace'); +is(@{$event->{current}->{nodes}}, 1, 'focus event gave the right number of windows on the workspace'); + +# reset and try again +$focus = AnyEvent->condvar; +cmd 'workspace ws-left; move right'; +$event = $focus->recv; +ok($event, 'moving from workspace with one window triggered focus ipc event'); +is($event->{current}->{name}, 'ws-right', 'focus event gave the right workspace'); +is(@{$event->{current}->{nodes}}, 2, 'focus event gave the right number of windows on the workspace'); + +exit_gracefully($pid); + +done_testing;