ysuccess(true);
}
+/*
+ * Focus a container and disable any other fullscreen container not permitting the focus.
+ *
+ */
+static void cmd_focus_force_focus(Con *con) {
+ /* Disable fullscreen container in workspace with container to be focused. */
+ Con *ws = con_get_workspace(con);
+ Con *fullscreen_on_ws = (focused && focused->fullscreen_mode == CF_GLOBAL) ? focused : con_get_fullscreen_con(ws, CF_OUTPUT);
+ if (fullscreen_on_ws && fullscreen_on_ws != con && !con_has_parent(con, fullscreen_on_ws)) {
+ con_disable_fullscreen(fullscreen_on_ws);
+ }
+ con_focus(con);
+}
+
/*
* Implementation of 'focus tiling|floating|mode_toggle'.
*
(!to_floating && current->type == CT_FLOATING_CON))
continue;
- con_focus(con_descend_focused(current));
+ cmd_focus_force_focus(con_descend_focused(current));
success = true;
break;
}
if (!ws)
continue;
- /* Check the fullscreen focus constraints. */
- if (!con_fullscreen_permits_focusing(current->con)) {
- LOG("Cannot change focus while in fullscreen mode (fullscreen rules).\n");
- ysuccess(false);
- return;
- }
-
/* In case this is a scratchpad window, call scratchpad_show(). */
if (ws == __i3_scratch) {
scratchpad_show(current->con);
* So we focus 'current' to make it the currently focused window of
* the target workspace, then revert focus. */
Con *currently_focused = focused;
- con_focus(current->con);
+ cmd_focus_force_focus(current->con);
con_focus(currently_focused);
/* Now switch to the workspace, then focus */
cmd 'focus child';
is($x->input_focus, $right2->id, 'bottom right window focused again');
-cmd '[id="' . $left->id . '"] focus';
-is($x->input_focus, $right2->id, 'prevented focus change to left window');
-
cmd 'focus up';
is($x->input_focus, $right1->id, 'allowed focus up');
cmd 'focus up';
is($x->input_focus, $right2->id, 'allowed focus wrap (up)');
-cmd '[id="' . $diff_ws->id . '"] focus';
-is($x->input_focus, $right2->id, 'prevented focus change to different ws');
-
################################################################################
# Same tests when we're in non-global fullscreen mode. It should now be possible
# to focus a container in a different workspace.
cmd 'focus child';
is($x->input_focus, $right2->id, 'bottom right window focused again');
-cmd '[id="' . $left->id . '"] focus';
-is($x->input_focus, $right2->id, 'prevented focus change to left window');
-
cmd 'focus up';
is($x->input_focus, $right1->id, 'allowed focus up');
cmd "move to workspace prev";
verify_move(2, 'prevented move to workspace by position');
-# TODO: Tests for "move to output" and "move workspace to output".
+################################################################################
+# Ensure it's possible to focus a window using the focus command despite
+# fullscreen window blocking it. Fullscreen window should lose its fullscreen
+# mode.
+################################################################################
+
+# first & second tiling, focus using id
+kill_all_windows;
+
+$tmp = fresh_workspace;
+my $first = open_window;
+my $second = open_window;
+cmd 'fullscreen';
+is($x->input_focus, $second->id, 'fullscreen window focused');
+is_num_fullscreen($tmp, 1, '1 fullscreen window');
+
+cmd '[id="'. $first->id .'"] focus';
+sync_with_i3;
+
+is($x->input_focus, $first->id, 'correctly focused using id');
+is_num_fullscreen($tmp, 0, 'no fullscreen windows');
+
+# first floating, second tiling, focus using 'focus floating'
+kill_all_windows;
+
+$tmp = fresh_workspace;
+my $first = open_floating_window;
+my $second = open_window;
+cmd 'fullscreen';
+is($x->input_focus, $second->id, 'fullscreen window focused');
+is_num_fullscreen($tmp, 1, '1 fullscreen window');
+
+cmd 'focus floating';
+sync_with_i3;
+
+is($x->input_focus, $first->id, 'correctly focused using focus floating');
+is_num_fullscreen($tmp, 0, 'no fullscreen windows');
+
+# first tiling, second floating, focus using 'focus tiling'
+kill_all_windows;
+
+$tmp = fresh_workspace;
+my $first = open_window;
+my $second = open_floating_window;
+cmd 'fullscreen';
+is($x->input_focus, $second->id, 'fullscreen window focused');
+is_num_fullscreen($tmp, 1, '1 fullscreen window');
+
+cmd 'focus tiling';
+sync_with_i3;
+is($x->input_focus, $first->id, 'correctly focused using focus tiling');
+is_num_fullscreen($tmp, 0, 'no fullscreen windows');
+
+################################################################################
+# When the fullscreen window is in an other workspace it should maintain its
+# fullscreen mode since it's not blocking the window to be focused.
+################################################################################
+
+kill_all_windows;
+
+$tmp = fresh_workspace;
+my $first = open_window;
+
+$tmp2 = fresh_workspace;
+my $second = open_window;
+cmd 'fullscreen';
+is($x->input_focus, $second->id, 'fullscreen window focused');
+is_num_fullscreen($tmp2, 1, '1 fullscreen window');
+
+cmd '[id="'. $first->id .'"] focus';
+sync_with_i3;
+
+is($x->input_focus, $first->id, 'correctly focused using focus id');
+is_num_fullscreen($tmp, 0, 'no fullscreen windows on first workspace');
+is_num_fullscreen($tmp2, 1, 'still one fullscreen window on second workspace');
+
+################################################################################
+# But a global window in another workspace is blocking the window to be focused.
+# Ensure that it loses its fullscreen mode.
+################################################################################
+
+kill_all_windows;
+
+$tmp = fresh_workspace;
+$first = open_window;
+
+$tmp2 = fresh_workspace;
+$second = open_window;
+cmd 'fullscreen global';
+is($x->input_focus, $second->id, 'global window focused');
+is_num_fullscreen($tmp2, 1, '1 fullscreen window');
+
+cmd '[id="'. $first->id .'"] focus';
+sync_with_i3;
+
+is($x->input_focus, $first->id, 'correctly focused using focus id');
+is_num_fullscreen($tmp2, 0, 'no fullscreen windows');
+
+
+# TODO: Tests for "move to output" and "move workspace to output".
done_testing;