]> git.sur5r.net Git - i3/i3/commitdiff
Extend the fullscreen command
authorMats <d912e3@gmail.com>
Sun, 26 Oct 2014 18:33:09 +0000 (19:33 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Wed, 10 Dec 2014 19:42:52 +0000 (20:42 +0100)
Rather than just toggling the fullscreen modes, allow to set them
directly with:

    fullscreen enable|toggle [global]
    fullscreen disable

For compatibility, retain the previous command and its toggling behavior:

    fullscreen [global]

fixes #1120

docs/userguide
i3.config
i3.config.keycodes
include/commands.h
include/con.h
man/i3.man
parser-specs/commands.spec
src/commands.c
src/con.c
testcases/i3-test.config
testcases/t/100-fullscreen.t

index e752ec82f197a95e5bf3dff32c1759d5370ec095..5f00fd6a47f59109000fc111dada66684546ffd6 100644 (file)
@@ -91,7 +91,7 @@ To display a window in fullscreen mode or to go out of fullscreen mode again,
 press +$mod+f+.
 
 There is also a global fullscreen mode in i3 in which the client will span all
-available outputs (the command is +fullscreen global+).
+available outputs (the command is +fullscreen toggle global+).
 
 === Opening other applications
 
@@ -367,7 +367,7 @@ bindcode [--release] [Modifiers+]keycode command
 *Examples*:
 --------------------------------
 # Fullscreen
-bindsym $mod+f fullscreen
+bindsym $mod+f fullscreen toggle
 
 # Restart
 bindsym $mod+Shift+r restart
@@ -1502,9 +1502,13 @@ Use +layout toggle split+, +layout stacking+, +layout tabbed+, +layout splitv+
 or +layout splith+ to change the current container layout to splith/splitv,
 stacking, tabbed layout, splitv or splith, respectively.
 
-To make the current window (!) fullscreen, use +fullscreen+, to make
-it floating (or tiling again) use +floating enable+ respectively +floating disable+
-(or +floating toggle+):
+To make the current window (!) fullscreen, use +fullscreen enable+ (or
++fullscreen enable global+ for the global mode), to leave either fullscreen
+mode use +fullscreen disable+, and to toggle between these two states use
++fullscreen toggle+ (or +fullscreen toggle global+).
+
+Likewise, to make the current window floating (or tiling again) use +floating
+enable+ respectively +floating disable+ (or +floating toggle+):
 
 *Syntax*:
 --------------
@@ -1525,7 +1529,7 @@ bindsym $mod+x layout toggle
 bindsym $mod+x layout toggle all
 
 # Toggle fullscreen
-bindsym $mod+f fullscreen
+bindsym $mod+f fullscreen toggle
 
 # Toggle floating/tiling
 bindsym $mod+t floating toggle
index 30b3f6a86a0703d1143b1731e669e12637281d69..d7e96fe9c01d185da6d007d02d0aff5be9b42ffc 100644 (file)
--- a/i3.config
+++ b/i3.config
@@ -75,7 +75,7 @@ bindsym Mod1+h split h
 bindsym Mod1+v split v
 
 # enter fullscreen mode for the focused container
-bindsym Mod1+f fullscreen
+bindsym Mod1+f fullscreen toggle
 
 # change container layout (stacked, tabbed, toggle split)
 bindsym Mod1+s layout stacking
index 27398515b1de5757b0815ed16434c29ea2b59ef0..93528a54eeafd50f31983a9d98aebc2141fb9f90 100644 (file)
@@ -69,7 +69,7 @@ bindcode $mod+43 split h
 bindcode $mod+55 split v
 
 # enter fullscreen mode for the focused container
-bindcode $mod+41 fullscreen
+bindcode $mod+41 fullscreen toggle
 
 # change container layout (stacked, tabbed, toggle split)
 bindcode $mod+39 layout stacking
index cb687890008c868fa54d62d366f53a2f78deb922..780a9e8eb781893dd3fb69c8642783b98c73e676 100644 (file)
@@ -187,10 +187,10 @@ void cmd_focus_level(I3_CMD, char *level);
 void cmd_focus(I3_CMD);
 
 /**
- * Implementation of 'fullscreen [global]'.
+ * Implementation of 'fullscreen [enable|disable|toggle] [global]'.
  *
  */
-void cmd_fullscreen(I3_CMD, char *fullscreen_mode);
+void cmd_fullscreen(I3_CMD, char *action, char *fullscreen_mode);
 
 /**
  * Implementation of 'move <direction> [<pixels> [px]]'.
index 184bc918c3b415ae75b9304644d4ec1c8280d0db..5d761f684ada5ebe7661fd6b34edbbae57426d45 100644 (file)
@@ -172,6 +172,18 @@ void con_fix_percent(Con *con);
  */
 void con_toggle_fullscreen(Con *con, int fullscreen_mode);
 
+/**
+ * Enables fullscreen mode for the given container, if necessary.
+ *
+ */
+void con_enable_fullscreen(Con *con, fullscreen_mode_t fullscreen_mode);
+
+/**
+ * Disables fullscreen mode for the given container, if necessary.
+ *
+ */
+void con_disable_fullscreen(Con *con);
+
 /**
  * Moves the given container to the currently focused container on the given
  * workspace.
index ea232fcf0069a87e99beea7bbb43a6e1d3da9067..203b42eea26e57ab7379fd180d50c8a4651b6146 100644 (file)
@@ -230,7 +230,7 @@ bindsym Mod1+h split h
 bindsym Mod1+v split v
 
 # enter fullscreen mode for the focused container
-bindsym Mod1+f fullscreen
+bindsym Mod1+f fullscreen toggle
 
 # change container layout (stacked, tabbed, default)
 bindsym Mod1+s layout stacking
index e3da62c91aae2b2ca39c6d19f6163a06b91b3f6b..82348df79c9c47d6b5dc9f352eceaaabb4b5100f 100644 (file)
@@ -156,12 +156,28 @@ state KILL:
   end
       -> call cmd_kill($kill_mode)
 
+# fullscreen enable|toggle [global]
+# fullscreen disable
 # fullscreen [global]
 state FULLSCREEN:
-  fullscreen_mode = 'global'
-      -> call cmd_fullscreen($fullscreen_mode)
+  action = 'disable'
+      -> call cmd_fullscreen($action, "output")
+  action = 'enable', 'toggle'
+      -> FULLSCREEN_MODE
+  action = ''
+      -> FULLSCREEN_COMPAT
+
+state FULLSCREEN_MODE:
+  mode = 'global'
+      -> call cmd_fullscreen($action, $mode)
   end
-      -> call cmd_fullscreen($fullscreen_mode)
+      -> call cmd_fullscreen($action, "output")
+
+state FULLSCREEN_COMPAT:
+  mode = 'global'
+      -> call cmd_fullscreen("toggle", $mode)
+  end
+      -> call cmd_fullscreen("toggle", "output")
 
 # split v|h|vertical|horizontal
 state SPLIT:
index 48df5e3d32e480f6e982bf5a80dedb6850404bee..e87617c97673d97e23ae3c6a48bbc45020513488 100644 (file)
@@ -1598,20 +1598,26 @@ void cmd_focus(I3_CMD) {
 }
 
 /*
- * Implementation of 'fullscreen [global]'.
+ * Implementation of 'fullscreen enable|toggle [global]' and
+ *                   'fullscreen disable'
  *
  */
-void cmd_fullscreen(I3_CMD, char *fullscreen_mode) {
-    if (fullscreen_mode == NULL)
-        fullscreen_mode = "output";
-    DLOG("toggling fullscreen, mode = %s\n", fullscreen_mode);
+void cmd_fullscreen(I3_CMD, char *action, char *fullscreen_mode) {
+    fullscreen_mode_t mode = strcmp(fullscreen_mode, "global") == 0 ? CF_GLOBAL : CF_OUTPUT;
+    DLOG("%s fullscreen, mode = %s\n", action, fullscreen_mode);
     owindow *current;
 
     HANDLE_EMPTY_MATCH;
 
     TAILQ_FOREACH(current, &owindows, owindows) {
         DLOG("matching: %p / %s\n", current->con, current->con->name);
-        con_toggle_fullscreen(current->con, (strcmp(fullscreen_mode, "global") == 0 ? CF_GLOBAL : CF_OUTPUT));
+        if (strcmp(action, "toggle") == 0) {
+            con_toggle_fullscreen(current->con, mode);
+        } else if (strcmp(action, "enable") == 0) {
+            con_enable_fullscreen(current->con, mode);
+        } else if (strcmp(action, "disable") == 0) {
+            con_disable_fullscreen(current->con);
+        }
     }
 
     cmd_output->needs_tree_render = true;
index 6c7b2d963d5d738fddca130ad247641a2f8e66bf..3293a9fd89f940cad06144d5d7f2553b8f362c95 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -565,37 +565,27 @@ void con_fix_percent(Con *con) {
  *
  */
 void con_toggle_fullscreen(Con *con, int fullscreen_mode) {
-    Con *workspace, *fullscreen;
-
     if (con->type == CT_WORKSPACE) {
         DLOG("You cannot make a workspace fullscreen.\n");
         return;
     }
 
     DLOG("toggling fullscreen for %p / %s\n", con, con->name);
-    if (con->fullscreen_mode == CF_NONE) {
-        /* 1: check if there already is a fullscreen con */
-        if (fullscreen_mode == CF_GLOBAL)
-            fullscreen = con_get_fullscreen_con(croot, CF_GLOBAL);
-        else {
-            workspace = con_get_workspace(con);
-            fullscreen = con_get_fullscreen_con(workspace, CF_OUTPUT);
-        }
-        if (fullscreen != NULL) {
-            /* Disable fullscreen for the currently fullscreened
-             * container and enable it for the one the user wants
-             * to have in fullscreen mode. */
-            LOG("Disabling fullscreen for (%p/%s) upon user request\n",
-                fullscreen, fullscreen->name);
-            fullscreen->fullscreen_mode = CF_NONE;
-        }
 
-        /* 2: enable fullscreen */
-        con->fullscreen_mode = fullscreen_mode;
-    } else {
-        /* 1: disable fullscreen */
-        con->fullscreen_mode = CF_NONE;
-    }
+    if (con->fullscreen_mode == CF_NONE)
+        con_enable_fullscreen(con, fullscreen_mode);
+    else
+        con_disable_fullscreen(con);
+}
+
+/*
+ * Sets the specified fullscreen mode for the given container, sends the
+ * “fullscreen_mode” event and changes the XCB fullscreen property of the
+ * container’s window, if any.
+ *
+ */
+static void con_set_fullscreen_mode(Con *con, fullscreen_mode_t fullscreen_mode) {
+    con->fullscreen_mode = fullscreen_mode;
 
     DLOG("mode now: %d\n", con->fullscreen_mode);
 
@@ -618,6 +608,79 @@ void con_toggle_fullscreen(Con *con, int fullscreen_mode) {
                         A__NET_WM_STATE, XCB_ATOM_ATOM, 32, num, values);
 }
 
+/*
+ * Enables fullscreen mode for the given container, if necessary.
+ *
+ * If the container’s mode is already CF_OUTPUT or CF_GLOBAL, the container is
+ * kept fullscreen but its mode is set to CF_GLOBAL and CF_OUTPUT,
+ * respectively.
+ *
+ * Other fullscreen containers will be disabled first, if they hide the new
+ * one.
+ *
+ */
+void con_enable_fullscreen(Con *con, fullscreen_mode_t fullscreen_mode) {
+    if (con->type == CT_WORKSPACE) {
+        DLOG("You cannot make a workspace fullscreen.\n");
+        return;
+    }
+
+    assert(fullscreen_mode == CF_GLOBAL || fullscreen_mode == CF_OUTPUT);
+
+    if (fullscreen_mode == CF_GLOBAL)
+        DLOG("enabling global fullscreen for %p / %s\n", con, con->name);
+    else
+        DLOG("enabling fullscreen for %p / %s\n", con, con->name);
+
+    if (con->fullscreen_mode == fullscreen_mode) {
+        DLOG("fullscreen already enabled for %p / %s\n", con, con->name);
+        return;
+    }
+
+    Con *con_ws = con_get_workspace(con);
+
+    /* Disable any fullscreen container that would conflict the new one. */
+    Con *fullscreen = con_get_fullscreen_con(croot, CF_GLOBAL);
+    if (fullscreen == NULL)
+        fullscreen = con_get_fullscreen_con(con_ws, CF_OUTPUT);
+    if (fullscreen != NULL)
+        con_disable_fullscreen(fullscreen);
+
+    /* Set focus to new fullscreen container. Unless in global fullscreen mode
+     * and on another workspace restore focus afterwards.
+     * Switch to the container’s workspace if mode is global. */
+    Con *cur_ws = con_get_workspace(focused);
+    Con *old_focused = focused;
+    if (fullscreen_mode == CF_GLOBAL && cur_ws != con_ws)
+        workspace_show(con_ws);
+    con_focus(con);
+    if (fullscreen_mode != CF_GLOBAL && cur_ws != con_ws)
+        con_focus(old_focused);
+
+    con_set_fullscreen_mode(con, fullscreen_mode);
+}
+
+/*
+ * Disables fullscreen mode for the given container regardless of the mode, if
+ * necessary.
+ *
+ */
+void con_disable_fullscreen(Con *con) {
+    if (con->type == CT_WORKSPACE) {
+        DLOG("You cannot make a workspace fullscreen.\n");
+        return;
+    }
+
+    DLOG("disabling fullscreen for %p / %s\n", con, con->name);
+
+    if (con->fullscreen_mode == CF_NONE) {
+        DLOG("fullscreen already disabled for %p / %s\n", con, con->name);
+        return;
+    }
+
+    con_set_fullscreen_mode(con, CF_NONE);
+}
+
 /*
  * Moves the given container to the currently focused container on the given
  * workspace.
index 513dda3679b242c9236874fdd4624d82543cda4e..9d0b7d66b15e528286314623d15c0939832cf6e5 100644 (file)
@@ -20,7 +20,7 @@ bindsym Mod1+h split h
 bindsym Mod1+v split v
 
 # Fullscreen (Mod1+f)
-bindsym Mod1+f fullscreen
+bindsym Mod1+f fullscreen toggle
 
 # Stacking (Mod1+s)
 bindsym Mod1+s layout stacking
index bb9403b41ec4c44e5b1e0d64f4e3edcd5be88f6e..458fff935497e69f9d228ca078293eeb58fd918c 100644 (file)
@@ -255,4 +255,131 @@ $swindow = open_window({
 is(fullscreen_windows($tmp), 1, 'one fullscreen window on ws');
 is($x->input_focus, $swindow->id, 'fullscreen window focused');
 
+################################################################################
+# Verify that command ‘fullscreen enable’ works and is idempotent.
+################################################################################
+
+$tmp = fresh_workspace;
+
+$window = open_window;
+is($x->input_focus, $window->id, 'window focused');
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+cmd 'fullscreen enable';
+is($x->input_focus, $window->id, 'window still focused');
+is(fullscreen_windows($tmp), 1, 'one fullscreen window on workspace');
+
+cmd 'fullscreen enable';
+is($x->input_focus, $window->id, 'window still focused');
+is(fullscreen_windows($tmp), 1, 'still one fullscreen window on workspace');
+
+$window->fullscreen(0);
+sync_with_i3;
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+################################################################################
+# Verify that command ‘fullscreen enable global’ works and is idempotent.
+################################################################################
+
+$tmp = fresh_workspace;
+
+$window = open_window;
+is($x->input_focus, $window->id, 'window focused');
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+cmd 'fullscreen enable global';
+is($x->input_focus, $window->id, 'window still focused');
+is(fullscreen_windows($tmp), 1, 'one fullscreen window on workspace');
+
+cmd 'fullscreen enable global';
+is($x->input_focus, $window->id, 'window still focused');
+is(fullscreen_windows($tmp), 1, 'still one fullscreen window on workspace');
+
+$window->fullscreen(0);
+sync_with_i3;
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+################################################################################
+# Verify that command ‘fullscreen disable’ works and is idempotent.
+################################################################################
+
+$tmp = fresh_workspace;
+
+$window = open_window;
+is($x->input_focus, $window->id, 'window focused');
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+$window->fullscreen(1);
+sync_with_i3;
+is(fullscreen_windows($tmp), 1, 'one fullscreen window on workspace');
+
+cmd 'fullscreen disable';
+is($x->input_focus, $window->id, 'window still focused');
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+cmd 'fullscreen disable';
+is($x->input_focus, $window->id, 'window still focused');
+is(fullscreen_windows($tmp), 0, 'still no fullscreen window on workspace');
+
+################################################################################
+# Verify that command ‘fullscreen toggle’ works.
+################################################################################
+
+$tmp = fresh_workspace;
+
+$window = open_window;
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+cmd 'fullscreen toggle';
+is($x->input_focus, $window->id, 'window still focused');
+is(fullscreen_windows($tmp), 1, 'one fullscreen window on workspace');
+
+cmd 'fullscreen toggle';
+is($x->input_focus, $window->id, 'window still focused');
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+################################################################################
+# Verify that a window’s fullscreen is disabled when another one is enabled
+# on the same workspace. The new fullscreen window should be focused.
+################################################################################
+
+$tmp = fresh_workspace;
+
+$window = open_window;
+$other = open_window;
+
+is($x->input_focus, $other->id, 'other window focused');
+is(fullscreen_windows($tmp), 0, 'no fullscreen window on workspace');
+
+cmd 'fullscreen enable';
+is($x->input_focus, $other->id, 'other window focused');
+is(fullscreen_windows($tmp), 1, 'one fullscreen window on workspace');
+
+cmd '[id="' . $window->id . '"] fullscreen enable';
+is($x->input_focus, $window->id, 'window focused');
+is(fullscreen_windows($tmp), 1, 'one fullscreen window on workspace');
+
+################################################################################
+# Verify that when a global fullscreen is enabled the window is focused and
+# its workspace is selected, so that disabling the fullscreen keeps the window
+# focused and visible.
+################################################################################
+
+$tmp = fresh_workspace;
+
+$window = open_window;
+
+is($x->input_focus, $window->id, 'window focused');
+
+cmd 'workspace ' . get_unused_workspace;
+isnt($x->input_focus, $window->id, 'window not focused');
+isnt(focused_ws(), $tmp, 'workspace not selected');
+
+cmd '[id="' . $window->id . '"] fullscreen enable global';
+is($x->input_focus, $window->id, 'window focused');
+
+cmd 'fullscreen disable';
+is($x->input_focus, $window->id, 'window still focused');
+is(focused_ws(), $tmp, 'workspace selected');
+
 done_testing;