diff --git a/src/commands.c b/src/commands.c index fd81e65c..bef0989f 100644 --- a/src/commands.c +++ b/src/commands.c @@ -185,9 +185,26 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t continue; new_col = cols; + DLOG("Fixed it to new col %d\n", new_col); + break; + } + } + + if (t_ws->table[new_col][new_row]->currently_focused == NULL) { + DLOG("Cell still empty, checking for full cols above spanned width...\n"); + DLOG("new_col = %d\n", new_col); + DLOG("colspan = %d\n", container->colspan); + for (int cols = new_col; + cols < container->col + container->colspan; + cols += t_ws->table[cols][new_row]->colspan) { + DLOG("candidate: new_row = %d, cols = %d\n", new_row, cols); + if (t_ws->table[cols][new_row]->currently_focused == NULL) + continue; + + new_col = cols; + DLOG("Fixed it to new col %d\n", new_col); break; } - DLOG("Fixed it to new col %d\n", new_col); } } else if (direction == D_LEFT || direction == D_RIGHT) { if (direction == D_RIGHT && cell_exists(t_ws, current_col+1, current_row)) @@ -227,10 +244,28 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t continue; new_row = rows; + DLOG("Fixed it to new row %d\n", new_row); break; } - DLOG("Fixed it to new row %d\n", new_row); } + + if (t_ws->table[new_col][new_row]->currently_focused == NULL) { + DLOG("Cell still empty, checking for full cols near full spanned height...\n"); + DLOG("new_row = %d\n", new_row); + DLOG("rowspan = %d\n", container->rowspan); + for (int rows = new_row; + rows < container->row + container->rowspan; + rows += t_ws->table[new_col][rows]->rowspan) { + DLOG("candidate: new_col = %d, rows = %d\n", new_col, rows); + if (t_ws->table[new_col][rows]->currently_focused == NULL) + continue; + + new_row = rows; + DLOG("Fixed it to new col %d\n", new_row); + break; + } + } + } else { ELOG("direction unhandled\n"); return; diff --git a/testcases/t/06-focus.t b/testcases/t/06-focus.t index efdf5749..5ca3e062 100644 --- a/testcases/t/06-focus.t +++ b/testcases/t/06-focus.t @@ -4,7 +4,7 @@ # the workspace to be empty). # TODO: skip it by default? -use Test::More tests => 8; +use Test::More tests => 14; use Test::Deep; use X11::XCB qw(:all); use Data::Dumper; @@ -76,4 +76,50 @@ is($focus, $bottom->id, "Bottom window focused (wrapping to the top works)"); $focus = focus_after("j"); is($focus, $top->id, "Top window focused (wrapping to the bottom works)"); +############################################### +# Test focus with empty containers and colspan +############################################### + +# Switch to the 10. workspace +$sock->write(i3test::format_ipc_command("10")); +sleep 0.25; + +$top = i3test::open_standard_window($x); +$bottom = i3test::open_standard_window($x); +sleep 0.25; + +$focus = focus_after("mj"); +$focus = focus_after("mh"); +$focus = focus_after("k"); +is($focus, $bottom->id, "Selecting top window without snapping doesn't work"); + +$focus = focus_after("sl"); +is($focus, $bottom->id, "Bottom window focused"); + +$focus = focus_after("k"); +is($focus, $top->id, "Top window focused"); + +# Same thing, but left/right instead of top/bottom + +# Switch to the 11. workspace +$sock->write(i3test::format_ipc_command("11")); +sleep 0.25; + +my $left = i3test::open_standard_window($x); +my $right = i3test::open_standard_window($x); +sleep 0.25; + +$focus = focus_after("ml"); +$focus = focus_after("h"); +$focus = focus_after("mk"); +$focus = focus_after("l"); +is($focus, $left->id, "Selecting right window without snapping doesn't work"); + +$focus = focus_after("sj"); +is($focus, $left->id, "left window focused"); + +$focus = focus_after("l"); +is($focus, $right->id, "right window focused"); + + diag( "Testing i3, Perl $], $^X" );