]> git.sur5r.net Git - i3/i3/commitdiff
Make 'focus' disable blocking fullscreen windows 2969/head
authorOrestis Floros <orestisf1993@gmail.com>
Sat, 16 Sep 2017 23:20:48 +0000 (02:20 +0300)
committerOrestis Floros <orestisf1993@gmail.com>
Mon, 11 Dec 2017 17:14:33 +0000 (19:14 +0200)
The problem here is that con_fullscreen_permits_focusing() does not
check if there is a blocking fullscreen container in the workspace that
the container to be focused belongs. This makes it possible to focus a
container behind a fullscreen window if it's in an unfocused workspace.

This commit introduces a change in the 'focus' command behaviour. When
focusing a container blocked by a fullscreen container, either CF_OUTPUT
or CF_GLOBAL, the blocking container loses its fullscreen mode and the
target container is focused like normal.

This should not affect directional focus commands: left, right, up,
down, parent, child.

Fixes issue #1819.

src/commands.c
testcases/t/156-fullscreen-focus.t

index 264cd04f63cbd590e0e92fff81ab5829feafde62..162f0892f4105941afe19aa33d2726c997b3c4f4 100644 (file)
@@ -1250,6 +1250,20 @@ void cmd_focus_direction(I3_CMD, const char *direction) {
     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'.
  *
@@ -1274,7 +1288,7 @@ void cmd_focus_window_mode(I3_CMD, const char *window_mode) {
             (!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;
     }
@@ -1341,13 +1355,6 @@ void cmd_focus(I3_CMD) {
         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);
@@ -1371,7 +1378,7 @@ void cmd_focus(I3_CMD) {
          * 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 */
index 7a5e38ca136b36548454c401cb8644f6561a4b40..cfa2405e4b3e124021fcba5f28550c5aba18d74e 100644 (file)
@@ -157,9 +157,6 @@ isnt($x->input_focus, $right2->id, 'bottom right window no longer focused');
 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');
 
@@ -178,9 +175,6 @@ is($x->input_focus, $right1->id, 'allowed focus wrap (down)');
 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.
@@ -202,9 +196,6 @@ isnt($x->input_focus, $right2->id, 'bottom right window no longer focused');
 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');
 
@@ -323,6 +314,105 @@ verify_move(2, 'prevented move to workspace by name');
 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;