]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #2953 from CyberShadow/focus_wrapping
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Wed, 27 Sep 2017 16:31:39 +0000 (09:31 -0700)
committerGitHub <noreply@github.com>
Wed, 27 Sep 2017 16:31:39 +0000 (09:31 -0700)
Add "focus_wrapping" option

1  2 
docs/userguide
include/config_directives.h
include/data.h
parser-specs/config.spec
src/config_directives.c
src/tree.c
testcases/t/201-config-parser.t

diff --combined docs/userguide
index d682c1384de457f17db21f9825739929c6dd51f4,bfb3da661fc9e69eb3ce13cbb257a8eebf4792a8..5225c39149539342158c0774b93f54922419bc1d
@@@ -760,10 -760,6 +760,10 @@@ title change. As i3 will get the title 
  window (mapping means actually displaying it on the screen), you’d need to have
  to match on 'Firefox' in this case.
  
 +You can also assign a window to show up on a specific output. You can use RandR
 +names such as +VGA1+ or names relative to the output with the currently focused
 +workspace such as +left+ and +down+.
 +
  Assignments are processed by i3 in the order in which they appear in the config
  file. The first one which matches the window wins and later assignments are not
  considered.
  *Syntax*:
  ------------------------------------------------------------
  assign <criteria> [→] [workspace] [number] <workspace>
 +assign <criteria> [→] output left|right|up|down|primary|<output>
  ------------------------------------------------------------
  
  *Examples*:
@@@ -796,20 -791,9 +796,20 @@@ assign [class="^URxvt$"] → number "2
  
  # Start urxvt -name irssi
  assign [class="^URxvt$" instance="^irssi$"] → 3
 +
 +# Assign urxvt to the output right of the current one
 +assign [class="^URxvt$"] → output right
 +
 +# Assign urxvt to the primary output
 +assign [class="^URxvt$"] → output primary
  ----------------------
  
 -Note that the arrow is not required, it just looks good :-). If you decide to
 +Note that you might not have a primary output configured yet. To do so, run:
 +-------------------------
 +xrandr --output <output> --primary
 +-------------------------
 +
 +Also, the arrow is not required, it just looks good :-). If you decide to
  use it, it has to be a UTF-8 encoded arrow, not `->` or something like that.
  
  To get the class and instance, you can use +xprop+. After clicking on the
@@@ -824,7 -808,7 +824,7 @@@ The first part of the WM_CLASS is the i
  second part is the class ("URxvt" in this example).
  
  Should you have any problems with assignments, make sure to check the i3
 -logfile first (see http://i3wm.org/docs/debugging.html). It includes more
 +logfile first (see https://i3wm.org/docs/debugging.html). It includes more
  details about the matching process and the window’s actual class, instance and
  title when starting up.
  
@@@ -1055,30 -1039,43 +1055,43 @@@ popup_during_fullscreen smar
  
  === Focus wrapping
  
- When being in a tabbed or stacked container, the first container will be
- focused when you use +focus down+ on the last container -- the focus wraps. If
- however there is another stacked/tabbed container in that direction, focus will
- be set on that container. This is the default behavior so you can navigate to
- all your windows without having to use +focus parent+.
+ By default, when in a container with several windows or child containers, the
+ opposite window will be focused when trying to move the focus over the edge of
+ a container (and there are no other containers in that direction) -- the focus
+ wraps.
+ If desired, you can disable this behavior by setting the +focus_wrapping+
+ configuration directive to the value +no+.
+ When enabled, focus wrapping does not occur by default if there is another
+ window or container in the specified direction, and focus will instead be set
+ on that window or container. This is the default behavior so you can navigate
+ to all your windows without having to use +focus parent+.
  
  If you want the focus to *always* wrap and you are aware of using +focus
- parent+ to switch to different containers, you can use the
- +force_focus_wrapping+ configuration directive. After enabling it, the focus
- will always wrap.
+ parent+ to switch to different containers, you can instead set +focus_wrapping+
+ to the value +force+.
  
  *Syntax*:
  ---------------------------
- force_focus_wrapping yes|no
- ---------------------------
+ focus_wrapping yes|no|force
  
- *Example*:
- ------------------------
+ # Legacy syntax, equivalent to "focus_wrapping force"
  force_focus_wrapping yes
- ------------------------
+ ---------------------------
+ *Examples*:
+ -----------------
+ # Disable focus wrapping
+ focus_wrapping no
+ # Force focus wrapping
+ focus_wrapping force
+ -----------------
  
  === Forcing Xinerama
  
 -As explained in-depth in <http://i3wm.org/docs/multi-monitor.html>, some X11
 +As explained in-depth in <https://i3wm.org/docs/multi-monitor.html>, some X11
  video drivers (especially the nVidia binary driver) only provide support for
  Xinerama instead of RandR. In such a situation, i3 must be told to use the
  inferior Xinerama API explicitly and therefore don’t provide support for
@@@ -2254,6 -2251,7 +2267,6 @@@ bindsym $mod+x move container to outpu
  bindsym $mod+x move container to output primary
  --------------------------------------------------------
  
 --------------------------------
  Note that you might not have a primary output configured yet. To do so, run:
  -------------------------
  xrandr --output <output> --primary
@@@ -2469,7 -2467,7 +2482,7 @@@ bindsym $mod+u border non
  [[shmlog]]
  === Enabling shared memory logging
  
 -As described in http://i3wm.org/docs/debugging.html, i3 can log to a shared
 +As described in https://i3wm.org/docs/debugging.html, i3 can log to a shared
  memory buffer, which you can dump using +i3-dump-log+. The +shmlog+ command
  allows you to enable or disable the shared memory logging at runtime.
  
index 5318bae809cbc45eba158f93b4902a4ae92b6ea9,66defa8f9f07cf71f687d7fe1625e5551fe58300..1191a7c6e34a476da70e286e16f0f39f4b4b1cac
@@@ -49,6 -49,7 +49,7 @@@ CFGFUN(workspace_layout, const char *la
  CFGFUN(workspace_back_and_forth, const char *value);
  CFGFUN(focus_follows_mouse, const char *value);
  CFGFUN(mouse_warping, const char *value);
+ CFGFUN(focus_wrapping, const char *value);
  CFGFUN(force_focus_wrapping, const char *value);
  CFGFUN(force_xinerama, const char *value);
  CFGFUN(disable_randr15, const char *value);
@@@ -57,7 -58,6 +58,7 @@@ CFGFUN(force_display_urgency_hint, cons
  CFGFUN(focus_on_window_activation, const char *mode);
  CFGFUN(show_marks, const char *value);
  CFGFUN(hide_edge_borders, const char *borders);
 +CFGFUN(assign_output, const char *output);
  CFGFUN(assign, const char *workspace, bool is_number);
  CFGFUN(no_focus);
  CFGFUN(ipc_socket, const char *path);
diff --combined include/data.h
index 632dfb4f04c98191a0b9c11405e7a0cff0c074a4,258ea94fe06ec357f22904df50c220864e2b639f..69a46e464331172172873a70940af6d348cb09bd
@@@ -132,6 -132,15 +132,15 @@@ typedef enum 
      POINTER_WARPING_OUTPUT = 0,
      POINTER_WARPING_NONE = 1
  } warping_t;
+ /**
+  * Focus wrapping modes.
+  */
+ typedef enum {
+     FOCUS_WRAPPING_OFF = 0,
+     FOCUS_WRAPPING_ON = 1,
+     FOCUS_WRAPPING_FORCE = 2
+ } focus_wrapping_t;
  
  /**
   * Stores a rectangle, for example the size of a window, the child window etc.
@@@ -557,8 -566,7 +566,8 @@@ struct Assignment 
          A_COMMAND = (1 << 0),
          A_TO_WORKSPACE = (1 << 1),
          A_NO_FOCUS = (1 << 2),
 -        A_TO_WORKSPACE_NUMBER = (1 << 3)
 +        A_TO_WORKSPACE_NUMBER = (1 << 3),
 +        A_TO_OUTPUT = (1 << 4)
      } type;
  
      /** the criteria to check if a window matches */
      union {
          char *command;
          char *workspace;
 +        char *output;
      } dest;
  
      TAILQ_ENTRY(Assignment)
diff --combined parser-specs/config.spec
index 8c89b3f912024a6695d2a7f13687cf8bcbf1d6c3,6b8265437c4c6bc450b013276d41807522694fbb..c31567a64b87d29dc340cd821621f15c2636fb45
@@@ -36,6 -36,7 +36,7 @@@ state INITIAL
    'no_focus'                               -> NO_FOCUS
    'focus_follows_mouse'                    -> FOCUS_FOLLOWS_MOUSE
    'mouse_warping'                          -> MOUSE_WARPING
+   'focus_wrapping'                         -> FOCUS_WRAPPING
    'force_focus_wrapping'                   -> FORCE_FOCUS_WRAPPING
    'force_xinerama', 'force-xinerama'       -> FORCE_XINERAMA
    'disable_randr15', 'disable-randr15'     -> DISABLE_RANDR15
@@@ -141,7 -142,7 +142,7 @@@ state FOR_WINDOW_COMMAND
    command = string
        -> call cfg_for_window($command)
  
 -# assign <criteria> [→] workspace
 +# assign <criteria> [→] [workspace | output] <name>
  state ASSIGN:
    '['
        -> call cfg_criteria_init(ASSIGN_WORKSPACE); CRITERIA
  state ASSIGN_WORKSPACE:
    '→'
        ->
 +  'output'
 +      -> ASSIGN_OUTPUT
    'workspace'
        ->
    'number'
    workspace = string
        -> call cfg_assign($workspace, 0)
  
 +state ASSIGN_OUTPUT:
 +  output = string
 +      -> call cfg_assign_output($output)
 +
  state ASSIGN_WORKSPACE_NUMBER:
    number = string
        -> call cfg_assign($number, 1)
@@@ -209,6 -204,11 +210,11 @@@ state MOUSE_WARPING
    value = 'none', 'output'
        -> call cfg_mouse_warping($value)
  
+ # focus_wrapping
+ state FOCUS_WRAPPING:
+   value = '1', 'yes', 'true', 'on', 'enable', 'active', '0', 'no', 'false', 'off', 'disable', 'inactive', 'force'
+       -> call cfg_focus_wrapping($value)
  # force_focus_wrapping
  state FORCE_FOCUS_WRAPPING:
    value = word
diff --combined src/config_directives.c
index c981ff60910729c57aec228d289e18e7ea37362c,8d5cf1f050069164aa5541084190062fc275291a..1cf875ef00aeaf5d30c52f9944f84217a99fc19b
@@@ -264,8 -264,27 +264,27 @@@ CFGFUN(disable_randr15, const char *val
      config.disable_randr15 = eval_boolstr(value);
  }
  
+ CFGFUN(focus_wrapping, const char *value) {
+     if (strcmp(value, "force") == 0) {
+         config.focus_wrapping = FOCUS_WRAPPING_FORCE;
+     } else if (eval_boolstr(value)) {
+         config.focus_wrapping = FOCUS_WRAPPING_ON;
+     } else {
+         config.focus_wrapping = FOCUS_WRAPPING_OFF;
+     }
+ }
  CFGFUN(force_focus_wrapping, const char *value) {
-     config.force_focus_wrapping = eval_boolstr(value);
+     /* Legacy syntax. */
+     if (eval_boolstr(value)) {
+         config.focus_wrapping = FOCUS_WRAPPING_FORCE;
+     } else {
+         /* For "force_focus_wrapping off", don't enable or disable
+          * focus wrapping, just ensure it's not forced. */
+         if (config.focus_wrapping == FOCUS_WRAPPING_FORCE) {
+             config.focus_wrapping = FOCUS_WRAPPING_ON;
+         }
+     }
  }
  
  CFGFUN(workspace_back_and_forth, const char *value) {
@@@ -377,20 -396,6 +396,20 @@@ CFGFUN(color, const char *colorclass, c
  #undef APPLY_COLORS
  }
  
 +CFGFUN(assign_output, const char *output) {
 +    if (match_is_empty(current_match)) {
 +        ELOG("Match is empty, ignoring this assignment\n");
 +        return;
 +    }
 +
 +    DLOG("New assignment, using above criteria, to output \"%s\".\n", output);
 +    Assignment *assignment = scalloc(1, sizeof(Assignment));
 +    match_copy(&(assignment->match), current_match);
 +    assignment->type = A_TO_OUTPUT;
 +    assignment->dest.output = sstrdup(output);
 +    TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
 +}
 +
  CFGFUN(assign, const char *workspace, bool is_number) {
      if (match_is_empty(current_match)) {
          ELOG("Match is empty, ignoring this assignment\n");
diff --combined src/tree.c
index d5f457dd24dc268921ff89acf8c2dd76499035cb,fc9526e6d196e65a01016c9a500e6ec0b079eec1..a6cc59fbb8faf8260e21719edba5bb85e164fc85
@@@ -266,7 -266,7 +266,7 @@@ bool tree_close_internal(Con *con, kill
               * will be mapped when i3 closes its connection (e.g. when
               * restarting). This is not what we want, since some apps keep
               * unmapped windows around and don’t expect them to suddenly be
 -             * mapped. See http://bugs.i3wm.org/1617 */
 +             * mapped. See https://bugs.i3wm.org/1617 */
              xcb_change_save_set(conn, XCB_SET_MODE_DELETE, con->window->id);
  
              /* Ignore X11 errors for the ReparentWindow request.
@@@ -641,7 -641,7 +641,7 @@@ static bool _tree_next(Con *con, char w
          next = TAILQ_PREV(current, nodes_head, nodes);
  
      if (!next) {
-         if (!config.force_focus_wrapping) {
+         if (config.focus_wrapping != FOCUS_WRAPPING_FORCE) {
              /* If there is no next/previous container, we check if we can focus one
               * when going higher (without wrapping, though). If so, we are done, if
               * not, we wrap */
   *
   */
  void tree_next(char way, orientation_t orientation) {
-     _tree_next(focused, way, orientation, true);
+     _tree_next(focused, way, orientation,
+                config.focus_wrapping != FOCUS_WRAPPING_OFF);
  }
  
  /*
index 861f8a35b3ffc9cc0074bc5cb8bb69e422690779,3e2c42972bdb96c1f86c6fd9236751938df037ec..ece7e9b9a35012e68cb0f41b98e1c4ee05c421d9
@@@ -2,13 -2,13 +2,13 @@@
  # vim:ts=4:sw=4:expandtab
  #
  # Please read the following documents before working on tests:
 -# • http://build.i3wm.org/docs/testsuite.html
 +# • https://build.i3wm.org/docs/testsuite.html
  #   (or docs/testsuite)
  #
 -# • http://build.i3wm.org/docs/lib-i3test.html
 +# • https://build.i3wm.org/docs/lib-i3test.html
  #   (alternatively: perldoc ./testcases/lib/i3test.pm)
  #
 -# • http://build.i3wm.org/docs/ipc.html
 +# • https://build.i3wm.org/docs/ipc.html
  #   (or docs/ipc)
  #
  # • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
@@@ -470,6 -470,7 +470,7 @@@ my $expected_all_tokens = "ERROR: CONFI
          no_focus
          focus_follows_mouse
          mouse_warping
+         focus_wrapping
          force_focus_wrapping
          force_xinerama
          force-xinerama